diff options
author | egnappahz | 2022-02-23 16:39:49 +0100 |
---|---|---|
committer | egnappahz | 2022-02-23 16:39:49 +0100 |
commit | 9eb8251e573726fe4574c346f211ef877140dcbc (patch) | |
tree | eaad83ec9a8ab6a86e76fd85f30de469ffeb754d | |
parent | 32af25adaf5401f2431c64adb3b4ae5ef6bb493d (diff) | |
download | aur-9eb8251e573726fe4574c346f211ef877140dcbc.tar.gz |
Add some upstream patches
-rw-r--r-- | .SRCINFO | 10 | ||||
-rw-r--r-- | 010-ffmpeg-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch | 674 | ||||
-rw-r--r-- | 030-ffmpeg-Add-ability-for-ffmpeg-to-run-svt-vp9.patch | 792 | ||||
-rw-r--r-- | 040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch | 145 | ||||
-rw-r--r-- | 050-ffmpeg-vmaf-2.x.patch | 949 | ||||
-rw-r--r-- | PKGBUILD | 19 |
6 files changed, 2584 insertions, 5 deletions
@@ -1,7 +1,7 @@ pkgbase = ffmpeg-nocuda pkgdesc = Complete solution to record, convert and stream audio and video (without nvidias propriatary blobs) pkgver = 5.0 - pkgrel = 2 + pkgrel = 3 url = https://www.ffmpeg.org/ arch = x86_64 license = GPL3 @@ -79,6 +79,14 @@ pkgbase = ffmpeg-nocuda provides = ffmpeg conflicts = ffmpeg source = git+https://git.ffmpeg.org/ffmpeg.git#tag=n5.0 + source = 010-ffmpeg-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch + source = 030-ffmpeg-Add-ability-for-ffmpeg-to-run-svt-vp9.patch + source = 040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch + source = 050-ffmpeg-vmaf-2.x.patch + sha256sums = SKIP + sha256sums = SKIP + sha256sums = SKIP + sha256sums = SKIP sha256sums = SKIP pkgname = ffmpeg-nocuda diff --git a/010-ffmpeg-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch b/010-ffmpeg-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch new file mode 100644 index 000000000000..d2046a12307d --- /dev/null +++ b/010-ffmpeg-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch @@ -0,0 +1,674 @@ +From eb67d4a6ae6707740dc8403424f31409fdce5704 Mon Sep 17 00:00:00 2001 +From: Jing Sun <jing.a.sun@intel.com> +Date: Wed, 21 Nov 2018 11:33:04 +0800 +Subject: [PATCH] lavc/svt_hevc: add libsvt hevc encoder wrapper + +Signed-off-by: Zhengxu Huang <zhengxu.huang@intel.com> +Signed-off-by: Hassene Tmar <hassene.tmar@intel.com> +Signed-off-by: Jun Zhao <jun.zhao@intel.com> +Signed-off-by: Jing Sun <jing.a.sun@intel.com> +Signed-off-by: Austin Hu <austin.hu@intel.com> +Signed-off-by: Guo Jiansheng <jiansheng.guo@intel.com> +Signed-off-by: Christopher Degawa <ccom@randomderp.com> +Signed-off-by: Guo Jiansheng <jiansheng.guo@intel.com> +--- + configure | 4 + + libavcodec/Makefile | 1 + + libavcodec/allcodecs.c | 1 + + libavcodec/libsvt_hevc.c | 584 +++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 590 insertions(+) + create mode 100644 libavcodec/libsvt_hevc.c + +diff --git a/configure b/configure +index 6bfd98b..93c87cb 100755 +--- a/configure ++++ b/configure +@@ -288,6 +288,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] +@@ -1792,6 +1793,7 @@ EXTERNAL_LIBRARY_LIST=" + gnutls + jni + ladspa ++ libsvthevc + libaom + libass + libbluray +@@ -3315,6 +3317,7 @@ libx264_encoder_select="atsc_a53" + libx264rgb_encoder_deps="libx264" + libx264rgb_encoder_select="libx264_encoder" + libx265_encoder_deps="libx265" ++libsvt_hevc_encoder_deps="libsvthevc" + libxavs_encoder_deps="libxavs" + libxavs2_encoder_deps="libxavs2" + libxvid_encoder_deps="libxvid" +@@ -6535,6 +6538,7 @@ enabled mmal && { check_lib mmal interface/mmal/mmal.h mmal_port_co + check_lib mmal interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host; } || + die "ERROR: mmal not found" && + check_func_headers interface/mmal/mmal.h "MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS"; } ++enabled libsvthevc && require_pkg_config libsvthevc SvtHevcEnc EbApi.h EbInitHandle + enabled openal && { { for al_extralibs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do + check_lib openal 'AL/al.h' alGetError "${al_extralibs}" && break; done } || + die "ERROR: openal not found"; } && +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index 4fa8d7a..192ed45 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1064,6 +1064,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 623db2a..280480f 100644 +--- a/libavcodec/allcodecs.c ++++ b/libavcodec/allcodecs.c +@@ -774,6 +774,7 @@ extern LIBX264_CONST AVCodec ff_libx264_encoder; + #endif + extern const AVCodec ff_libx264rgb_encoder; + extern AVCodec ff_libx265_encoder; ++extern AVCodec ff_libsvt_hevc_encoder; + extern const AVCodec ff_libxavs_encoder; + extern const AVCodec ff_libxavs2_encoder; + extern const AVCodec ff_libxvid_encoder; +diff --git a/libavcodec/libsvt_hevc.c b/libavcodec/libsvt_hevc.c +new file mode 100644 +index 0000000..2c013a9 +--- /dev/null ++++ b/libavcodec/libsvt_hevc.c +@@ -0,0 +1,584 @@ ++/* ++* 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 "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 AVCodecDefault eb_enc_defaults[] = { ++ { "b", "7M" }, ++ { "qmin", "10" }, ++ { "qmax", "48" }, ++ { "g", "-2" }, ++ { NULL }, ++}; ++ ++AVCodec ff_libsvt_hevc_encoder = { ++ .name = "libsvt_hevc", ++ .long_name = NULL_IF_CONFIG_SMALL("SVT-HEVC(Scalable Video Technology for HEVC) encoder"), ++ .priv_data_size = sizeof(SvtContext), ++ .type = AVMEDIA_TYPE_VIDEO, ++ .id = AV_CODEC_ID_HEVC, ++ .init = eb_enc_init, ++ .encode2 = eb_encode_frame, ++ .close = eb_enc_close, ++ .capabilities = AV_CODEC_CAP_DELAY, ++ .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 }, ++ .priv_class = &class, ++ .defaults = eb_enc_defaults, ++ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, ++ .wrapper_name = "libsvt_hevc", ++}; +-- +2.7.4 + diff --git a/030-ffmpeg-Add-ability-for-ffmpeg-to-run-svt-vp9.patch b/030-ffmpeg-Add-ability-for-ffmpeg-to-run-svt-vp9.patch new file mode 100644 index 000000000000..fad2b35bb7d4 --- /dev/null +++ b/030-ffmpeg-Add-ability-for-ffmpeg-to-run-svt-vp9.patch @@ -0,0 +1,792 @@ +From dbd08eed9ec185b907d78508ea1d44c3a8d9ca6d Mon Sep 17 00:00:00 2001 +From: hassene <hassene.tmar@intel.com> +Date: Fri, 15 Feb 2019 17:43:54 -0800 +Subject: [PATCH] Add ability for ffmpeg to run svt vp9 + +Signed-off-by: hassene <hassene.tmar@intel.com> +Signed-off-by: Jing Sun <jing.a.sun@intel.com> +Signed-off-by: Austin Hu <austin.hu@intel.com> +Signed-off-by: Guo Jiansheng <jiansheng.guo@intel.com> +Signed-off-by: Andrei Bich <dronimal@yandex-team.ru> +--- + configure | 4 + + libavcodec/Makefile | 1 + + libavcodec/allcodecs.c | 1 + + libavcodec/libsvt_vp9.c | 705 ++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 711 insertions(+) + create mode 100644 libavcodec/libsvt_vp9.c + +diff --git a/configure b/configure +index b124411..2fa6805 100755 +--- a/configure ++++ b/configure +@@ -285,6 +285,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] +@@ -1832,6 +1833,7 @@ EXTERNAL_LIBRARY_LIST=" + librtmp + libshine + libsmbclient ++ libsvtvp9 + libsnappy + libsoxr + libspeex +@@ -3311,6 +3313,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" +@@ -6523,6 +6526,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 04f28c6..060e198 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1060,6 +1060,7 @@ OBJS-$(CONFIG_LIBVPX_VP8_DECODER) += libvpxdec.o + 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 623db2a..56307d8 100644 +--- a/libavcodec/allcodecs.c ++++ b/libavcodec/allcodecs.c +@@ -759,6 +759,7 @@ extern const AVCodec ff_libvpx_vp8_encoder; + extern const AVCodec ff_libvpx_vp8_decoder; + extern AVCodec ff_libvpx_vp9_encoder; + extern AVCodec ff_libvpx_vp9_decoder; ++extern AVCodec ff_libsvt_vp9_encoder; + /* preferred over libwebp */ + extern const AVCodec ff_libwebp_anim_encoder; + extern const AVCodec ff_libwebp_encoder; +diff --git a/libavcodec/libsvt_vp9.c b/libavcodec/libsvt_vp9.c +new file mode 100644 +index 0000000..6ed6e62 +--- /dev/null ++++ b/libavcodec/libsvt_vp9.c +@@ -0,0 +1,705 @@ ++/* ++* 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 <stdint.h> ++#include "EbSvtVp9ErrorCodes.h" ++#include "EbSvtVp9Enc.h" ++ ++#include "libavutil/common.h" ++#include "libavutil/frame.h" ++#include "libavutil/opt.h" ++#include "libavcodec/get_bits.h" ++ ++#include "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 * 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; ++ } ++ ++#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 AVCodecDefault eb_enc_defaults[] = { ++ { "b", "7M" }, ++ { "flags", "-cgop" }, ++ { "qmin", "10" }, ++ { "qmax", "48" }, ++ { NULL }, ++}; ++ ++AVCodec ff_libsvt_vp9_encoder = { ++ .name = "libsvt_vp9", ++ .long_name = NULL_IF_CONFIG_SMALL("SVT-VP9(Scalable Video Technology for VP9) encoder"), ++ .priv_data_size = sizeof(SvtContext), ++ .type = AVMEDIA_TYPE_VIDEO, ++ .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 ++ .receive_packet = eb_receive_packet, ++ .close = eb_enc_close, ++ .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS, ++ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, ++ AV_PIX_FMT_NONE }, ++ .priv_class = &class, ++ .defaults = eb_enc_defaults, ++ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, ++ .wrapper_name = "libsvt_vp9", ++}; +-- +2.7.4 + 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 new file mode 100644 index 000000000000..374335dce5d0 --- /dev/null +++ b/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch @@ -0,0 +1,145 @@ +<!DOCTYPE html> +<html lang='en'> +<head> +<title>040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch - aur.git - AUR Package Repositories</title> +<meta name='generator' content='cgit v1.2.3-20-gbe07'/> +<meta name='robots' content='index, nofollow'/> +<link rel='stylesheet' type='text/css' href='/static/css/cgit.css'/> +<link rel='shortcut icon' href='/static/images/favicon.ico'/> +<link rel='alternate' title='Atom feed' href='https://aur.archlinux.org/cgit/aur.git/atom/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch?h=ffmpeg-full' type='application/atom+xml'/> +<link rel='vcs-git' href='https://aur.archlinux.org/ffmpeg-full.git/' title='aur.git Git repository'/> +</head> +<body> + <div id="archnavbar" class="anb-aur"> + <div id="archnavbarlogo"><h1><a href="/" title="Return to the main page">Arch Linux User Repository</a></h1></div> + <div id="archnavbarmenu"> + <ul id="archnavbarlist"> + <li id="anb-home"><a href="https://www.archlinux.org/" title="Arch news, packages, projects and more">Home</a></li> + <li id="anb-packages"><a href="https://www.archlinux.org/packages/" title="Arch Package Database">Packages</a></li> + <li id="anb-forums"><a href="https://bbs.archlinux.org/" title="Community forums">Forums</a></li> + <li id="anb-wiki"><a href="https://wiki.archlinux.org/" title="Community documentation">Wiki</a></li> + <li id="anb-bugs"><a href="https://bugs.archlinux.org/" title="Report and track bugs">Bugs</a></li> + <li id="anb-security"><a href="https://security.archlinux.org/" title="Arch Linux Security Tracker">Security</a></li> + <li id="anb-aur"><a href="/" title="Arch Linux User Repository">AUR</a></li> + <li id="anb-download"><a href="https://www.archlinux.org/download/" title="Get Arch Linux">Download</a></li> + </ul> + </div> + </div><!-- #archnavbar --> +<div id='cgit'><table id='header'> +<tr> +<td class='main'>AUR : ffmpeg-full.git</td></tr> +<tr><td class='sub'>AUR Package Repositories | click <a href='/pkgbase/ffmpeg-full/'>here</a> to return to the package base details page</td><td class='sub right'></td></tr></table> +<table class='tabs'><tr><td> +<a href='/cgit/aur.git/?h=ffmpeg-full'>summary</a><a href='/cgit/aur.git/log/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch?h=ffmpeg-full'>log</a><a class='active' href='/cgit/aur.git/tree/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch?h=ffmpeg-full'>tree</a><a href='/cgit/aur.git/commit/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch?h=ffmpeg-full'>commit</a><a href='/cgit/aur.git/diff/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch?h=ffmpeg-full'>diff</a><a href='/cgit/aur.git/stats/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch?h=ffmpeg-full'>stats</a></td><td class='form'><form class='right' method='get' action='/cgit/aur.git/log/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch'> +<input type='hidden' name='h' value='ffmpeg-full'/><select name='qt'> +<option value='grep'>log msg</option> +<option value='author'>author</option> +<option value='committer'>committer</option> +<option value='range'>range</option> +</select> +<input class='txt' type='search' size='10' name='q' value=''/> +<input type='submit' value='search'/> +</form> +</td></tr></table> +<div class='path'>path: <a href='/cgit/aur.git/tree/?h=ffmpeg-full'>root</a>/<a href='/cgit/aur.git/tree/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch?h=ffmpeg-full'>040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch</a></div><div class='content'>blob: fb5589800d3d3bd59a42182496fe8eb862d6c4a9 (<a href='/cgit/aur.git/plain/040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch?h=ffmpeg-full'>plain</a>) +<table summary='blob content' class='blob'> +<tr><td class='linenumbers'><pre><a id='n1' href='#n1'>1</a> +<a id='n2' href='#n2'>2</a> +<a id='n3' href='#n3'>3</a> +<a id='n4' href='#n4'>4</a> +<a id='n5' href='#n5'>5</a> +<a id='n6' href='#n6'>6</a> +<a id='n7' href='#n7'>7</a> +<a id='n8' href='#n8'>8</a> +<a id='n9' href='#n9'>9</a> +<a id='n10' href='#n10'>10</a> +<a id='n11' href='#n11'>11</a> +<a id='n12' href='#n12'>12</a> +<a id='n13' href='#n13'>13</a> +<a id='n14' href='#n14'>14</a> +<a id='n15' href='#n15'>15</a> +<a id='n16' href='#n16'>16</a> +<a id='n17' href='#n17'>17</a> +<a id='n18' href='#n18'>18</a> +<a id='n19' href='#n19'>19</a> +<a id='n20' href='#n20'>20</a> +<a id='n21' href='#n21'>21</a> +<a id='n22' href='#n22'>22</a> +<a id='n23' href='#n23'>23</a> +<a id='n24' href='#n24'>24</a> +<a id='n25' href='#n25'>25</a> +<a id='n26' href='#n26'>26</a> +<a id='n27' href='#n27'>27</a> +<a id='n28' href='#n28'>28</a> +<a id='n29' href='#n29'>29</a> +<a id='n30' href='#n30'>30</a> +<a id='n31' href='#n31'>31</a> +<a id='n32' href='#n32'>32</a> +<a id='n33' href='#n33'>33</a> +<a id='n34' href='#n34'>34</a> +<a id='n35' href='#n35'>35</a> +<a id='n36' href='#n36'>36</a> +<a id='n37' href='#n37'>37</a> +<a id='n38' href='#n38'>38</a> +<a id='n39' href='#n39'>39</a> +<a id='n40' href='#n40'>40</a> +<a id='n41' href='#n41'>41</a> +<a id='n42' href='#n42'>42</a> +<a id='n43' href='#n43'>43</a> +<a id='n44' href='#n44'>44</a> +</pre></td> +<td class='lines'><pre><code>From 95aab0fd83619408995720ce53d7a74790580220 Mon Sep 17 00:00:00 2001 +From: "liberato@chromium.org" <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] +<span class="hl kwa">---</span> + 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 +<span class="hl kwa">--- a/libavformat/avformat.h</span> +<span class="hl kwb">+++ b/libavformat/avformat.h</span> +@@ -1010,6 +1010,10 @@ struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); + */ + int64_t av_stream_get_end_pts(const AVStream *st); + +<span class="hl kwb">+// Chromium: We use the internal field first_dts vvv</span> +<span class="hl kwb">+int64_t av_stream_get_first_dts(const AVStream *st);</span> +<span class="hl kwb">+// Chromium: We use the internal field first_dts ^^^</span> +<span class="hl kwb">+</span> + #define AV_PROGRAM_RUNNING 1 + + /** +diff --git a/libavformat/utils.c b/libavformat/utils.c +index de7580c32d..0ef0fe530e 100644 +<span class="hl kwa">--- a/libavformat/utils.c</span> +<span class="hl kwb">+++ b/libavformat/utils.c</span> +@@ -121,6 +121,13 @@ int64_t av_stream_get_end_pts(const AVStream *st) + return AV_NOPTS_VALUE; + } + +<span class="hl kwb">+// Chromium: We use the internal field first_dts vvv</span> +<span class="hl kwb">+int64_t av_stream_get_first_dts(const AVStream *st)</span> +<span class="hl kwb">+{</span> +<span class="hl kwb">+ return cffstream(st)->first_dts;</span> +<span class="hl kwb">+}</span> +<span class="hl kwb">+// Chromium: We use the internal field first_dts ^^^</span> +<span class="hl kwb">+</span> + struct AVCodecParserContext *av_stream_get_parser(const AVStream *st) + { + return st->internal->parser; +</code></pre></td></tr></table> +</div> <!-- class=content --> +<div id="footer"> + <p> + Copyright © 2004-2020 aurweb Development Team – + <strong>AUR packages are user produced content. Any use of the provided files is at your own risk.</strong> + </p> +</div> +</div> <!-- id=cgit --> +</body> +</html> diff --git a/050-ffmpeg-vmaf-2.x.patch b/050-ffmpeg-vmaf-2.x.patch new file mode 100644 index 000000000000..6619a99c177f --- /dev/null +++ b/050-ffmpeg-vmaf-2.x.patch @@ -0,0 +1,949 @@ +--- a/configure ++++ b/configure +@@ -3751,7 +3751,7 @@ vaguedenoiser_filter_deps="gpl" + vflip_vulkan_filter_deps="vulkan spirv_compiler" + vidstabdetect_filter_deps="libvidstab" + vidstabtransform_filter_deps="libvidstab" +-libvmaf_filter_deps="libvmaf pthreads" ++libvmaf_filter_deps="libvmaf" + zmq_filter_deps="libzmq" + zoompan_filter_deps="swscale" + zscale_filter_deps="libzimg const_nan" +@@ -6626,7 +6626,7 @@ enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame + enabled libuavs3d && require_pkg_config libuavs3d "uavs3d >= 1.1.41" uavs3d.h uavs3d_decode + enabled libv4l2 && require_pkg_config libv4l2 libv4l2 libv4l2.h v4l2_ioctl + enabled libvidstab && require_pkg_config libvidstab "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit +-enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 1.5.2" libvmaf.h compute_vmaf ++enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 2.0.0" libvmaf.h vmaf_init + enabled libvo_amrwbenc && require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_init -lvo-amrwbenc + enabled libvorbis && require_pkg_config libvorbis vorbis vorbis/codec.h vorbis_info_init && + require_pkg_config libvorbisenc vorbisenc vorbis/vorbisenc.h vorbis_encode_init +--- a/doc/filters.texi ++++ b/doc/filters.texi +@@ -14666,68 +14666,60 @@ ffmpeg -i input.mov -vf lensfun=make=Canon:model="Canon EOS 100D":lens_model="Ca + + @section libvmaf + +-Obtain the VMAF (Video Multi-Method Assessment Fusion) +-score between two input videos. ++Calulate the VMAF (Video Multi-Method Assessment Fusion) score for a ++reference/distorted pair of input videos. + +-The first input is the encoded video, and the second input is the reference video. ++The first input is the distorted video, and the second input is the reference video. + + The obtained VMAF score is printed through the logging system. + + It requires Netflix's vmaf library (libvmaf) as a pre-requisite. + After installing the library it can be enabled using: + @code{./configure --enable-libvmaf}. +-If no model path is specified it uses the default model: @code{vmaf_v0.6.1.pkl}. + + The filter has following options: + + @table @option +-@item model_path +-Set the model path which is to be used for SVM. +-Default value: @code{"/usr/local/share/model/vmaf_v0.6.1.pkl"} +- +-@item log_path +-Set the file path to be used to store logs. ++@item model ++A `|` delimited list of vmaf models. Each model can be configured with a number of parameters. ++Default value: @code{"version=vmaf_v0.6.1"} + +-@item log_fmt +-Set the format of the log file (csv, json or xml). ++@item model_path ++Deprecated, use model='path=...'. + + @item enable_transform +-This option can enable/disable the @code{score_transform} applied to the final predicted VMAF score, +-if you have specified score_transform option in the input parameter file passed to @code{run_vmaf_training.py} +-Default value: @code{false} ++Deprecated, use model='enable_transform=true'. + + @item phone_model +-Invokes the phone model which will generate VMAF scores higher than in the +-regular model, which is more suitable for laptop, TV, etc. viewing conditions. +-Default value: @code{false} ++Deprecated, use model='enable_transform=true'. ++ ++@item enable_conf_interval ++Deprecated, use model='enable_conf_interval=true'. ++ ++@item feature ++A `|` delimited list of features. Each feature can be configured with a number of parameters. + + @item psnr +-Enables computing psnr along with vmaf. +-Default value: @code{false} ++Deprecated, use feature='name=psnr'. + + @item ssim +-Enables computing ssim along with vmaf. +-Default value: @code{false} ++Deprecated, use feature='name=ssim'. + + @item ms_ssim +-Enables computing ms_ssim along with vmaf. +-Default value: @code{false} ++Deprecated, use feature='name=ms_ssim'. + +-@item pool +-Set the pool method to be used for computing vmaf. +-Options are @code{min}, @code{harmonic_mean} or @code{mean} (default). ++@item log_path ++Set the file path to be used to store log files. ++ ++@item log_fmt ++Set the format of the log file (xml, json, csv, or sub). + + @item n_threads +-Set number of threads to be used when computing vmaf. +-Default value: @code{0}, which makes use of all available logical processors. ++Set number of threads to be used when initializing libvmaf. ++Default value: @code{0}, no threads. + + @item n_subsample +-Set interval for frame subsampling used when computing vmaf. +-Default value: @code{1} +- +-@item enable_conf_interval +-Enables confidence interval. +-Default value: @code{false} ++Set frame subsampling interval to be used. + @end table + + This filter also supports the @ref{framesync} options. +@@ -14735,23 +14727,31 @@ This filter also supports the @ref{framesync} options. + @subsection Examples + @itemize + @item +-On the below examples the input file @file{main.mpg} being processed is +-compared with the reference file @file{ref.mpg}. ++In the examples below, a distorted video @file{distorted.mpg} is ++compared with a reference file @file{reference.mpg}. + ++@item ++Basic usage: ++@example ++ffmpeg -i distorted.mpg -i reference.mpg -lavfi libvmaf=log_path=output.xml -f null - ++@end example ++ ++@item ++Example with multiple models: + @example +-ffmpeg -i main.mpg -i ref.mpg -lavfi libvmaf -f null - ++ffmpeg -i distorted.mpg -i reference.mpg -lavfi libvmaf='model=version=vmaf_v0.6.1\\:name=vmaf|version=vmaf_v0.6.1neg\\:name=vmaf_neg' -f null - + @end example + + @item +-Example with options: ++Example with multiple addtional features: + @example +-ffmpeg -i main.mpg -i ref.mpg -lavfi libvmaf="psnr=1:log_fmt=json" -f null - ++ffmpeg -i distorted.mpg -i reference.mpg -lavfi libvmaf='feature=name=psnr|name=ciede' -f null - + @end example + + @item + Example with options and different containers: + @example +-ffmpeg -i main.mpg -i ref.mkv -lavfi "[0:v]settb=AVTB,setpts=PTS-STARTPTS[main];[1:v]settb=AVTB,setpts=PTS-STARTPTS[ref];[main][ref]libvmaf=psnr=1:log_fmt=json" -f null - ++ffmpeg -i distorted.mpg -i reference.mkv -lavfi "[0:v]settb=AVTB,setpts=PTS-STARTPTS[main];[1:v]settb=AVTB,setpts=PTS-STARTPTS[ref];[main][ref]libvmaf=log_fmt=json:log_path=output.json" -f null - + @end example + @end itemize + +--- a/libavfilter/vf_libvmaf.c ++++ b/libavfilter/vf_libvmaf.c +@@ -24,8 +24,8 @@ + * Calculate the VMAF between two input videos. + */ + +-#include <pthread.h> + #include <libvmaf.h> ++ + #include "libavutil/avstring.h" + #include "libavutil/opt.h" + #include "libavutil/pixdesc.h" +@@ -39,23 +39,9 @@ + typedef struct LIBVMAFContext { + const AVClass *class; + FFFrameSync fs; +- const AVPixFmtDescriptor *desc; +- int width; +- int height; +- double vmaf_score; +- int vmaf_thread_created; +- pthread_t vmaf_thread; +- pthread_mutex_t lock; +- pthread_cond_t cond; +- int eof; +- AVFrame *gmain; +- AVFrame *gref; +- int frame_set; + char *model_path; + char *log_path; + char *log_fmt; +- int disable_clip; +- int disable_avx; + int enable_transform; + int phone_model; + int psnr; +@@ -65,184 +51,487 @@ typedef struct LIBVMAFContext { + int n_threads; + int n_subsample; + int enable_conf_interval; +- int error; ++ char *model_cfg; ++ char *feature_cfg; ++ VmafContext *vmaf; ++ VmafModel **model; ++ unsigned model_cnt; ++ unsigned frame_cnt; ++ unsigned bpc; + } LIBVMAFContext; + + #define OFFSET(x) offsetof(LIBVMAFContext, x) + #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + + static const AVOption libvmaf_options[] = { +- {"model_path", "Set the model to be used for computing vmaf.", OFFSET(model_path), AV_OPT_TYPE_STRING, {.str="/usr/local/share/model/vmaf_v0.6.1.pkl"}, 0, 1, FLAGS}, +- {"log_path", "Set the file path to be used to store logs.", OFFSET(log_path), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS}, +- {"log_fmt", "Set the format of the log (csv, json or xml).", OFFSET(log_fmt), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS}, +- {"enable_transform", "Enables transform for computing vmaf.", OFFSET(enable_transform), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, +- {"phone_model", "Invokes the phone model that will generate higher VMAF scores.", OFFSET(phone_model), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, +- {"psnr", "Enables computing psnr along with vmaf.", OFFSET(psnr), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, +- {"ssim", "Enables computing ssim along with vmaf.", OFFSET(ssim), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, +- {"ms_ssim", "Enables computing ms-ssim along with vmaf.", OFFSET(ms_ssim), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, ++ {"model_path", "use model='path=...'.", OFFSET(model_path), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS|AV_OPT_FLAG_DEPRECATED}, ++ {"log_path", "Set the file path to be used to write log.", OFFSET(log_path), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS}, ++ {"log_fmt", "Set the format of the log (csv, json, xml, or sub).", OFFSET(log_fmt), AV_OPT_TYPE_STRING, {.str="xml"}, 0, 1, FLAGS}, ++ {"enable_transform", "use model='enable_transform=true'.", OFFSET(enable_transform), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS|AV_OPT_FLAG_DEPRECATED}, ++ {"phone_model", "use model='enable_transform=true'.", OFFSET(phone_model), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS|AV_OPT_FLAG_DEPRECATED}, ++ {"psnr", "use feature='name=psnr'.", OFFSET(psnr), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS|AV_OPT_FLAG_DEPRECATED}, ++ {"ssim", "use feature='name=ssim'.", OFFSET(ssim), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS|AV_OPT_FLAG_DEPRECATED}, ++ {"ms_ssim", "use feature='name=ms_ssim'.", OFFSET(ms_ssim), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS|AV_OPT_FLAG_DEPRECATED}, + {"pool", "Set the pool method to be used for computing vmaf.", OFFSET(pool), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS}, + {"n_threads", "Set number of threads to be used when computing vmaf.", OFFSET(n_threads), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT_MAX, FLAGS}, + {"n_subsample", "Set interval for frame subsampling used when computing vmaf.", OFFSET(n_subsample), AV_OPT_TYPE_INT, {.i64=1}, 1, UINT_MAX, FLAGS}, +- {"enable_conf_interval", "Enables confidence interval.", OFFSET(enable_conf_interval), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, ++ {"enable_conf_interval", "model='enable_conf_interval=true'.", OFFSET(enable_conf_interval), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS|AV_OPT_FLAG_DEPRECATED}, ++ {"model", "Set the model to be used for computing vmaf.", OFFSET(model_cfg), AV_OPT_TYPE_STRING, {.str="version=vmaf_v0.6.1"}, 0, 1, FLAGS}, ++ {"feature", "Set the feature to be used for computing vmaf.", OFFSET(feature_cfg), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS}, + { NULL } + }; + + FRAMESYNC_DEFINE_CLASS(libvmaf, LIBVMAFContext, fs); + +-#define read_frame_fn(type, bits) \ +- static int read_frame_##bits##bit(float *ref_data, float *main_data, \ +- float *temp_data, int stride, void *ctx) \ +-{ \ +- LIBVMAFContext *s = (LIBVMAFContext *) ctx; \ +- int ret; \ +- \ +- pthread_mutex_lock(&s->lock); \ +- \ +- while (!s->frame_set && !s->eof) { \ +- pthread_cond_wait(&s->cond, &s->lock); \ +- } \ +- \ +- if (s->frame_set) { \ +- int ref_stride = s->gref->linesize[0]; \ +- int main_stride = s->gmain->linesize[0]; \ +- \ +- const type *ref_ptr = (const type *) s->gref->data[0]; \ +- const type *main_ptr = (const type *) s->gmain->data[0]; \ +- \ +- float *ptr = ref_data; \ +- float factor = 1.f / (1 << (bits - 8)); \ +- \ +- int h = s->height; \ +- int w = s->width; \ +- \ +- int i,j; \ +- \ +- for (i = 0; i < h; i++) { \ +- for ( j = 0; j < w; j++) { \ +- ptr[j] = ref_ptr[j] * factor; \ +- } \ +- ref_ptr += ref_stride / sizeof(*ref_ptr); \ +- ptr += stride / sizeof(*ptr); \ +- } \ +- \ +- ptr = main_data; \ +- \ +- for (i = 0; i < h; i++) { \ +- for (j = 0; j < w; j++) { \ +- ptr[j] = main_ptr[j] * factor; \ +- } \ +- main_ptr += main_stride / sizeof(*main_ptr); \ +- ptr += stride / sizeof(*ptr); \ +- } \ +- } \ +- \ +- ret = !s->frame_set; \ +- \ +- av_frame_unref(s->gref); \ +- av_frame_unref(s->gmain); \ +- s->frame_set = 0; \ +- \ +- pthread_cond_signal(&s->cond); \ +- pthread_mutex_unlock(&s->lock); \ +- \ +- if (ret) { \ +- return 2; \ +- } \ +- \ +- return 0; \ ++static enum VmafPixelFormat pix_fmt_map(enum AVPixelFormat av_pix_fmt) ++{ ++ switch (av_pix_fmt) { ++ case AV_PIX_FMT_YUV420P: ++ case AV_PIX_FMT_YUV420P10LE: ++ case AV_PIX_FMT_YUV420P12LE: ++ case AV_PIX_FMT_YUV420P16LE: ++ return VMAF_PIX_FMT_YUV420P; ++ case AV_PIX_FMT_YUV422P: ++ case AV_PIX_FMT_YUV422P10LE: ++ case AV_PIX_FMT_YUV422P12LE: ++ case AV_PIX_FMT_YUV422P16LE: ++ return VMAF_PIX_FMT_YUV422P; ++ case AV_PIX_FMT_YUV444P: ++ case AV_PIX_FMT_YUV444P10LE: ++ case AV_PIX_FMT_YUV444P12LE: ++ case AV_PIX_FMT_YUV444P16LE: ++ return VMAF_PIX_FMT_YUV444P; ++ default: ++ return VMAF_PIX_FMT_UNKNOWN; ++ } + } + +-read_frame_fn(uint8_t, 8); +-read_frame_fn(uint16_t, 10); ++static int copy_picture_data(AVFrame *src, VmafPicture *dst, unsigned bpc) ++{ ++ int err = vmaf_picture_alloc(dst, pix_fmt_map(src->format), bpc, ++ src->width, src->height); ++ if (err) ++ return AVERROR(ENOMEM); ++ ++ for (unsigned i = 0; i < 3; i++) { ++ uint8_t *src_data = src->data[i]; ++ uint8_t *dst_data = dst->data[i]; ++ for (unsigned j = 0; j < dst->h[i]; j++) { ++ memcpy(dst_data, src_data, sizeof(*dst_data) * dst->w[i]); ++ src_data += src->linesize[i]; ++ dst_data += dst->stride[i]; ++ } ++ } ++ ++ return 0; ++} + +-static void compute_vmaf_score(LIBVMAFContext *s) ++static int do_vmaf(FFFrameSync *fs) + { +- int (*read_frame)(float *ref_data, float *main_data, float *temp_data, +- int stride, void *ctx); +- char *format; ++ AVFilterContext *ctx = fs->parent; ++ LIBVMAFContext *s = ctx->priv; ++ VmafPicture pic_ref, pic_dist; ++ AVFrame *ref, *dist; ++ int err = 0; + +- if (s->desc->comp[0].depth <= 8) { +- read_frame = read_frame_8bit; +- } else { +- read_frame = read_frame_10bit; ++ int ret = ff_framesync_dualinput_get(fs, &dist, &ref); ++ if (ret < 0) ++ return ret; ++ if (ctx->is_disabled || !ref) ++ return ff_filter_frame(ctx->outputs[0], dist); ++ ++ err = copy_picture_data(ref, &pic_ref, s->bpc); ++ if (err) { ++ av_log(s, AV_LOG_ERROR, "problem during vmaf_picture_alloc.\n"); ++ return AVERROR(ENOMEM); ++ } ++ ++ err = copy_picture_data(dist, &pic_dist, s->bpc); ++ if (err) { ++ av_log(s, AV_LOG_ERROR, "problem during vmaf_picture_alloc.\n"); ++ vmaf_picture_unref(&pic_ref); ++ return AVERROR(ENOMEM); + } + +- format = (char *) s->desc->name; ++ err = vmaf_read_pictures(s->vmaf, &pic_ref, &pic_dist, s->frame_cnt++); ++ if (err) { ++ av_log(s, AV_LOG_ERROR, "problem during vmaf_read_pictures.\n"); ++ return AVERROR(EINVAL); ++ } + +- s->error = compute_vmaf(&s->vmaf_score, format, s->width, s->height, +- read_frame, s, s->model_path, s->log_path, +- s->log_fmt, 0, 0, s->enable_transform, +- s->phone_model, s->psnr, s->ssim, +- s->ms_ssim, s->pool, +- s->n_threads, s->n_subsample, s->enable_conf_interval); ++ return ff_filter_frame(ctx->outputs[0], dist); + } + +-static void *call_vmaf(void *ctx) ++ ++static AVDictionary **delimited_dict_parse(char *str, unsigned *cnt) + { +- LIBVMAFContext *s = (LIBVMAFContext *) ctx; +- compute_vmaf_score(s); +- if (!s->error) { +- av_log(ctx, AV_LOG_INFO, "VMAF score: %f\n",s->vmaf_score); +- } else { +- pthread_mutex_lock(&s->lock); +- pthread_cond_signal(&s->cond); +- pthread_mutex_unlock(&s->lock); ++ AVDictionary **dict = NULL; ++ char *str_copy = NULL; ++ char *saveptr = NULL; ++ unsigned cnt2; ++ int err = 0; ++ ++ if (!str) ++ return NULL; ++ ++ cnt2 = 1; ++ for (char *p = str; *p; p++) { ++ if (*p == '|') ++ cnt2++; ++ } ++ ++ dict = av_calloc(cnt2, sizeof(*dict)); ++ if (!dict) ++ goto fail; ++ ++ str_copy = av_strdup(str); ++ if (!str_copy) ++ goto fail; ++ ++ *cnt = 0; ++ for (unsigned i = 0; i < cnt2; i++) { ++ char *s = av_strtok(i == 0 ? str_copy : NULL, "|", &saveptr); ++ if (!s) ++ continue; ++ err = av_dict_parse_string(&dict[(*cnt)++], s, "=", ":", 0); ++ if (err) ++ goto fail; ++ } ++ ++ av_free(str_copy); ++ return dict; ++ ++fail: ++ if (dict) { ++ for (unsigned i = 0; i < *cnt; i++) { ++ if (dict[i]) ++ av_dict_free(&dict[i]); ++ } ++ av_free(dict); + } +- pthread_exit(NULL); ++ ++ av_free(str_copy); ++ *cnt = 0; + return NULL; + } + +-static int do_vmaf(FFFrameSync *fs) ++static int parse_features(AVFilterContext *ctx) + { +- AVFilterContext *ctx = fs->parent; + LIBVMAFContext *s = ctx->priv; +- AVFrame *master, *ref; +- int ret; ++ AVDictionary **dict = NULL; ++ unsigned dict_cnt; ++ int err = 0; + +- ret = ff_framesync_dualinput_get(fs, &master, &ref); +- if (ret < 0) +- return ret; +- if (!ref) +- return ff_filter_frame(ctx->outputs[0], master); ++ if (!s->feature_cfg) ++ return 0; ++ ++ dict = delimited_dict_parse(s->feature_cfg, &dict_cnt); ++ if (!dict) { ++ av_log(ctx, AV_LOG_ERROR, ++ "could not parse feature config: %s\n", s->feature_cfg); ++ return AVERROR(EINVAL); ++ } + +- pthread_mutex_lock(&s->lock); ++ for (unsigned i = 0; i < dict_cnt; i++) { ++ char *feature_name = NULL; ++ VmafFeatureDictionary *feature_opts_dict = NULL; ++ AVDictionaryEntry *e = NULL; ++ ++ while (e = av_dict_get(dict[i], "", e, AV_DICT_IGNORE_SUFFIX)) { ++ if (av_stristr(e->key, "name")) { ++ feature_name = e->value; ++ continue; ++ } ++ ++ err = vmaf_feature_dictionary_set(&feature_opts_dict, e->key, ++ e->value); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "could not set feature option: %s.%s=%s\n", ++ feature_name, e->key, e->value); ++ goto exit; ++ } ++ } ++ ++ err = vmaf_use_feature(s->vmaf, feature_name, feature_opts_dict); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "problem during vmaf_use_feature: %s\n", feature_name); ++ goto exit; ++ } ++ } + +- while (s->frame_set && !s->error) { +- pthread_cond_wait(&s->cond, &s->lock); ++exit: ++ for (unsigned i = 0; i < dict_cnt; i++) { ++ if (dict[i]) ++ av_dict_free(&dict[i]); + } ++ av_free(dict); ++ return err; ++} ++ ++static int parse_models(AVFilterContext *ctx) ++{ ++ LIBVMAFContext *s = ctx->priv; ++ AVDictionary **dict; ++ unsigned dict_cnt; ++ int err = 0; ++ ++ if (!s->model_cfg) return 0; + +- if (s->error) { ++ dict_cnt = 0; ++ dict = delimited_dict_parse(s->model_cfg, &dict_cnt); ++ if (!dict) { + av_log(ctx, AV_LOG_ERROR, +- "libvmaf encountered an error, check log for details\n"); +- pthread_mutex_unlock(&s->lock); ++ "could not parse model config: %s\n", s->model_cfg); + return AVERROR(EINVAL); + } + +- av_frame_ref(s->gref, ref); +- av_frame_ref(s->gmain, master); ++ s->model_cnt = dict_cnt; ++ s->model = av_calloc(s->model_cnt, sizeof(*s->model)); ++ if (!s->model) ++ return AVERROR(ENOMEM); ++ ++ for (unsigned i = 0; i < dict_cnt; i++) { ++ VmafModelConfig model_cfg = { 0 }; ++ AVDictionaryEntry *e = NULL; ++ char *version = NULL; ++ char *path = NULL; ++ ++ while (e = av_dict_get(dict[i], "", e, AV_DICT_IGNORE_SUFFIX)) { ++ if (av_stristr(e->key, "disable_clip")) { ++ model_cfg.flags |= av_stristr(e->value, "true") ? ++ VMAF_MODEL_FLAG_DISABLE_CLIP : 0; ++ continue; ++ } ++ ++ if (av_stristr(e->key, "enable_transform")) { ++ model_cfg.flags |= av_stristr(e->value, "true") ? ++ VMAF_MODEL_FLAG_ENABLE_TRANSFORM : 0; ++ continue; ++ } ++ ++ if (av_stristr(e->key, "name")) { ++ model_cfg.name = e->value; ++ continue; ++ } ++ ++ if (av_stristr(e->key, "version")) { ++ version = e->value; ++ continue; ++ } ++ ++ if (av_stristr(e->key, "path")) { ++ path = e->value; ++ continue; ++ } ++ } ++ ++ if (version) { ++ err = vmaf_model_load(&s->model[i], &model_cfg, version); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "could not load libvmaf model with version: %s\n", ++ version); ++ goto exit; ++ } ++ } ++ ++ if (path && !s->model[i]) { ++ err = vmaf_model_load_from_path(&s->model[i], &model_cfg, path); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "could not load libvmaf model with path: %s\n", ++ path); ++ goto exit; ++ } ++ } ++ ++ if (!s->model[i]) { ++ av_log(ctx, AV_LOG_ERROR, ++ "could not load libvmaf model with config: %s\n", ++ s->model_cfg); ++ goto exit; ++ } ++ ++ while (e = av_dict_get(dict[i], "", e, AV_DICT_IGNORE_SUFFIX)) { ++ VmafFeatureDictionary *feature_opts_dict = NULL; ++ char *feature_opt = NULL; ++ ++ char *feature_name = av_strtok(e->key, ".", &feature_opt); ++ if (!feature_opt) ++ continue; ++ ++ err = vmaf_feature_dictionary_set(&feature_opts_dict, ++ feature_opt, e->value); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "could not set feature option: %s.%s=%s\n", ++ feature_name, feature_opt, e->value); ++ err = AVERROR(EINVAL); ++ goto exit; ++ } ++ ++ err = vmaf_model_feature_overload(s->model[i], feature_name, ++ feature_opts_dict); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "could not overload feature: %s\n", feature_name); ++ err = AVERROR(EINVAL); ++ goto exit; ++ } ++ } ++ } ++ ++ for (unsigned i = 0; i < s->model_cnt; i++) { ++ err = vmaf_use_features_from_model(s->vmaf, s->model[i]); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "problem during vmaf_use_features_from_model\n"); ++ err = AVERROR(EINVAL); ++ goto exit; ++ } ++ } ++ ++exit: ++ for (unsigned i = 0; i < dict_cnt; i++) { ++ if (dict[i]) ++ av_dict_free(&dict[i]); ++ } ++ av_free(dict); ++ return err; ++} ++ ++static enum VmafLogLevel log_level_map(int log_level) ++{ ++ switch (log_level) { ++ case AV_LOG_QUIET: ++ return VMAF_LOG_LEVEL_NONE; ++ case AV_LOG_ERROR: ++ return VMAF_LOG_LEVEL_ERROR; ++ case AV_LOG_WARNING: ++ return VMAF_LOG_LEVEL_WARNING; ++ case AV_LOG_INFO: ++ return VMAF_LOG_LEVEL_INFO; ++ case AV_LOG_DEBUG: ++ return VMAF_LOG_LEVEL_DEBUG; ++ default: ++ return VMAF_LOG_LEVEL_INFO; ++ } ++} ++ ++static int parse_deprecated_options(AVFilterContext *ctx) ++{ ++ LIBVMAFContext *s = ctx->priv; ++ VmafModel *model = NULL; ++ VmafModelCollection *model_collection = NULL; ++ enum VmafModelFlags flags = VMAF_MODEL_FLAGS_DEFAULT; ++ int err = 0; ++ ++ VmafModelConfig model_cfg = { ++ .name = "vmaf", ++ .flags = flags, ++ }; ++ ++ if (s->enable_transform || s->phone_model) ++ flags |= VMAF_MODEL_FLAG_ENABLE_TRANSFORM; ++ ++ if (!s->model_path) ++ goto extra_metrics_only; ++ ++ if (s->enable_conf_interval) { ++ err = vmaf_model_collection_load_from_path(&model, &model_collection, ++ &model_cfg, s->model_path); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "problem loading model file: %s\n", s->model_path); ++ goto exit; ++ } ++ ++ err = vmaf_use_features_from_model_collection(s->vmaf, model_collection); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "problem loading feature extractors from model file: %s\n", ++ s->model_path); ++ goto exit; ++ } ++ } else { ++ err = vmaf_model_load_from_path(&model, &model_cfg, s->model_path); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "problem loading model file: %s\n", s->model_path); ++ goto exit; ++ } ++ err = vmaf_use_features_from_model(s->vmaf, model); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "problem loading feature extractors from model file: %s\n", ++ s->model_path); ++ goto exit; ++ } ++ } ++ ++extra_metrics_only: ++ if (s->psnr) { ++ VmafFeatureDictionary *d = NULL; ++ vmaf_feature_dictionary_set(&d, "enable_chroma", "false"); ++ ++ err = vmaf_use_feature(s->vmaf, "psnr", d); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "problem loading feature extractor: psnr\n"); ++ goto exit; ++ } ++ } + +- s->frame_set = 1; ++ if (s->ssim) { ++ err = vmaf_use_feature(s->vmaf, "float_ssim", NULL); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "problem loading feature extractor: ssim\n"); ++ goto exit; ++ } ++ } + +- pthread_cond_signal(&s->cond); +- pthread_mutex_unlock(&s->lock); ++ if (s->ms_ssim) { ++ err = vmaf_use_feature(s->vmaf, "float_ms_ssim", NULL); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "problem loading feature extractor: ms_ssim\n"); ++ goto exit; ++ } ++ } + +- return ff_filter_frame(ctx->outputs[0], master); ++exit: ++ return err; + } + + static av_cold int init(AVFilterContext *ctx) + { + LIBVMAFContext *s = ctx->priv; ++ int err = 0; + +- s->gref = av_frame_alloc(); +- s->gmain = av_frame_alloc(); +- if (!s->gref || !s->gmain) +- return AVERROR(ENOMEM); ++ VmafConfiguration cfg = { ++ .log_level = log_level_map(av_log_get_level()), ++ .n_subsample = s->n_subsample, ++ .n_threads = s->n_threads, ++ }; ++ ++ err = vmaf_init(&s->vmaf, cfg); ++ if (err) ++ return AVERROR(EINVAL); ++ ++ err = parse_deprecated_options(ctx); ++ if (err) ++ return err; + +- s->error = 0; ++ err = parse_models(ctx); ++ if (err) ++ return err; + +- s->vmaf_thread_created = 0; +- pthread_mutex_init(&s->lock, NULL); +- pthread_cond_init (&s->cond, NULL); ++ err = parse_features(ctx); ++ if (err) ++ return err; + + s->fs.on_event = do_vmaf; + return 0; +@@ -256,26 +545,31 @@ static const enum AVPixelFormat pix_fmts[] = { + + static int config_input_ref(AVFilterLink *inlink) + { +- AVFilterContext *ctx = inlink->dst; ++ AVFilterContext *ctx = inlink->dst; + LIBVMAFContext *s = ctx->priv; +- int th; ++ const AVPixFmtDescriptor *desc; ++ int err = 0; + +- if (ctx->inputs[0]->w != ctx->inputs[1]->w || +- ctx->inputs[0]->h != ctx->inputs[1]->h) { +- av_log(ctx, AV_LOG_ERROR, "Width and height of input videos must be same.\n"); +- return AVERROR(EINVAL); ++ if (ctx->inputs[0]->w != ctx->inputs[1]->w) { ++ av_log(ctx, AV_LOG_ERROR, "input width must match.\n"); ++ err |= AVERROR(EINVAL); + } + +- s->desc = av_pix_fmt_desc_get(inlink->format); +- s->width = ctx->inputs[0]->w; +- s->height = ctx->inputs[0]->h; ++ if (ctx->inputs[0]->h != ctx->inputs[1]->h) { ++ av_log(ctx, AV_LOG_ERROR, "input height must match.\n"); ++ err |= AVERROR(EINVAL); ++ } + +- th = pthread_create(&s->vmaf_thread, NULL, call_vmaf, (void *) s); +- if (th) { +- av_log(ctx, AV_LOG_ERROR, "Thread creation failed.\n"); +- return AVERROR(EINVAL); ++ if (ctx->inputs[0]->format != ctx->inputs[1]->format) { ++ av_log(ctx, AV_LOG_ERROR, "input pix_fmt must match.\n"); ++ err |= AVERROR(EINVAL); + } +- s->vmaf_thread_created = 1; ++ ++ if (err) ++ return err; ++ ++ desc = av_pix_fmt_desc_get(inlink->format); ++ s->bpc = desc->comp[0].depth; + + return 0; + } +@@ -307,28 +601,80 @@ static int activate(AVFilterContext *ctx) + return ff_framesync_activate(&s->fs); + } + ++static enum VmafOutputFormat log_fmt_map(const char *log_fmt) ++{ ++ if (log_fmt) { ++ if (av_stristr(log_fmt, "xml")) ++ return VMAF_OUTPUT_FORMAT_XML; ++ if (av_stristr(log_fmt, "json")) ++ return VMAF_OUTPUT_FORMAT_JSON; ++ if (av_stristr(log_fmt, "csv")) ++ return VMAF_OUTPUT_FORMAT_CSV; ++ if (av_stristr(log_fmt, "sub")) ++ return VMAF_OUTPUT_FORMAT_SUB; ++ } ++ ++ return VMAF_OUTPUT_FORMAT_XML; ++} ++ ++static enum VmafPoolingMethod pool_method_map(const char *pool_method) ++{ ++ if (pool_method) { ++ if (av_stristr(pool_method, "min")) ++ return VMAF_POOL_METHOD_MIN; ++ if (av_stristr(pool_method, "mean")) ++ return VMAF_POOL_METHOD_MEAN; ++ if (av_stristr(pool_method, "harmonic_mean")) ++ return VMAF_POOL_METHOD_HARMONIC_MEAN; ++ } ++ ++ return VMAF_POOL_METHOD_MEAN; ++} ++ + static av_cold void uninit(AVFilterContext *ctx) + { + LIBVMAFContext *s = ctx->priv; ++ int err = 0; + + ff_framesync_uninit(&s->fs); + +- pthread_mutex_lock(&s->lock); +- s->eof = 1; +- pthread_cond_signal(&s->cond); +- pthread_mutex_unlock(&s->lock); ++ if (!s->frame_cnt) ++ goto clean_up; + +- if (s->vmaf_thread_created) +- { +- pthread_join(s->vmaf_thread, NULL); +- s->vmaf_thread_created = 0; ++ err = vmaf_read_pictures(s->vmaf, NULL, NULL, 0); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "problem flushing libvmaf context.\n"); + } + +- av_frame_free(&s->gref); +- av_frame_free(&s->gmain); ++ for (unsigned i = 0; i < s->model_cnt; i++) { ++ double vmaf_score; ++ err = vmaf_score_pooled(s->vmaf, s->model[i], pool_method_map(s->pool), ++ &vmaf_score, 0, s->frame_cnt - 1); ++ if (err) { ++ av_log(ctx, AV_LOG_ERROR, ++ "problem getting pooled vmaf score.\n"); ++ } ++ ++ av_log(ctx, AV_LOG_INFO, "VMAF score: %f\n", vmaf_score); ++ } ++ ++ if (s->vmaf) { ++ if (s->log_path && !err) ++ vmaf_write_output(s->vmaf, s->log_path, log_fmt_map(s->log_fmt)); ++ } ++ ++clean_up: ++ if (s->model) { ++ for (unsigned i = 0; i < s->model_cnt; i++) { ++ if (s->model[i]) ++ vmaf_model_destroy(s->model[i]); ++ } ++ av_free(s->model); ++ } + +- pthread_mutex_destroy(&s->lock); +- pthread_cond_destroy(&s->cond); ++ if (s->vmaf) ++ vmaf_close(s->vmaf); + } + + static const AVFilterPad libvmaf_inputs[] = { +-- +2.20.1 + @@ -2,7 +2,7 @@ pkgname=ffmpeg-nocuda pkgver=5.0 gitver=n${pkgver} -pkgrel=2 +pkgrel=3 pkgdesc='Complete solution to record, convert and stream audio and video (without nvidias propriatary blobs)' arch=('x86_64') url='https://www.ffmpeg.org/' @@ -72,8 +72,18 @@ provides=('libavcodec.so' 'libavdevice.so' 'libavfilter.so' 'libavformat.so' 'libavutil.so' 'libpostproc.so' 'libswresample.so' 'libswscale.so' 'ffmpeg') conflicts=('ffmpeg') -source=("git+https://git.ffmpeg.org/ffmpeg.git#tag=$gitver") -sha256sums=('SKIP') +source=("git+https://git.ffmpeg.org/ffmpeg.git#tag=$gitver" + 010-ffmpeg-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch + 030-ffmpeg-Add-ability-for-ffmpeg-to-run-svt-vp9.patch + 040-ffmpeg-add-av_stream_get_first_dts-for-chromium.patch + 050-ffmpeg-vmaf-2.x.patch +) +sha256sums=('SKIP' +'SKIP' +'SKIP' +'SKIP' +'SKIP' +) prepare() { cd ${srcdir}/ffmpeg @@ -84,7 +94,8 @@ prepare() { msg2 "Patching gitsource" echo "Applying $patch" - git apply $patch || exit 2 + #git apply $patch || exit 2 + patch -Np1 -i $patch done <<< $(ls ../*.patch 2> /dev/null) } |