diff --git a/.SRCINFO b/.SRCINFO index ed1857a..0fd2f6a 100644 --- a/.SRCINFO +++ b/.SRCINFO @@ -1,20 +1,21 @@ pkgbase = ffmpeg-full pkgdesc = Complete solution to record, convert and stream audio and video (all possible features including libfdk-aac) - pkgver = 7.1.2 + pkgver = 8.0 pkgrel = 1 - url = https://www.ffmpeg.org/ + url = https://ffmpeg.org/ arch = x86_64 license = LicenseRef-nonfree-and-unredistributable makedepends = amf-headers makedepends = clang + makedepends = cmake makedepends = cuda makedepends = ffnvcodec-headers + makedepends = git makedepends = gmp makedepends = libgl makedepends = libomxil-bellagio makedepends = lv2 makedepends = nasm - makedepends = patchutils makedepends = opencl-headers makedepends = vulkan-headers depends = alsa-lib @@ -24,8 +25,10 @@ pkgbase = ffmpeg-full depends = bzip2 depends = cairo depends = celt + depends = chromaprint-fftw depends = codec2 depends = dav1d + depends = davs2 depends = flite1 depends = fontconfig depends = freetype2 @@ -45,6 +48,7 @@ pkgbase = ffmpeg-full depends = lcevcdec depends = lcms2 depends = lensfun-git + depends = libaribcaption depends = libass depends = libavc1394 depends = libbluray @@ -61,6 +65,7 @@ pkgbase = ffmpeg-full depends = libiec61883 depends = libilbc depends = libjxl + depends = libklvanc depends = liblc3 depends = libmodplug depends = libmysofa @@ -88,6 +93,7 @@ pkgbase = ffmpeg-full depends = lilv depends = ocl-icd depends = openal + depends = openapv depends = opencore-amr depends = opencv2 depends = openh264 @@ -97,84 +103,78 @@ pkgbase = ffmpeg-full depends = qrencode depends = quirc depends = rav1e + depends = rockchip-mpp depends = rtmpdump depends = rubberband depends = sdl2 + depends = shine depends = smbclient depends = snappy depends = sndio depends = speex - depends = spirv-tools depends = srt depends = svt-av1 depends = svt-hevc depends = svt-vp9 depends = tesseract depends = twolame + depends = uavs3d-git depends = v4l-utils depends = vapoursynth depends = vid.stab depends = vmaf + depends = vo-amrwbenc depends = vulkan-icd-loader + depends = vvenc depends = x264 depends = x265 + depends = xavs + depends = xavs2 + depends = xevd + depends = xeve depends = xvidcore depends = xz depends = zeromq depends = zimg depends = zlib depends = zvbi - depends = chromaprint-fftw - depends = davs2 - depends = libaribcaption - depends = libklvanc - depends = rockchip-mpp - depends = shine - depends = uavs3d-git - depends = vo-amrwbenc - depends = vvenc - depends = xavs - depends = xavs2 - depends = xevd - depends = xeve - optdepends = nvidia-utils: for NVIDIA NVDEC/NVENC support + optdepends = nvidia-utils: for NVIDIA CUVID/NVDEC/NVENC support optdepends = vpl-runtime: for Intel Quick Sync Video + provides = ffmpeg provides = libavcodec.so provides = libavdevice.so provides = libavfilter.so provides = libavformat.so provides = libavutil.so - provides = libpostproc.so provides = libswscale.so provides = libswresample.so - provides = ffmpeg conflicts = ffmpeg - source = https://ffmpeg.org/releases/ffmpeg-7.1.2.tar.xz - source = https://ffmpeg.org/releases/ffmpeg-7.1.2.tar.xz.asc - source = https://github.com/obsproject/obs-studio/archive/32.0.0/obs-studio-32.0.0.tar.gz - source = 010-ffmpeg-add-svt-hevc-ged80959.patch::https://raw.githubusercontent.com/OpenVisualCloud/SVT-HEVC/ed80959ebb5586aa7763c91a397d44be1798587c/ffmpeg_plugin/master-0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch + source = https://ffmpeg.org/releases/ffmpeg-8.0.tar.xz + source = https://ffmpeg.org/releases/ffmpeg-8.0.tar.xz.asc + source = https://github.com/obsproject/obs-studio/archive/32.0.1/obs-studio-32.0.1.tar.gz + source = https://github.com/ggml-org/whisper.cpp/archive/v1.8.0/whisper.cpp-1.8.0.tar.gz + source = 010-ffmpeg-add-svt-hevc.patch source = 020-ffmpeg-add-svt-hevc-docs-ged80959.patch::https://raw.githubusercontent.com/OpenVisualCloud/SVT-HEVC/ed80959ebb5586aa7763c91a397d44be1798587c/ffmpeg_plugin/0002-doc-Add-libsvt_hevc-encoder-docs.patch - source = 030-ffmpeg-add-svt-vp9-g3b9a3fa.patch::https://raw.githubusercontent.com/OpenVisualCloud/SVT-VP9/3b9a3fa43da4cc5fe60c7d22afe2be15341392ea/ffmpeg_plugin/master-0001-Add-ability-for-ffmpeg-to-run-svt-vp9.patch - source = 031-ffmpeg-add-svt-vp9.patch + source = 030-ffmpeg-add-svt-vp9.patch source = 040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch - source = 050-ffmpeg-fix-nvidia-vulkan-decoding-segfault.patch - source = 060-ffmpeg-fix-cuda-nvcc-with-gcc14.patch - source = 070-ffmpeg-lcevcdec4.0.0-fix.patch - source = 080-ffmpeg-cuda13-fix.patch + source = 050-ffmpeg-fix-cuda-nvcc-with-gcc14.patch + source = 060-ffmpeg-whisper.cpp-fix-pkgconfig.patch + source = 070-ffmpeg-lcevcdec4.0.0-fix.patch::https://git.ffmpeg.org/gitweb/ffmpeg.git/patch/fa23202cc7baab899894e8d22d82851a84967848 + source = 080-ffmpeg-cuda13-fix.patch::https://git.ffmpeg.org/gitweb/ffmpeg.git/patch/f8a300c6739ea2ca648579d7faf3ae9811b9f19a source = LICENSE validpgpkeys = FCF986EA15E6E293A5644F10B4322F04D67658D8 - sha256sums = 089bc60fb59d6aecc5d994ff530fd0dcb3ee39aa55867849a2bbc4e555f9c304 + sha256sums = b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e sha256sums = SKIP - sha256sums = 6c73099d53aee7b57faa624431891901d9c84b2d93e284d27799fdc33868d113 - sha256sums = 9047e18d34716812d4ea7eafc1d0fd8b376d922a4b6b4dc20237662fcaf0c996 + sha256sums = 906278ccedb5ed919e586697467eb7fa4205fceeda127386ce5b74026113ba96 + sha256sums = c006a5e472ee41e7a733d0bf7326e339c8b281d3a91a1c8a35468fa0a051940f + sha256sums = 4b1053cc01244c79e3b23dc696eaff1aeb0627a2098e1a720a025d4ad75b5c16 sha256sums = a164ebdc4d281352bf7ad1b179aae4aeb33f1191c444bed96cb8ab333c046f81 - sha256sums = 59da61f2b2c556fbe0cdbf84bcc00977ee3d2447085decb21f6298226559f2aa - sha256sums = aa0daffc4d234b6621b63c298dc165d29522c5087f8905a923d23ee2d164e9ad - sha256sums = 57697441b8f3ff3be883a2444b4cb89eed452764d24965e74e7b101e6af7f70a - sha256sums = 5a3731d1410747703948c87e46bb3aef820c6038f7101ab37f9d072cd1d15d15 - sha256sums = f749aeb2f5afd9920cb4e3e3e4a64d014b01bce374cf5c593df728611f898e7e - sha256sums = 2ff4ba31e43d6d397542ec25df224cef01cf501409e202255e9414e482ba14cf - sha256sums = 9c3b4bc1c5e8687f610b5d251c2ec759c4fa1ddda999863e908e6046b9bab3bf + sha256sums = da01eb3ca31d35d23257760875e14bed808b3fea02f290028adaed76062125a0 + sha256sums = 5cb2475de410f5696072687af88e91461cdacd1bb636ac14a3b348e3383934f1 + sha256sums = 9f3d84b3abe1077b3d6c1a25f36dcddf6419a7fe3217a4edd52aab6f0e4cd838 + sha256sums = 98b3d28cbd13bb575c602785f6b8cb0b66ea3128ab5a3a82fc1645822320c136 + sha256sums = d2bacb3a5b0201503554c3394ea1f3fbc8ad79d5c2721e0c226134d40812ad08 + sha256sums = 79e3fbc30c86e0db789af78e79dc23227e5f6887531bcd52b2defa8526d1455b sha256sums = 04a7176400907fd7db0d69116b99de49e582a6e176b3bfb36a03e50a4cb26a36 pkgname = ffmpeg-full diff --git a/010-ffmpeg-add-svt-hevc.patch b/010-ffmpeg-add-svt-hevc.patch new file mode 100644 index 0000000..ce2ceba --- /dev/null +++ b/010-ffmpeg-add-svt-hevc.patch @@ -0,0 +1,646 @@ +--- a/configure ++++ b/configure +@@ -339,6 +339,7 @@ External library support: + --enable-whisper enable whisper filter [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] +@@ -1979,6 +1980,7 @@ EXTERNAL_LIBRARY_LIST=" + libsrt + libssh + libsvtav1 ++ libsvthevc + libtensorflow + libtesseract + libtheora +@@ -3678,6 +3680,7 @@ vapoursynth_demuxer_deps="vapoursynth" + videotoolbox_suggest="coreservices" + videotoolbox_deps="corefoundation coremedia corevideo VTDecompressionSessionDecodeFrame" + videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames" ++libsvt_hevc_encoder_deps="libsvthevc" + + # demuxers / muxers + ac3_demuxer_select="ac3_parser" +@@ -7150,6 +7153,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 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1201,6 +1201,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_LIBXEVD_DECODER) += libxevd.o +--- a/libavcodec/allcodecs.c ++++ b/libavcodec/allcodecs.c +@@ -827,6 +827,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; +--- /dev/null ++++ b/libavcodec/libsvt_hevc.c +@@ -0,0 +1,586 @@ ++/* ++* 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/mem.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 (AV_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 != AV_PROFILE_HEVC_REXT)) { ++ av_log(avctx, AV_LOG_WARNING, "Rext Profile forced for 422 or 444\n"); ++ param->profile = AV_PROFILE_HEVC_REXT; ++ } ++ ++ if ((AV_PROFILE_HEVC_MAIN == param->profile) && ++ (param->encoderBitDepth > 8)) { ++ av_log(avctx, AV_LOG_WARNING, "Main10 Profile forced for 10 bits\n"); ++ param->profile = AV_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; ++ } else { ++ param->frameRateNumerator = avctx->time_base.den; ++ param->frameRateDenominator = ++ avctx->time_base.num; ++ } ++ ++ 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 = AV_PROFILE_HEVC_MAIN }, AV_PROFILE_HEVC_MAIN, AV_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.44.0 + diff --git a/030-ffmpeg-add-svt-vp9.patch b/030-ffmpeg-add-svt-vp9.patch new file mode 100644 index 0000000..bd9cc98 --- /dev/null +++ b/030-ffmpeg-add-svt-vp9.patch @@ -0,0 +1,764 @@ +--- a/configure ++++ b/configure +@@ -294,6 +294,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-libvvenc enable H.266/VVC encoding via vvenc [no] + --enable-libwebp enable WebP encoding via libwebp [no] + --enable-libx264 enable H.264 encoding via x264 [no] +@@ -1991,6 +1992,7 @@ EXTERNAL_LIBRARY_LIST=" + libvmaf + libvorbis + libvpx ++ libsvtvp9 + libvvenc + libwebp + libxevd +@@ -3660,6 +3662,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" + libvvenc_encoder_deps="libvvenc" + libwebp_encoder_deps="libwebp" + libwebp_anim_encoder_deps="libwebp" +@@ -7195,6 +7198,7 @@ enabled libvpx && { + fi + } + ++enabled libsvtvp9 && require_pkg_config libsvtvp9 SvtVp9Enc EbSvtVp9Enc.h eb_vp9_svt_init_handle + enabled libvvenc && require_pkg_config libvvenc "libvvenc >= 1.6.1" "vvenc/vvenc.h" vvenc_get_version + enabled libwebp && { + enabled libwebp_encoder && require_pkg_config libwebp "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1195,6 +1195,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_LIBVVENC_ENCODER) += libvvenc.o + OBJS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.o libwebpenc.o + OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o libwebpenc_animencoder.o +--- a/libavcodec/allcodecs.c ++++ b/libavcodec/allcodecs.c +@@ -813,6 +813,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; + extern const FFCodec ff_libvvenc_encoder; + /* preferred over libwebp */ + extern const FFCodec ff_libwebp_anim_encoder; +--- /dev/null ++++ b/libavcodec/libsvt_vp9.c +@@ -0,0 +1,707 @@ ++/* ++* 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 "libavutil/mem.h" ++#include "libavcodec/get_bits.h" ++#include "libavcodec/version.h" ++ ++#include "codec_internal.h" ++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 93, 100) ++#include "encode.h" ++#endif ++ ++#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; ++ } else { ++ param->frame_rate_numerator = avctx->time_base.den; ++ param->frame_rate_denominator = avctx->time_base.num; ++ } ++ ++ 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; ++ } ++ ++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 93, 100) ++ 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; ++ ++ eb_send_frame(avctx, frame); ++ av_frame_unref(svt_enc->frame); ++#endif ++ ++ ++ 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 }, ++}; ++ ++const FFCodec ff_libsvt_vp9_encoder = { ++ .p.name = "libsvt_vp9", ++ CODEC_LONG_NAME("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, ++#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 93, 100) ++ .send_frame = eb_send_frame, ++#endif ++ FF_CODEC_RECEIVE_PACKET_CB(eb_receive_packet), ++ .close = eb_enc_close, ++ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS, ++ CODEC_PIXFMTS(AV_PIX_FMT_YUV420P, ++ AV_PIX_FMT_NONE), ++ .p.priv_class = &class, ++ .defaults = eb_enc_defaults, ++ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, ++ .p.wrapper_name = "libsvt_vp9", ++}; diff --git a/031-ffmpeg-add-svt-vp9.patch b/031-ffmpeg-add-svt-vp9.patch deleted file mode 100644 index 06b3f23..0000000 --- a/031-ffmpeg-add-svt-vp9.patch +++ /dev/null @@ -1,54 +0,0 @@ ---- a/configure -+++ b/configure -@@ -294,6 +294,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-libvvenc enable H.266/VVC encoding via vvenc [no] - --enable-libwebp enable WebP encoding via libwebp [no] - --enable-libx264 enable H.264 encoding via x264 [no] -@@ -1971,6 +1972,7 @@ EXTERNAL_LIBRARY_LIST=" - libvmaf - libvorbis - libvpx -+ libsvtvp9 - libvvenc - libwebp - libxevd -@@ -3577,6 +3579,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" - libvvenc_encoder_deps="libvvenc" - libwebp_encoder_deps="libwebp" - libwebp_anim_encoder_deps="libwebp" -@@ -7040,6 +7043,7 @@ enabled libvpx && { - fi - } - -+enabled libsvtvp9 && require_pkg_config libsvtvp9 SvtVp9Enc EbSvtVp9Enc.h eb_vp9_svt_init_handle - enabled libvvenc && require_pkg_config libvvenc "libvvenc >= 1.6.1" "vvenc/vvenc.h" vvenc_get_version - enabled libwebp && { - enabled libwebp_encoder && require_pkg_config libwebp "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion ---- a/libavcodec/Makefile -+++ b/libavcodec/Makefile -@@ -1161,6 +1161,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_LIBVVENC_ENCODER) += libvvenc.o - OBJS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.o libwebpenc.o - OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o libwebpenc_animencoder.o ---- a/libavcodec/allcodecs.c -+++ b/libavcodec/allcodecs.c -@@ -800,6 +800,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; - extern const FFCodec ff_libvvenc_encoder; - /* preferred over libwebp */ - extern const FFCodec ff_libwebp_anim_encoder; diff --git a/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch b/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch index fa89a4c..a96fa78 100644 --- a/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch +++ b/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch @@ -1,6 +1,6 @@ --- a/libavformat/avformat.h +++ b/libavformat/avformat.h -@@ -1202,6 +1202,10 @@ typedef struct AVStreamGroup { +@@ -1179,6 +1179,10 @@ typedef struct AVStreamGroup { struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); @@ -13,7 +13,7 @@ /** --- a/libavformat/utils.c +++ b/libavformat/utils.c -@@ -44,6 +44,13 @@ +@@ -47,6 +47,13 @@ * various utility functions for use within FFmpeg */ diff --git a/060-ffmpeg-fix-cuda-nvcc-with-gcc14.patch b/050-ffmpeg-fix-cuda-nvcc-with-gcc14.patch similarity index 82% rename from 060-ffmpeg-fix-cuda-nvcc-with-gcc14.patch rename to 050-ffmpeg-fix-cuda-nvcc-with-gcc14.patch index 1201f9b..ebe69ca 100644 --- a/060-ffmpeg-fix-cuda-nvcc-with-gcc14.patch +++ b/050-ffmpeg-fix-cuda-nvcc-with-gcc14.patch @@ -1,6 +1,6 @@ --- a/configure +++ b/configure -@@ -6769,7 +6769,7 @@ if [ -z "$nvccflags" ]; then +@@ -6898,7 +6898,7 @@ if [ -z "$nvccflags" ]; then nvccflags=$nvccflags_default fi diff --git a/050-ffmpeg-fix-nvidia-vulkan-decoding-segfault.patch b/050-ffmpeg-fix-nvidia-vulkan-decoding-segfault.patch deleted file mode 100644 index 0ba6f75..0000000 --- a/050-ffmpeg-fix-nvidia-vulkan-decoding-segfault.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- a/libavutil/vulkan.c -+++ b/libavutil/vulkan.c -@@ -671,6 +671,9 @@ int ff_vk_exec_add_dep_frame(FFVulkanContext *s, FFVkExecContext *e, AVFrame *f, - uint32_t *queue_family_dst; - VkAccessFlagBits *access_dst; - -+ if (!f || !f->hw_frames_ctx) -+ return 1; -+ - AVHWFramesContext *hwfc = (AVHWFramesContext *)f->hw_frames_ctx->data; - AVVulkanFramesContext *vkfc = hwfc->hwctx; - AVVkFrame *vkf = (AVVkFrame *)f->data[0]; diff --git a/060-ffmpeg-whisper.cpp-fix-pkgconfig.patch b/060-ffmpeg-whisper.cpp-fix-pkgconfig.patch new file mode 100644 index 0000000..435a880 --- /dev/null +++ b/060-ffmpeg-whisper.cpp-fix-pkgconfig.patch @@ -0,0 +1,10 @@ +--- a/cmake/whisper.pc.in ++++ b/cmake/whisper.pc.in +@@ -6,5 +6,5 @@ includedir=${prefix}/include + Name: whisper + Description: Port of OpenAI's Whisper model in C/C++ + Version: @PROJECT_VERSION@ +-Libs: -L${libdir} -lggml -lggml-base -lwhisper +-Cflags: -I${includedir} ++Libs: -L${libdir} -lwhisper -lggml -lggml-cpu -lggml-base -lstdc++ -lm -fopenmp -fPIC ++Cflags: -I${includedir} -fopenmp -fPIC diff --git a/070-ffmpeg-lcevcdec4.0.0-fix.patch b/070-ffmpeg-lcevcdec4.0.0-fix.patch deleted file mode 100644 index ff266b1..0000000 --- a/070-ffmpeg-lcevcdec4.0.0-fix.patch +++ /dev/null @@ -1,40 +0,0 @@ ---- a/libavcodec/lcevcdec.c -+++ b/libavcodec/lcevcdec.c -@@ -139,7 +139,7 @@ static int lcevc_send_frame(void *logctx - if (!sd) - return 1; - -- res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size); -+ res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, (uint64_t) in->pts, sd->data, sd->size); - if (res != LCEVC_Success) - return AVERROR_EXTERNAL; - -@@ -147,7 +147,7 @@ static int lcevc_send_frame(void *logctx - if (ret < 0) - return ret; - -- res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, NULL); -+ res = LCEVC_SendDecoderBase(lcevc->decoder, (uint64_t) in->pts, picture, -1, NULL); - if (res != LCEVC_Success) - return AVERROR_EXTERNAL; - ---- a/libavfilter/vf_lcevc.c -+++ b/libavfilter/vf_lcevc.c -@@ -139,7 +139,7 @@ static int send_frame(AVFilterLink *inlink, AVFrame *in) - return ret; - - if (sd) { -- res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size); -+ res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, (uint64_t) in->pts, sd->data, sd->size); - if (res == LCEVC_Again) - return AVERROR(EAGAIN); - else if (res != LCEVC_Success) { -@@ -148,7 +148,7 @@ static int send_frame(AVFilterLink *inlink, AVFrame *in) - } - } - -- res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, in); -+ res = LCEVC_SendDecoderBase(lcevc->decoder, (uint64_t) in->pts, picture, -1, in); - if (res != LCEVC_Success) { - av_log(ctx, AV_LOG_ERROR, "LCEVC_SendDecoderBase failed\n"); - LCEVC_FreePicture(lcevc->decoder, picture); diff --git a/080-ffmpeg-cuda13-fix.patch b/080-ffmpeg-cuda13-fix.patch deleted file mode 100644 index 2362139..0000000 --- a/080-ffmpeg-cuda13-fix.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/configure -+++ a/configure -@@ -4711,7 +4711,7 @@ set_default nvcc - - if enabled cuda_nvcc; then - if $nvcc $nvccflags_default 2>&1 | grep -qi unsupported; then -- nvccflags_default="-gencode arch=compute_60,code=sm_60 -O2" -+ nvccflags_default="-gencode arch=compute_75,code=sm_75 -O2" - fi - fi - diff --git a/PKGBUILD b/PKGBUILD index 9344958..b87c7a8 100644 --- a/PKGBUILD +++ b/PKGBUILD @@ -2,14 +2,14 @@ # Contributor: Iacopo Isimbaldi pkgname=ffmpeg-full -pkgver=7.1.2 +pkgver=8.0 pkgrel=1 _svt_hevc_ver='ed80959ebb5586aa7763c91a397d44be1798587c' -_svt_vp9_ver='3b9a3fa43da4cc5fe60c7d22afe2be15341392ea' -_obs_studio_ver='32.0.0' +_obs_studio_ver='32.0.1' +_whispercpp_ver='1.8.0' pkgdesc='Complete solution to record, convert and stream audio and video (all possible features including libfdk-aac)' arch=('x86_64') -url='https://www.ffmpeg.org/' +url='https://ffmpeg.org/' license=('LicenseRef-nonfree-and-unredistributable') depends=( 'alsa-lib' @@ -19,8 +19,10 @@ depends=( 'bzip2' 'cairo' 'celt' + 'chromaprint-fftw' 'codec2' 'dav1d' + 'davs2' 'flite1' 'fontconfig' 'freetype2' @@ -40,6 +42,7 @@ depends=( 'lcevcdec' 'lcms2' 'lensfun-git' + 'libaribcaption' 'libass' 'libavc1394' 'libbluray' @@ -56,6 +59,7 @@ depends=( 'libiec61883' 'libilbc' 'libjxl' + 'libklvanc' 'liblc3' 'libmodplug' 'libmysofa' @@ -83,6 +87,7 @@ depends=( 'lilv' 'ocl-icd' 'openal' + 'openapv' 'opencore-amr' 'opencv2' 'openh264' @@ -92,120 +97,130 @@ depends=( 'qrencode' 'quirc' 'rav1e' + 'rockchip-mpp' 'rtmpdump' 'rubberband' 'sdl2' + 'shine' 'smbclient' 'snappy' 'sndio' 'speex' - 'spirv-tools' 'srt' 'svt-av1' 'svt-hevc' 'svt-vp9' 'tesseract' 'twolame' + 'uavs3d-git' 'v4l-utils' 'vapoursynth' # loaded on-demand by dlopen() 'vid.stab' 'vmaf' + 'vo-amrwbenc' 'vulkan-icd-loader' # loaded on-demand by dlopen() + 'vvenc' 'x264' 'x265' + 'xavs' + 'xavs2' + 'xevd' + 'xeve' 'xvidcore' 'xz' 'zeromq' 'zimg' 'zlib' - 'zvbi' - # aur: - 'chromaprint-fftw' - 'davs2' - 'libaribcaption' - 'libklvanc' - 'rockchip-mpp' - 'shine' - 'uavs3d-git' - 'vo-amrwbenc' - 'vvenc' - 'xavs' - 'xavs2' - 'xevd' - 'xeve' -) + 'zvbi') optdepends=( - 'nvidia-utils: for NVIDIA NVDEC/NVENC support' - 'vpl-runtime: for Intel Quick Sync Video' -) + 'nvidia-utils: for NVIDIA CUVID/NVDEC/NVENC support' + 'vpl-runtime: for Intel Quick Sync Video') makedepends=( 'amf-headers' 'clang' + 'cmake' 'cuda' 'ffnvcodec-headers' + 'git' 'gmp' 'libgl' 'libomxil-bellagio' 'lv2' 'nasm' - 'patchutils' 'opencl-headers' - 'vulkan-headers' -) -provides=('libavcodec.so' 'libavdevice.so' 'libavfilter.so' 'libavformat.so' - 'libavutil.so' 'libpostproc.so' 'libswscale.so' 'libswresample.so' - 'ffmpeg') + 'vulkan-headers') +provides=( + 'ffmpeg' + 'libavcodec.so' + 'libavdevice.so' + 'libavfilter.so' + 'libavformat.so' + 'libavutil.so' + 'libswscale.so' + 'libswresample.so') conflicts=('ffmpeg') source=("https://ffmpeg.org/releases/ffmpeg-${pkgver}.tar.xz"{,.asc} "https://github.com/obsproject/obs-studio/archive/${_obs_studio_ver}/obs-studio-${_obs_studio_ver}.tar.gz" - "010-ffmpeg-add-svt-hevc-g${_svt_hevc_ver:0:7}.patch"::"https://raw.githubusercontent.com/OpenVisualCloud/SVT-HEVC/${_svt_hevc_ver}/ffmpeg_plugin/master-0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch" + "https://github.com/ggml-org/whisper.cpp/archive/v${_whispercpp_ver}/whisper.cpp-${_whispercpp_ver}.tar.gz" + '010-ffmpeg-add-svt-hevc.patch' "020-ffmpeg-add-svt-hevc-docs-g${_svt_hevc_ver:0:7}.patch"::"https://raw.githubusercontent.com/OpenVisualCloud/SVT-HEVC/${_svt_hevc_ver}/ffmpeg_plugin/0002-doc-Add-libsvt_hevc-encoder-docs.patch" - "030-ffmpeg-add-svt-vp9-g${_svt_vp9_ver:0:7}.patch"::"https://raw.githubusercontent.com/OpenVisualCloud/SVT-VP9/${_svt_vp9_ver}/ffmpeg_plugin/master-0001-Add-ability-for-ffmpeg-to-run-svt-vp9.patch" - "031-ffmpeg-add-svt-vp9.patch" + '030-ffmpeg-add-svt-vp9.patch' '040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch' - '050-ffmpeg-fix-nvidia-vulkan-decoding-segfault.patch' - '060-ffmpeg-fix-cuda-nvcc-with-gcc14.patch' - '070-ffmpeg-lcevcdec4.0.0-fix.patch' - '080-ffmpeg-cuda13-fix.patch' + '050-ffmpeg-fix-cuda-nvcc-with-gcc14.patch' + '060-ffmpeg-whisper.cpp-fix-pkgconfig.patch' + '070-ffmpeg-lcevcdec4.0.0-fix.patch'::'https://git.ffmpeg.org/gitweb/ffmpeg.git/patch/fa23202cc7baab899894e8d22d82851a84967848' + '080-ffmpeg-cuda13-fix.patch'::'https://git.ffmpeg.org/gitweb/ffmpeg.git/patch/f8a300c6739ea2ca648579d7faf3ae9811b9f19a' 'LICENSE') -sha256sums=('089bc60fb59d6aecc5d994ff530fd0dcb3ee39aa55867849a2bbc4e555f9c304' +sha256sums=('b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e' 'SKIP' - '6c73099d53aee7b57faa624431891901d9c84b2d93e284d27799fdc33868d113' - '9047e18d34716812d4ea7eafc1d0fd8b376d922a4b6b4dc20237662fcaf0c996' + '906278ccedb5ed919e586697467eb7fa4205fceeda127386ce5b74026113ba96' + 'c006a5e472ee41e7a733d0bf7326e339c8b281d3a91a1c8a35468fa0a051940f' + '4b1053cc01244c79e3b23dc696eaff1aeb0627a2098e1a720a025d4ad75b5c16' 'a164ebdc4d281352bf7ad1b179aae4aeb33f1191c444bed96cb8ab333c046f81' - '59da61f2b2c556fbe0cdbf84bcc00977ee3d2447085decb21f6298226559f2aa' - 'aa0daffc4d234b6621b63c298dc165d29522c5087f8905a923d23ee2d164e9ad' - '57697441b8f3ff3be883a2444b4cb89eed452764d24965e74e7b101e6af7f70a' - '5a3731d1410747703948c87e46bb3aef820c6038f7101ab37f9d072cd1d15d15' - 'f749aeb2f5afd9920cb4e3e3e4a64d014b01bce374cf5c593df728611f898e7e' - '2ff4ba31e43d6d397542ec25df224cef01cf501409e202255e9414e482ba14cf' - '9c3b4bc1c5e8687f610b5d251c2ec759c4fa1ddda999863e908e6046b9bab3bf' + 'da01eb3ca31d35d23257760875e14bed808b3fea02f290028adaed76062125a0' + '5cb2475de410f5696072687af88e91461cdacd1bb636ac14a3b348e3383934f1' + '9f3d84b3abe1077b3d6c1a25f36dcddf6419a7fe3217a4edd52aab6f0e4cd838' + '98b3d28cbd13bb575c602785f6b8cb0b66ea3128ab5a3a82fc1645822320c136' + 'd2bacb3a5b0201503554c3394ea1f3fbc8ad79d5c2721e0c226134d40812ad08' + '79e3fbc30c86e0db789af78e79dc23227e5f6887531bcd52b2defa8526d1455b' '04a7176400907fd7db0d69116b99de49e582a6e176b3bfb36a03e50a4cb26a36') validpgpkeys=('FCF986EA15E6E293A5644F10B4322F04D67658D8') prepare() { - rm -f "ffmpeg-${pkgver}/libavcodec/"libsvt_{hevc,vp9}.c - patch -d "ffmpeg-${pkgver}" -Np1 -i "${srcdir}/010-ffmpeg-add-svt-hevc-g${_svt_hevc_ver:0:7}.patch" + rm -f "ffmpeg-${pkgver}/libavcodec"/libsvt_{hevc,vp9}.c + patch -d "ffmpeg-${pkgver}" -Np1 -i "${srcdir}/010-ffmpeg-add-svt-hevc.patch" patch -d "ffmpeg-${pkgver}" -Np1 -i "${srcdir}/020-ffmpeg-add-svt-hevc-docs-g${_svt_hevc_ver:0:7}.patch" - patch -d "ffmpeg-${pkgver}" -Np1 -i "${srcdir}/031-ffmpeg-add-svt-vp9.patch" - patch -d "ffmpeg-${pkgver}" -Np1 -i <(filterdiff -i b/libavcodec/libsvt_vp9.c "030-ffmpeg-add-svt-vp9-g${_svt_vp9_ver:0:7}.patch") + patch -d "ffmpeg-${pkgver}" -Np1 -i "${srcdir}/030-ffmpeg-add-svt-vp9.patch" patch -d "ffmpeg-${pkgver}" -Np1 -i "${srcdir}/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch" - patch -d "ffmpeg-${pkgver}" -Np1 -i "${srcdir}/050-ffmpeg-fix-nvidia-vulkan-decoding-segfault.patch" - patch -d "ffmpeg-${pkgver}" -Np1 -i "${srcdir}/060-ffmpeg-fix-cuda-nvcc-with-gcc14.patch" + patch -d "ffmpeg-${pkgver}" -Np1 -i "${srcdir}/050-ffmpeg-fix-cuda-nvcc-with-gcc14.patch" + patch -d "whisper.cpp-${_whispercpp_ver}" -Np1 -i "${srcdir}/060-ffmpeg-whisper.cpp-fix-pkgconfig.patch" patch -d "ffmpeg-${pkgver}" -Np1 -i "${srcdir}/070-ffmpeg-lcevcdec4.0.0-fix.patch" patch -d "ffmpeg-${pkgver}" -Np1 -i "${srcdir}/080-ffmpeg-cuda13-fix.patch" } build() { + # whisper.cpp AUR package conflicts with imagemagick at the time of writing + # building it locally as a static library for the time being, as imagemagick is a commonly used package (high usage in pkgstats) + cmake -B build/whisper.cpp -S "whisper.cpp-${_whispercpp_ver}" \ + -G 'Unix Makefiles' \ + -DBUILD_SHARED_LIBS:BOOL='OFF' \ + -DCMAKE_BUILD_TYPE:STRING='None' \ + -DCMAKE_INSTALL_PREFIX:PATH="${srcdir}/staging" \ + -DWHISPER_BUILD_EXAMPLES:BOOL='OFF' \ + -DWHISPER_BUILD_TESTS:BOOL='OFF' \ + -Wno-dev + cmake --build build/whisper.cpp --target install + cd "ffmpeg-${pkgver}" printf '%s\n' ' -> Running ffmpeg configure script...' export CFLAGS+=' -isystem/opt/cuda/include' export CFLAGS+=" -isystem${srcdir}/obs-studio-${_obs_studio_ver}/plugins/decklink/linux/decklink-sdk" export LDFLAGS+=' -L/opt/cuda/lib64' + export PKG_CONFIG_PATH="${srcdir}/staging/lib/pkgconfig${PKG_CONFIG_PATH:+":${PKG_CONFIG_PATH}"}" # fix build of libavfilter/asrc_flite.c with gcc 14 - export CFLAGS+=' -Wno-incompatible-pointer-types' + export CFLAGS+=' -Wno-error=incompatible-pointer-types' ./configure \ --prefix='/usr' \ @@ -267,6 +282,7 @@ build() { --enable-liblensfun \ --enable-libmodplug \ --enable-libmp3lame \ + --enable-liboapv \ --enable-libopencore-amrnb \ --enable-libopencore-amrwb \ --enable-libopencv \ @@ -340,6 +356,7 @@ build() { --enable-sdl2 \ --enable-vapoursynth \ --enable-vulkan \ + --enable-whisper \ --enable-xlib \ --enable-zlib \ \ @@ -353,6 +370,7 @@ build() { --disable-libnpp \ --enable-nvdec \ --enable-nvenc \ + --disable-ohcodec \ --enable-omx \ --enable-rkmpp \ --enable-v4l2-m2m \