diff --git a/multimedia/compat-ffmpeg5/0001-lavc-libopenh264-Drop-openh264-runtime-version-check.patch b/multimedia/compat-ffmpeg5/0001-lavc-libopenh264-Drop-openh264-runtime-version-check.patch new file mode 100644 index 0000000..7066f16 --- /dev/null +++ b/multimedia/compat-ffmpeg5/0001-lavc-libopenh264-Drop-openh264-runtime-version-check.patch @@ -0,0 +1,109 @@ +From a641e629591d68bd3edd99bddec623dc31295f6b Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Wed, 6 Dec 2023 14:37:34 +0100 +Subject: [PATCH] lavc/libopenh264: Drop openh264 runtime version checks + +Years ago, openh264 releases often changed their ABI without changing +the library soname. To avoid running into ABI issues, a version check +was added to lavc libopenh264 code to error out at runtime in case the +build time and runtime openh264 versions don't match. + +This should no longer be an issue with newer openh264 releases and we +can drop the runtime version check and rely on upstream doing the right +thing and bump the library soname if the ABI changes, similar to how +other libraries are consumed in ffmpeg. + +Almost all major distributions now include openh264 and this means there +are more eyes on ABI changes and issues are discovered and reported +quickly. See e.g. https://github.com/cisco/openh264/issues/3564 where an +ABI issue was quickly discovered and fixed. + +Relaxing the check allows downstream distributions to build ffmpeg +against e.g. openh264 2.3.1 and ship an update to ABI-compatible +openh264 2.4.0, without needing to coordinate a lock step update between +ffmpeg and openh264 (which can be difficult if openh264 is distributed +by Cisco and ffmpeg comes from the distro, such as is the case for +Fedora). + +Signed-off-by: Kalev Lember +--- + libavcodec/libopenh264.c | 15 --------------- + libavcodec/libopenh264.h | 2 -- + libavcodec/libopenh264dec.c | 4 ---- + libavcodec/libopenh264enc.c | 4 ---- + 4 files changed, 25 deletions(-) + +diff --git a/libavcodec/libopenh264.c b/libavcodec/libopenh264.c +index 0f6d28ed88..c80c85ea8b 100644 +--- a/libavcodec/libopenh264.c ++++ b/libavcodec/libopenh264.c +@@ -46,18 +46,3 @@ void ff_libopenh264_trace_callback(void *ctx, int level, const char *msg) + int equiv_ffmpeg_log_level = libopenh264_to_ffmpeg_log_level(level); + av_log(ctx, equiv_ffmpeg_log_level, "%s\n", msg); + } +- +-int ff_libopenh264_check_version(void *logctx) +-{ +- // Mingw GCC < 4.7 on x86_32 uses an incorrect/buggy ABI for the WelsGetCodecVersion +- // function (for functions returning larger structs), thus skip the check in those +- // configurations. +-#if !defined(_WIN32) || !defined(__GNUC__) || !ARCH_X86_32 || AV_GCC_VERSION_AT_LEAST(4, 7) +- OpenH264Version libver = WelsGetCodecVersion(); +- if (memcmp(&libver, &g_stCodecVersion, sizeof(libver))) { +- av_log(logctx, AV_LOG_ERROR, "Incorrect library version loaded\n"); +- return AVERROR(EINVAL); +- } +-#endif +- return 0; +-} +diff --git a/libavcodec/libopenh264.h b/libavcodec/libopenh264.h +index dbb9c5d429..0b462d6fdc 100644 +--- a/libavcodec/libopenh264.h ++++ b/libavcodec/libopenh264.h +@@ -34,6 +34,4 @@ + + void ff_libopenh264_trace_callback(void *ctx, int level, const char *msg); + +-int ff_libopenh264_check_version(void *logctx); +- + #endif /* AVCODEC_LIBOPENH264_H */ +diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c +index 7d650ae03e..b6a9bba2dc 100644 +--- a/libavcodec/libopenh264dec.c ++++ b/libavcodec/libopenh264dec.c +@@ -52,13 +52,9 @@ static av_cold int svc_decode_init(AVCodecContext *avctx) + { + SVCContext *s = avctx->priv_data; + SDecodingParam param = { 0 }; +- int err; + int log_level; + WelsTraceCallback callback_function; + +- if ((err = ff_libopenh264_check_version(avctx)) < 0) +- return AVERROR_DECODER_NOT_FOUND; +- + if (WelsCreateDecoder(&s->decoder)) { + av_log(avctx, AV_LOG_ERROR, "Unable to create decoder\n"); + return AVERROR_UNKNOWN; +diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c +index f518d0894e..6f231d22b2 100644 +--- a/libavcodec/libopenh264enc.c ++++ b/libavcodec/libopenh264enc.c +@@ -110,14 +110,10 @@ static av_cold int svc_encode_init(AVCodecContext *avctx) + { + SVCContext *s = avctx->priv_data; + SEncParamExt param = { 0 }; +- int err; + int log_level; + WelsTraceCallback callback_function; + AVCPBProperties *props; + +- if ((err = ff_libopenh264_check_version(avctx)) < 0) +- return AVERROR_ENCODER_NOT_FOUND; +- + if (WelsCreateSVCEncoder(&s->encoder)) { + av_log(avctx, AV_LOG_ERROR, "Unable to create encoder\n"); + return AVERROR_UNKNOWN; +-- +2.43.0 + diff --git a/multimedia/compat-ffmpeg5/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch b/multimedia/compat-ffmpeg5/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch new file mode 100644 index 0000000..3e1c9e3 --- /dev/null +++ b/multimedia/compat-ffmpeg5/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch @@ -0,0 +1,674 @@ +From 673e67dfff221da589e28216927fe5efd5b40586 Mon Sep 17 00:00:00 2001 +From: Jing Sun +Date: Wed, 21 Nov 2018 11:33:04 +0800 +Subject: [PATCH] lavc/svt_hevc: add libsvt hevc encoder wrapper + +Signed-off-by: Zhengxu Huang +Signed-off-by: Hassene Tmar +Signed-off-by: Jun Zhao +Signed-off-by: Jing Sun +Signed-off-by: Austin Hu +Signed-off-by: Christopher Degawa +Signed-off-by: Guo Jiansheng +--- + configure | 4 + + libavcodec/Makefile | 1 + + libavcodec/allcodecs.c | 1 + + libavcodec/libsvt_hevc.c | 585 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 591 insertions(+) + create mode 100644 libavcodec/libsvt_hevc.c + +diff --git a/configure b/configure +index c726076da1..c00fcd0294 100755 +--- a/configure ++++ b/configure +@@ -291,6 +291,7 @@ External library support: + --enable-libwebp enable WebP encoding via libwebp [no] + --enable-libx264 enable H.264 encoding via x264 [no] + --enable-libx265 enable HEVC encoding via x265 [no] ++ --enable-libsvthevc enable HEVC encoding via svt [no] + --enable-libxavs enable AVS encoding via xavs [no] + --enable-libxavs2 enable AVS2 encoding via xavs2 [no] + --enable-libxcb enable X11 grabbing using XCB [autodetect] +@@ -1852,6 +1853,7 @@ EXTERNAL_LIBRARY_LIST=" + libsrt + libssh + libsvtav1 ++ libsvthevc + libtensorflow + libtesseract + libtheora +@@ -3404,6 +3406,7 @@ vapoursynth_demuxer_deps="vapoursynth" + videotoolbox_suggest="coreservices" + videotoolbox_deps="corefoundation coremedia corevideo" + videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames" ++libsvt_hevc_encoder_deps="libsvthevc" + + # demuxers / muxers + ac3_demuxer_select="ac3_parser" +@@ -6678,6 +6681,7 @@ enabled libssh && require_pkg_config libssh libssh libssh/sftp.h sftp + enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init + enabled libsrt && require_pkg_config libsrt "srt >= 1.3.0" srt/srt.h srt_socket + enabled libsvtav1 && require_pkg_config libsvtav1 "SvtAv1Enc >= 0.9.0" EbSvtAv1Enc.h svt_av1_enc_init_handle ++enabled libsvthevc && require_pkg_config libsvthevc SvtHevcEnc EbApi.h EbInitHandle + enabled libtensorflow && require libtensorflow tensorflow/c/c_api.h TF_Version -ltensorflow + enabled libtesseract && require_pkg_config libtesseract tesseract tesseract/capi.h TessBaseAPICreate + enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index 1fb963f820..77c9926ea6 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1126,6 +1126,7 @@ OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o libwebpenc_anim + OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o + OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o + OBJS-$(CONFIG_LIBX265_ENCODER) += libx265.o ++OBJS-$(CONFIG_LIBSVT_HEVC_ENCODER) += libsvt_hevc.o + OBJS-$(CONFIG_LIBXAVS_ENCODER) += libxavs.o + OBJS-$(CONFIG_LIBXAVS2_ENCODER) += libxavs2.o + OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o +diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c +index ff82423a88..57f085415c 100644 +--- a/libavcodec/allcodecs.c ++++ b/libavcodec/allcodecs.c +@@ -812,6 +812,7 @@ extern LIBX264_CONST FFCodec ff_libx264_encoder; + #endif + extern const FFCodec ff_libx264rgb_encoder; + extern FFCodec ff_libx265_encoder; ++extern FFCodec ff_libsvt_hevc_encoder; + extern const FFCodec ff_libxavs_encoder; + extern const FFCodec ff_libxavs2_encoder; + extern const FFCodec ff_libxvid_encoder; +diff --git a/libavcodec/libsvt_hevc.c b/libavcodec/libsvt_hevc.c +new file mode 100644 +index 0000000000..739144ca0c +--- /dev/null ++++ b/libavcodec/libsvt_hevc.c +@@ -0,0 +1,585 @@ ++/* ++* Scalable Video Technology for HEVC encoder library plugin ++* ++* Copyright (c) 2019 Intel Corporation ++* ++* This file is part of FFmpeg. ++* ++* FFmpeg is free software; you can redistribute it and/or ++* modify it under the terms of the GNU Lesser General Public ++* License as published by the Free Software Foundation; either ++* version 2.1 of the License, or (at your option) any later version. ++* ++* FFmpeg is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++* Lesser General Public License for more details. ++* ++* You should have received a copy of the GNU Lesser General Public ++* License along with this program; if not, write to the Free Software ++* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++*/ ++ ++#include "EbApi.h" ++ ++#include "libavutil/common.h" ++#include "libavutil/frame.h" ++#include "libavutil/opt.h" ++ ++#include "codec_internal.h" ++#include "internal.h" ++#include "avcodec.h" ++#include "encode.h" ++ ++typedef enum eos_status { ++ EOS_NOT_REACHED = 0, ++ EOS_SENT, ++ EOS_RECEIVED ++}EOS_STATUS; ++ ++typedef struct SvtContext { ++ AVClass *class; ++ ++ EB_H265_ENC_CONFIGURATION enc_params; ++ EB_COMPONENTTYPE *svt_handle; ++ EB_BUFFERHEADERTYPE in_buf; ++ uint8_t *in_data; ++ EOS_STATUS eos_flag; ++ ++ // User options. ++ int profile; ++ int hierarchical_level; ++ int enc_mode; ++ int tier; ++ int level; ++ int rc_mode; ++ int scd; ++ int tune; ++ int base_layer_switch_mode; ++ int qp; ++ int aud; ++ int asm_type; ++ int forced_idr; ++ int la_depth; ++ int thread_count; ++ int target_socket; ++ int high_dynamic_range; ++ int unrestricted_motion_vector; ++ int tile_row_count; ++ int tile_col_count; ++ int tile_slice_mode; ++ int pred_struct; ++ int vid_info; ++} SvtContext; ++ ++static int error_mapping(EB_ERRORTYPE svt_ret) ++{ ++ switch (svt_ret) { ++ case EB_ErrorInsufficientResources: ++ return AVERROR(ENOMEM); ++ ++ case EB_ErrorUndefined: ++ case EB_ErrorInvalidComponent: ++ case EB_ErrorBadParameter: ++ return AVERROR(EINVAL); ++ ++ case EB_ErrorDestroyThreadFailed: ++ case EB_ErrorSemaphoreUnresponsive: ++ case EB_ErrorDestroySemaphoreFailed: ++ case EB_ErrorCreateMutexFailed: ++ case EB_ErrorMutexUnresponsive: ++ case EB_ErrorDestroyMutexFailed: ++ return AVERROR_EXTERNAL; ++ ++ case EB_NoErrorEmptyQueue: ++ return AVERROR(EAGAIN); ++ ++ case EB_ErrorNone: ++ return 0; ++ ++ default: ++ return AVERROR_UNKNOWN; ++ } ++} ++ ++static void free_buffer(SvtContext *svt_enc) ++{ ++ if (svt_enc && svt_enc->in_data) { ++ av_freep(&svt_enc->in_data); ++ svt_enc->in_data = NULL; ++ } ++} ++ ++static EB_ERRORTYPE alloc_buffer(SvtContext *svt_enc) ++{ ++ EB_BUFFERHEADERTYPE *in_buf = &svt_enc->in_buf; ++ EB_H265_ENC_INPUT *in_data = NULL; ++ ++ memset(in_buf, 0, sizeof(*in_buf)); ++ in_buf->nSize = sizeof(*in_buf); ++ in_buf->sliceType = EB_INVALID_PICTURE; ++ ++ in_data = (EB_H265_ENC_INPUT *)av_mallocz(sizeof(*in_data)); ++ if (in_data) { ++ svt_enc->in_data = in_buf->pBuffer = (uint8_t *)in_data; ++ return EB_ErrorNone; ++ } else { ++ return EB_ErrorInsufficientResources; ++ } ++} ++ ++static int config_enc_params(EB_H265_ENC_CONFIGURATION *param, ++ AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ ++ param->sourceWidth = avctx->width; ++ param->sourceHeight = avctx->height; ++ ++ if ((avctx->pix_fmt == AV_PIX_FMT_YUV420P10) || ++ (avctx->pix_fmt == AV_PIX_FMT_YUV422P10) || ++ (avctx->pix_fmt == AV_PIX_FMT_YUV444P10)) { ++ av_log(avctx, AV_LOG_DEBUG, "Set 10 bits depth input\n"); ++ param->encoderBitDepth = 10; ++ } else { ++ av_log(avctx, AV_LOG_DEBUG, "Set 8 bits depth input\n"); ++ param->encoderBitDepth = 8; ++ } ++ ++ if ((avctx->pix_fmt == AV_PIX_FMT_YUV420P) || ++ (avctx->pix_fmt == AV_PIX_FMT_YUV420P10)) ++ param->encoderColorFormat = EB_YUV420; ++ else if ((avctx->pix_fmt == AV_PIX_FMT_YUV422P) || ++ (avctx->pix_fmt == AV_PIX_FMT_YUV422P10)) ++ param->encoderColorFormat = EB_YUV422; ++ else ++ param->encoderColorFormat = EB_YUV444; ++ ++ param->profile = svt_enc->profile; ++ ++ if (FF_PROFILE_HEVC_MAIN_STILL_PICTURE == param->profile) { ++ av_log(avctx, AV_LOG_ERROR, "Main Still Picture Profile not supported\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if ((param->encoderColorFormat >= EB_YUV422) && ++ (param->profile != FF_PROFILE_HEVC_REXT)) { ++ av_log(avctx, AV_LOG_WARNING, "Rext Profile forced for 422 or 444\n"); ++ param->profile = FF_PROFILE_HEVC_REXT; ++ } ++ ++ if ((FF_PROFILE_HEVC_MAIN == param->profile) && ++ (param->encoderBitDepth > 8)) { ++ av_log(avctx, AV_LOG_WARNING, "Main10 Profile forced for 10 bits\n"); ++ param->profile = FF_PROFILE_HEVC_MAIN_10; ++ } ++ ++ param->targetBitRate = avctx->bit_rate; ++ param->vbvMaxrate = avctx->rc_max_rate; ++ param->vbvBufsize = avctx->rc_buffer_size; ++ ++ if (avctx->gop_size > 0) ++ param->intraPeriodLength = avctx->gop_size - 1; ++ ++ if ((avctx->framerate.num > 0) && (avctx->framerate.den > 0)) { ++ param->frameRateNumerator = avctx->framerate.num; ++ param->frameRateDenominator = ++ avctx->framerate.den * avctx->ticks_per_frame; ++ } else { ++ param->frameRateNumerator = avctx->time_base.den; ++ param->frameRateDenominator = ++ avctx->time_base.num * avctx->ticks_per_frame; ++ } ++ ++ param->hierarchicalLevels = svt_enc->hierarchical_level; ++ param->encMode = svt_enc->enc_mode; ++ param->tier = svt_enc->tier; ++ param->level = svt_enc->level; ++ param->rateControlMode = svt_enc->rc_mode; ++ param->sceneChangeDetection = svt_enc->scd; ++ param->tune = svt_enc->tune; ++ param->baseLayerSwitchMode = svt_enc->base_layer_switch_mode; ++ param->qp = svt_enc->qp; ++ param->accessUnitDelimiter = svt_enc->aud; ++ param->asmType = svt_enc->asm_type; ++ param->intraRefreshType = svt_enc->forced_idr; ++ param->highDynamicRangeInput = svt_enc->high_dynamic_range; ++ param->targetSocket = svt_enc->target_socket; ++ if (param->rateControlMode) { ++ param->maxQpAllowed = avctx->qmax; ++ param->minQpAllowed = avctx->qmin; ++ } ++ ++ if (svt_enc->la_depth != -1) ++ param->lookAheadDistance = svt_enc->la_depth; ++ ++ if ((svt_enc->thread_count > 0) && ++ (svt_enc->thread_count < (EB_THREAD_COUNT_MIN_CORE * EB_THREAD_COUNT_FACTOR))) { ++ param->threadCount = EB_THREAD_COUNT_MIN_CORE * EB_THREAD_COUNT_FACTOR; ++ av_log(avctx, AV_LOG_WARNING, "Thread count is set too small, forced to %"PRId32"\n", ++ param->threadCount); ++ } else if (svt_enc->thread_count % EB_THREAD_COUNT_MIN_CORE) { ++ param->threadCount = (svt_enc->thread_count + EB_THREAD_COUNT_MIN_CORE - 1) ++ / EB_THREAD_COUNT_MIN_CORE * EB_THREAD_COUNT_MIN_CORE; ++ av_log(avctx, AV_LOG_DEBUG, "Thread count is rounded to %"PRId32"\n", ++ param->threadCount); ++ } else { ++ param->threadCount = svt_enc->thread_count; ++ } ++ ++ if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) ++ param->codeVpsSpsPps = 0; ++ else ++ param->codeVpsSpsPps = 1; ++ ++ param->codeEosNal = 1; ++ ++ if (svt_enc->unrestricted_motion_vector == 0 || svt_enc->unrestricted_motion_vector == 1) { ++ param->unrestrictedMotionVector = svt_enc->unrestricted_motion_vector; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Unrestricted Motion Vector should be set 0 or 1\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if(svt_enc->tile_row_count >= 1 && svt_enc->tile_row_count <= 16) { ++ param->tileRowCount = svt_enc->tile_row_count; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Tile Row Count should between 1-16\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if(svt_enc->tile_col_count >= 1 && svt_enc->tile_col_count <= 16) { ++ param->tileColumnCount = svt_enc->tile_col_count; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Tile Column Count should between 1-16\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if(svt_enc->tile_slice_mode == 0 || svt_enc->tile_slice_mode == 1) { ++ param->tileSliceMode = svt_enc->tile_slice_mode; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Tile Slice Mode should be set 0 or 1\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if(svt_enc->pred_struct >= 0 && svt_enc->pred_struct <= 2) { ++ param->predStructure = svt_enc->pred_struct; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Pred Structure should between 0-2\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if(svt_enc->vid_info == 0 || svt_enc->vid_info == 1) { ++ param->videoUsabilityInfo = svt_enc->vid_info; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Video Usability Info should be set 0 or 1\n"); ++ return EB_ErrorBadParameter; ++ } ++ return EB_ErrorNone; ++} ++ ++static void read_in_data(EB_H265_ENC_CONFIGURATION *config, ++ const AVFrame *frame, ++ EB_BUFFERHEADERTYPE *header_ptr) ++{ ++ uint8_t is16bit; ++ uint64_t frame_size; ++ EB_H265_ENC_INPUT *in_data = (EB_H265_ENC_INPUT *)header_ptr->pBuffer; ++ ++ is16bit = config->encoderBitDepth > 8; ++ frame_size = (uint64_t)(config->sourceWidth * config->sourceHeight) << is16bit; ++ ++ in_data->luma = frame->data[0]; ++ in_data->cb = frame->data[1]; ++ in_data->cr = frame->data[2]; ++ ++ in_data->yStride = frame->linesize[0] >> is16bit; ++ in_data->cbStride = frame->linesize[1] >> is16bit; ++ in_data->crStride = frame->linesize[2] >> is16bit; ++ ++ if (config->encoderColorFormat == EB_YUV420) ++ frame_size *= 3/2u; ++ else if (config->encoderColorFormat == EB_YUV422) ++ frame_size *= 2u; ++ else ++ frame_size *= 3u; ++ ++ header_ptr->nFilledLen += frame_size; ++} ++ ++static av_cold int eb_enc_init(AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ EB_ERRORTYPE svt_ret; ++ ++ svt_enc->eos_flag = EOS_NOT_REACHED; ++ ++ svt_ret = EbInitHandle(&svt_enc->svt_handle, svt_enc, &svt_enc->enc_params); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to init handle\n"); ++ return error_mapping(svt_ret); ++ } ++ ++ svt_ret = config_enc_params(&svt_enc->enc_params, avctx); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to config parameters\n"); ++ goto failed_init_handle; ++ } ++ ++ svt_ret = EbH265EncSetParameter(svt_enc->svt_handle, &svt_enc->enc_params); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to set parameters\n"); ++ goto failed_init_handle; ++ } ++ ++ svt_ret = EbInitEncoder(svt_enc->svt_handle); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to init encoder\n"); ++ goto failed_init_handle; ++ } ++ ++ if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { ++ EB_BUFFERHEADERTYPE *header_ptr = NULL; ++ ++ svt_ret = EbH265EncStreamHeader(svt_enc->svt_handle, &header_ptr); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to build stream header\n"); ++ goto failed_init_encoder; ++ } ++ ++ avctx->extradata_size = header_ptr->nFilledLen; ++ avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); ++ if (!avctx->extradata) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to allocate extradata\n"); ++ svt_ret = EB_ErrorInsufficientResources; ++ goto failed_init_encoder; ++ } ++ memcpy(avctx->extradata, header_ptr->pBuffer, avctx->extradata_size); ++ memset(avctx->extradata+avctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++ } ++ ++ svt_ret = alloc_buffer(svt_enc); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to alloc data buffer\n"); ++ goto failed_init_encoder; ++ } ++ return 0; ++ ++failed_init_encoder: ++ EbDeinitEncoder(svt_enc->svt_handle); ++failed_init_handle: ++ EbDeinitHandle(svt_enc->svt_handle); ++ svt_enc->svt_handle = NULL; ++ svt_enc = NULL; ++ return error_mapping(svt_ret); ++} ++ ++static int eb_encode_frame(AVCodecContext *avctx, AVPacket *pkt, ++ const AVFrame *frame, int *got_packet) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ EB_BUFFERHEADERTYPE *header_ptr = &svt_enc->in_buf; ++ EB_ERRORTYPE svt_ret; ++ int av_ret; ++ ++ if (EOS_RECEIVED == svt_enc->eos_flag) { ++ *got_packet = 0; ++ return 0; ++ } ++ ++ if (!frame) { ++ if (!svt_enc->eos_flag) { ++ svt_enc->eos_flag = EOS_SENT; ++ ++ header_ptr->nAllocLen = 0; ++ header_ptr->nFilledLen = 0; ++ header_ptr->nTickCount = 0; ++ header_ptr->nFlags = EB_BUFFERFLAG_EOS; ++ header_ptr->pBuffer = NULL; ++ ++ EbH265EncSendPicture(svt_enc->svt_handle, header_ptr); ++ ++ av_log(avctx, AV_LOG_DEBUG, "Sent EOS\n"); ++ } ++ } else { ++ read_in_data(&svt_enc->enc_params, frame, header_ptr); ++ header_ptr->pts = frame->pts; ++ ++ EbH265EncSendPicture(svt_enc->svt_handle, header_ptr); ++ ++ av_log(avctx, AV_LOG_DEBUG, "Sent PTS %"PRId64"\n", header_ptr->pts); ++ } ++ ++ header_ptr = NULL; ++ svt_ret = EbH265GetPacket(svt_enc->svt_handle, &header_ptr, svt_enc->eos_flag); ++ ++ if (svt_ret == EB_NoErrorEmptyQueue) { ++ *got_packet = 0; ++ av_log(avctx, AV_LOG_DEBUG, "Received none\n"); ++ return 0; ++ } else if (svt_ret == EB_ErrorMax) { ++ *got_packet = 0; ++ av_log(avctx, AV_LOG_ERROR, "Received NULL packet with error code 0x%X\n", header_ptr->nFlags); ++ return AVERROR_INVALIDDATA; ++ } ++ ++ av_log(avctx, AV_LOG_DEBUG, "Received PTS %"PRId64" packet\n", header_ptr->pts); ++ ++ av_ret = ff_alloc_packet(avctx, pkt, header_ptr->nFilledLen); ++ if (av_ret) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to allocate a packet\n"); ++ EbH265ReleaseOutBuffer(&header_ptr); ++ return av_ret; ++ } ++ ++ memcpy(pkt->data, header_ptr->pBuffer, header_ptr->nFilledLen); ++ pkt->size = header_ptr->nFilledLen; ++ pkt->pts = header_ptr->pts; ++ pkt->dts = header_ptr->dts; ++ ++ if ((header_ptr->sliceType == EB_IDR_PICTURE) || ++ (header_ptr->sliceType == EB_I_PICTURE)) ++ pkt->flags |= AV_PKT_FLAG_KEY; ++ if (header_ptr->sliceType == EB_NON_REF_PICTURE) ++ pkt->flags |= AV_PKT_FLAG_DISPOSABLE; ++ ++ EbH265ReleaseOutBuffer(&header_ptr); ++ ++ *got_packet = 1; ++ ++ if (EB_BUFFERFLAG_EOS == header_ptr->nFlags) ++ svt_enc->eos_flag = EOS_RECEIVED; ++ ++ return 0; ++} ++ ++static av_cold int eb_enc_close(AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ ++ if (svt_enc) { ++ free_buffer(svt_enc); ++ ++ if (svt_enc->svt_handle) { ++ EbDeinitEncoder(svt_enc->svt_handle); ++ EbDeinitHandle(svt_enc->svt_handle); ++ svt_enc->svt_handle = NULL; ++ } ++ } ++ ++ return 0; ++} ++ ++#define OFFSET(x) offsetof(SvtContext, x) ++#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ++static const AVOption options[] = { ++ { "asm_type", "Assembly instruction set type [0: C Only, 1: Auto]", OFFSET(asm_type), ++ AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, ++ ++ { "aud", "Include Access Unit Delimiter", OFFSET(aud), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, ++ ++ { "bl_mode", "Random Access Prediction Structure type setting", OFFSET(base_layer_switch_mode), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, ++ ++ { "forced-idr", "If forcing keyframes, force them as IDR frames.", OFFSET(forced_idr), ++ AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE }, ++ ++ { "hielevel", "Hierarchical prediction levels setting", OFFSET(hierarchical_level), ++ AV_OPT_TYPE_INT, { .i64 = 3 }, 0, 3, VE , "hielevel"}, ++ { "flat", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "hielevel" }, ++ { "1 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "hielevel" }, ++ { "2 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "hielevel" }, ++ { "3 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 3 }, INT_MIN, INT_MAX, VE, "hielevel" }, ++ ++ { "la_depth", "Look ahead distance [0, 256]", OFFSET(la_depth), ++ AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 256, VE }, ++ ++ { "level", "Set level (level_idc)", OFFSET(level), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 0xff, VE, "level" }, ++ ++ { "preset", "Encoding preset [0, 12]", ++ OFFSET(enc_mode), AV_OPT_TYPE_INT, { .i64 = 7 }, 0, 12, VE }, ++ ++ { "profile", "Profile setting, Main Still Picture Profile not supported", OFFSET(profile), ++ AV_OPT_TYPE_INT, { .i64 = FF_PROFILE_HEVC_MAIN }, FF_PROFILE_HEVC_MAIN, FF_PROFILE_HEVC_REXT, VE, "profile"}, ++ ++ { "qp", "QP value for intra frames", OFFSET(qp), ++ AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 51, VE }, ++ ++ { "rc", "Bit rate control mode", OFFSET(rc_mode), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE , "rc"}, ++ { "cqp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "rc" }, ++ { "vbr", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "rc" }, ++ ++ { "sc_detection", "Scene change detection", OFFSET(scd), ++ AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, ++ ++ { "socket", "Target CPU socket to use. -1 use all available", OFFSET(target_socket), ++ AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 1, VE }, ++ ++ { "thread_count", "Number of threads [0: Auto, 96: Min]", OFFSET(thread_count), ++ AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, VE }, ++ ++ { "tier", "Set tier (general_tier_flag)", OFFSET(tier), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE, "tier" }, ++ { "main", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "tier" }, ++ { "high", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, VE, "tier" }, ++ ++ { "tune", "Quality tuning mode", OFFSET(tune), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 2, VE, "tune" }, ++ { "sq", "Visually optimized mode", 0, ++ AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "tune" }, ++ { "oq", "PSNR / SSIM optimized mode", 0, ++ AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "tune" }, ++ { "vmaf", "VMAF optimized mode", 0, ++ AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "tune" }, ++ { "hdr", "High dynamic range input (HDR10)", OFFSET(high_dynamic_range), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 1, VE, "hdr" }, ++ { "umv", "Enables or disables unrestricted motion vectors", OFFSET(unrestricted_motion_vector), ++ AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, ++ { "tile_row_cnt", "tile count in the row", OFFSET(tile_row_count), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 16, VE }, ++ { "tile_col_cnt", "tile count in the column", OFFSET(tile_col_count), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 16, VE }, ++ { "tile_slice_mode", "per slice per tile, only valid for multi-tile", OFFSET(tile_slice_mode), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, ++ { "pred_struct", "The prediction structure", OFFSET(pred_struct), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 2, VE }, ++ { "vid_info", "Enables or disables sending a vui structure in the HEVC Elementary bitstream.", OFFSET(vid_info), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, ++ {NULL}, ++}; ++ ++static const AVClass class = { ++ .class_name = "libsvt_hevc", ++ .item_name = av_default_item_name, ++ .option = options, ++ .version = LIBAVUTIL_VERSION_INT, ++}; ++ ++static const FFCodecDefault eb_enc_defaults[] = { ++ { "b", "7M" }, ++ { "qmin", "10" }, ++ { "qmax", "48" }, ++ { "g", "-2" }, ++ { NULL }, ++}; ++ ++FFCodec ff_libsvt_hevc_encoder = { ++ .p.name = "libsvt_hevc", ++ .p.long_name = NULL_IF_CONFIG_SMALL("SVT-HEVC(Scalable Video Technology for HEVC) encoder"), ++ .priv_data_size = sizeof(SvtContext), ++ .p.type = AVMEDIA_TYPE_VIDEO, ++ .p.id = AV_CODEC_ID_HEVC, ++ .init = eb_enc_init, ++ FF_CODEC_ENCODE_CB(eb_encode_frame), ++ .close = eb_enc_close, ++ .p.capabilities = AV_CODEC_CAP_DELAY, ++ .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, ++ AV_PIX_FMT_YUV420P10, ++ AV_PIX_FMT_YUV422P, ++ AV_PIX_FMT_YUV422P10, ++ AV_PIX_FMT_YUV444P, ++ AV_PIX_FMT_YUV444P10, ++ AV_PIX_FMT_NONE }, ++ .p.priv_class = &class, ++ .defaults = eb_enc_defaults, ++ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, ++ .p.wrapper_name = "libsvt_hevc", ++}; +-- +2.39.1 + diff --git a/multimedia/compat-ffmpeg5/0002-doc-Add-libsvt_hevc-encoder-docs.patch b/multimedia/compat-ffmpeg5/0002-doc-Add-libsvt_hevc-encoder-docs.patch new file mode 100644 index 0000000..0fd2b4a --- /dev/null +++ b/multimedia/compat-ffmpeg5/0002-doc-Add-libsvt_hevc-encoder-docs.patch @@ -0,0 +1,201 @@ +From 6b0a4fd63454e3c2185efe741e50e80df5c9a4a4 Mon Sep 17 00:00:00 2001 +From: Jing Sun +Date: Tue, 5 Mar 2019 15:04:58 +0800 +Subject: [PATCH 2/2] doc: Add libsvt_hevc encoder docs + +Add docs for libsvt_hevc encoder in encoders.texi and general.texi + +Signed-off-by: Jun Zhao +Signed-off-by: Zhengxu Huang +Signed-off-by: Hassene Tmar +Signed-off-by: Jing Sun +--- + doc/encoders.texi | 152 ++++++++++++++++++++++++++++++++++++++ + doc/general_contents.texi | 8 ++ + 2 files changed, 160 insertions(+) + +diff --git a/doc/encoders.texi b/doc/encoders.texi +index a92eb0eb2f..535e15764b 100644 +--- a/doc/encoders.texi ++++ b/doc/encoders.texi +@@ -1884,6 +1884,158 @@ Set maximum NAL size in bytes. + Allow skipping frames to hit the target bitrate if set to 1. + @end table + ++@section libsvt_hevc ++ ++Scalable Video Technology for HEVC (SVT-HEVC) encoder wrapper. ++ ++This encoder requires the presence of the headers and ++library during configuration. You need to explicitly configure the ++build with @code{--enable-libsvthevc}. The library is detected using ++@command{pkg-config}. ++ ++For more information about the library see ++@url{https://github.com/intel/SVT-HEVC.git}. ++ ++@subsection Options ++ ++The following FFmpeg global options affect the configurations of the ++libsvt_hevc encoder: ++ ++@table @option ++@item b (@emph{bitrate}) ++Set the bitrate (as a number of bits per second). Default is 7M. ++ ++@item g / @option{gop_size} ++Set the GOP size. Default is -2 (unspecified). ++ ++@item flags +cgop ++Enable closed GOP. ++ ++@item qmin (@emph{min-q}) ++Default is 10 ++ ++@item qmax (@emph{max-q}) ++Default is 48 ++ ++Set minimum/maximum quantisation values. Valid range is from 0 to 51 ++(Only used when bit rate control mode @option{rc} is set to 1(vbr) mode. ++It is required that qmax >= qmin). ++ ++@item profile (@emph{profile}) ++Set profile restrictions. Can assume one of the following possible values: ++ ++@table @samp ++@item main ++main profile ++@item main10 ++main10 profile ++@item rext ++rext profile ++@end table ++ ++Default is 1 (main). ++ ++@item level (@emph{level}) ++ ++@option{level} sets the value of @emph{level}. ++Set level (level_idc). Default is 0 (to be determined by the encoder). ++ ++@end table ++ ++The encoder also has its own specific options: ++ ++@table @option ++@item aud (@emph{aud}) ++Enable use of access unit delimiters when set to 1. Default is 0 (Off). ++ ++@item hielevel ++Set hierarchical levels. Can assume one of the following possible values: ++ ++@table @samp ++@item flat ++flat more ++@item 1 level ++Minigop size is 2^1 ++@item 2 level ++Minigop size is 2^2 ++@item 3 level ++Minigop size is 2^3 ++@end table ++ ++Default is 3 level. ++ ++@item la_depth ++Set look-ahead depth, depending on @option{rc}: for @var{vbr}, it's recommended ++to unset it and use the default value (the intra period); for @var{cqp}, better ++specify the look-ahead depth. ++ ++The range is @var{-1-256}. Default is -1 (unset and the default value to be used). ++ ++@item preset ++Set the quality vs density tradeoff point at which the encoding is to be performed. ++Higher perset value, higher density and lower quality. ++ ++The range is @var{0-12}. Default is 9. ++ ++@item tier ++Set @emph{general_tier_flag}. This may affect the level chosen for the stream ++if it is not explicitly specified. Can assume one of the following possible values: ++ ++@item socket ++Target CPU socket to use. 0 or 1 are supported. -1 use all available (default) ++ ++@table @samp ++@item main ++main tier ++@item high ++high tier ++@end table ++ ++Default is 1 (main). ++ ++@item rc ++Set bit rate control mode. Can assume one of the following possible values: ++ ++@table @samp ++@item cqp ++Constant QP (CQP) mode ++@item vbr ++Variable Bit Rate (VBR) mode ++@end table ++ ++Default is 0 (cqp). ++ ++@item forced_idr ++Force keyframes to be IDR if set to >=0 (the value sets headers insertion interval). Default is -1 (CRA). ++ ++@item asm_type ++Auto select highest supported asm if set to 1 or C only if 0. Default is 1. ++ ++@item qp ++Initial quantization parameter for the intra pictures used when ++@option{rc} is cqp mode. The range is from @var{0-51}. Default is 32. ++ ++@item sc_detection ++Enables or disables the scene change detection algorithm. Default is 0 (disabled). ++ ++@item tune ++Set quality tuning mode. Can assume one of the following possible values: ++ ++@table @samp ++@item sq ++Visually optimized mode ++@item oq ++PSNR / SSIM optimized mode ++@item vmaf ++VMAF optimized mode ++@end table ++ ++Default is 1 (oq). ++ ++@item bl_mode ++Enables or disables Random Access Prediction. Default is 0 (disabled). ++@end table ++ + @section libtheora + + libtheora Theora encoder wrapper. +diff --git a/doc/general_contents.texi b/doc/general_contents.texi +index 33ece6e884..cd46332fc4 100644 +--- a/doc/general_contents.texi ++++ b/doc/general_contents.texi +@@ -267,6 +267,14 @@ Go to @url{https://github.com/OpenVisualCloud/SVT-AV1/} and follow the instructi + for installing the library. Then pass @code{--enable-libsvtav1} to configure to + enable it. + ++@section Scalable Video Technology for HEVC ++ ++FFmpeg can make use of the SVT-HEVC library for HEVC encoding. ++ ++Go to @url{https://github.com/intel/SVT-HEVC.git} and follow the instructions ++for installing the library. Pass @code{--enable-libsvthevc} to configure to ++enable it. ++ + @section TwoLAME + + FFmpeg can make use of the TwoLAME library for MP2 encoding. +-- +1.8.3.1 + diff --git a/multimedia/compat-ffmpeg5/030-ffmpeg-add-svt-vp9.patch b/multimedia/compat-ffmpeg5/030-ffmpeg-add-svt-vp9.patch new file mode 100644 index 0000000..65a1301 --- /dev/null +++ b/multimedia/compat-ffmpeg5/030-ffmpeg-add-svt-vp9.patch @@ -0,0 +1,805 @@ +From add426a72d980a3037333c43cf91b46d8616436e Mon Sep 17 00:00:00 2001 +From: hassene +Date: Sun, 21 May 2023 17:54:03 -0400 +Subject: [PATCH] Add ability for ffmpeg to run svt vp9 + +Signed-off-by: hassene +Signed-off-by: Jing Sun +Signed-off-by: Austin Hu +Signed-off-by: Andrei Bich +Signed-off-by: Guo Jiansheng +Co-Authored-By: Fredrick R. Brennan +--- + configure | 4 + + libavcodec/Makefile | 1 + + libavcodec/allcodecs.c | 1 + + libavcodec/libsvt_vp9.c | 700 ++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 706 insertions(+) + create mode 100644 libavcodec/libsvt_vp9.c + +diff --git a/configure b/configure +index a54398c57f..dd7607731f 100755 +--- a/configure ++++ b/configure +@@ -289,6 +289,7 @@ External library support: + --enable-libvorbis enable Vorbis en/decoding via libvorbis, + native implementation exists [no] + --enable-libvpx enable VP8 and VP9 de/encoding via libvpx [no] ++ --enable-libsvtvp9 enable VP9 encoding via svt [no] + --enable-libwebp enable WebP encoding via libwebp [no] + --enable-libx264 enable H.264 encoding via x264 [no] + --enable-libx265 enable HEVC encoding via x265 [no] +@@ -1848,6 +1849,7 @@ EXTERNAL_LIBRARY_LIST=" + libshaderc + libshine + libsmbclient ++ libsvtvp9 + libsnappy + libsoxr + libspeex +@@ -3390,6 +3392,7 @@ libvpx_vp8_decoder_deps="libvpx" + libvpx_vp8_encoder_deps="libvpx" + libvpx_vp9_decoder_deps="libvpx" + libvpx_vp9_encoder_deps="libvpx" ++libsvt_vp9_encoder_deps="libsvtvp9" + libwebp_encoder_deps="libwebp" + libwebp_anim_encoder_deps="libwebp" + libx262_encoder_deps="libx262" +@@ -6727,6 +6730,7 @@ enabled libvpx && { + fi + } + ++enabled libsvtvp9 && require_pkg_config libsvtvp9 SvtVp9Enc EbSvtVp9Enc.h eb_vp9_svt_init_handle + enabled libwebp && { + enabled libwebp_encoder && require_pkg_config libwebp "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion + enabled libwebp_anim_encoder && check_pkg_config libwebp_anim_encoder "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit; } +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index 9c38240025..1984cb970c 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1099,6 +1099,7 @@ + OBJS-$(CONFIG_LIBVPX_VP8_ENCODER) += libvpxenc.o + OBJS-$(CONFIG_LIBVPX_VP9_DECODER) += libvpxdec.o libvpx.o + OBJS-$(CONFIG_LIBVPX_VP9_ENCODER) += libvpxenc.o libvpx.o ++OBJS-$(CONFIG_LIBSVT_VP9_ENCODER) += libsvt_vp9.o + OBJS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.o libwebpenc.o + OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o libwebpenc_animencoder.o + OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o +diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c +index 184bb8521f..bda526f755 100644 +--- a/libavcodec/allcodecs.c ++++ b/libavcodec/allcodecs.c +@@ -781,6 +781,7 @@ + extern const FFCodec ff_libvpx_vp8_decoder; + extern FFCodec ff_libvpx_vp9_encoder; + extern FFCodec ff_libvpx_vp9_decoder; ++extern const FFCodec ff_libsvt_vp9_encoder; + /* preferred over libwebp */ + extern const FFCodec ff_libwebp_anim_encoder; + extern const FFCodec ff_libwebp_encoder; +diff -Naur a/libavcodec/codec_internal.h b/libavcodec/codec_internal.h +--- a/libavcodec/codec_internal.h ++++ b/libavcodec/codec_internal.h +@@ -75,6 +75,14 @@ + #define FF_CODEC_CAP_SETS_FRAME_PROPS (1 << 8) + + /** ++ * The codec is not known to be init-threadsafe (i.e. it might be unsafe ++ * to initialize this codec and another codec concurrently, typically because ++ * the codec calls external APIs that are not known to be thread-safe). ++ * Therefore calling the codec's init function needs to be guarded with a lock. ++ */ ++#define FF_CODEC_CAP_NOT_INIT_THREADSAFE (1 << 9) ++ ++/** + * FFCodec.codec_tags termination value + */ + #define FF_CODEC_TAGS_END -1 +diff --git a/libavcodec/libsvt_vp9.c b/libavcodec/libsvt_vp9.c +new file mode 100644 +index 0000000000..5f99367924 +--- /dev/null ++++ b/libavcodec/libsvt_vp9.c +@@ -0,0 +1,700 @@ ++/* ++* Scalable Video Technology for VP9 encoder library plugin ++* ++* Copyright (c) 2018 Intel Corporation ++* ++* This file is part of FFmpeg. ++* ++* FFmpeg is free software; you can redistribute it and/or ++* modify it under the terms of the GNU Lesser General Public ++* License as published by the Free Software Foundation; either ++* version 2.1 of the License, or (at your option) any later version. ++* ++* FFmpeg is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++* Lesser General Public License for more details. ++* ++* You should have received a copy of the GNU Lesser General Public ++* License along with this program; if not, write to the Free Software ++* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++*/ ++ ++#include ++#include "EbSvtVp9ErrorCodes.h" ++#include "EbSvtVp9Enc.h" ++ ++#include "libavutil/common.h" ++#include "libavutil/frame.h" ++#include "libavutil/opt.h" ++#include "libavcodec/get_bits.h" ++ ++#include "codec_internal.h" ++#include "internal.h" ++#include "encode.h" ++#include "avcodec.h" ++ ++#define SUPERFRAME_INDEX_MAX_SIZE 128 ++ ++#define RECIVED_FRAMES_MAX_SIZE 32 ++#define MAX_VP9_SUPERFRAME_SIZE 8 ++ ++typedef enum eos_status { ++ EOS_NOT_REACHED = 0, ++ EOS_REACHED, ++ EOS_TOTRIGGER ++}EOS_STATUS; ++ ++typedef struct SvtReceivedFrameStruct { ++ // fields for AVPacket ++ AVBufferRef *buf; ++ int64_t pts; ++ int64_t dts; ++ int size; ++ int flags; ++ ++ // svt fields: ++ int ready_flag; // frame or superframe in data is visible ++ int frames_count; ++ int frames_sizes[MAX_VP9_SUPERFRAME_SIZE]; ++} SvtReceivedFrameStruct; ++ ++typedef struct SvtContext { ++ AVClass *class; ++ ++ EbSvtVp9EncConfiguration enc_params; ++ EbComponentType *svt_handle; ++ ++ EbBufferHeaderType *in_buf; ++ int raw_size; ++ ++ AVFrame *frame; ++ ++ AVBufferPool* pool; ++ ++ EOS_STATUS eos_flag; ++ ++ // User options. ++ int enc_mode; ++ int rc_mode; ++ int tune; ++ int qp; ++ ++ int target_socket; ++ ++ int forced_idr; ++ ++ int level; ++ ++ int base_layer_switch_mode; ++ ++ ++ int64_t last_ready_dts; ++ SvtReceivedFrameStruct received_frames[RECIVED_FRAMES_MAX_SIZE]; ++ int received_frames_size; ++} SvtContext; ++ ++static int error_mapping(EbErrorType svt_ret) ++{ ++ int err; ++ ++ switch (svt_ret) { ++ case EB_ErrorInsufficientResources: ++ err = AVERROR(ENOMEM); ++ break; ++ ++ case EB_ErrorUndefined: ++ case EB_ErrorInvalidComponent: ++ case EB_ErrorBadParameter: ++ err = AVERROR(EINVAL); ++ break; ++ ++ case EB_ErrorDestroyThreadFailed: ++ case EB_ErrorSemaphoreUnresponsive: ++ case EB_ErrorDestroySemaphoreFailed: ++ case EB_ErrorCreateMutexFailed: ++ case EB_ErrorMutexUnresponsive: ++ case EB_ErrorDestroyMutexFailed: ++ err = AVERROR_EXTERNAL; ++ break; ++ ++ case EB_NoErrorEmptyQueue: ++ err = AVERROR(EAGAIN); ++ ++ case EB_ErrorNone: ++ err = 0; ++ break; ++ ++ default: ++ err = AVERROR_UNKNOWN; ++ } ++ ++ return err; ++} ++ ++static void free_buffer(SvtContext *svt_enc) ++{ ++ if (svt_enc->in_buf) { ++ EbSvtEncInput *in_data = (EbSvtEncInput *)svt_enc->in_buf->p_buffer; ++ av_freep(&in_data); ++ av_freep(&svt_enc->in_buf); ++ } ++ av_buffer_pool_uninit(&svt_enc->pool); ++} ++ ++static int alloc_buffer(EbSvtVp9EncConfiguration *config, SvtContext *svt_enc) ++{ ++ const size_t luma_size_8bit = ++ config->source_width * config->source_height; ++ const size_t luma_size_10bit = ++ (config->encoder_bit_depth > 8) ? luma_size_8bit : 0; ++ ++ EbSvtEncInput *in_data; ++ ++ svt_enc->raw_size = ((luma_size_8bit + luma_size_10bit) * 3 / 2) * MAX_VP9_SUPERFRAME_SIZE + SUPERFRAME_INDEX_MAX_SIZE; ++ ++ // allocate buffer for in and out ++ svt_enc->in_buf = av_mallocz(sizeof(*svt_enc->in_buf)); ++ if (!svt_enc->in_buf) ++ goto failed; ++ ++ ++ svt_enc->in_buf->p_buffer = (unsigned char *)av_mallocz(sizeof(*in_data)); ++ if (!svt_enc->in_buf->p_buffer) ++ goto failed; ++ ++ svt_enc->in_buf->size = sizeof(*svt_enc->in_buf); ++ svt_enc->in_buf->p_app_private = NULL; ++ ++ svt_enc->pool = av_buffer_pool_init(svt_enc->raw_size, NULL); ++ if (!svt_enc->pool) ++ goto failed; ++ ++ svt_enc->received_frames_size = 0; ++ svt_enc->last_ready_dts = -1e9; ++ ++ return 0; ++ ++failed: ++ free_buffer(svt_enc); ++ return AVERROR(ENOMEM); ++} ++ ++static int config_enc_params(EbSvtVp9EncConfiguration *param, ++ AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ int ret; ++ int ten_bits = 0; ++ ++ param->source_width = avctx->width; ++ param->source_height = avctx->height; ++ ++ if (avctx->pix_fmt == AV_PIX_FMT_YUV420P10LE) { ++ av_log(avctx, AV_LOG_DEBUG , "Encoder 10 bits depth input\n"); ++ // Disable Compressed 10-bit format default ++ ten_bits = 1; ++ } ++ ++ // Update param from options ++ param->enc_mode = svt_enc->enc_mode; ++ param->level = svt_enc->level; ++ param->rate_control_mode = svt_enc->rc_mode; ++ param->tune = svt_enc->tune; ++ param->base_layer_switch_mode = svt_enc->base_layer_switch_mode; ++ param->qp = svt_enc->qp; ++ param->target_socket = svt_enc->target_socket; ++ param->target_bit_rate = avctx->bit_rate; ++ if (avctx->gop_size > 0) ++ param->intra_period = avctx->gop_size - 1; ++ ++ if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { ++ param->frame_rate_numerator = avctx->framerate.num; ++ param->frame_rate_denominator = avctx->framerate.den * avctx->ticks_per_frame; ++ } else { ++ param->frame_rate_numerator = avctx->time_base.den; ++ param->frame_rate_denominator = avctx->time_base.num * avctx->ticks_per_frame; ++ } ++ ++ if (param->rate_control_mode) { ++ param->max_qp_allowed = avctx->qmax; ++ param->min_qp_allowed = avctx->qmin; ++ } ++ ++ if (ten_bits) { ++ param->encoder_bit_depth = 10; ++ } ++ ++ ret = alloc_buffer(param, svt_enc); ++ ++ return ret; ++} ++ ++static void read_in_data(EbSvtVp9EncConfiguration *config, ++ const AVFrame *frame, ++ EbBufferHeaderType *headerPtr) ++{ ++ uint8_t is16bit = config->encoder_bit_depth > 8; ++ uint64_t luma_size = ++ (uint64_t)config->source_width * config->source_height<< is16bit; ++ EbSvtEncInput *in_data = (EbSvtEncInput *)headerPtr->p_buffer; ++ ++ // support yuv420p and yuv420p010 ++ in_data->luma = frame->data[0]; ++ in_data->cb = frame->data[1]; ++ in_data->cr = frame->data[2]; ++ ++ // stride info ++ in_data->y_stride = frame->linesize[0] >> is16bit; ++ in_data->cb_stride = frame->linesize[1] >> is16bit; ++ in_data->cr_stride = frame->linesize[2] >> is16bit; ++ ++ headerPtr->n_filled_len += luma_size * 3/2u; ++} ++ ++static av_cold int eb_enc_init(AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ EbErrorType svt_ret; ++ ++ svt_enc->eos_flag = EOS_NOT_REACHED; ++ ++ svt_ret = eb_vp9_svt_init_handle(&svt_enc->svt_handle, svt_enc, &svt_enc->enc_params); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Error init encoder handle\n"); ++ goto failed; ++ } ++ ++ svt_ret = config_enc_params(&svt_enc->enc_params, avctx); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Error configure encoder parameters\n"); ++ goto failed_init_handle; ++ } ++ ++ svt_ret = eb_vp9_svt_enc_set_parameter(svt_enc->svt_handle, &svt_enc->enc_params); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Error setting encoder parameters\n"); ++ goto failed_init_handle; ++ } ++ ++ svt_ret = eb_vp9_init_encoder(svt_enc->svt_handle); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Error init encoder\n"); ++ goto failed_init_handle; ++ } ++ ++ svt_enc->frame = av_frame_alloc(); ++ if (!svt_enc->frame) ++ return AVERROR(ENOMEM); ++ ++ // if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { ++ // EbBufferHeaderType* headerPtr; ++ // headerPtr->size = sizeof(headerPtr); ++ // headerPtr->n_filled_len = 0; /* in/out */ ++ // headerPtr->p_buffer = av_malloc(10 * 1024 * 1024); ++ // headerPtr->n_alloc_len = (10 * 1024 * 1024); ++ // ++ // if (!headerPtr->p_buffer) { ++ // av_log(avctx, AV_LOG_ERROR, ++ // "Cannot allocate buffer size %d.\n", headerPtr->n_alloc_len); ++ // svt_ret = EB_ErrorInsufficientResources; ++ // goto failed_init_enc; ++ // } ++ // ++ // svt_ret = eb_svt_enc_stream_header(svt_enc->svt_handle, &headerPtr); ++ // if (svt_ret != EB_ErrorNone) { ++ // av_log(avctx, AV_LOG_ERROR, "Error when build stream header.\n"); ++ // av_freep(&headerPtr->p_buffer); ++ // goto failed_init_enc; ++ // } ++ // ++ // avctx->extradata_size = headerPtr->n_filled_len; ++ // avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); ++ // if (!avctx->extradata) { ++ // av_log(avctx, AV_LOG_ERROR, ++ // "Cannot allocate VP9 header of size %d.\n", avctx->extradata_size); ++ // av_freep(&headerPtr->p_buffer); ++ // svt_ret = EB_ErrorInsufficientResources; ++ // goto failed_init_enc; ++ // } ++ // memcpy(avctx->extradata, headerPtr->p_buffer, avctx->extradata_size); ++ // ++ // av_freep(&headerPtr->p_buffer); ++ // } ++ return 0; ++ ++//failed_init_enc: ++// eb_deinit_encoder(svt_enc->svt_handle); ++failed_init_handle: ++ eb_vp9_deinit_handle(svt_enc->svt_handle); ++failed: ++ free_buffer(svt_enc); ++ return error_mapping(svt_ret); ++} ++ ++static int eb_send_frame(AVCodecContext *avctx, const AVFrame *frame) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ EbBufferHeaderType *headerPtr = svt_enc->in_buf; ++ ++ if (!frame) { ++ if (svt_enc->eos_flag == EOS_REACHED) ++ return 0; ++ ++ EbBufferHeaderType headerPtrLast; ++ headerPtrLast.n_alloc_len = 0; ++ headerPtrLast.n_filled_len = 0; ++ headerPtrLast.n_tick_count = 0; ++ headerPtrLast.p_app_private = NULL; ++ headerPtrLast.p_buffer = NULL; ++ headerPtrLast.flags = EB_BUFFERFLAG_EOS; ++ ++ eb_vp9_svt_enc_send_picture(svt_enc->svt_handle, &headerPtrLast); ++ svt_enc->eos_flag = EOS_REACHED; ++ av_log(avctx, AV_LOG_DEBUG, "Finish sending frames!!!\n"); ++ return 0; ++ } ++ ++ read_in_data(&svt_enc->enc_params, frame, headerPtr); ++ ++ headerPtr->flags = 0; ++ headerPtr->p_app_private = NULL; ++ headerPtr->pts = frame->pts; ++ switch (frame->pict_type) { ++ case AV_PICTURE_TYPE_I: ++ headerPtr->pic_type = svt_enc->forced_idr > 0 ? EB_IDR_PICTURE : EB_I_PICTURE; ++ break; ++ case AV_PICTURE_TYPE_P: ++ headerPtr->pic_type = EB_P_PICTURE; ++ break; ++ case AV_PICTURE_TYPE_B: ++ headerPtr->pic_type = EB_B_PICTURE; ++ break; ++ default: ++ headerPtr->pic_type = EB_INVALID_PICTURE; ++ break; ++ } ++ eb_vp9_svt_enc_send_picture(svt_enc->svt_handle, headerPtr); ++ ++ return 0; ++} ++ ++static int is_frame_visible(uint8_t const* ptr, int size) { ++ GetBitContext gb; ++ int ret, visible, profile; ++ if ((ret = init_get_bits8(&gb, ptr, size)) < 0) { ++ return ret; ++ } ++ ++ // frame marker ++ get_bits(&gb, 2); ++ profile = get_bits1(&gb); ++ profile |= get_bits1(&gb) << 1; ++ ++ // reserved_zero ++ if (profile == 3) profile += get_bits1(&gb); // reserved_zero ++ ++ // read show_existing_frame ++ if (get_bits1(&gb)) { ++ // show_existing_frame == 1 ++ visible = 1; ++ } else { ++ // show_existing_frame == 0 ++ // keyframe (frame_type actually) ++ get_bits1(&gb); ++ // read show_frame ++ visible = get_bits1(&gb) ? 2 : 0; ++ } ++ ++ return visible; ++} ++ ++static int get_received_frame(SvtContext *svt_enc, AVPacket *pkt) { ++ SvtReceivedFrameStruct* rfs = &svt_enc->received_frames[0]; ++ ++ if (svt_enc->received_frames_size == 0 || !rfs->ready_flag) { ++ return AVERROR(EAGAIN); ++ } ++ ++ pkt->buf = rfs->buf; ++ pkt->data = rfs->buf->data; ++ pkt->dts = rfs->dts; ++ pkt->pts = rfs->pts; ++ pkt->flags = rfs->flags; ++ pkt->size = rfs->size; ++ ++ --svt_enc->received_frames_size; ++ for (int i = 0; i < svt_enc->received_frames_size; ++i) { ++ svt_enc->received_frames[i] = svt_enc->received_frames[i + 1]; ++ } ++ ++ return 0; ++} ++ ++static int put_received_frame(AVCodecContext *avctx, uint8_t* data, int size, int keyframe, int64_t dts, int64_t pts) { ++ SvtContext *svt_enc = avctx->priv_data; ++ SvtReceivedFrameStruct* rfs; ++ ++ if (svt_enc->received_frames_size == 0 || svt_enc->received_frames[svt_enc->received_frames_size - 1].ready_flag) { ++ ++svt_enc->received_frames_size; ++ if (svt_enc->received_frames_size > RECIVED_FRAMES_MAX_SIZE) { ++ av_log(avctx, AV_LOG_ERROR, "Fail: svt_enc->received_frames_size > RECIVED_FRAMES_MAX_SIZE \n"); ++ return AVERROR_BUG; ++ } ++ ++ rfs = &svt_enc->received_frames[svt_enc->received_frames_size - 1]; ++ ++ rfs->buf = av_buffer_pool_get(svt_enc->pool); ++ if (!rfs->buf) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to allocate output packet.\n"); ++ return AVERROR(ENOMEM); ++ } ++ ++ rfs->size = 0; ++ rfs->flags = 0; ++ rfs->ready_flag = 0; ++ rfs->frames_count = 0; ++ } else { ++ rfs = &svt_enc->received_frames[svt_enc->received_frames_size - 1]; ++ } ++ ++ rfs->pts = pts; ++ rfs->dts = dts; ++ rfs->flags = (keyframe ? AV_PKT_FLAG_KEY : 0); ++ ++ ++rfs->frames_count; ++ if (rfs->frames_count > MAX_VP9_SUPERFRAME_SIZE) { ++ av_log(avctx, AV_LOG_ERROR, "Fail: rfs->frames_count > MAX_VP9_SUPERFRAME_SIZE \n"); ++ return AVERROR_BUG; ++ } ++ ++ rfs->frames_sizes[rfs->frames_count - 1] = size; ++ ++ memcpy(rfs->buf->data + rfs->size, data, size); ++ rfs->size += size; ++ ++ int visible = is_frame_visible(data, size); ++ if (visible < 0) { ++ av_log(avctx, AV_LOG_ERROR, "Fail: is_frame_visible \n"); ++ return visible; ++ } ++ ++ ++ rfs->ready_flag = visible; ++ ++ if (rfs->ready_flag) { ++ if (rfs->dts <= svt_enc->last_ready_dts) { ++ rfs->dts = svt_enc->last_ready_dts + 1; ++ } ++ svt_enc->last_ready_dts = rfs->dts; ++ ++ } ++ ++ // add superframe_index if needed ++ if (rfs->ready_flag && rfs->frames_count > 1) { ++ // superframe_header: ++ // 110 - superframe_marker ++ // 11 = 3 = bytes_per_framesize_minus_1 - use 4-bytes size ++ // xxx = frames_in_superframe_minus_1 ++ uint8_t header = 0b11011000; ++ header |= (rfs->frames_count - 1) & 0b111; ++ ++ uint8_t* ptr = rfs->buf->data + rfs->size; ++ ++ ptr[0] = header; ++ ++ptr; ++ ++ for (int i = 0; i < rfs->frames_count; ++i) { ++ ptr[0] = (rfs->frames_sizes[i] >> 0) & 0xff; ++ ptr[1] = (rfs->frames_sizes[i] >> 8) & 0xff; ++ ptr[2] = (rfs->frames_sizes[i] >> 16) & 0xff; ++ ptr[3] = (rfs->frames_sizes[i] >> 24) & 0xff; ++ ++ ptr += 4; ++ } ++ ++ ptr[0] = header; ++ ++ptr; ++ ++ rfs->size = ptr - rfs->buf->data; ++ } ++ ++ return 0; ++} ++ ++static int eb_receive_packet(AVCodecContext *avctx, AVPacket *pkt) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ EbBufferHeaderType *headerPtr; ++ EbErrorType svt_ret; ++ AVBufferRef *ref; ++ int ret = 0; ++ ++ if (get_received_frame(svt_enc, pkt) == 0) { ++ return 0; ++ } ++ ++ if (EOS_TOTRIGGER == svt_enc->eos_flag) { ++ pkt = NULL; ++ return AVERROR_EOF; ++ } ++ ++ AVFrame *frame = svt_enc->frame; ++ ret = ff_encode_get_frame(avctx, frame); ++ if (ret < 0 && ret != AVERROR_EOF) { ++ return ret; ++ } ++ if (ret == AVERROR_EOF) ++ frame = NULL; ++ ++ ret = eb_send_frame(avctx, frame); ++ if (ret < 0) ++ return ret; ++ av_frame_unref(svt_enc->frame); ++ ++ for (;;) { ++ svt_ret = eb_vp9_svt_get_packet(svt_enc->svt_handle, &headerPtr, svt_enc->eos_flag); ++ if (svt_ret == EB_NoErrorEmptyQueue) { ++ return AVERROR(EAGAIN); ++ } ++ ++ if (EB_BUFFERFLAG_EOS & headerPtr->flags) ++ svt_enc->eos_flag = EOS_TOTRIGGER; ++ ++ ret = 0; ++ ++ // ignore headerPtr->dts on purpose ++ ++ if (headerPtr->flags & EB_BUFFERFLAG_SHOW_EXT) { ++ ret = put_received_frame(avctx, headerPtr->p_buffer, headerPtr->n_filled_len - 4, 0, headerPtr->pts - 3, headerPtr->pts - 3); ++ if (ret != 0) goto end; ++ ret = put_received_frame(avctx, headerPtr->p_buffer + headerPtr->n_filled_len - 4, 1, 0, headerPtr->pts - 2, headerPtr->pts - 2); ++ if (ret != 0) goto end; ++ ret = put_received_frame(avctx, headerPtr->p_buffer + headerPtr->n_filled_len - 3, 1, 0, headerPtr->pts - 1, headerPtr->pts - 1); ++ if (ret != 0) goto end; ++ ret = put_received_frame(avctx, headerPtr->p_buffer + headerPtr->n_filled_len - 2, 1, 0, headerPtr->pts + 0, headerPtr->pts + 0); ++ if (ret != 0) goto end; ++ ret = put_received_frame(avctx, headerPtr->p_buffer + headerPtr->n_filled_len - 1, 1, 0, headerPtr->pts + 1, headerPtr->pts + 1); ++ if (ret != 0) goto end; ++ } else { ++ ret = put_received_frame(avctx, headerPtr->p_buffer, headerPtr->n_filled_len, headerPtr->pic_type == EB_IDR_PICTURE, headerPtr->pts, headerPtr->pts); ++ if (ret != 0) goto end; ++ } ++ ++ ret = get_received_frame(svt_enc, pkt); ++ ++ end: ++ eb_vp9_svt_release_out_buffer(&headerPtr); ++ ++ if (ret == AVERROR(EAGAIN)) { ++ continue; ++ } ++ ++ break; ++ } ++ ++ ++ ++ return ret; ++} ++ ++static av_cold int eb_enc_close(AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ ++ eb_vp9_deinit_encoder(svt_enc->svt_handle); ++ eb_vp9_deinit_handle(svt_enc->svt_handle); ++ ++ av_frame_free(&svt_enc->frame); ++ ++ free_buffer(svt_enc); ++ ++ return 0; ++} ++ ++#define OFFSET(x) offsetof(SvtContext, x) ++#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ++static const AVOption options[] = { ++ { "preset", "Encoding preset [1, 1]", ++ OFFSET(enc_mode), AV_OPT_TYPE_INT, { .i64 = 9 }, 0, 9, VE }, ++ ++ { "level", "Set level (level_idc)", OFFSET(level), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 0xff, VE, "level" }, ++ ++#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ ++ { .i64 = value }, 0, 0, VE, "level" ++ { LEVEL("1", 10) }, ++ { LEVEL("2", 20) }, ++ { LEVEL("2.1", 21) }, ++ { LEVEL("3", 30) }, ++ { LEVEL("3.1", 31) }, ++ { LEVEL("4", 40) }, ++ { LEVEL("4.1", 41) }, ++ { LEVEL("5", 50) }, ++ { LEVEL("5.1", 51) }, ++ { LEVEL("5.2", 52) }, ++ { LEVEL("6", 60) }, ++ { LEVEL("6.1", 61) }, ++ { LEVEL("6.2", 62) }, ++#undef LEVEL ++ ++ { "tune", "Tune mode", OFFSET(tune), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, VE , "tune"}, ++ { "vq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "tune" }, ++ { "ssim", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "tune" }, ++ { "vmaf", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "tune" }, ++ ++ { "rc", "Bit rate control mode", OFFSET(rc_mode), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, VE , "rc"}, ++ { "cqp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "rc" }, ++ { "vbr", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "rc" }, ++ { "cbr", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "rc" }, ++ ++ { "qp", "QP value for intra frames", OFFSET(qp), ++ AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 51, VE }, ++ ++ { "socket", "Target CPU socket to use. -1 use all available", OFFSET(target_socket), ++ AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, ++ ++ { "bl_mode", "Random Access Prediction Structure type setting", OFFSET(base_layer_switch_mode), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, ++ ++ { "forced-idr", "If forcing keyframes, force them as IDR frames.", OFFSET(forced_idr), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, -1, 1, VE }, ++ ++ {NULL}, ++}; ++ ++static const AVClass class = { ++ .class_name = "libsvt_vp9", ++ .item_name = av_default_item_name, ++ .option = options, ++ .version = LIBAVUTIL_VERSION_INT, ++}; ++ ++static const FFCodecDefault eb_enc_defaults[] = { ++ { "b", "7M" }, ++ { "flags", "-cgop" }, ++ { "qmin", "10" }, ++ { "qmax", "48" }, ++ { NULL }, ++}; ++ ++FFCodec ff_libsvt_vp9_encoder = { ++ .p.name = "libsvt_vp9", ++ .p.long_name = NULL_IF_CONFIG_SMALL("SVT-VP9(Scalable Video Technology for VP9) encoder"), ++ .priv_data_size = sizeof(SvtContext), ++ .p.type = AVMEDIA_TYPE_VIDEO, ++ .p.id = AV_CODEC_ID_VP9, ++ .init = eb_enc_init, ++ FF_CODEC_RECEIVE_PACKET_CB(eb_receive_packet), ++ .close = eb_enc_close, ++ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS, ++ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | ++ FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP, ++ .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, ++ AV_PIX_FMT_NONE }, ++ .p.priv_class = &class, ++ .defaults = eb_enc_defaults, ++ .p.wrapper_name = "libsvt_vp9", ++}; +-- +2.40.1 diff --git a/multimedia/compat-ffmpeg5/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch b/multimedia/compat-ffmpeg5/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch new file mode 100644 index 0000000..130d0ae --- /dev/null +++ b/multimedia/compat-ffmpeg5/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch @@ -0,0 +1,47 @@ +From 95aab0fd83619408995720ce53d7a74790580220 Mon Sep 17 00:00:00 2001 +From: "liberato@chromium.org" +Date: Wed, 7 Jul 2021 19:01:22 -0700 +Subject: [PATCH] Add av_stream_get_first_dts for Chromium + +[foutrelis: adjust for new FFStream struct replacing AVStreamInternal] +--- + libavformat/avformat.h | 4 ++++ + libavformat/utils.c | 7 +++++++ + 2 files changed, 11 insertions(+) + +diff --git a/libavformat/avformat.h b/libavformat/avformat.h +index cd7b0d941c..b4a6dce885 100644 +--- a/libavformat/avformat.h ++++ b/libavformat/avformat.h +@@ -1010,6 +1010,10 @@ struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); + */ + int64_t av_stream_get_end_pts(const AVStream *st); + ++// Chromium: We use the internal field first_dts vvv ++int64_t av_stream_get_first_dts(const AVStream *st); ++// Chromium: We use the internal field first_dts ^^^ ++ + #define AV_PROGRAM_RUNNING 1 + + /** +diff --git a/libavformat/utils.c b/libavformat/utils.c +index de7580c32d..0ef0fe530e 100644 +--- a/libavformat/utils.c ++++ b/libavformat/utils.c +@@ -55,6 +55,13 @@ + return ff_mutex_unlock(&avformat_mutex) ? -1 : 0; + } + ++// Chromium: We use the internal field first_dts vvv ++int64_t av_stream_get_first_dts(const AVStream *st) ++{ ++ return cffstream(st)->first_dts; ++} ++// Chromium: We use the internal field first_dts ^^^ ++ + /* an arbitrarily chosen "sane" max packet size -- 50M */ + #define SANE_CHUNK_SIZE (50000000) + + struct AVCodecParserContext *av_stream_get_parser(const AVStream *st) + { + return st->internal->parser; diff --git a/multimedia/compat-ffmpeg5/ffmpeg-allow-fdk-aac-free.patch b/multimedia/compat-ffmpeg5/ffmpeg-allow-fdk-aac-free.patch new file mode 100644 index 0000000..3b87cce --- /dev/null +++ b/multimedia/compat-ffmpeg5/ffmpeg-allow-fdk-aac-free.patch @@ -0,0 +1,26 @@ +From: Andreas Schneider + +fdk-aac-free-devel is GPL compatible + +See https://bugzilla.redhat.com/show_bug.cgi?id=1501522#c112 + +Index: ffmpeg-5.0/configure +=================================================================== +--- ffmpeg-5.0.orig/configure 2022-02-09 20:07:49.490888877 +0100 ++++ ffmpeg-5.0/configure 2022-02-09 20:08:30.102854308 +0100 +@@ -1783,7 +1783,6 @@ EXTERNAL_LIBRARY_GPL_LIST=" + + EXTERNAL_LIBRARY_NONFREE_LIST=" + decklink +- libfdk_aac + libtls + " + +@@ -1822,6 +1821,7 @@ EXTERNAL_LIBRARY_LIST=" + libdav1d + libdc1394 + libdrm ++ libfdk_aac + libflite + libfontconfig + libfreetype diff --git a/multimedia/compat-ffmpeg5/ffmpeg-codec-choice.patch b/multimedia/compat-ffmpeg5/ffmpeg-codec-choice.patch new file mode 100644 index 0000000..3c2bf10 --- /dev/null +++ b/multimedia/compat-ffmpeg5/ffmpeg-codec-choice.patch @@ -0,0 +1,56 @@ +From: Jan Engelhardt + +Edit the default codec selection such that + + ffmpeg -i youtube.blah.webm foobar.mkv + +without any further arguments can produce a result even on a +reduced codec selection list. + +--- + libavformat/matroskaenc.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +Index: ffmpeg-5.0/libavformat/matroskaenc.c +=================================================================== +--- ffmpeg-5.0.orig/libavformat/matroskaenc.c 2022-01-14 19:45:40.000000000 +0100 ++++ ffmpeg-5.0/libavformat/matroskaenc.c 2022-02-04 08:29:14.582130919 +0100 +@@ -2887,16 +2887,24 @@ static int mkv_query_codec(enum AVCodecI + return 0; + } + ++#define PREFAUDIO \ ++ CONFIG_LIBOPUS_ENCODER ? AV_CODEC_ID_OPUS : \ ++ CONFIG_AAC_ENCODER ? AV_CODEC_ID_AAC : \ ++ CONFIG_VORBIS_ENCODER ? AV_CODEC_ID_VORBIS : \ ++ AV_CODEC_ID_AC3 + const AVOutputFormat ff_matroska_muxer = { + .name = "matroska", + .long_name = NULL_IF_CONFIG_SMALL("Matroska"), + .mime_type = "video/x-matroska", + .extensions = "mkv", + .priv_data_size = sizeof(MatroskaMuxContext), +- .audio_codec = CONFIG_LIBVORBIS_ENCODER ? +- AV_CODEC_ID_VORBIS : AV_CODEC_ID_AC3, +- .video_codec = CONFIG_LIBX264_ENCODER ? +- AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4, ++ .audio_codec = PREFAUDIO, ++ .video_codec = ++ CONFIG_LIBVPX_VP9_ENCODER ? AV_CODEC_ID_VP9 : \ ++ CONFIG_LIBX264_ENCODER ? AV_CODEC_ID_H264 : \ ++ CONFIG_LIBVPX_VP8_ENCODER ? AV_CODEC_ID_VP8 : \ ++ CONFIG_MPEG4_ENCODER ? AV_CODEC_ID_MPEG4 : \ ++ AV_CODEC_ID_THEORA, + .init = mkv_init, + .deinit = mkv_deinit, + .write_header = mkv_write_header, +@@ -2954,8 +2962,7 @@ const AVOutputFormat ff_matroska_audio_m + .mime_type = "audio/x-matroska", + .extensions = "mka", + .priv_data_size = sizeof(MatroskaMuxContext), +- .audio_codec = CONFIG_LIBVORBIS_ENCODER ? +- AV_CODEC_ID_VORBIS : AV_CODEC_ID_AC3, ++ .audio_codec = PREFAUDIO, + .video_codec = AV_CODEC_ID_NONE, + .init = mkv_init, + .deinit = mkv_deinit, diff --git a/multimedia/compat-ffmpeg5/ffmpeg-dlopen-openh264.patch b/multimedia/compat-ffmpeg5/ffmpeg-dlopen-openh264.patch new file mode 100644 index 0000000..a283f85 --- /dev/null +++ b/multimedia/compat-ffmpeg5/ffmpeg-dlopen-openh264.patch @@ -0,0 +1,363 @@ +From 1f48740db0dda8d6ec1b97a7f4a794e381a65636 Mon Sep 17 00:00:00 2001 +From: Neal Gompa +Date: Wed, 12 Oct 2022 09:41:27 -0400 +Subject: [PATCH] avcodec/openh264: Add the ability to dlopen() OpenH264 + +We can't directly depend on OpenH264, but we can weakly link to it +and gracefully expose the capability. + +Co-authored-by: Andreas Schneider +Co-authored-by: Neal Gompa + +Signed-off-by: Andreas Schneider +Signed-off-by: Neal Gompa +--- + configure | 3 + + libavcodec/Makefile | 1 + + libavcodec/libopenh264.c | 5 ++ + libavcodec/libopenh264_dlopen.c | 147 ++++++++++++++++++++++++++++++++ + libavcodec/libopenh264_dlopen.h | 58 +++++++++++++ + libavcodec/libopenh264dec.c | 10 +++ + libavcodec/libopenh264enc.c | 10 +++ + 7 files changed, 234 insertions(+) + create mode 100644 libavcodec/libopenh264_dlopen.c + create mode 100644 libavcodec/libopenh264_dlopen.h + +diff --git a/configure b/configure +index ba5793b2ff..8855c1a908 100755 +--- a/configure ++++ b/configure +@@ -251,6 +251,7 @@ External library support: + --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no] + --enable-libopencv enable video filtering via libopencv [no] + --enable-libopenh264 enable H.264 encoding via OpenH264 [no] ++ --enable-libopenh264-dlopen enable H.264 encoding via dlopen()'ed OpenH264 [no] + --enable-libopenjpeg enable JPEG 2000 de/encoding via OpenJPEG [no] + --enable-libopenmpt enable decoding tracked files via libopenmpt [no] + --enable-libopenvino enable OpenVINO as a DNN module backend +@@ -1844,6 +1845,7 @@ EXTERNAL_LIBRARY_LIST=" + libmysofa + libopencv + libopenh264 ++ libopenh264_dlopen + libopenjpeg + libopenmpt + libopenvino +@@ -6596,6 +6598,7 @@ enabled libopencv && { check_headers opencv2/core/core_c.h && + require libopencv opencv2/core/core_c.h cvCreateImageHeader -lopencv_core -lopencv_imgproc; } || + require_pkg_config libopencv opencv opencv/cxcore.h cvCreateImageHeader; } + enabled libopenh264 && require_pkg_config libopenh264 openh264 wels/codec_api.h WelsGetCodecVersion ++enabled libopenh264_dlopen && enable libopenh264 && add_cppflags "-I$(dirname `readlink -f $0`)/ffdlopenhdrs/include -DCONFIG_LIBOPENH264_DLOPEN=1" + enabled libopenjpeg && { check_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version || + { require_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } } + enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create -lstdc++ && append libopenmpt_extralibs "-lstdc++" +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index 457ec58377..08a26fba5f 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1075,6 +1075,7 @@ OBJS-$(CONFIG_LIBMP3LAME_ENCODER) += libmp3lame.o + OBJS-$(CONFIG_LIBOPENCORE_AMRNB_DECODER) += libopencore-amr.o + OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER) += libopencore-amr.o + OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER) += libopencore-amr.o ++OBJS-$(CONFIG_LIBOPENH264_DLOPEN) += libopenh264_dlopen.o + OBJS-$(CONFIG_LIBOPENH264_DECODER) += libopenh264dec.o libopenh264.o + OBJS-$(CONFIG_LIBOPENH264_ENCODER) += libopenh264enc.o libopenh264.o + OBJS-$(CONFIG_LIBOPENJPEG_DECODER) += libopenjpegdec.o +diff --git a/libavcodec/libopenh264.c b/libavcodec/libopenh264.c +index c80c85ea8b..128c3d9846 100644 +--- a/libavcodec/libopenh264.c ++++ b/libavcodec/libopenh264.c +@@ -20,8 +20,13 @@ + */ + + #include ++ ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++#include "libopenh264_dlopen.h" ++#else + #include + #include ++#endif + + #include "libavutil/error.h" + #include "libavutil/log.h" +diff --git a/libavcodec/libopenh264_dlopen.c b/libavcodec/libopenh264_dlopen.c +new file mode 100644 +index 0000000000..49ea8ff44f +--- /dev/null ++++ b/libavcodec/libopenh264_dlopen.c +@@ -0,0 +1,147 @@ ++/* ++ * OpenH264 dlopen code ++ * ++ * Copyright (C) 2022 Andreas Schneider ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include ++ ++#include "libopenh264_dlopen.h" ++ ++/* ++ * The symbol binding makes sure we do not run into strict aliasing issues which ++ * can lead into segfaults. ++ */ ++typedef int (*__oh264_WelsCreateSVCEncoder)(ISVCEncoder **); ++typedef void (*__oh264_WelsDestroySVCEncoder)(ISVCEncoder *); ++typedef int (*__oh264_WelsGetDecoderCapability)(SDecoderCapability *); ++typedef long (*__oh264_WelsCreateDecoder)(ISVCDecoder **); ++typedef void (*__oh264_WelsDestroyDecoder)(ISVCDecoder *); ++typedef OpenH264Version (*__oh264_WelsGetCodecVersion)(void); ++typedef void (*__oh264_WelsGetCodecVersionEx)(OpenH264Version *); ++ ++#define OH264_SYMBOL_ENTRY(i) \ ++ union { \ ++ __oh264_##i f; \ ++ void *obj; \ ++ } _oh264_##i ++ ++struct oh264_symbols { ++ OH264_SYMBOL_ENTRY(WelsCreateSVCEncoder); ++ OH264_SYMBOL_ENTRY(WelsDestroySVCEncoder); ++ OH264_SYMBOL_ENTRY(WelsGetDecoderCapability); ++ OH264_SYMBOL_ENTRY(WelsCreateDecoder); ++ OH264_SYMBOL_ENTRY(WelsDestroyDecoder); ++ OH264_SYMBOL_ENTRY(WelsGetCodecVersion); ++ OH264_SYMBOL_ENTRY(WelsGetCodecVersionEx); ++}; ++ ++/* Symbols are bound by loadLibOpenH264() */ ++static struct oh264_symbols openh264_symbols; ++ ++int oh264_WelsCreateSVCEncoder(ISVCEncoder **ppEncoder) { ++ return openh264_symbols._oh264_WelsCreateSVCEncoder.f(ppEncoder); ++} ++ ++void oh264_WelsDestroySVCEncoder(ISVCEncoder *pEncoder) { ++ return openh264_symbols._oh264_WelsDestroySVCEncoder.f(pEncoder); ++} ++ ++int oh264_WelsGetDecoderCapability(SDecoderCapability *pDecCapability) { ++ return openh264_symbols._oh264_WelsGetDecoderCapability.f(pDecCapability); ++} ++ ++long oh264_WelsCreateDecoder(ISVCDecoder **ppDecoder) { ++ return openh264_symbols._oh264_WelsCreateDecoder.f(ppDecoder); ++} ++ ++void oh264_WelsDestroyDecoder(ISVCDecoder *pDecoder) { ++ return openh264_symbols._oh264_WelsDestroyDecoder.f(pDecoder); ++} ++ ++OpenH264Version oh264_WelsGetCodecVersion(void) { ++ return openh264_symbols._oh264_WelsGetCodecVersion.f(); ++} ++ ++void oh264_WelsGetCodecVersionEx(OpenH264Version *pVersion) { ++ openh264_symbols._oh264_WelsGetCodecVersionEx.f(pVersion); ++} ++ ++static void *_oh264_bind_symbol(AVCodecContext *avctx, ++ void *handle, ++ const char *sym_name) { ++ void *sym = NULL; ++ ++ sym = dlsym(handle, sym_name); ++ if (sym == NULL) { ++ const char *err = dlerror(); ++ av_log(avctx, ++ AV_LOG_WARNING, ++ "%s: Failed to bind %s\n", ++ err, ++ sym_name); ++ return NULL; ++ } ++ ++ return sym; ++} ++ ++#define oh264_bind_symbol(avctx, handle, sym_name) \ ++ if (openh264_symbols._oh264_##sym_name.obj == NULL) { \ ++ openh264_symbols._oh264_##sym_name.obj = _oh264_bind_symbol(avctx, handle, #sym_name); \ ++ if (openh264_symbols._oh264_##sym_name.obj == NULL) { \ ++ return 1; \ ++ } \ ++ } ++ ++int loadLibOpenH264(AVCodecContext *avctx) { ++ static bool initialized = false; ++ void *libopenh264 = NULL; ++ const char *err = NULL; ++ ++ if (initialized) { ++ return 0; ++ } ++ ++#define OPENH264_LIB "libopenh264.so.7" ++ libopenh264 = dlopen(OPENH264_LIB, RTLD_LAZY); ++ err = dlerror(); ++ if (err != NULL) { ++ av_log(avctx, AV_LOG_WARNING, ++ "%s: %s is missing, openh264 support will be disabled\n", err, ++ OPENH264_LIB); ++ ++ if (libopenh264 != NULL) { ++ dlclose(libopenh264); ++ } ++ return 1; ++ } ++ ++ oh264_bind_symbol(avctx, libopenh264, WelsCreateSVCEncoder); ++ oh264_bind_symbol(avctx, libopenh264, WelsDestroySVCEncoder); ++ oh264_bind_symbol(avctx, libopenh264, WelsGetDecoderCapability); ++ oh264_bind_symbol(avctx, libopenh264, WelsCreateDecoder); ++ oh264_bind_symbol(avctx, libopenh264, WelsDestroyDecoder); ++ oh264_bind_symbol(avctx, libopenh264, WelsGetCodecVersion); ++ oh264_bind_symbol(avctx, libopenh264, WelsGetCodecVersionEx); ++ ++ initialized = true; ++ ++ return 0; ++} +diff --git a/libavcodec/libopenh264_dlopen.h b/libavcodec/libopenh264_dlopen.h +new file mode 100644 +index 0000000000..d7d8bb7cad +--- /dev/null ++++ b/libavcodec/libopenh264_dlopen.h +@@ -0,0 +1,58 @@ ++/* ++ * OpenH264 dlopen code ++ * ++ * Copyright (C) 2022 Andreas Schneider ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#ifndef HAVE_LIBOPENH264_DLOPEN_H ++#define HAVE_LIBOPENH264_DLOPEN_H ++ ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++ ++#include ++#include ++ ++#include "avcodec.h" ++ ++int oh264_WelsCreateSVCEncoder(ISVCEncoder **ppEncoder); ++#define WelsCreateSVCEncoder oh264_WelsCreateSVCEncoder ++ ++void oh264_WelsDestroySVCEncoder(ISVCEncoder *pEncoder); ++#define WelsDestroySVCEncoder oh264_WelsDestroySVCEncoder ++ ++int oh264_WelsGetDecoderCapability(SDecoderCapability *pDecCapability); ++#define WelsGetDecoderCapability oh264_WelsGetDecoderCapability ++ ++long oh264_WelsCreateDecoder(ISVCDecoder **ppDecoder); ++#define WelsCreateDecoder oh264_WelsCreateDecoder ++ ++void oh264_WelsDestroyDecoder(ISVCDecoder *pDecoder); ++#define WelsDestroyDecoder oh264_WelsDestroyDecoder ++ ++OpenH264Version oh264_WelsGetCodecVersion(void); ++#define WelsGetCodecVersion oh264_WelsGetCodecVersion ++ ++void oh264_WelsGetCodecVersionEx(OpenH264Version *pVersion); ++#define WelsGetCodecVersionEx oh264_WelsGetCodecVersionEx ++ ++int loadLibOpenH264(AVCodecContext *avctx); ++ ++#endif /* CONFIG_LIBOPENH264_DLOPEN */ ++ ++#endif /* HAVE_LIBOPENH264_DLOPEN_H */ +diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c +index 7e14d4dd7d..a805598446 100644 +--- a/libavcodec/libopenh264dec.c ++++ b/libavcodec/libopenh264dec.c +@@ -19,8 +19,12 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++#include "libopenh264_dlopen.h" ++#else + #include + #include ++#endif + + #include "libavutil/common.h" + #include "libavutil/fifo.h" +@@ -55,6 +59,12 @@ static av_cold int svc_decode_init(AVCodecContext *avctx) + int log_level; + WelsTraceCallback callback_function; + ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++ if (loadLibOpenH264(avctx)) { ++ return AVERROR_DECODER_NOT_FOUND; ++ } ++#endif ++ + if (WelsCreateDecoder(&s->decoder)) { + av_log(avctx, AV_LOG_ERROR, "Unable to create decoder\n"); + return AVERROR_UNKNOWN; +diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c +index 5257906567..80481f3d0a 100644 +--- a/libavcodec/libopenh264enc.c ++++ b/libavcodec/libopenh264enc.c +@@ -19,8 +19,12 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++#include "libopenh264_dlopen.h" ++#else + #include + #include ++#endif + + #include "libavutil/attributes.h" + #include "libavutil/common.h" +@@ -114,6 +118,12 @@ static av_cold int svc_encode_init(AVCodecContext *avctx) + WelsTraceCallback callback_function; + AVCPBProperties *props; + ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++ if (loadLibOpenH264(avctx)) { ++ return AVERROR_ENCODER_NOT_FOUND; ++ } ++#endif ++ + if (WelsCreateSVCEncoder(&s->encoder)) { + av_log(avctx, AV_LOG_ERROR, "Unable to create encoder\n"); + return AVERROR_UNKNOWN; +-- +2.36.1 + diff --git a/multimedia/compat-ffmpeg5/ffmpeg.spec b/multimedia/compat-ffmpeg5/ffmpeg.spec index 5a85d26..9072f3d 100644 --- a/multimedia/compat-ffmpeg5/ffmpeg.spec +++ b/multimedia/compat-ffmpeg5/ffmpeg.spec @@ -45,8 +45,11 @@ %ifarch x86_64 %global _with_mfx 1 %global _with_svtav1 1 +%global _with_svtvp9 1 +%global _with_svthevc 1 %global _with_vapoursynth 1 %global _with_vmaf 1 +%global _with_openh264 1 %endif # flavor nonfree @@ -111,7 +114,7 @@ ExclusiveArch: armv7hnl Summary: Digital VCR and streaming server Name: compat-ffmpeg5%{?flavor} Version: 5.1.4 -Release: 1%{?date:.%{?date}%{?date:git}%{?rel}}%{?dist} +Release: 2%{?date:.%{?date}%{?date:git}%{?rel}}%{?dist} License: %{ffmpeg_license} URL: http://ffmpeg.org/ %if 0%{?date} @@ -119,6 +122,23 @@ Source0: ffmpeg-%{?branch}%{date}.tar.bz2 %else Source0: http://ffmpeg.org/releases/ffmpeg-%{version}.tar.xz %endif + +# lavc/svt_hevc: add libsvt hevc encoder wrapper +Patch1: 0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch +# Add libsvt_hevc encoder docs +Patch2: 0002-doc-Add-libsvt_hevc-encoder-docs.patch +# Add ability for ffmpeg to run svt vp9 +Patch3: 030-ffmpeg-add-svt-vp9.patch +# Compatibility fix for chromium +Patch4: 040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch + +# Fedora patches +Patch5: ffmpeg-allow-fdk-aac-free.patch +Patch6: 0001-lavc-libopenh264-Drop-openh264-runtime-version-check.patch +%{!?_with_openh264:Patch7: ffmpeg-dlopen-openh264.patch} +Patch8: ffmpeg-codec-choice.patch + + Conflicts: %{name}-free Requires: %{name}-libs%{?_isa} = %{version}-%{release} %{?_with_cuda:BuildRequires: cuda-minimal-build-%{_cuda_version_rpm} cuda-drivers-devel} @@ -207,7 +227,10 @@ BuildRequires: soxr-devel BuildRequires: speex-devel BuildRequires: pkgconfig(srt) %{?_with_svtav1:BuildRequires: svt-av1-devel >= 0.9.0} +%{?_with_svtvp9:BuildRequires: svt-vp9-devel} +%{?_with_svthevc:BuildRequires: svt-hevc-devel} %{?_with_tesseract:BuildRequires: tesseract-devel} +%{?_with_openh264:BuildRequires: openh264-devel} #BuildRequires: texi2html BuildRequires: texinfo %{?_with_twolame:BuildRequires: twolame-devel} @@ -223,6 +246,7 @@ BuildRequires: zlib-devel %{?_with_zmq:BuildRequires: zeromq-devel} %{!?_without_zvbi:BuildRequires: zvbi-devel} + %description FFmpeg is a complete and free Internet live audio and video broadcasting solution for Linux/Unix. It also includes a digital @@ -243,6 +267,7 @@ Provides: libavdevice%{?flavor}%{_isa} Provides: libavdevice5%{?flavor}%{_isa} Obsoletes: libavdevice5 <= %{version} %{?_with_vmaf:Recommends: vmaf-models} +%{!?_with_openh264:Recommends: openh264} %description libs FFmpeg is a complete and free Internet live audio and video @@ -344,7 +369,11 @@ This package contains development files for %{name} --enable-libsrt \\\ --enable-libssh \\\ %{?_with_svtav1:--enable-libsvtav1} \\\ + %{?_with_svtvp9:--enable-libsvtvp9} \\\ + %{?_with_svthevc:--enable-libsvthevc} \\\ %{?_with_tesseract:--enable-libtesseract} \\\ + %{?_with_openh264:--enable-libopenh264} \\\ + %{!?_with_openh264-dlopen:--enable-libopenh264} \\\ --enable-libtheora \\\ %{?_with_twolame:--enable-libtwolame} \\\ --enable-libvorbis \\\ @@ -480,6 +509,10 @@ rm -rf %buildroot%{_mandir}/man* %changelog +* Wed Mar 6 2024 Raven - 5.1.4-2 +- fix for chromium +- add openh264 support + * Mon Nov 13 2023 Raven - 5.1.4-1 - Update to 5.1.4 release diff --git a/multimedia/ffmpeg/0001-lavc-libopenh264-Drop-openh264-runtime-version-check.patch b/multimedia/ffmpeg/0001-lavc-libopenh264-Drop-openh264-runtime-version-check.patch new file mode 100644 index 0000000..7066f16 --- /dev/null +++ b/multimedia/ffmpeg/0001-lavc-libopenh264-Drop-openh264-runtime-version-check.patch @@ -0,0 +1,109 @@ +From a641e629591d68bd3edd99bddec623dc31295f6b Mon Sep 17 00:00:00 2001 +From: Kalev Lember +Date: Wed, 6 Dec 2023 14:37:34 +0100 +Subject: [PATCH] lavc/libopenh264: Drop openh264 runtime version checks + +Years ago, openh264 releases often changed their ABI without changing +the library soname. To avoid running into ABI issues, a version check +was added to lavc libopenh264 code to error out at runtime in case the +build time and runtime openh264 versions don't match. + +This should no longer be an issue with newer openh264 releases and we +can drop the runtime version check and rely on upstream doing the right +thing and bump the library soname if the ABI changes, similar to how +other libraries are consumed in ffmpeg. + +Almost all major distributions now include openh264 and this means there +are more eyes on ABI changes and issues are discovered and reported +quickly. See e.g. https://github.com/cisco/openh264/issues/3564 where an +ABI issue was quickly discovered and fixed. + +Relaxing the check allows downstream distributions to build ffmpeg +against e.g. openh264 2.3.1 and ship an update to ABI-compatible +openh264 2.4.0, without needing to coordinate a lock step update between +ffmpeg and openh264 (which can be difficult if openh264 is distributed +by Cisco and ffmpeg comes from the distro, such as is the case for +Fedora). + +Signed-off-by: Kalev Lember +--- + libavcodec/libopenh264.c | 15 --------------- + libavcodec/libopenh264.h | 2 -- + libavcodec/libopenh264dec.c | 4 ---- + libavcodec/libopenh264enc.c | 4 ---- + 4 files changed, 25 deletions(-) + +diff --git a/libavcodec/libopenh264.c b/libavcodec/libopenh264.c +index 0f6d28ed88..c80c85ea8b 100644 +--- a/libavcodec/libopenh264.c ++++ b/libavcodec/libopenh264.c +@@ -46,18 +46,3 @@ void ff_libopenh264_trace_callback(void *ctx, int level, const char *msg) + int equiv_ffmpeg_log_level = libopenh264_to_ffmpeg_log_level(level); + av_log(ctx, equiv_ffmpeg_log_level, "%s\n", msg); + } +- +-int ff_libopenh264_check_version(void *logctx) +-{ +- // Mingw GCC < 4.7 on x86_32 uses an incorrect/buggy ABI for the WelsGetCodecVersion +- // function (for functions returning larger structs), thus skip the check in those +- // configurations. +-#if !defined(_WIN32) || !defined(__GNUC__) || !ARCH_X86_32 || AV_GCC_VERSION_AT_LEAST(4, 7) +- OpenH264Version libver = WelsGetCodecVersion(); +- if (memcmp(&libver, &g_stCodecVersion, sizeof(libver))) { +- av_log(logctx, AV_LOG_ERROR, "Incorrect library version loaded\n"); +- return AVERROR(EINVAL); +- } +-#endif +- return 0; +-} +diff --git a/libavcodec/libopenh264.h b/libavcodec/libopenh264.h +index dbb9c5d429..0b462d6fdc 100644 +--- a/libavcodec/libopenh264.h ++++ b/libavcodec/libopenh264.h +@@ -34,6 +34,4 @@ + + void ff_libopenh264_trace_callback(void *ctx, int level, const char *msg); + +-int ff_libopenh264_check_version(void *logctx); +- + #endif /* AVCODEC_LIBOPENH264_H */ +diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c +index 7d650ae03e..b6a9bba2dc 100644 +--- a/libavcodec/libopenh264dec.c ++++ b/libavcodec/libopenh264dec.c +@@ -52,13 +52,9 @@ static av_cold int svc_decode_init(AVCodecContext *avctx) + { + SVCContext *s = avctx->priv_data; + SDecodingParam param = { 0 }; +- int err; + int log_level; + WelsTraceCallback callback_function; + +- if ((err = ff_libopenh264_check_version(avctx)) < 0) +- return AVERROR_DECODER_NOT_FOUND; +- + if (WelsCreateDecoder(&s->decoder)) { + av_log(avctx, AV_LOG_ERROR, "Unable to create decoder\n"); + return AVERROR_UNKNOWN; +diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c +index f518d0894e..6f231d22b2 100644 +--- a/libavcodec/libopenh264enc.c ++++ b/libavcodec/libopenh264enc.c +@@ -110,14 +110,10 @@ static av_cold int svc_encode_init(AVCodecContext *avctx) + { + SVCContext *s = avctx->priv_data; + SEncParamExt param = { 0 }; +- int err; + int log_level; + WelsTraceCallback callback_function; + AVCPBProperties *props; + +- if ((err = ff_libopenh264_check_version(avctx)) < 0) +- return AVERROR_ENCODER_NOT_FOUND; +- + if (WelsCreateSVCEncoder(&s->encoder)) { + av_log(avctx, AV_LOG_ERROR, "Unable to create encoder\n"); + return AVERROR_UNKNOWN; +-- +2.43.0 + diff --git a/multimedia/ffmpeg/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch b/multimedia/ffmpeg/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch new file mode 100644 index 0000000..3215162 --- /dev/null +++ b/multimedia/ffmpeg/0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch @@ -0,0 +1,674 @@ +From be059eaeefdc49e93066a8b618d5635e9a2c696a Mon Sep 17 00:00:00 2001 +From: Jing Sun +Date: Wed, 21 Nov 2018 11:33:04 +0800 +Subject: [PATCH] lavc/svt_hevc: add libsvt hevc encoder wrapper + +Signed-off-by: Zhengxu Huang +Signed-off-by: Hassene Tmar +Signed-off-by: Jun Zhao +Signed-off-by: Jing Sun +Signed-off-by: Austin Hu +Signed-off-by: Christopher Degawa +Signed-off-by: Guo Jiansheng +--- + configure | 4 + + libavcodec/Makefile | 1 + + libavcodec/allcodecs.c | 1 + + libavcodec/libsvt_hevc.c | 585 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 591 insertions(+) + create mode 100644 libavcodec/libsvt_hevc.c + +diff --git a/configure b/configure +index c8ae0a061d..9cc741d2a7 100755 +--- a/configure ++++ b/configure +@@ -330,6 +330,7 @@ External library support: + --enable-vapoursynth enable VapourSynth demuxer [no] + --disable-xlib disable xlib [autodetect] + --disable-zlib disable zlib [autodetect] ++ --enable-libsvthevc enable HEVC encoding via svt [no] + + The following libraries provide various hardware acceleration features: + --disable-amf disable AMF video encoding code [autodetect] +@@ -1898,6 +1899,7 @@ EXTERNAL_LIBRARY_LIST=" + libsrt + libssh + libsvtav1 ++ libsvthevc + libtensorflow + libtesseract + libtheora +@@ -3495,6 +3497,7 @@ vapoursynth_demuxer_deps="vapoursynth" + videotoolbox_suggest="coreservices" + videotoolbox_deps="corefoundation coremedia corevideo" + videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames" ++libsvt_hevc_encoder_deps="libsvthevc" + + # demuxers / muxers + ac3_demuxer_select="ac3_parser" +@@ -6868,6 +6871,7 @@ enabled libssh && require_pkg_config libssh "libssh >= 0.6.0" libssh/ + enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init + enabled libsrt && require_pkg_config libsrt "srt >= 1.3.0" srt/srt.h srt_socket + enabled libsvtav1 && require_pkg_config libsvtav1 "SvtAv1Enc >= 0.9.0" EbSvtAv1Enc.h svt_av1_enc_init_handle ++enabled libsvthevc && require_pkg_config libsvthevc SvtHevcEnc EbApi.h EbInitHandle + enabled libtensorflow && require libtensorflow tensorflow/c/c_api.h TF_Version -ltensorflow + enabled libtesseract && require_pkg_config libtesseract tesseract tesseract/capi.h TessBaseAPICreate + enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index bb42095165..08ebc58d7d 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1143,6 +1143,7 @@ + OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o + OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o + OBJS-$(CONFIG_LIBX265_ENCODER) += libx265.o ++OBJS-$(CONFIG_LIBSVT_HEVC_ENCODER) += libsvt_hevc.o + OBJS-$(CONFIG_LIBXAVS_ENCODER) += libxavs.o + OBJS-$(CONFIG_LIBXAVS2_ENCODER) += libxavs2.o + OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o +diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c +index 93ce8e3224..b709c7d551 100644 +--- a/libavcodec/allcodecs.c ++++ b/libavcodec/allcodecs.c +@@ -829,6 +829,7 @@ extern const FFCodec ff_libxavs_encoder; + extern const FFCodec ff_libxavs2_encoder; + extern const FFCodec ff_libxvid_encoder; + extern const FFCodec ff_libzvbi_teletext_decoder; ++extern const FFCodec ff_libsvt_hevc_encoder; + + /* text */ + extern const FFCodec ff_bintext_decoder; +diff --git a/libavcodec/libsvt_hevc.c b/libavcodec/libsvt_hevc.c +new file mode 100644 +index 0000000000..80b53a2157 +--- /dev/null ++++ b/libavcodec/libsvt_hevc.c +@@ -0,0 +1,585 @@ ++/* ++* Scalable Video Technology for HEVC encoder library plugin ++* ++* Copyright (c) 2019 Intel Corporation ++* ++* This file is part of FFmpeg. ++* ++* FFmpeg is free software; you can redistribute it and/or ++* modify it under the terms of the GNU Lesser General Public ++* License as published by the Free Software Foundation; either ++* version 2.1 of the License, or (at your option) any later version. ++* ++* FFmpeg is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++* Lesser General Public License for more details. ++* ++* You should have received a copy of the GNU Lesser General Public ++* License along with this program; if not, write to the Free Software ++* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++*/ ++ ++#include "EbApi.h" ++ ++#include "libavutil/common.h" ++#include "libavutil/frame.h" ++#include "libavutil/opt.h" ++ ++#include "codec_internal.h" ++#include "internal.h" ++#include "avcodec.h" ++#include "encode.h" ++ ++typedef enum eos_status { ++ EOS_NOT_REACHED = 0, ++ EOS_SENT, ++ EOS_RECEIVED ++}EOS_STATUS; ++ ++typedef struct SvtContext { ++ AVClass *class; ++ ++ EB_H265_ENC_CONFIGURATION enc_params; ++ EB_COMPONENTTYPE *svt_handle; ++ EB_BUFFERHEADERTYPE in_buf; ++ uint8_t *in_data; ++ EOS_STATUS eos_flag; ++ ++ // User options. ++ int profile; ++ int hierarchical_level; ++ int enc_mode; ++ int tier; ++ int level; ++ int rc_mode; ++ int scd; ++ int tune; ++ int base_layer_switch_mode; ++ int qp; ++ int aud; ++ int asm_type; ++ int forced_idr; ++ int la_depth; ++ int thread_count; ++ int target_socket; ++ int high_dynamic_range; ++ int unrestricted_motion_vector; ++ int tile_row_count; ++ int tile_col_count; ++ int tile_slice_mode; ++ int pred_struct; ++ int vid_info; ++} SvtContext; ++ ++static int error_mapping(EB_ERRORTYPE svt_ret) ++{ ++ switch (svt_ret) { ++ case EB_ErrorInsufficientResources: ++ return AVERROR(ENOMEM); ++ ++ case EB_ErrorUndefined: ++ case EB_ErrorInvalidComponent: ++ case EB_ErrorBadParameter: ++ return AVERROR(EINVAL); ++ ++ case EB_ErrorDestroyThreadFailed: ++ case EB_ErrorSemaphoreUnresponsive: ++ case EB_ErrorDestroySemaphoreFailed: ++ case EB_ErrorCreateMutexFailed: ++ case EB_ErrorMutexUnresponsive: ++ case EB_ErrorDestroyMutexFailed: ++ return AVERROR_EXTERNAL; ++ ++ case EB_NoErrorEmptyQueue: ++ return AVERROR(EAGAIN); ++ ++ case EB_ErrorNone: ++ return 0; ++ ++ default: ++ return AVERROR_UNKNOWN; ++ } ++} ++ ++static void free_buffer(SvtContext *svt_enc) ++{ ++ if (svt_enc && svt_enc->in_data) { ++ av_freep(&svt_enc->in_data); ++ svt_enc->in_data = NULL; ++ } ++} ++ ++static EB_ERRORTYPE alloc_buffer(SvtContext *svt_enc) ++{ ++ EB_BUFFERHEADERTYPE *in_buf = &svt_enc->in_buf; ++ EB_H265_ENC_INPUT *in_data = NULL; ++ ++ memset(in_buf, 0, sizeof(*in_buf)); ++ in_buf->nSize = sizeof(*in_buf); ++ in_buf->sliceType = EB_INVALID_PICTURE; ++ ++ in_data = (EB_H265_ENC_INPUT *)av_mallocz(sizeof(*in_data)); ++ if (in_data) { ++ svt_enc->in_data = in_buf->pBuffer = (uint8_t *)in_data; ++ return EB_ErrorNone; ++ } else { ++ return EB_ErrorInsufficientResources; ++ } ++} ++ ++static int config_enc_params(EB_H265_ENC_CONFIGURATION *param, ++ AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ ++ param->sourceWidth = avctx->width; ++ param->sourceHeight = avctx->height; ++ ++ if ((avctx->pix_fmt == AV_PIX_FMT_YUV420P10) || ++ (avctx->pix_fmt == AV_PIX_FMT_YUV422P10) || ++ (avctx->pix_fmt == AV_PIX_FMT_YUV444P10)) { ++ av_log(avctx, AV_LOG_DEBUG, "Set 10 bits depth input\n"); ++ param->encoderBitDepth = 10; ++ } else { ++ av_log(avctx, AV_LOG_DEBUG, "Set 8 bits depth input\n"); ++ param->encoderBitDepth = 8; ++ } ++ ++ if ((avctx->pix_fmt == AV_PIX_FMT_YUV420P) || ++ (avctx->pix_fmt == AV_PIX_FMT_YUV420P10)) ++ param->encoderColorFormat = EB_YUV420; ++ else if ((avctx->pix_fmt == AV_PIX_FMT_YUV422P) || ++ (avctx->pix_fmt == AV_PIX_FMT_YUV422P10)) ++ param->encoderColorFormat = EB_YUV422; ++ else ++ param->encoderColorFormat = EB_YUV444; ++ ++ param->profile = svt_enc->profile; ++ ++ if (FF_PROFILE_HEVC_MAIN_STILL_PICTURE == param->profile) { ++ av_log(avctx, AV_LOG_ERROR, "Main Still Picture Profile not supported\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if ((param->encoderColorFormat >= EB_YUV422) && ++ (param->profile != FF_PROFILE_HEVC_REXT)) { ++ av_log(avctx, AV_LOG_WARNING, "Rext Profile forced for 422 or 444\n"); ++ param->profile = FF_PROFILE_HEVC_REXT; ++ } ++ ++ if ((FF_PROFILE_HEVC_MAIN == param->profile) && ++ (param->encoderBitDepth > 8)) { ++ av_log(avctx, AV_LOG_WARNING, "Main10 Profile forced for 10 bits\n"); ++ param->profile = FF_PROFILE_HEVC_MAIN_10; ++ } ++ ++ param->targetBitRate = avctx->bit_rate; ++ param->vbvMaxrate = avctx->rc_max_rate; ++ param->vbvBufsize = avctx->rc_buffer_size; ++ ++ if (avctx->gop_size > 0) ++ param->intraPeriodLength = avctx->gop_size - 1; ++ ++ if ((avctx->framerate.num > 0) && (avctx->framerate.den > 0)) { ++ param->frameRateNumerator = avctx->framerate.num; ++ param->frameRateDenominator = ++ avctx->framerate.den * avctx->ticks_per_frame; ++ } else { ++ param->frameRateNumerator = avctx->time_base.den; ++ param->frameRateDenominator = ++ avctx->time_base.num * avctx->ticks_per_frame; ++ } ++ ++ param->hierarchicalLevels = svt_enc->hierarchical_level; ++ param->encMode = svt_enc->enc_mode; ++ param->tier = svt_enc->tier; ++ param->level = svt_enc->level; ++ param->rateControlMode = svt_enc->rc_mode; ++ param->sceneChangeDetection = svt_enc->scd; ++ param->tune = svt_enc->tune; ++ param->baseLayerSwitchMode = svt_enc->base_layer_switch_mode; ++ param->qp = svt_enc->qp; ++ param->accessUnitDelimiter = svt_enc->aud; ++ param->asmType = svt_enc->asm_type; ++ param->intraRefreshType = svt_enc->forced_idr; ++ param->highDynamicRangeInput = svt_enc->high_dynamic_range; ++ param->targetSocket = svt_enc->target_socket; ++ if (param->rateControlMode) { ++ param->maxQpAllowed = avctx->qmax; ++ param->minQpAllowed = avctx->qmin; ++ } ++ ++ if (svt_enc->la_depth != -1) ++ param->lookAheadDistance = svt_enc->la_depth; ++ ++ if ((svt_enc->thread_count > 0) && ++ (svt_enc->thread_count < (EB_THREAD_COUNT_MIN_CORE * EB_THREAD_COUNT_FACTOR))) { ++ param->threadCount = EB_THREAD_COUNT_MIN_CORE * EB_THREAD_COUNT_FACTOR; ++ av_log(avctx, AV_LOG_WARNING, "Thread count is set too small, forced to %"PRId32"\n", ++ param->threadCount); ++ } else if (svt_enc->thread_count % EB_THREAD_COUNT_MIN_CORE) { ++ param->threadCount = (svt_enc->thread_count + EB_THREAD_COUNT_MIN_CORE - 1) ++ / EB_THREAD_COUNT_MIN_CORE * EB_THREAD_COUNT_MIN_CORE; ++ av_log(avctx, AV_LOG_DEBUG, "Thread count is rounded to %"PRId32"\n", ++ param->threadCount); ++ } else { ++ param->threadCount = svt_enc->thread_count; ++ } ++ ++ if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) ++ param->codeVpsSpsPps = 0; ++ else ++ param->codeVpsSpsPps = 1; ++ ++ param->codeEosNal = 1; ++ ++ if (svt_enc->unrestricted_motion_vector == 0 || svt_enc->unrestricted_motion_vector == 1) { ++ param->unrestrictedMotionVector = svt_enc->unrestricted_motion_vector; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Unrestricted Motion Vector should be set 0 or 1\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if(svt_enc->tile_row_count >= 1 && svt_enc->tile_row_count <= 16) { ++ param->tileRowCount = svt_enc->tile_row_count; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Tile Row Count should between 1-16\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if(svt_enc->tile_col_count >= 1 && svt_enc->tile_col_count <= 16) { ++ param->tileColumnCount = svt_enc->tile_col_count; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Tile Column Count should between 1-16\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if(svt_enc->tile_slice_mode == 0 || svt_enc->tile_slice_mode == 1) { ++ param->tileSliceMode = svt_enc->tile_slice_mode; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Tile Slice Mode should be set 0 or 1\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if(svt_enc->pred_struct >= 0 && svt_enc->pred_struct <= 2) { ++ param->predStructure = svt_enc->pred_struct; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Pred Structure should between 0-2\n"); ++ return EB_ErrorBadParameter; ++ } ++ ++ if(svt_enc->vid_info == 0 || svt_enc->vid_info == 1) { ++ param->videoUsabilityInfo = svt_enc->vid_info; ++ } else { ++ av_log(avctx, AV_LOG_ERROR, "Video Usability Info should be set 0 or 1\n"); ++ return EB_ErrorBadParameter; ++ } ++ return EB_ErrorNone; ++} ++ ++static void read_in_data(EB_H265_ENC_CONFIGURATION *config, ++ const AVFrame *frame, ++ EB_BUFFERHEADERTYPE *header_ptr) ++{ ++ uint8_t is16bit; ++ uint64_t frame_size; ++ EB_H265_ENC_INPUT *in_data = (EB_H265_ENC_INPUT *)header_ptr->pBuffer; ++ ++ is16bit = config->encoderBitDepth > 8; ++ frame_size = (uint64_t)(config->sourceWidth * config->sourceHeight) << is16bit; ++ ++ in_data->luma = frame->data[0]; ++ in_data->cb = frame->data[1]; ++ in_data->cr = frame->data[2]; ++ ++ in_data->yStride = frame->linesize[0] >> is16bit; ++ in_data->cbStride = frame->linesize[1] >> is16bit; ++ in_data->crStride = frame->linesize[2] >> is16bit; ++ ++ if (config->encoderColorFormat == EB_YUV420) ++ frame_size *= 3/2u; ++ else if (config->encoderColorFormat == EB_YUV422) ++ frame_size *= 2u; ++ else ++ frame_size *= 3u; ++ ++ header_ptr->nFilledLen += frame_size; ++} ++ ++static av_cold int eb_enc_init(AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ EB_ERRORTYPE svt_ret; ++ ++ svt_enc->eos_flag = EOS_NOT_REACHED; ++ ++ svt_ret = EbInitHandle(&svt_enc->svt_handle, svt_enc, &svt_enc->enc_params); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to init handle\n"); ++ return error_mapping(svt_ret); ++ } ++ ++ svt_ret = config_enc_params(&svt_enc->enc_params, avctx); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to config parameters\n"); ++ goto failed_init_handle; ++ } ++ ++ svt_ret = EbH265EncSetParameter(svt_enc->svt_handle, &svt_enc->enc_params); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to set parameters\n"); ++ goto failed_init_handle; ++ } ++ ++ svt_ret = EbInitEncoder(svt_enc->svt_handle); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to init encoder\n"); ++ goto failed_init_handle; ++ } ++ ++ if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { ++ EB_BUFFERHEADERTYPE *header_ptr = NULL; ++ ++ svt_ret = EbH265EncStreamHeader(svt_enc->svt_handle, &header_ptr); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to build stream header\n"); ++ goto failed_init_encoder; ++ } ++ ++ avctx->extradata_size = header_ptr->nFilledLen; ++ avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); ++ if (!avctx->extradata) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to allocate extradata\n"); ++ svt_ret = EB_ErrorInsufficientResources; ++ goto failed_init_encoder; ++ } ++ memcpy(avctx->extradata, header_ptr->pBuffer, avctx->extradata_size); ++ memset(avctx->extradata+avctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); ++ } ++ ++ svt_ret = alloc_buffer(svt_enc); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to alloc data buffer\n"); ++ goto failed_init_encoder; ++ } ++ return 0; ++ ++failed_init_encoder: ++ EbDeinitEncoder(svt_enc->svt_handle); ++failed_init_handle: ++ EbDeinitHandle(svt_enc->svt_handle); ++ svt_enc->svt_handle = NULL; ++ svt_enc = NULL; ++ return error_mapping(svt_ret); ++} ++ ++static int eb_encode_frame(AVCodecContext *avctx, AVPacket *pkt, ++ const AVFrame *frame, int *got_packet) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ EB_BUFFERHEADERTYPE *header_ptr = &svt_enc->in_buf; ++ EB_ERRORTYPE svt_ret; ++ int av_ret; ++ ++ if (EOS_RECEIVED == svt_enc->eos_flag) { ++ *got_packet = 0; ++ return 0; ++ } ++ ++ if (!frame) { ++ if (!svt_enc->eos_flag) { ++ svt_enc->eos_flag = EOS_SENT; ++ ++ header_ptr->nAllocLen = 0; ++ header_ptr->nFilledLen = 0; ++ header_ptr->nTickCount = 0; ++ header_ptr->nFlags = EB_BUFFERFLAG_EOS; ++ header_ptr->pBuffer = NULL; ++ ++ EbH265EncSendPicture(svt_enc->svt_handle, header_ptr); ++ ++ av_log(avctx, AV_LOG_DEBUG, "Sent EOS\n"); ++ } ++ } else { ++ read_in_data(&svt_enc->enc_params, frame, header_ptr); ++ header_ptr->pts = frame->pts; ++ ++ EbH265EncSendPicture(svt_enc->svt_handle, header_ptr); ++ ++ av_log(avctx, AV_LOG_DEBUG, "Sent PTS %"PRId64"\n", header_ptr->pts); ++ } ++ ++ header_ptr = NULL; ++ svt_ret = EbH265GetPacket(svt_enc->svt_handle, &header_ptr, svt_enc->eos_flag); ++ ++ if (svt_ret == EB_NoErrorEmptyQueue) { ++ *got_packet = 0; ++ av_log(avctx, AV_LOG_DEBUG, "Received none\n"); ++ return 0; ++ } else if (svt_ret == EB_ErrorMax) { ++ *got_packet = 0; ++ av_log(avctx, AV_LOG_ERROR, "Received NULL packet with error code 0x%X\n", header_ptr->nFlags); ++ return AVERROR_INVALIDDATA; ++ } ++ ++ av_log(avctx, AV_LOG_DEBUG, "Received PTS %"PRId64" packet\n", header_ptr->pts); ++ ++ av_ret = ff_alloc_packet(avctx, pkt, header_ptr->nFilledLen); ++ if (av_ret) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to allocate a packet\n"); ++ EbH265ReleaseOutBuffer(&header_ptr); ++ return av_ret; ++ } ++ ++ memcpy(pkt->data, header_ptr->pBuffer, header_ptr->nFilledLen); ++ pkt->size = header_ptr->nFilledLen; ++ pkt->pts = header_ptr->pts; ++ pkt->dts = header_ptr->dts; ++ ++ if ((header_ptr->sliceType == EB_IDR_PICTURE) || ++ (header_ptr->sliceType == EB_I_PICTURE)) ++ pkt->flags |= AV_PKT_FLAG_KEY; ++ if (header_ptr->sliceType == EB_NON_REF_PICTURE) ++ pkt->flags |= AV_PKT_FLAG_DISPOSABLE; ++ ++ EbH265ReleaseOutBuffer(&header_ptr); ++ ++ *got_packet = 1; ++ ++ if (EB_BUFFERFLAG_EOS == header_ptr->nFlags) ++ svt_enc->eos_flag = EOS_RECEIVED; ++ ++ return 0; ++} ++ ++static av_cold int eb_enc_close(AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ ++ if (svt_enc) { ++ free_buffer(svt_enc); ++ ++ if (svt_enc->svt_handle) { ++ EbDeinitEncoder(svt_enc->svt_handle); ++ EbDeinitHandle(svt_enc->svt_handle); ++ svt_enc->svt_handle = NULL; ++ } ++ } ++ ++ return 0; ++} ++ ++#define OFFSET(x) offsetof(SvtContext, x) ++#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ++static const AVOption options[] = { ++ { "asm_type", "Assembly instruction set type [0: C Only, 1: Auto]", OFFSET(asm_type), ++ AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, ++ ++ { "aud", "Include Access Unit Delimiter", OFFSET(aud), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, ++ ++ { "bl_mode", "Random Access Prediction Structure type setting", OFFSET(base_layer_switch_mode), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, ++ ++ { "forced-idr", "If forcing keyframes, force them as IDR frames.", OFFSET(forced_idr), ++ AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, VE }, ++ ++ { "hielevel", "Hierarchical prediction levels setting", OFFSET(hierarchical_level), ++ AV_OPT_TYPE_INT, { .i64 = 3 }, 0, 3, VE , "hielevel"}, ++ { "flat", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "hielevel" }, ++ { "1 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "hielevel" }, ++ { "2 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "hielevel" }, ++ { "3 level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 3 }, INT_MIN, INT_MAX, VE, "hielevel" }, ++ ++ { "la_depth", "Look ahead distance [0, 256]", OFFSET(la_depth), ++ AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 256, VE }, ++ ++ { "level", "Set level (level_idc)", OFFSET(level), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 0xff, VE, "level" }, ++ ++ { "preset", "Encoding preset [0, 12]", ++ OFFSET(enc_mode), AV_OPT_TYPE_INT, { .i64 = 7 }, 0, 12, VE }, ++ ++ { "profile", "Profile setting, Main Still Picture Profile not supported", OFFSET(profile), ++ AV_OPT_TYPE_INT, { .i64 = FF_PROFILE_HEVC_MAIN }, FF_PROFILE_HEVC_MAIN, FF_PROFILE_HEVC_REXT, VE, "profile"}, ++ ++ { "qp", "QP value for intra frames", OFFSET(qp), ++ AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 51, VE }, ++ ++ { "rc", "Bit rate control mode", OFFSET(rc_mode), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE , "rc"}, ++ { "cqp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "rc" }, ++ { "vbr", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "rc" }, ++ ++ { "sc_detection", "Scene change detection", OFFSET(scd), ++ AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, ++ ++ { "socket", "Target CPU socket to use. -1 use all available", OFFSET(target_socket), ++ AV_OPT_TYPE_INT, {.i64 = -1 }, -1, 1, VE }, ++ ++ { "thread_count", "Number of threads [0: Auto, 96: Min]", OFFSET(thread_count), ++ AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, VE }, ++ ++ { "tier", "Set tier (general_tier_flag)", OFFSET(tier), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE, "tier" }, ++ { "main", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "tier" }, ++ { "high", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, VE, "tier" }, ++ ++ { "tune", "Quality tuning mode", OFFSET(tune), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 2, VE, "tune" }, ++ { "sq", "Visually optimized mode", 0, ++ AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "tune" }, ++ { "oq", "PSNR / SSIM optimized mode", 0, ++ AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "tune" }, ++ { "vmaf", "VMAF optimized mode", 0, ++ AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "tune" }, ++ { "hdr", "High dynamic range input (HDR10)", OFFSET(high_dynamic_range), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 1, VE, "hdr" }, ++ { "umv", "Enables or disables unrestricted motion vectors", OFFSET(unrestricted_motion_vector), ++ AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, ++ { "tile_row_cnt", "tile count in the row", OFFSET(tile_row_count), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 16, VE }, ++ { "tile_col_cnt", "tile count in the column", OFFSET(tile_col_count), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 16, VE }, ++ { "tile_slice_mode", "per slice per tile, only valid for multi-tile", OFFSET(tile_slice_mode), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, ++ { "pred_struct", "The prediction structure", OFFSET(pred_struct), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 2, VE }, ++ { "vid_info", "Enables or disables sending a vui structure in the HEVC Elementary bitstream.", OFFSET(vid_info), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, ++ {NULL}, ++}; ++ ++static const AVClass class = { ++ .class_name = "libsvt_hevc", ++ .item_name = av_default_item_name, ++ .option = options, ++ .version = LIBAVUTIL_VERSION_INT, ++}; ++ ++static const FFCodecDefault eb_enc_defaults[] = { ++ { "b", "7M" }, ++ { "qmin", "10" }, ++ { "qmax", "48" }, ++ { "g", "-2" }, ++ { NULL }, ++}; ++ ++const FFCodec ff_libsvt_hevc_encoder = { ++ .p.name = "libsvt_hevc", ++ .p.long_name = NULL_IF_CONFIG_SMALL("SVT-HEVC(Scalable Video Technology for HEVC) encoder"), ++ .priv_data_size = sizeof(SvtContext), ++ .p.type = AVMEDIA_TYPE_VIDEO, ++ .p.id = AV_CODEC_ID_HEVC, ++ .init = eb_enc_init, ++ FF_CODEC_ENCODE_CB(eb_encode_frame), ++ .close = eb_enc_close, ++ .p.capabilities = AV_CODEC_CAP_DELAY, ++ .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, ++ AV_PIX_FMT_YUV420P10, ++ AV_PIX_FMT_YUV422P, ++ AV_PIX_FMT_YUV422P10, ++ AV_PIX_FMT_YUV444P, ++ AV_PIX_FMT_YUV444P10, ++ AV_PIX_FMT_NONE }, ++ .p.priv_class = &class, ++ .defaults = eb_enc_defaults, ++ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, ++ .p.wrapper_name = "libsvt_hevc", ++}; +-- +2.43.0 + diff --git a/multimedia/ffmpeg/0002-doc-Add-libsvt_hevc-encoder-docs.patch b/multimedia/ffmpeg/0002-doc-Add-libsvt_hevc-encoder-docs.patch new file mode 100644 index 0000000..0fd2b4a --- /dev/null +++ b/multimedia/ffmpeg/0002-doc-Add-libsvt_hevc-encoder-docs.patch @@ -0,0 +1,201 @@ +From 6b0a4fd63454e3c2185efe741e50e80df5c9a4a4 Mon Sep 17 00:00:00 2001 +From: Jing Sun +Date: Tue, 5 Mar 2019 15:04:58 +0800 +Subject: [PATCH 2/2] doc: Add libsvt_hevc encoder docs + +Add docs for libsvt_hevc encoder in encoders.texi and general.texi + +Signed-off-by: Jun Zhao +Signed-off-by: Zhengxu Huang +Signed-off-by: Hassene Tmar +Signed-off-by: Jing Sun +--- + doc/encoders.texi | 152 ++++++++++++++++++++++++++++++++++++++ + doc/general_contents.texi | 8 ++ + 2 files changed, 160 insertions(+) + +diff --git a/doc/encoders.texi b/doc/encoders.texi +index a92eb0eb2f..535e15764b 100644 +--- a/doc/encoders.texi ++++ b/doc/encoders.texi +@@ -1884,6 +1884,158 @@ Set maximum NAL size in bytes. + Allow skipping frames to hit the target bitrate if set to 1. + @end table + ++@section libsvt_hevc ++ ++Scalable Video Technology for HEVC (SVT-HEVC) encoder wrapper. ++ ++This encoder requires the presence of the headers and ++library during configuration. You need to explicitly configure the ++build with @code{--enable-libsvthevc}. The library is detected using ++@command{pkg-config}. ++ ++For more information about the library see ++@url{https://github.com/intel/SVT-HEVC.git}. ++ ++@subsection Options ++ ++The following FFmpeg global options affect the configurations of the ++libsvt_hevc encoder: ++ ++@table @option ++@item b (@emph{bitrate}) ++Set the bitrate (as a number of bits per second). Default is 7M. ++ ++@item g / @option{gop_size} ++Set the GOP size. Default is -2 (unspecified). ++ ++@item flags +cgop ++Enable closed GOP. ++ ++@item qmin (@emph{min-q}) ++Default is 10 ++ ++@item qmax (@emph{max-q}) ++Default is 48 ++ ++Set minimum/maximum quantisation values. Valid range is from 0 to 51 ++(Only used when bit rate control mode @option{rc} is set to 1(vbr) mode. ++It is required that qmax >= qmin). ++ ++@item profile (@emph{profile}) ++Set profile restrictions. Can assume one of the following possible values: ++ ++@table @samp ++@item main ++main profile ++@item main10 ++main10 profile ++@item rext ++rext profile ++@end table ++ ++Default is 1 (main). ++ ++@item level (@emph{level}) ++ ++@option{level} sets the value of @emph{level}. ++Set level (level_idc). Default is 0 (to be determined by the encoder). ++ ++@end table ++ ++The encoder also has its own specific options: ++ ++@table @option ++@item aud (@emph{aud}) ++Enable use of access unit delimiters when set to 1. Default is 0 (Off). ++ ++@item hielevel ++Set hierarchical levels. Can assume one of the following possible values: ++ ++@table @samp ++@item flat ++flat more ++@item 1 level ++Minigop size is 2^1 ++@item 2 level ++Minigop size is 2^2 ++@item 3 level ++Minigop size is 2^3 ++@end table ++ ++Default is 3 level. ++ ++@item la_depth ++Set look-ahead depth, depending on @option{rc}: for @var{vbr}, it's recommended ++to unset it and use the default value (the intra period); for @var{cqp}, better ++specify the look-ahead depth. ++ ++The range is @var{-1-256}. Default is -1 (unset and the default value to be used). ++ ++@item preset ++Set the quality vs density tradeoff point at which the encoding is to be performed. ++Higher perset value, higher density and lower quality. ++ ++The range is @var{0-12}. Default is 9. ++ ++@item tier ++Set @emph{general_tier_flag}. This may affect the level chosen for the stream ++if it is not explicitly specified. Can assume one of the following possible values: ++ ++@item socket ++Target CPU socket to use. 0 or 1 are supported. -1 use all available (default) ++ ++@table @samp ++@item main ++main tier ++@item high ++high tier ++@end table ++ ++Default is 1 (main). ++ ++@item rc ++Set bit rate control mode. Can assume one of the following possible values: ++ ++@table @samp ++@item cqp ++Constant QP (CQP) mode ++@item vbr ++Variable Bit Rate (VBR) mode ++@end table ++ ++Default is 0 (cqp). ++ ++@item forced_idr ++Force keyframes to be IDR if set to >=0 (the value sets headers insertion interval). Default is -1 (CRA). ++ ++@item asm_type ++Auto select highest supported asm if set to 1 or C only if 0. Default is 1. ++ ++@item qp ++Initial quantization parameter for the intra pictures used when ++@option{rc} is cqp mode. The range is from @var{0-51}. Default is 32. ++ ++@item sc_detection ++Enables or disables the scene change detection algorithm. Default is 0 (disabled). ++ ++@item tune ++Set quality tuning mode. Can assume one of the following possible values: ++ ++@table @samp ++@item sq ++Visually optimized mode ++@item oq ++PSNR / SSIM optimized mode ++@item vmaf ++VMAF optimized mode ++@end table ++ ++Default is 1 (oq). ++ ++@item bl_mode ++Enables or disables Random Access Prediction. Default is 0 (disabled). ++@end table ++ + @section libtheora + + libtheora Theora encoder wrapper. +diff --git a/doc/general_contents.texi b/doc/general_contents.texi +index 33ece6e884..cd46332fc4 100644 +--- a/doc/general_contents.texi ++++ b/doc/general_contents.texi +@@ -267,6 +267,14 @@ Go to @url{https://github.com/OpenVisualCloud/SVT-AV1/} and follow the instructi + for installing the library. Then pass @code{--enable-libsvtav1} to configure to + enable it. + ++@section Scalable Video Technology for HEVC ++ ++FFmpeg can make use of the SVT-HEVC library for HEVC encoding. ++ ++Go to @url{https://github.com/intel/SVT-HEVC.git} and follow the instructions ++for installing the library. Pass @code{--enable-libsvthevc} to configure to ++enable it. ++ + @section TwoLAME + + FFmpeg can make use of the TwoLAME library for MP2 encoding. +-- +1.8.3.1 + diff --git a/multimedia/ffmpeg/030-ffmpeg-add-svt-vp9.patch b/multimedia/ffmpeg/030-ffmpeg-add-svt-vp9.patch new file mode 100644 index 0000000..2b11490 --- /dev/null +++ b/multimedia/ffmpeg/030-ffmpeg-add-svt-vp9.patch @@ -0,0 +1,788 @@ +From add426a72d980a3037333c43cf91b46d8616436e Mon Sep 17 00:00:00 2001 +From: hassene +Date: Sun, 21 May 2023 17:54:03 -0400 +Subject: [PATCH] Add ability for ffmpeg to run svt vp9 + +Signed-off-by: hassene +Signed-off-by: Jing Sun +Signed-off-by: Austin Hu +Signed-off-by: Andrei Bich +Signed-off-by: Guo Jiansheng +Co-Authored-By: Fredrick R. Brennan +--- + configure | 4 + + libavcodec/Makefile | 1 + + libavcodec/allcodecs.c | 1 + + libavcodec/libsvt_vp9.c | 700 ++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 706 insertions(+) + create mode 100644 libavcodec/libsvt_vp9.c + +diff --git a/configure b/configure +index a54398c57f..dd7607731f 100755 +--- a/configure ++++ b/configure +@@ -289,6 +289,7 @@ External library support: + --enable-libvorbis enable Vorbis en/decoding via libvorbis, + native implementation exists [no] + --enable-libvpx enable VP8 and VP9 de/encoding via libvpx [no] ++ --enable-libsvtvp9 enable VP9 encoding via svt [no] + --enable-libwebp enable WebP encoding via libwebp [no] + --enable-libx264 enable H.264 encoding via x264 [no] + --enable-libx265 enable HEVC encoding via x265 [no] +@@ -1848,6 +1849,7 @@ EXTERNAL_LIBRARY_LIST=" + libshaderc + libshine + libsmbclient ++ libsvtvp9 + libsnappy + libsoxr + libspeex +@@ -3390,6 +3392,7 @@ libvpx_vp8_decoder_deps="libvpx" + libvpx_vp8_encoder_deps="libvpx" + libvpx_vp9_decoder_deps="libvpx" + libvpx_vp9_encoder_deps="libvpx" ++libsvt_vp9_encoder_deps="libsvtvp9" + libwebp_encoder_deps="libwebp" + libwebp_anim_encoder_deps="libwebp" + libx262_encoder_deps="libx262" +@@ -6727,6 +6730,7 @@ enabled libvpx && { + fi + } + ++enabled libsvtvp9 && require_pkg_config libsvtvp9 SvtVp9Enc EbSvtVp9Enc.h eb_vp9_svt_init_handle + enabled libwebp && { + enabled libwebp_encoder && require_pkg_config libwebp "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion + enabled libwebp_anim_encoder && check_pkg_config libwebp_anim_encoder "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit; } +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index 9c38240025..1984cb970c 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1128,6 +1128,7 @@ OBJS-$(CONFIG_LIBVPX_VP8_DECODER) += libvpxdec.o + OBJS-$(CONFIG_LIBVPX_VP8_ENCODER) += libvpxenc.o + OBJS-$(CONFIG_LIBVPX_VP9_DECODER) += libvpxdec.o + OBJS-$(CONFIG_LIBVPX_VP9_ENCODER) += libvpxenc.o ++OBJS-$(CONFIG_LIBSVT_VP9_ENCODER) += libsvt_vp9.o + OBJS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.o libwebpenc.o + OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o libwebpenc_animencoder.o + OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o +diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c +index 184bb8521f..bda526f755 100644 +--- a/libavcodec/allcodecs.c ++++ b/libavcodec/allcodecs.c +@@ -801,6 +801,7 @@ extern const FFCodec ff_libvpx_vp8_encoder; + extern const FFCodec ff_libvpx_vp8_decoder; + extern FFCodec ff_libvpx_vp9_encoder; + extern const FFCodec ff_libvpx_vp9_decoder; ++extern const FFCodec ff_libsvt_vp9_encoder; + /* preferred over libwebp */ + extern const FFCodec ff_libwebp_anim_encoder; + extern const FFCodec ff_libwebp_encoder; +diff --git a/libavcodec/libsvt_vp9.c b/libavcodec/libsvt_vp9.c +new file mode 100644 +index 0000000000..5f99367924 +--- /dev/null ++++ b/libavcodec/libsvt_vp9.c +@@ -0,0 +1,700 @@ ++/* ++* Scalable Video Technology for VP9 encoder library plugin ++* ++* Copyright (c) 2018 Intel Corporation ++* ++* This file is part of FFmpeg. ++* ++* FFmpeg is free software; you can redistribute it and/or ++* modify it under the terms of the GNU Lesser General Public ++* License as published by the Free Software Foundation; either ++* version 2.1 of the License, or (at your option) any later version. ++* ++* FFmpeg is distributed in the hope that it will be useful, ++* but WITHOUT ANY WARRANTY; without even the implied warranty of ++* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++* Lesser General Public License for more details. ++* ++* You should have received a copy of the GNU Lesser General Public ++* License along with this program; if not, write to the Free Software ++* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++*/ ++ ++#include ++#include "EbSvtVp9ErrorCodes.h" ++#include "EbSvtVp9Enc.h" ++ ++#include "libavutil/common.h" ++#include "libavutil/frame.h" ++#include "libavutil/opt.h" ++#include "libavcodec/get_bits.h" ++ ++#include "codec_internal.h" ++#include "internal.h" ++#include "encode.h" ++#include "avcodec.h" ++ ++#define SUPERFRAME_INDEX_MAX_SIZE 128 ++ ++#define RECIVED_FRAMES_MAX_SIZE 32 ++#define MAX_VP9_SUPERFRAME_SIZE 8 ++ ++typedef enum eos_status { ++ EOS_NOT_REACHED = 0, ++ EOS_REACHED, ++ EOS_TOTRIGGER ++}EOS_STATUS; ++ ++typedef struct SvtReceivedFrameStruct { ++ // fields for AVPacket ++ AVBufferRef *buf; ++ int64_t pts; ++ int64_t dts; ++ int size; ++ int flags; ++ ++ // svt fields: ++ int ready_flag; // frame or superframe in data is visible ++ int frames_count; ++ int frames_sizes[MAX_VP9_SUPERFRAME_SIZE]; ++} SvtReceivedFrameStruct; ++ ++typedef struct SvtContext { ++ AVClass *class; ++ ++ EbSvtVp9EncConfiguration enc_params; ++ EbComponentType *svt_handle; ++ ++ EbBufferHeaderType *in_buf; ++ int raw_size; ++ ++ AVFrame *frame; ++ ++ AVBufferPool* pool; ++ ++ EOS_STATUS eos_flag; ++ ++ // User options. ++ int enc_mode; ++ int rc_mode; ++ int tune; ++ int qp; ++ ++ int target_socket; ++ ++ int forced_idr; ++ ++ int level; ++ ++ int base_layer_switch_mode; ++ ++ ++ int64_t last_ready_dts; ++ SvtReceivedFrameStruct received_frames[RECIVED_FRAMES_MAX_SIZE]; ++ int received_frames_size; ++} SvtContext; ++ ++static int error_mapping(EbErrorType svt_ret) ++{ ++ int err; ++ ++ switch (svt_ret) { ++ case EB_ErrorInsufficientResources: ++ err = AVERROR(ENOMEM); ++ break; ++ ++ case EB_ErrorUndefined: ++ case EB_ErrorInvalidComponent: ++ case EB_ErrorBadParameter: ++ err = AVERROR(EINVAL); ++ break; ++ ++ case EB_ErrorDestroyThreadFailed: ++ case EB_ErrorSemaphoreUnresponsive: ++ case EB_ErrorDestroySemaphoreFailed: ++ case EB_ErrorCreateMutexFailed: ++ case EB_ErrorMutexUnresponsive: ++ case EB_ErrorDestroyMutexFailed: ++ err = AVERROR_EXTERNAL; ++ break; ++ ++ case EB_NoErrorEmptyQueue: ++ err = AVERROR(EAGAIN); ++ ++ case EB_ErrorNone: ++ err = 0; ++ break; ++ ++ default: ++ err = AVERROR_UNKNOWN; ++ } ++ ++ return err; ++} ++ ++static void free_buffer(SvtContext *svt_enc) ++{ ++ if (svt_enc->in_buf) { ++ EbSvtEncInput *in_data = (EbSvtEncInput *)svt_enc->in_buf->p_buffer; ++ av_freep(&in_data); ++ av_freep(&svt_enc->in_buf); ++ } ++ av_buffer_pool_uninit(&svt_enc->pool); ++} ++ ++static int alloc_buffer(EbSvtVp9EncConfiguration *config, SvtContext *svt_enc) ++{ ++ const size_t luma_size_8bit = ++ config->source_width * config->source_height; ++ const size_t luma_size_10bit = ++ (config->encoder_bit_depth > 8) ? luma_size_8bit : 0; ++ ++ EbSvtEncInput *in_data; ++ ++ svt_enc->raw_size = ((luma_size_8bit + luma_size_10bit) * 3 / 2) * MAX_VP9_SUPERFRAME_SIZE + SUPERFRAME_INDEX_MAX_SIZE; ++ ++ // allocate buffer for in and out ++ svt_enc->in_buf = av_mallocz(sizeof(*svt_enc->in_buf)); ++ if (!svt_enc->in_buf) ++ goto failed; ++ ++ ++ svt_enc->in_buf->p_buffer = (unsigned char *)av_mallocz(sizeof(*in_data)); ++ if (!svt_enc->in_buf->p_buffer) ++ goto failed; ++ ++ svt_enc->in_buf->size = sizeof(*svt_enc->in_buf); ++ svt_enc->in_buf->p_app_private = NULL; ++ ++ svt_enc->pool = av_buffer_pool_init(svt_enc->raw_size, NULL); ++ if (!svt_enc->pool) ++ goto failed; ++ ++ svt_enc->received_frames_size = 0; ++ svt_enc->last_ready_dts = -1e9; ++ ++ return 0; ++ ++failed: ++ free_buffer(svt_enc); ++ return AVERROR(ENOMEM); ++} ++ ++static int config_enc_params(EbSvtVp9EncConfiguration *param, ++ AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ int ret; ++ int ten_bits = 0; ++ ++ param->source_width = avctx->width; ++ param->source_height = avctx->height; ++ ++ if (avctx->pix_fmt == AV_PIX_FMT_YUV420P10LE) { ++ av_log(avctx, AV_LOG_DEBUG , "Encoder 10 bits depth input\n"); ++ // Disable Compressed 10-bit format default ++ ten_bits = 1; ++ } ++ ++ // Update param from options ++ param->enc_mode = svt_enc->enc_mode; ++ param->level = svt_enc->level; ++ param->rate_control_mode = svt_enc->rc_mode; ++ param->tune = svt_enc->tune; ++ param->base_layer_switch_mode = svt_enc->base_layer_switch_mode; ++ param->qp = svt_enc->qp; ++ param->target_socket = svt_enc->target_socket; ++ param->target_bit_rate = avctx->bit_rate; ++ if (avctx->gop_size > 0) ++ param->intra_period = avctx->gop_size - 1; ++ ++ if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { ++ param->frame_rate_numerator = avctx->framerate.num; ++ param->frame_rate_denominator = avctx->framerate.den * avctx->ticks_per_frame; ++ } else { ++ param->frame_rate_numerator = avctx->time_base.den; ++ param->frame_rate_denominator = avctx->time_base.num * avctx->ticks_per_frame; ++ } ++ ++ if (param->rate_control_mode) { ++ param->max_qp_allowed = avctx->qmax; ++ param->min_qp_allowed = avctx->qmin; ++ } ++ ++ if (ten_bits) { ++ param->encoder_bit_depth = 10; ++ } ++ ++ ret = alloc_buffer(param, svt_enc); ++ ++ return ret; ++} ++ ++static void read_in_data(EbSvtVp9EncConfiguration *config, ++ const AVFrame *frame, ++ EbBufferHeaderType *headerPtr) ++{ ++ uint8_t is16bit = config->encoder_bit_depth > 8; ++ uint64_t luma_size = ++ (uint64_t)config->source_width * config->source_height<< is16bit; ++ EbSvtEncInput *in_data = (EbSvtEncInput *)headerPtr->p_buffer; ++ ++ // support yuv420p and yuv420p010 ++ in_data->luma = frame->data[0]; ++ in_data->cb = frame->data[1]; ++ in_data->cr = frame->data[2]; ++ ++ // stride info ++ in_data->y_stride = frame->linesize[0] >> is16bit; ++ in_data->cb_stride = frame->linesize[1] >> is16bit; ++ in_data->cr_stride = frame->linesize[2] >> is16bit; ++ ++ headerPtr->n_filled_len += luma_size * 3/2u; ++} ++ ++static av_cold int eb_enc_init(AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ EbErrorType svt_ret; ++ ++ svt_enc->eos_flag = EOS_NOT_REACHED; ++ ++ svt_ret = eb_vp9_svt_init_handle(&svt_enc->svt_handle, svt_enc, &svt_enc->enc_params); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Error init encoder handle\n"); ++ goto failed; ++ } ++ ++ svt_ret = config_enc_params(&svt_enc->enc_params, avctx); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Error configure encoder parameters\n"); ++ goto failed_init_handle; ++ } ++ ++ svt_ret = eb_vp9_svt_enc_set_parameter(svt_enc->svt_handle, &svt_enc->enc_params); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Error setting encoder parameters\n"); ++ goto failed_init_handle; ++ } ++ ++ svt_ret = eb_vp9_init_encoder(svt_enc->svt_handle); ++ if (svt_ret != EB_ErrorNone) { ++ av_log(avctx, AV_LOG_ERROR, "Error init encoder\n"); ++ goto failed_init_handle; ++ } ++ ++ svt_enc->frame = av_frame_alloc(); ++ if (!svt_enc->frame) ++ return AVERROR(ENOMEM); ++ ++ // if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { ++ // EbBufferHeaderType* headerPtr; ++ // headerPtr->size = sizeof(headerPtr); ++ // headerPtr->n_filled_len = 0; /* in/out */ ++ // headerPtr->p_buffer = av_malloc(10 * 1024 * 1024); ++ // headerPtr->n_alloc_len = (10 * 1024 * 1024); ++ // ++ // if (!headerPtr->p_buffer) { ++ // av_log(avctx, AV_LOG_ERROR, ++ // "Cannot allocate buffer size %d.\n", headerPtr->n_alloc_len); ++ // svt_ret = EB_ErrorInsufficientResources; ++ // goto failed_init_enc; ++ // } ++ // ++ // svt_ret = eb_svt_enc_stream_header(svt_enc->svt_handle, &headerPtr); ++ // if (svt_ret != EB_ErrorNone) { ++ // av_log(avctx, AV_LOG_ERROR, "Error when build stream header.\n"); ++ // av_freep(&headerPtr->p_buffer); ++ // goto failed_init_enc; ++ // } ++ // ++ // avctx->extradata_size = headerPtr->n_filled_len; ++ // avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); ++ // if (!avctx->extradata) { ++ // av_log(avctx, AV_LOG_ERROR, ++ // "Cannot allocate VP9 header of size %d.\n", avctx->extradata_size); ++ // av_freep(&headerPtr->p_buffer); ++ // svt_ret = EB_ErrorInsufficientResources; ++ // goto failed_init_enc; ++ // } ++ // memcpy(avctx->extradata, headerPtr->p_buffer, avctx->extradata_size); ++ // ++ // av_freep(&headerPtr->p_buffer); ++ // } ++ return 0; ++ ++//failed_init_enc: ++// eb_deinit_encoder(svt_enc->svt_handle); ++failed_init_handle: ++ eb_vp9_deinit_handle(svt_enc->svt_handle); ++failed: ++ free_buffer(svt_enc); ++ return error_mapping(svt_ret); ++} ++ ++static int eb_send_frame(AVCodecContext *avctx, const AVFrame *frame) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ EbBufferHeaderType *headerPtr = svt_enc->in_buf; ++ ++ if (!frame) { ++ if (svt_enc->eos_flag == EOS_REACHED) ++ return 0; ++ ++ EbBufferHeaderType headerPtrLast; ++ headerPtrLast.n_alloc_len = 0; ++ headerPtrLast.n_filled_len = 0; ++ headerPtrLast.n_tick_count = 0; ++ headerPtrLast.p_app_private = NULL; ++ headerPtrLast.p_buffer = NULL; ++ headerPtrLast.flags = EB_BUFFERFLAG_EOS; ++ ++ eb_vp9_svt_enc_send_picture(svt_enc->svt_handle, &headerPtrLast); ++ svt_enc->eos_flag = EOS_REACHED; ++ av_log(avctx, AV_LOG_DEBUG, "Finish sending frames!!!\n"); ++ return 0; ++ } ++ ++ read_in_data(&svt_enc->enc_params, frame, headerPtr); ++ ++ headerPtr->flags = 0; ++ headerPtr->p_app_private = NULL; ++ headerPtr->pts = frame->pts; ++ switch (frame->pict_type) { ++ case AV_PICTURE_TYPE_I: ++ headerPtr->pic_type = svt_enc->forced_idr > 0 ? EB_IDR_PICTURE : EB_I_PICTURE; ++ break; ++ case AV_PICTURE_TYPE_P: ++ headerPtr->pic_type = EB_P_PICTURE; ++ break; ++ case AV_PICTURE_TYPE_B: ++ headerPtr->pic_type = EB_B_PICTURE; ++ break; ++ default: ++ headerPtr->pic_type = EB_INVALID_PICTURE; ++ break; ++ } ++ eb_vp9_svt_enc_send_picture(svt_enc->svt_handle, headerPtr); ++ ++ return 0; ++} ++ ++static int is_frame_visible(uint8_t const* ptr, int size) { ++ GetBitContext gb; ++ int ret, visible, profile; ++ if ((ret = init_get_bits8(&gb, ptr, size)) < 0) { ++ return ret; ++ } ++ ++ // frame marker ++ get_bits(&gb, 2); ++ profile = get_bits1(&gb); ++ profile |= get_bits1(&gb) << 1; ++ ++ // reserved_zero ++ if (profile == 3) profile += get_bits1(&gb); // reserved_zero ++ ++ // read show_existing_frame ++ if (get_bits1(&gb)) { ++ // show_existing_frame == 1 ++ visible = 1; ++ } else { ++ // show_existing_frame == 0 ++ // keyframe (frame_type actually) ++ get_bits1(&gb); ++ // read show_frame ++ visible = get_bits1(&gb) ? 2 : 0; ++ } ++ ++ return visible; ++} ++ ++static int get_received_frame(SvtContext *svt_enc, AVPacket *pkt) { ++ SvtReceivedFrameStruct* rfs = &svt_enc->received_frames[0]; ++ ++ if (svt_enc->received_frames_size == 0 || !rfs->ready_flag) { ++ return AVERROR(EAGAIN); ++ } ++ ++ pkt->buf = rfs->buf; ++ pkt->data = rfs->buf->data; ++ pkt->dts = rfs->dts; ++ pkt->pts = rfs->pts; ++ pkt->flags = rfs->flags; ++ pkt->size = rfs->size; ++ ++ --svt_enc->received_frames_size; ++ for (int i = 0; i < svt_enc->received_frames_size; ++i) { ++ svt_enc->received_frames[i] = svt_enc->received_frames[i + 1]; ++ } ++ ++ return 0; ++} ++ ++static int put_received_frame(AVCodecContext *avctx, uint8_t* data, int size, int keyframe, int64_t dts, int64_t pts) { ++ SvtContext *svt_enc = avctx->priv_data; ++ SvtReceivedFrameStruct* rfs; ++ ++ if (svt_enc->received_frames_size == 0 || svt_enc->received_frames[svt_enc->received_frames_size - 1].ready_flag) { ++ ++svt_enc->received_frames_size; ++ if (svt_enc->received_frames_size > RECIVED_FRAMES_MAX_SIZE) { ++ av_log(avctx, AV_LOG_ERROR, "Fail: svt_enc->received_frames_size > RECIVED_FRAMES_MAX_SIZE \n"); ++ return AVERROR_BUG; ++ } ++ ++ rfs = &svt_enc->received_frames[svt_enc->received_frames_size - 1]; ++ ++ rfs->buf = av_buffer_pool_get(svt_enc->pool); ++ if (!rfs->buf) { ++ av_log(avctx, AV_LOG_ERROR, "Failed to allocate output packet.\n"); ++ return AVERROR(ENOMEM); ++ } ++ ++ rfs->size = 0; ++ rfs->flags = 0; ++ rfs->ready_flag = 0; ++ rfs->frames_count = 0; ++ } else { ++ rfs = &svt_enc->received_frames[svt_enc->received_frames_size - 1]; ++ } ++ ++ rfs->pts = pts; ++ rfs->dts = dts; ++ rfs->flags = (keyframe ? AV_PKT_FLAG_KEY : 0); ++ ++ ++rfs->frames_count; ++ if (rfs->frames_count > MAX_VP9_SUPERFRAME_SIZE) { ++ av_log(avctx, AV_LOG_ERROR, "Fail: rfs->frames_count > MAX_VP9_SUPERFRAME_SIZE \n"); ++ return AVERROR_BUG; ++ } ++ ++ rfs->frames_sizes[rfs->frames_count - 1] = size; ++ ++ memcpy(rfs->buf->data + rfs->size, data, size); ++ rfs->size += size; ++ ++ int visible = is_frame_visible(data, size); ++ if (visible < 0) { ++ av_log(avctx, AV_LOG_ERROR, "Fail: is_frame_visible \n"); ++ return visible; ++ } ++ ++ ++ rfs->ready_flag = visible; ++ ++ if (rfs->ready_flag) { ++ if (rfs->dts <= svt_enc->last_ready_dts) { ++ rfs->dts = svt_enc->last_ready_dts + 1; ++ } ++ svt_enc->last_ready_dts = rfs->dts; ++ ++ } ++ ++ // add superframe_index if needed ++ if (rfs->ready_flag && rfs->frames_count > 1) { ++ // superframe_header: ++ // 110 - superframe_marker ++ // 11 = 3 = bytes_per_framesize_minus_1 - use 4-bytes size ++ // xxx = frames_in_superframe_minus_1 ++ uint8_t header = 0b11011000; ++ header |= (rfs->frames_count - 1) & 0b111; ++ ++ uint8_t* ptr = rfs->buf->data + rfs->size; ++ ++ ptr[0] = header; ++ ++ptr; ++ ++ for (int i = 0; i < rfs->frames_count; ++i) { ++ ptr[0] = (rfs->frames_sizes[i] >> 0) & 0xff; ++ ptr[1] = (rfs->frames_sizes[i] >> 8) & 0xff; ++ ptr[2] = (rfs->frames_sizes[i] >> 16) & 0xff; ++ ptr[3] = (rfs->frames_sizes[i] >> 24) & 0xff; ++ ++ ptr += 4; ++ } ++ ++ ptr[0] = header; ++ ++ptr; ++ ++ rfs->size = ptr - rfs->buf->data; ++ } ++ ++ return 0; ++} ++ ++static int eb_receive_packet(AVCodecContext *avctx, AVPacket *pkt) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ EbBufferHeaderType *headerPtr; ++ EbErrorType svt_ret; ++ AVBufferRef *ref; ++ int ret = 0; ++ ++ if (get_received_frame(svt_enc, pkt) == 0) { ++ return 0; ++ } ++ ++ if (EOS_TOTRIGGER == svt_enc->eos_flag) { ++ pkt = NULL; ++ return AVERROR_EOF; ++ } ++ ++ AVFrame *frame = svt_enc->frame; ++ ret = ff_encode_get_frame(avctx, frame); ++ if (ret < 0 && ret != AVERROR_EOF) { ++ return ret; ++ } ++ if (ret == AVERROR_EOF) ++ frame = NULL; ++ ++ ret = eb_send_frame(avctx, frame); ++ if (ret < 0) ++ return ret; ++ av_frame_unref(svt_enc->frame); ++ ++ for (;;) { ++ svt_ret = eb_vp9_svt_get_packet(svt_enc->svt_handle, &headerPtr, svt_enc->eos_flag); ++ if (svt_ret == EB_NoErrorEmptyQueue) { ++ return AVERROR(EAGAIN); ++ } ++ ++ if (EB_BUFFERFLAG_EOS & headerPtr->flags) ++ svt_enc->eos_flag = EOS_TOTRIGGER; ++ ++ ret = 0; ++ ++ // ignore headerPtr->dts on purpose ++ ++ if (headerPtr->flags & EB_BUFFERFLAG_SHOW_EXT) { ++ ret = put_received_frame(avctx, headerPtr->p_buffer, headerPtr->n_filled_len - 4, 0, headerPtr->pts - 3, headerPtr->pts - 3); ++ if (ret != 0) goto end; ++ ret = put_received_frame(avctx, headerPtr->p_buffer + headerPtr->n_filled_len - 4, 1, 0, headerPtr->pts - 2, headerPtr->pts - 2); ++ if (ret != 0) goto end; ++ ret = put_received_frame(avctx, headerPtr->p_buffer + headerPtr->n_filled_len - 3, 1, 0, headerPtr->pts - 1, headerPtr->pts - 1); ++ if (ret != 0) goto end; ++ ret = put_received_frame(avctx, headerPtr->p_buffer + headerPtr->n_filled_len - 2, 1, 0, headerPtr->pts + 0, headerPtr->pts + 0); ++ if (ret != 0) goto end; ++ ret = put_received_frame(avctx, headerPtr->p_buffer + headerPtr->n_filled_len - 1, 1, 0, headerPtr->pts + 1, headerPtr->pts + 1); ++ if (ret != 0) goto end; ++ } else { ++ ret = put_received_frame(avctx, headerPtr->p_buffer, headerPtr->n_filled_len, headerPtr->pic_type == EB_IDR_PICTURE, headerPtr->pts, headerPtr->pts); ++ if (ret != 0) goto end; ++ } ++ ++ ret = get_received_frame(svt_enc, pkt); ++ ++ end: ++ eb_vp9_svt_release_out_buffer(&headerPtr); ++ ++ if (ret == AVERROR(EAGAIN)) { ++ continue; ++ } ++ ++ break; ++ } ++ ++ ++ ++ return ret; ++} ++ ++static av_cold int eb_enc_close(AVCodecContext *avctx) ++{ ++ SvtContext *svt_enc = avctx->priv_data; ++ ++ eb_vp9_deinit_encoder(svt_enc->svt_handle); ++ eb_vp9_deinit_handle(svt_enc->svt_handle); ++ ++ av_frame_free(&svt_enc->frame); ++ ++ free_buffer(svt_enc); ++ ++ return 0; ++} ++ ++#define OFFSET(x) offsetof(SvtContext, x) ++#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ++static const AVOption options[] = { ++ { "preset", "Encoding preset [1, 1]", ++ OFFSET(enc_mode), AV_OPT_TYPE_INT, { .i64 = 9 }, 0, 9, VE }, ++ ++ { "level", "Set level (level_idc)", OFFSET(level), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 0xff, VE, "level" }, ++ ++#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ ++ { .i64 = value }, 0, 0, VE, "level" ++ { LEVEL("1", 10) }, ++ { LEVEL("2", 20) }, ++ { LEVEL("2.1", 21) }, ++ { LEVEL("3", 30) }, ++ { LEVEL("3.1", 31) }, ++ { LEVEL("4", 40) }, ++ { LEVEL("4.1", 41) }, ++ { LEVEL("5", 50) }, ++ { LEVEL("5.1", 51) }, ++ { LEVEL("5.2", 52) }, ++ { LEVEL("6", 60) }, ++ { LEVEL("6.1", 61) }, ++ { LEVEL("6.2", 62) }, ++#undef LEVEL ++ ++ { "tune", "Tune mode", OFFSET(tune), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, VE , "tune"}, ++ { "vq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "tune" }, ++ { "ssim", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "tune" }, ++ { "vmaf", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "tune" }, ++ ++ { "rc", "Bit rate control mode", OFFSET(rc_mode), ++ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, VE , "rc"}, ++ { "cqp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "rc" }, ++ { "vbr", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "rc" }, ++ { "cbr", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "rc" }, ++ ++ { "qp", "QP value for intra frames", OFFSET(qp), ++ AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 51, VE }, ++ ++ { "socket", "Target CPU socket to use. -1 use all available", OFFSET(target_socket), ++ AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, ++ ++ { "bl_mode", "Random Access Prediction Structure type setting", OFFSET(base_layer_switch_mode), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, ++ ++ { "forced-idr", "If forcing keyframes, force them as IDR frames.", OFFSET(forced_idr), ++ AV_OPT_TYPE_BOOL, { .i64 = 0 }, -1, 1, VE }, ++ ++ {NULL}, ++}; ++ ++static const AVClass class = { ++ .class_name = "libsvt_vp9", ++ .item_name = av_default_item_name, ++ .option = options, ++ .version = LIBAVUTIL_VERSION_INT, ++}; ++ ++static const FFCodecDefault eb_enc_defaults[] = { ++ { "b", "7M" }, ++ { "flags", "-cgop" }, ++ { "qmin", "10" }, ++ { "qmax", "48" }, ++ { NULL }, ++}; ++ ++FFCodec ff_libsvt_vp9_encoder = { ++ .p.name = "libsvt_vp9", ++ .p.long_name = NULL_IF_CONFIG_SMALL("SVT-VP9(Scalable Video Technology for VP9) encoder"), ++ .priv_data_size = sizeof(SvtContext), ++ .p.type = AVMEDIA_TYPE_VIDEO, ++ .p.id = AV_CODEC_ID_VP9, ++ .init = eb_enc_init, ++ FF_CODEC_RECEIVE_PACKET_CB(eb_receive_packet), ++ .close = eb_enc_close, ++ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS, ++ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE | ++ FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP, ++ .p.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, ++ AV_PIX_FMT_NONE }, ++ .p.priv_class = &class, ++ .defaults = eb_enc_defaults, ++ .p.wrapper_name = "libsvt_vp9", ++}; +-- +2.40.1 + diff --git a/multimedia/ffmpeg/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch b/multimedia/ffmpeg/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch new file mode 100644 index 0000000..3f4605d --- /dev/null +++ b/multimedia/ffmpeg/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch @@ -0,0 +1,29 @@ +--- a/libavformat/avformat.h ++++ b/libavformat/avformat.h +@@ -1020,6 +1020,10 @@ attribute_deprecated + int64_t av_stream_get_end_pts(const AVStream *st); + #endif + ++// Chromium: We use the internal field first_dts vvv ++int64_t av_stream_get_first_dts(const AVStream *st); ++// Chromium: We use the internal field first_dts ^^^ ++ + #define AV_PROGRAM_RUNNING 1 + + /** +--- a/libavformat/utils.c ++++ b/libavformat/utils.c +@@ -56,6 +56,13 @@ int ff_unlock_avformat(void) + return ff_mutex_unlock(&avformat_mutex) ? -1 : 0; + } + ++// Chromium: We use the internal field first_dts vvv ++int64_t av_stream_get_first_dts(const AVStream *st) ++{ ++ return ffstream(st)->first_dts; ++} ++// Chromium: We use the internal field first_dts ^^^ ++ + /* an arbitrarily chosen "sane" max packet size -- 50M */ + #define SANE_CHUNK_SIZE (50000000) + diff --git a/multimedia/ffmpeg/ffmpeg-allow-fdk-aac-free.patch b/multimedia/ffmpeg/ffmpeg-allow-fdk-aac-free.patch new file mode 100644 index 0000000..3b87cce --- /dev/null +++ b/multimedia/ffmpeg/ffmpeg-allow-fdk-aac-free.patch @@ -0,0 +1,26 @@ +From: Andreas Schneider + +fdk-aac-free-devel is GPL compatible + +See https://bugzilla.redhat.com/show_bug.cgi?id=1501522#c112 + +Index: ffmpeg-5.0/configure +=================================================================== +--- ffmpeg-5.0.orig/configure 2022-02-09 20:07:49.490888877 +0100 ++++ ffmpeg-5.0/configure 2022-02-09 20:08:30.102854308 +0100 +@@ -1783,7 +1783,6 @@ EXTERNAL_LIBRARY_GPL_LIST=" + + EXTERNAL_LIBRARY_NONFREE_LIST=" + decklink +- libfdk_aac + libtls + " + +@@ -1822,6 +1821,7 @@ EXTERNAL_LIBRARY_LIST=" + libdav1d + libdc1394 + libdrm ++ libfdk_aac + libflite + libfontconfig + libfreetype diff --git a/multimedia/ffmpeg/ffmpeg-c99.patch b/multimedia/ffmpeg/ffmpeg-c99.patch new file mode 100644 index 0000000..0ae4d8a --- /dev/null +++ b/multimedia/ffmpeg/ffmpeg-c99.patch @@ -0,0 +1,67 @@ +From 42982b5a5d461530a792e69b3e8abdd9d6d67052 Mon Sep 17 00:00:00 2001 +From: Frank Plowman +Date: Fri, 22 Dec 2023 12:00:01 +0000 +Subject: [PATCH] avformat/ffrtmpcrypt: Fix int-conversion warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +Content-type: text/plain + +The gcrypt definition of `bn_new` used to use the return statement +on errors, with an AVERROR return value, regardless of the signature +of the function where the macro is used - it is called in +`dh_generate_key` and `ff_dh_init` which return pointers. As a result, +compiling with gcrypt and the ffrtmpcrypt protocol resulted in an +int-conversion warning. GCC 14 may upgrade these to errors [1]. + +This patch fixes the problem by changing the macro to remove `AVERROR` +and instead set `bn` to null if the allocation fails. This is the +behaviour of all the other `bn_new` implementations and so the result is +already checked at all the callsites. AFAICT, this should be the only +change needed to get ffmpeg off Fedora's naughty list of projects with +warnings which may be upgraded to errors in GCC 14 [2]. + +[1]: https://gcc.gnu.org/pipermail/gcc/2023-May/241264.html +[2]: https://www.mail-archive.com/devel@lists.fedoraproject.org/msg196024.html + +Signed-off-by: Frank Plowman +Signed-off-by: Martin Storsjö +--- + libavformat/rtmpdh.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/libavformat/rtmpdh.c b/libavformat/rtmpdh.c +index 5ddae537a1..6a6c2ccd87 100644 +--- a/libavformat/rtmpdh.c ++++ b/libavformat/rtmpdh.c +@@ -113,15 +113,18 @@ static int bn_modexp(FFBigNum bn, FFBigNum y, FFBigNum q, FFBigNum p) + return 0; + } + #elif CONFIG_GCRYPT +-#define bn_new(bn) \ +- do { \ +- if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { \ +- if (!gcry_check_version("1.5.4")) \ +- return AVERROR(EINVAL); \ +- gcry_control(GCRYCTL_DISABLE_SECMEM, 0); \ +- gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); \ +- } \ +- bn = gcry_mpi_new(1); \ ++#define bn_new(bn) \ ++ do { \ ++ if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) { \ ++ if (gcry_check_version("1.5.4")) { \ ++ gcry_control(GCRYCTL_DISABLE_SECMEM, 0); \ ++ gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); \ ++ } \ ++ } \ ++ if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) \ ++ bn = gcry_mpi_new(1); \ ++ else \ ++ bn = NULL; \ + } while (0) + #define bn_free(bn) gcry_mpi_release(bn) + #define bn_set_word(bn, w) gcry_mpi_set_ui(bn, w) +-- +2.43.0 + diff --git a/multimedia/ffmpeg/ffmpeg-codec-choice.patch b/multimedia/ffmpeg/ffmpeg-codec-choice.patch new file mode 100644 index 0000000..221b4f6 --- /dev/null +++ b/multimedia/ffmpeg/ffmpeg-codec-choice.patch @@ -0,0 +1,57 @@ +From: Jan Engelhardt + +Edit the default codec selection such that + + ffmpeg -i youtube.blah.webm foobar.mkv + +without any further arguments can produce a result even on a +reduced codec selection list. + +--- + libavformat/matroskaenc.c | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +Index: ffmpeg-6.0/libavformat/matroskaenc.c +=================================================================== +--- ffmpeg-6.0.orig/libavformat/matroskaenc.c ++++ ffmpeg-6.0/libavformat/matroskaenc.c +@@ -3321,16 +3321,25 @@ static int mkv_query_codec(enum AVCodecI + return 0; + } + ++#define PREFAUDIO \ ++ CONFIG_LIBOPUS_ENCODER ? AV_CODEC_ID_OPUS : \ ++ CONFIG_AAC_ENCODER ? AV_CODEC_ID_AAC : \ ++ CONFIG_VORBIS_ENCODER ? AV_CODEC_ID_VORBIS : \ ++ AV_CODEC_ID_AC3 ++ + const FFOutputFormat ff_matroska_muxer = { + .p.name = "matroska", + .p.long_name = NULL_IF_CONFIG_SMALL("Matroska"), + .p.mime_type = "video/x-matroska", + .p.extensions = "mkv", + .priv_data_size = sizeof(MatroskaMuxContext), +- .p.audio_codec = CONFIG_LIBVORBIS_ENCODER ? +- AV_CODEC_ID_VORBIS : AV_CODEC_ID_AC3, +- .p.video_codec = CONFIG_LIBX264_ENCODER ? +- AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4, ++ .p.audio_codec = PREFAUDIO, ++ .p.video_codec = ++ CONFIG_LIBVPX_VP9_ENCODER ? AV_CODEC_ID_VP9 : \ ++ CONFIG_LIBX264_ENCODER ? AV_CODEC_ID_H264 : \ ++ CONFIG_LIBVPX_VP8_ENCODER ? AV_CODEC_ID_VP8 : \ ++ CONFIG_MPEG4_ENCODER ? AV_CODEC_ID_MPEG4 : \ ++ AV_CODEC_ID_THEORA, + .init = mkv_init, + .deinit = mkv_deinit, + .write_header = mkv_write_header, +@@ -3388,8 +3397,7 @@ const FFOutputFormat ff_matroska_audio_m + .p.mime_type = "audio/x-matroska", + .p.extensions = "mka", + .priv_data_size = sizeof(MatroskaMuxContext), +- .p.audio_codec = CONFIG_LIBVORBIS_ENCODER ? +- AV_CODEC_ID_VORBIS : AV_CODEC_ID_AC3, ++ .p.audio_codec = PREFAUDIO, + .p.video_codec = AV_CODEC_ID_NONE, + .init = mkv_init, + .deinit = mkv_deinit, diff --git a/multimedia/ffmpeg/ffmpeg-dlopen-openh264.patch b/multimedia/ffmpeg/ffmpeg-dlopen-openh264.patch new file mode 100644 index 0000000..329606b --- /dev/null +++ b/multimedia/ffmpeg/ffmpeg-dlopen-openh264.patch @@ -0,0 +1,363 @@ +From 3daa49cae0bfc3de434dd28c3a23ae877f0639db Mon Sep 17 00:00:00 2001 +From: Neal Gompa +Date: Thu, 4 Jan 2024 10:21:17 -0500 +Subject: [PATCH] lavc/openh264: Add the ability to dlopen() OpenH264 + +We can't directly depend on OpenH264, but we can weakly link to it +and gracefully expose the capability. + +Co-authored-by: Andreas Schneider +Co-authored-by: Neal Gompa + +Signed-off-by: Andreas Schneider +Signed-off-by: Neal Gompa +--- + configure | 3 + + libavcodec/Makefile | 1 + + libavcodec/libopenh264.c | 5 ++ + libavcodec/libopenh264_dlopen.c | 147 ++++++++++++++++++++++++++++++++ + libavcodec/libopenh264_dlopen.h | 58 +++++++++++++ + libavcodec/libopenh264dec.c | 10 +++ + libavcodec/libopenh264enc.c | 10 +++ + 7 files changed, 234 insertions(+) + create mode 100644 libavcodec/libopenh264_dlopen.c + create mode 100644 libavcodec/libopenh264_dlopen.h + +diff --git a/configure b/configure +index 1f0b9497cb..97fa4a5d6a 100755 +--- a/configure ++++ b/configure +@@ -249,6 +249,7 @@ External library support: + --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-amrwb [no] + --enable-libopencv enable video filtering via libopencv [no] + --enable-libopenh264 enable H.264 encoding via OpenH264 [no] ++ --enable-libopenh264-dlopen enable H.264 encoding via dlopen()'ed OpenH264 [no] + --enable-libopenjpeg enable JPEG 2000 de/encoding via OpenJPEG [no] + --enable-libopenmpt enable decoding tracked files via libopenmpt [no] + --enable-libopenvino enable OpenVINO as a DNN module backend +@@ -1871,6 +1872,7 @@ EXTERNAL_LIBRARY_LIST=" + libmysofa + libopencv + libopenh264 ++ libopenh264_dlopen + libopenjpeg + libopenmpt + libopenvino +@@ -6765,6 +6767,7 @@ enabled libopencv && { check_headers opencv2/core/core_c.h && + require libopencv opencv2/core/core_c.h cvCreateImageHeader -lopencv_core -lopencv_imgproc; } || + require_pkg_config libopencv opencv opencv/cxcore.h cvCreateImageHeader; } + enabled libopenh264 && require_pkg_config libopenh264 openh264 wels/codec_api.h WelsGetCodecVersion ++enabled libopenh264_dlopen && enable libopenh264 && add_cppflags "-I$(dirname `readlink -f $0`)/ffdlopenhdrs/include -DCONFIG_LIBOPENH264_DLOPEN=1" + enabled libopenjpeg && { check_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version || + { require_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } } + enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create -lstdc++ && append libopenmpt_extralibs "-lstdc++" +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index 580a8d6b54..c27d229f6d 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1115,6 +1115,7 @@ OBJS-$(CONFIG_LIBMP3LAME_ENCODER) += libmp3lame.o + OBJS-$(CONFIG_LIBOPENCORE_AMRNB_DECODER) += libopencore-amr.o + OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER) += libopencore-amr.o + OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER) += libopencore-amr.o ++OBJS-$(CONFIG_LIBOPENH264_DLOPEN) += libopenh264_dlopen.o + OBJS-$(CONFIG_LIBOPENH264_DECODER) += libopenh264dec.o libopenh264.o + OBJS-$(CONFIG_LIBOPENH264_ENCODER) += libopenh264enc.o libopenh264.o + OBJS-$(CONFIG_LIBOPENJPEG_ENCODER) += libopenjpegenc.o +diff --git a/libavcodec/libopenh264.c b/libavcodec/libopenh264.c +index c80c85ea8b..128c3d9846 100644 +--- a/libavcodec/libopenh264.c ++++ b/libavcodec/libopenh264.c +@@ -20,8 +20,13 @@ + */ + + #include ++ ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++#include "libopenh264_dlopen.h" ++#else + #include + #include ++#endif + + #include "libavutil/error.h" + #include "libavutil/log.h" +diff --git a/libavcodec/libopenh264_dlopen.c b/libavcodec/libopenh264_dlopen.c +new file mode 100644 +index 0000000000..49ea8ff44f +--- /dev/null ++++ b/libavcodec/libopenh264_dlopen.c +@@ -0,0 +1,147 @@ ++/* ++ * OpenH264 dlopen code ++ * ++ * Copyright (C) 2022 Andreas Schneider ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include ++ ++#include "libopenh264_dlopen.h" ++ ++/* ++ * The symbol binding makes sure we do not run into strict aliasing issues which ++ * can lead into segfaults. ++ */ ++typedef int (*__oh264_WelsCreateSVCEncoder)(ISVCEncoder **); ++typedef void (*__oh264_WelsDestroySVCEncoder)(ISVCEncoder *); ++typedef int (*__oh264_WelsGetDecoderCapability)(SDecoderCapability *); ++typedef long (*__oh264_WelsCreateDecoder)(ISVCDecoder **); ++typedef void (*__oh264_WelsDestroyDecoder)(ISVCDecoder *); ++typedef OpenH264Version (*__oh264_WelsGetCodecVersion)(void); ++typedef void (*__oh264_WelsGetCodecVersionEx)(OpenH264Version *); ++ ++#define OH264_SYMBOL_ENTRY(i) \ ++ union { \ ++ __oh264_##i f; \ ++ void *obj; \ ++ } _oh264_##i ++ ++struct oh264_symbols { ++ OH264_SYMBOL_ENTRY(WelsCreateSVCEncoder); ++ OH264_SYMBOL_ENTRY(WelsDestroySVCEncoder); ++ OH264_SYMBOL_ENTRY(WelsGetDecoderCapability); ++ OH264_SYMBOL_ENTRY(WelsCreateDecoder); ++ OH264_SYMBOL_ENTRY(WelsDestroyDecoder); ++ OH264_SYMBOL_ENTRY(WelsGetCodecVersion); ++ OH264_SYMBOL_ENTRY(WelsGetCodecVersionEx); ++}; ++ ++/* Symbols are bound by loadLibOpenH264() */ ++static struct oh264_symbols openh264_symbols; ++ ++int oh264_WelsCreateSVCEncoder(ISVCEncoder **ppEncoder) { ++ return openh264_symbols._oh264_WelsCreateSVCEncoder.f(ppEncoder); ++} ++ ++void oh264_WelsDestroySVCEncoder(ISVCEncoder *pEncoder) { ++ return openh264_symbols._oh264_WelsDestroySVCEncoder.f(pEncoder); ++} ++ ++int oh264_WelsGetDecoderCapability(SDecoderCapability *pDecCapability) { ++ return openh264_symbols._oh264_WelsGetDecoderCapability.f(pDecCapability); ++} ++ ++long oh264_WelsCreateDecoder(ISVCDecoder **ppDecoder) { ++ return openh264_symbols._oh264_WelsCreateDecoder.f(ppDecoder); ++} ++ ++void oh264_WelsDestroyDecoder(ISVCDecoder *pDecoder) { ++ return openh264_symbols._oh264_WelsDestroyDecoder.f(pDecoder); ++} ++ ++OpenH264Version oh264_WelsGetCodecVersion(void) { ++ return openh264_symbols._oh264_WelsGetCodecVersion.f(); ++} ++ ++void oh264_WelsGetCodecVersionEx(OpenH264Version *pVersion) { ++ openh264_symbols._oh264_WelsGetCodecVersionEx.f(pVersion); ++} ++ ++static void *_oh264_bind_symbol(AVCodecContext *avctx, ++ void *handle, ++ const char *sym_name) { ++ void *sym = NULL; ++ ++ sym = dlsym(handle, sym_name); ++ if (sym == NULL) { ++ const char *err = dlerror(); ++ av_log(avctx, ++ AV_LOG_WARNING, ++ "%s: Failed to bind %s\n", ++ err, ++ sym_name); ++ return NULL; ++ } ++ ++ return sym; ++} ++ ++#define oh264_bind_symbol(avctx, handle, sym_name) \ ++ if (openh264_symbols._oh264_##sym_name.obj == NULL) { \ ++ openh264_symbols._oh264_##sym_name.obj = _oh264_bind_symbol(avctx, handle, #sym_name); \ ++ if (openh264_symbols._oh264_##sym_name.obj == NULL) { \ ++ return 1; \ ++ } \ ++ } ++ ++int loadLibOpenH264(AVCodecContext *avctx) { ++ static bool initialized = false; ++ void *libopenh264 = NULL; ++ const char *err = NULL; ++ ++ if (initialized) { ++ return 0; ++ } ++ ++#define OPENH264_LIB "libopenh264.so.7" ++ libopenh264 = dlopen(OPENH264_LIB, RTLD_LAZY); ++ err = dlerror(); ++ if (err != NULL) { ++ av_log(avctx, AV_LOG_WARNING, ++ "%s: %s is missing, openh264 support will be disabled\n", err, ++ OPENH264_LIB); ++ ++ if (libopenh264 != NULL) { ++ dlclose(libopenh264); ++ } ++ return 1; ++ } ++ ++ oh264_bind_symbol(avctx, libopenh264, WelsCreateSVCEncoder); ++ oh264_bind_symbol(avctx, libopenh264, WelsDestroySVCEncoder); ++ oh264_bind_symbol(avctx, libopenh264, WelsGetDecoderCapability); ++ oh264_bind_symbol(avctx, libopenh264, WelsCreateDecoder); ++ oh264_bind_symbol(avctx, libopenh264, WelsDestroyDecoder); ++ oh264_bind_symbol(avctx, libopenh264, WelsGetCodecVersion); ++ oh264_bind_symbol(avctx, libopenh264, WelsGetCodecVersionEx); ++ ++ initialized = true; ++ ++ return 0; ++} +diff --git a/libavcodec/libopenh264_dlopen.h b/libavcodec/libopenh264_dlopen.h +new file mode 100644 +index 0000000000..d7d8bb7cad +--- /dev/null ++++ b/libavcodec/libopenh264_dlopen.h +@@ -0,0 +1,58 @@ ++/* ++ * OpenH264 dlopen code ++ * ++ * Copyright (C) 2022 Andreas Schneider ++ * ++ * This file is part of FFmpeg. ++ * ++ * FFmpeg is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * FFmpeg is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with FFmpeg; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#ifndef HAVE_LIBOPENH264_DLOPEN_H ++#define HAVE_LIBOPENH264_DLOPEN_H ++ ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++ ++#include ++#include ++ ++#include "avcodec.h" ++ ++int oh264_WelsCreateSVCEncoder(ISVCEncoder **ppEncoder); ++#define WelsCreateSVCEncoder oh264_WelsCreateSVCEncoder ++ ++void oh264_WelsDestroySVCEncoder(ISVCEncoder *pEncoder); ++#define WelsDestroySVCEncoder oh264_WelsDestroySVCEncoder ++ ++int oh264_WelsGetDecoderCapability(SDecoderCapability *pDecCapability); ++#define WelsGetDecoderCapability oh264_WelsGetDecoderCapability ++ ++long oh264_WelsCreateDecoder(ISVCDecoder **ppDecoder); ++#define WelsCreateDecoder oh264_WelsCreateDecoder ++ ++void oh264_WelsDestroyDecoder(ISVCDecoder *pDecoder); ++#define WelsDestroyDecoder oh264_WelsDestroyDecoder ++ ++OpenH264Version oh264_WelsGetCodecVersion(void); ++#define WelsGetCodecVersion oh264_WelsGetCodecVersion ++ ++void oh264_WelsGetCodecVersionEx(OpenH264Version *pVersion); ++#define WelsGetCodecVersionEx oh264_WelsGetCodecVersionEx ++ ++int loadLibOpenH264(AVCodecContext *avctx); ++ ++#endif /* CONFIG_LIBOPENH264_DLOPEN */ ++ ++#endif /* HAVE_LIBOPENH264_DLOPEN_H */ +diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c +index b6a9bba2dc..e042189161 100644 +--- a/libavcodec/libopenh264dec.c ++++ b/libavcodec/libopenh264dec.c +@@ -19,8 +19,12 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++#include "libopenh264_dlopen.h" ++#else + #include + #include ++#endif + + #include "libavutil/common.h" + #include "libavutil/fifo.h" +@@ -55,6 +59,12 @@ static av_cold int svc_decode_init(AVCodecContext *avctx) + int log_level; + WelsTraceCallback callback_function; + ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++ if (loadLibOpenH264(avctx)) { ++ return AVERROR_DECODER_NOT_FOUND; ++ } ++#endif ++ + if (WelsCreateDecoder(&s->decoder)) { + av_log(avctx, AV_LOG_ERROR, "Unable to create decoder\n"); + return AVERROR_UNKNOWN; +diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c +index 6f231d22b2..3f0e990d80 100644 +--- a/libavcodec/libopenh264enc.c ++++ b/libavcodec/libopenh264enc.c +@@ -19,8 +19,12 @@ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++#include "libopenh264_dlopen.h" ++#else + #include + #include ++#endif + + #include "libavutil/attributes.h" + #include "libavutil/common.h" +@@ -114,6 +118,12 @@ static av_cold int svc_encode_init(AVCodecContext *avctx) + WelsTraceCallback callback_function; + AVCPBProperties *props; + ++#ifdef CONFIG_LIBOPENH264_DLOPEN ++ if (loadLibOpenH264(avctx)) { ++ return AVERROR_ENCODER_NOT_FOUND; ++ } ++#endif ++ + if (WelsCreateSVCEncoder(&s->encoder)) { + av_log(avctx, AV_LOG_ERROR, "Unable to create encoder\n"); + return AVERROR_UNKNOWN; +-- +2.43.0 + diff --git a/multimedia/ffmpeg/ffmpeg.spec b/multimedia/ffmpeg/ffmpeg.spec index a1b2921..305da3a 100644 --- a/multimedia/ffmpeg/ffmpeg.spec +++ b/multimedia/ffmpeg/ffmpeg.spec @@ -42,6 +42,8 @@ %global _with_smb 1 %global _with_snappy 1 %global _with_svtav1 1 +%global _with_svtvp9 1 +%global _with_svthevc 1 %global _with_tesseract 1 %global _with_twolame 1 %global _with_wavpack 1 @@ -54,6 +56,7 @@ %global _with_vpl 1 %global _with_vapoursynth 1 %global _with_vmaf 1 +%global _with_openh264 1 %endif # flavor nonfree @@ -122,7 +125,7 @@ ExclusiveArch: armv7hnl Summary: Digital VCR and streaming server Name: ffmpeg%{?flavor} Version: 6.1.1 -Release: 1%{?date:.%{?date}%{?date:git}%{?rel}}%{?dist} +Release: 2%{?date:.%{?date}%{?date:git}%{?rel}}%{?dist} License: %{ffmpeg_license} URL: https://ffmpeg.org/ %if 0%{?date} @@ -132,7 +135,23 @@ Source0: https://ffmpeg.org/releases/ffmpeg-%{version}.tar.xz Source1: https://ffmpeg.org/releases/ffmpeg-%{version}.tar.xz.asc Source2: https://ffmpeg.org/ffmpeg-devel.asc %endif + Patch0: 0001-revert-librsvg-bump.patch +# lavc/svt_hevc: add libsvt hevc encoder wrapper +Patch1: 0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch +# Add libsvt_hevc encoder docs +Patch2: 0002-doc-Add-libsvt_hevc-encoder-docs.patch +# Add ability for ffmpeg to run svt vp9 +Patch3: 030-ffmpeg-add-svt-vp9.patch +# Compatibility fix for chromium +Patch4: 040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch + +# Fedora patches +Patch5: 0001-lavc-libopenh264-Drop-openh264-runtime-version-check.patch +Patch6: ffmpeg-allow-fdk-aac-free.patch +Patch7: ffmpeg-c99.patch +Patch8: ffmpeg-codec-choice.patch +%{!?_with_openh264:Patch9: ffmpeg-dlopen-openh264.patch} Conflicts: %{name}-free Requires: %{name}-libs%{?_isa} = %{version}-%{release} @@ -223,7 +242,10 @@ BuildRequires: soxr-devel BuildRequires: speex-devel BuildRequires: pkgconfig(srt) %{?_with_svtav1:BuildRequires: svt-av1-devel >= 1.1.0} +%{?_with_svtvp9:BuildRequires: svt-vp9-devel} +%{?_with_svthevc:BuildRequires: svt-hevc-devel} %{?_with_tesseract:BuildRequires: tesseract-devel} +%{?_with_openh264:BuildRequires: openh264-devel} #BuildRequires: texi2html BuildRequires: texinfo %{?_with_twolame:BuildRequires: twolame-devel} @@ -256,6 +278,7 @@ Conflicts: libpostproc-free Conflicts: libswresample-free Conflicts: libswscale-free %{?_with_vmaf:Recommends: vmaf-models} +%{!?_with_openh264:Recommends: openh264} %description libs FFmpeg is a complete and free Internet live audio and video @@ -376,7 +399,11 @@ Freeworld libavcodec to complement the distro counterparts --enable-libsrt \\\ --enable-libssh \\\ %{?_with_svtav1:--enable-libsvtav1} \\\ + %{?_with_svtvp9:--enable-libsvtvp9} \\\ + %{?_with_svthevc:--enable-libsvthevc} \\\ %{?_with_tesseract:--enable-libtesseract} \\\ + %{?_with_openh264:--enable-libopenh264} \\\ + %{!?_with_openh264-dlopen:--enable-libopenh264} \\\ --enable-libtheora \\\ %{?_with_twolame:--enable-libtwolame} \\\ --enable-libvorbis \\\ @@ -539,6 +566,10 @@ strip %{buildroot}%{_libdir}/%{name}/libavcodec.so.* %changelog +* Wed Mar 6 2024 Raven - 6.1.1-2 +- fix for chromium +- add openh264 support + * Wed Jan 3 2024 Raven - 6.1.1-1 - Update to 6.1.1 release diff --git a/multimedia/openh264/openh264.spec b/multimedia/openh264/openh264.spec new file mode 100644 index 0000000..20ad5de --- /dev/null +++ b/multimedia/openh264/openh264.spec @@ -0,0 +1,129 @@ +# ref: https://src.fedoraproject.org/rpms/openh264/blob/rawhide/f/openh264.spec +# To get the gmp-api commit to use, run: +# rm -rf gmp-api;make gmp-bootstrap;cd gmp-api;git rev-parse HEAD +%global commit1 e7d30b921df736a1121a0c8e0cf3ab1ce5b8a4b7 +%global shortcommit1 %(c=%{commit1}; echo ${c:0:7}) + +# Filter out soname provides for the mozilla plugin +%global __provides_exclude_from ^%{_libdir}/mozilla/plugins/ + +Name: openh264 +Version: 2.4.1 +Release: 2%{?dist} +Summary: H.264 codec library + +License: BSD-2-Clause +URL: https://www.openh264.org/ +Source0: https://github.com/cisco/openh264/archive/v%{version}/openh264-%{version}.tar.gz +Source1: https://github.com/mozilla/gmp-api/archive/%{commit1}/gmp-api-%{shortcommit1}.tar.gz + +BuildRequires: gcc-c++ +BuildRequires: make +BuildRequires: nasm + + +%description +OpenH264 is a codec library which supports H.264 encoding and decoding. It is +suitable for use in real time applications such as WebRTC. + + +%package devel +Summary: Development files for %{name} +Requires: %{name}%{?_isa} = %{version}-%{release} + + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + + +%package -n mozilla-openh264 +Summary: H.264 codec support for Mozilla browsers +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: mozilla-filesystem%{?_isa} + +%description -n mozilla-openh264 +The mozilla-openh264 package contains a H.264 codec plugin for Mozilla +browsers. + + +%prep +%setup -q + +# Extract gmp-api archive +tar -xf %{S:1} +mv gmp-api-%{commit1} gmp-api + + +%build +# Update the makefile with our build options +# Must be done in %%build in order to pick up correct LDFLAGS. +sed -i -e 's|^CFLAGS_OPT=.*$|CFLAGS_OPT=%{optflags}|' Makefile +sed -i -e 's|^PREFIX=.*$|PREFIX=%{_prefix}|' Makefile +sed -i -e 's|^LIBDIR_NAME=.*$|LIBDIR_NAME=%{_lib}|' Makefile +sed -i -e 's|^SHAREDLIB_DIR=.*$|SHAREDLIB_DIR=%{_libdir}|' Makefile +sed -i -e '/^CFLAGS_OPT=/i LDFLAGS=%{__global_ldflags}' Makefile + +# First build the openh264 libraries +make %{?_smp_mflags} + +# ... then build the mozilla plugin +make plugin %{?_smp_mflags} + + +%install +%make_install + +# Install mozilla plugin +mkdir -p $RPM_BUILD_ROOT%{_libdir}/mozilla/plugins/gmp-gmpopenh264/system-installed +cp -a libgmpopenh264.so* gmpopenh264.info $RPM_BUILD_ROOT%{_libdir}/mozilla/plugins/gmp-gmpopenh264/system-installed/ + +mkdir -p $RPM_BUILD_ROOT%{_libdir}/firefox/defaults/pref +cat > $RPM_BUILD_ROOT%{_libdir}/firefox/defaults/pref/gmpopenh264.js << EOF +pref("media.gmp-gmpopenh264.autoupdate", false); +pref("media.gmp-gmpopenh264.version", "system-installed"); +EOF + +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/profile.d +cat > $RPM_BUILD_ROOT%{_sysconfdir}/profile.d/gmpopenh264.sh << 'EOF' +if [[ ":$MOZ_GMP_PATH:" != *":%{_libdir}/mozilla/plugins/gmp-gmpopenh264/system-installed:"* ]]; then + MOZ_GMP_PATH="${MOZ_GMP_PATH}${MOZ_GMP_PATH:+:}%{_libdir}/mozilla/plugins/gmp-gmpopenh264/system-installed" + export MOZ_GMP_PATH +fi +EOF + +mkdir -p $RPM_BUILD_ROOT%{_datadir}/fish/vendor_conf.d +cat > $RPM_BUILD_ROOT%{_datadir}/fish/vendor_conf.d/gmpopenh264.fish << 'EOF' +set -x --path MOZ_GMP_PATH $MOZ_GMP_PATH +set dir %{_libdir}/mozilla/plugins/gmp-gmpopenh264/system-installed +if not contains $dir $MOZ_GMP_PATH + set -p MOZ_GMP_PATH $dir +end +set -e dir +EOF + +# Remove static libraries +rm $RPM_BUILD_ROOT%{_libdir}/*.a + + +%files +%license LICENSE +%doc README.md +%{_libdir}/libopenh264.so.7 +%{_libdir}/libopenh264.so.%{version} + +%files devel +%{_includedir}/wels/ +%{_libdir}/libopenh264.so +%{_libdir}/pkgconfig/openh264.pc + +%files -n mozilla-openh264 +%{_sysconfdir}/profile.d/gmpopenh264.sh +%dir %{_libdir}/firefox +%dir %{_libdir}/firefox/defaults +%dir %{_libdir}/firefox/defaults/pref +%{_libdir}/firefox/defaults/pref/gmpopenh264.js +%{_libdir}/mozilla/plugins/gmp-gmpopenh264/ +%dir %{_datadir}/fish +%dir %{_datadir}/fish/vendor_conf.d +%{_datadir}/fish/vendor_conf.d/gmpopenh264.fish diff --git a/multimedia/svt-hevc/cmake.patch b/multimedia/svt-hevc/cmake.patch new file mode 100644 index 0000000..7f619f6 --- /dev/null +++ b/multimedia/svt-hevc/cmake.patch @@ -0,0 +1,27 @@ +diff -uNdr SVT-HEVC-1.5.0_old/CMakeLists.txt SVT-HEVC-1.5.0_new/CMakeLists.txt +--- SVT-HEVC-1.5.0_old/CMakeLists.txt 2020-08-04 00:57:25.000000000 +0300 ++++ SVT-HEVC-1.5.0_new/CMakeLists.txt 2021-02-07 10:58:15.333859295 +0300 +@@ -100,11 +100,9 @@ + -Wformat-security + -fPIE + -fPIC +- -D_FORTIFY_SOURCE=2 +- /GS +- /sdl) ++ -D_FORTIFY_SOURCE=2) + if(MSVC) +- list(APPEND flags_to_test /MP) ++ list(APPEND flags_to_test /MP /GS /sdl) + else() + option(NATIVE "Build for native performance (march=native)") + list(INSERT flags_to_test 0 -Wall) +@@ -119,8 +117,7 @@ + endif() + endif() + set(release_flags_to_test +- -O2 +- -O3) ++ -O2) + set(debug_flags_to_test + -O0) + diff --git a/multimedia/svt-hevc/svt-hevc.spec b/multimedia/svt-hevc/svt-hevc.spec new file mode 100644 index 0000000..ef58ae9 --- /dev/null +++ b/multimedia/svt-hevc/svt-hevc.spec @@ -0,0 +1,109 @@ +Name: svt-hevc +Version: 1.5.1 +Release: 6%{?dist} +Summary: Scalable Video Technology for HEVC Encoder + +License: BSD-2-Clause-Patent +URL: https://github.com/OpenVisualCloud/SVT-HEVC +Source0: %url/archive/v%{version}/SVT-HEVC-%{version}.tar.gz +# Correct build flags +Patch0: cmake.patch + +BuildRequires: gcc +BuildRequires: cmake +BuildRequires: yasm +BuildRequires: meson + +Requires: %{name}-libs%{?_isa} = %{version}-%{release} + +ExclusiveArch: x86_64 + +%description +The Scalable Video Technology for HEVC Encoder (SVT-HEVC Encoder) is an +HEVC-compliant encoder library core that achieves excellent density-quality +tradeoffs, and is highly optimized for Intel® Xeon™ Scalable Processor and +Xeon™ D processors. + +%package libs +Summary: Libraries for svt-hevc + +%description libs +Libraries for development svt-hevc. + +%package devel +Summary: Include files and mandatory libraries for development svt-hevc +Requires: %{name}-libs%{?_isa} = %{version}-%{release} + +%description devel +Include files and mandatory libraries for development svt-hevc. + +%prep +%autosetup -p1 -n SVT-HEVC-%{version} + + +%build +%cmake -G Ninja + +%cmake_build + + +%install +%cmake_install + +%files +%{_bindir}/SvtHevcEncApp + +%files libs +%license LICENSE.md +%doc README.md Docs/svt-hevc_encoder_user_guide.md +%{_libdir}/libSvtHevcEnc.so.1* + +%files devel +%{_includedir}/%{name} +%{_libdir}/libSvtHevcEnc.so +%{_libdir}/pkgconfig/*.pc + +%changelog +* Sun Feb 04 2024 RPM Fusion Release Engineering - 1.5.1-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Wed Aug 02 2023 RPM Fusion Release Engineering - 1.5.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + +* Mon Aug 08 2022 RPM Fusion Release Engineering - 1.5.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild and ffmpeg + 5.1 + +* Wed Feb 09 2022 RPM Fusion Release Engineering - 1.5.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + +* Tue Aug 03 2021 RPM Fusion Release Engineering - 1.5.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + +* Tue May 18 2021 Vasiliy Glazov - 1.5.1-1 +- Update to 1.5.1 + +* Sun Feb 07 2021 Vasiliy Glazov - 1.5.0-4 +- Fix build for GCC 11 +- Remove gstreamer plugin + +* Thu Feb 04 2021 RPM Fusion Release Engineering - 1.5.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Tue Aug 18 2020 RPM Fusion Release Engineering - 1.5.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Tue Aug 04 2020 Vasiliy Glazov - 1.5.0-1 +- Update to 1.5.0 + +* Wed Feb 05 2020 RPM Fusion Release Engineering - 1.4.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Mon Dec 30 2019 Vasiliy Glazov - 1.4.3-1 +- Update to 1.4.3 + +* Tue Sep 17 2019 Vasiliy Glazov - 1.4.1-2 +- Correct build gstreamer plugin + +* Tue Sep 17 2019 Vasiliy Glazov - 1.4.1-1 +- Initial release