mirror of
https://git.freebsd.org/ports.git
synced 2025-05-15 08:41:51 -04:00
multimedia/ffmpeg: update to 6.0
* --enable-avresample is gone per https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/420cedd49745 * SHADERC replaces GLSLANG per https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/da72aca7b025 * VULKAN is enabled per https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/fa2e460f635 * LIBPLACEBO is enabled to have even more Vulkan goodies * LCMS2 is enabled for better ICC profile support * JXL is enabled for https://github.com/mpv-player/mpv/commit/1345977f9976 Changes: https://git.ffmpeg.org/gitweb/ffmpeg.git/blob/n6.0:/Changelog PR: 261302 Reported by: Repology Exp-run by: antoine Approved by: tcberner
This commit is contained in:
parent
7adde68777
commit
685e477b80
6 changed files with 93 additions and 1438 deletions
|
@ -1,6 +1,5 @@
|
|||
PORTNAME= ffmpeg
|
||||
PORTVERSION= 4.4.4
|
||||
PORTREVISION= 1
|
||||
PORTVERSION= 6.0
|
||||
PORTEPOCH= 1
|
||||
CATEGORIES= multimedia audio net
|
||||
MASTER_SITES= https://ffmpeg.org/releases/
|
||||
|
@ -28,28 +27,28 @@ USE_PERL5= build
|
|||
SHEBANG_FILES= doc/texi2pod.pl
|
||||
NOPRECIOUSMAKEVARS= yes # ARCH
|
||||
|
||||
PORTSCOUT= limit:^4\.
|
||||
PORTSCOUT= limit:^6\.
|
||||
|
||||
# Option CHROMAPRINT disabled, it cannot work and people are baffled.
|
||||
OPTIONS_DEFINE= ALSA AMR_NB AMR_WB AOM ARIBB24 ASM ASS BS2B CACA CDIO \
|
||||
CODEC2 DAV1D DAVS2 DC1394 DEBUG DOCS DRM FDK_AAC FLITE \
|
||||
FONTCONFIG FREETYPE FREI0R FRIBIDI GLSLANG GME GSM ICONV ILBC \
|
||||
JACK KLVANC KVAZAAR LADSPA LAME LENSFUN LIBBLURAY LIBRSVG2 \
|
||||
JACK JXL KLVANC KVAZAAR LADSPA LAME LCMS2 LENSFUN LIBBLURAY LIBPLACEBO LIBRSVG2 \
|
||||
LIBXML2 LTO LV2 MODPLUG MYSOFA NETWORK NVENC OPENAL OPENCL OPENGL \
|
||||
OPENH264 OPENJPEG OPENMPT OPENVINO OPTIMIZED_CFLAGS OPUS POCKETSPHINX \
|
||||
PULSEAUDIO RAV1E RABBITMQ RIST RTCPU RUBBERBAND SDL SMB SNAPPY \
|
||||
PULSEAUDIO RAV1E RABBITMQ RIST RTCPU RUBBERBAND SDL SHADERC SMB SNAPPY \
|
||||
SNDIO SOXR SPEEX SRT SSH SVTAV1 SVTHEVC SVTVP9 TENSORFLOW \
|
||||
TESSERACT THEORA TWOLAME UAVS3D V4L VAAPI VAPOURSYNTH VDPAU VIDSTAB \
|
||||
VMAF VO_AMRWBENC VORBIS VPX VULKAN WEBP X264 X265 \
|
||||
XAVS2 XCB XVID XVIDEO ZIMG ZMQ ZVBI
|
||||
# intel-media-sdk only for i386/amd64
|
||||
OPTIONS_DEFINE_amd64= MFX
|
||||
OPTIONS_DEFINE_amd64= MFX VPL
|
||||
OPTIONS_DEFINE_i386= MFX
|
||||
|
||||
OPTIONS_DEFAULT= AOM ASM ASS DAV1D DRM FONTCONFIG FREETYPE FREI0R GMP \
|
||||
GNUTLS ICONV LAME LIBXML2 NETWORK OPTIMIZED_CFLAGS OPUS \
|
||||
RTCPU SVTAV1 V4L VAAPI VDPAU VMAF VORBIS VPX WEBP X264 \
|
||||
X265 XCB
|
||||
GNUTLS ICONV JXL LAME LCMS2 LIBPLACEBO LIBXML2 NETWORK \
|
||||
OPTIMIZED_CFLAGS OPUS RTCPU SVTAV1 V4L VAAPI VDPAU VMAF \
|
||||
VORBIS VPX VULKAN WEBP X264 X265 XCB
|
||||
OPTIONS_DEFAULT_amd64= NVENC
|
||||
OPTIONS_DEFAULT_i386= NVENC
|
||||
|
||||
|
@ -122,10 +121,12 @@ RIST_DESC= Reliable Internet Stream Transport protocol via librist
|
|||
RUBBERBAND_DESC=Time-stretching and pitch-shifting with librubberband
|
||||
RTCPU_DESC= Detect CPU capabilities at runtime
|
||||
RTMP_DESC= RTMP(T)E protocol support
|
||||
SHADERC_DESC= GLSL->SPIRV compilation via libshaderc
|
||||
SRT_DESC= Haivision SRT protocol via libsrt
|
||||
SVTAV1_DESC= AV1 encoding via SVT-AV1
|
||||
SVTHEVC_DESC= HEVC encoding via SVT-HEVC
|
||||
SVTVP9_DESC= VP9 encoding via SVT-VP9
|
||||
LIBPLACEBO_DESC=GPU filters from libplacebo
|
||||
LIBRTMP_DESC= ${RTMP_DESC} via librtmp
|
||||
TENSORFLOW_DESC=TensorFlow as a DNN module backend for DNN based filters like sr
|
||||
TESSERACT_DESC= Optical Character Recognition via Tesseract
|
||||
|
@ -134,6 +135,7 @@ UAVS3D_DESC= AVS3 decoding via libuavs3d
|
|||
VAPOURSYNTH_DESC= VapourSynth demuxer
|
||||
VIDSTAB_DESC= Video stabilization filter
|
||||
VMAF_DESC= VMAF filter via libvmaf
|
||||
VPL_DESC= Intel oneVPL (aka Quick Sync Video)
|
||||
VULKAN_DESC= Vulkan filters
|
||||
XAVS2_DESC= AVS2 encoding via libxavs2
|
||||
XCB_DESC= X11 grabbing using XCB
|
||||
|
@ -282,6 +284,10 @@ ILBC_CONFIGURE_ENABLE= libilbc
|
|||
JACK_LIB_DEPENDS= libjack.so:audio/jack
|
||||
JACK_CONFIGURE_ENABLE= libjack
|
||||
|
||||
# jxl
|
||||
JXL_LIB_DEPENDS= libjxl.so:graphics/libjxl
|
||||
JXL_CONFIGURE_ENABLE= libjxl
|
||||
|
||||
# klvanc
|
||||
KLVANC_LIB_DEPENDS= libklvanc.so:multimedia/libklvanc
|
||||
KLVANC_CONFIGURE_ENABLE= libklvanc
|
||||
|
@ -299,6 +305,10 @@ LADSPA_CONFIGURE_ENABLE= ladspa
|
|||
LAME_LIB_DEPENDS= libmp3lame.so:audio/lame
|
||||
LAME_CONFIGURE_ENABLE= libmp3lame
|
||||
|
||||
# lcms2
|
||||
LCMS2_LIB_DEPENDS= liblcms2.so:graphics/lcms2
|
||||
LCMS2_CONFIGURE_ENABLE= lcms2
|
||||
|
||||
# lensfun
|
||||
LENSFUN_LIB_DEPENDS= liblensfun.so:graphics/lensfun
|
||||
LENSFUN_CONFIGURE_ENABLE= liblensfun
|
||||
|
@ -307,6 +317,10 @@ LENSFUN_CONFIGURE_ENABLE= liblensfun
|
|||
LIBBLURAY_LIB_DEPENDS= libbluray.so:multimedia/libbluray
|
||||
LIBBLURAY_CONFIGURE_ENABLE= libbluray
|
||||
|
||||
# libplacebo
|
||||
LIBPLACEBO_LIB_DEPENDS= libplacebo.so:graphics/libplacebo
|
||||
LIBPLACEBO_CONFIGURE_ENABLE= libplacebo
|
||||
|
||||
# librsvg
|
||||
LIBRSVG2_USES= gnome
|
||||
LIBRSVG2_USE= GNOME=cairo,librsvg2
|
||||
|
@ -351,7 +365,7 @@ MYSOFA_CONFIGURE_ENABLE= libmysofa
|
|||
NETWORK_CONFIGURE_ENABLE= network
|
||||
|
||||
# nvenc
|
||||
NVENC_BUILD_DEPENDS= ${LOCALBASE}/include/ffnvcodec/nvEncodeAPI.h:multimedia/ffnvcodec-headers
|
||||
NVENC_BUILD_DEPENDS= ffnvcodec-headers>=11.1.5.2:multimedia/ffnvcodec-headers
|
||||
NVENC_CONFIGURE_ENABLE= nvenc
|
||||
|
||||
# OpenAL
|
||||
|
@ -433,6 +447,11 @@ SDL_USES= sdl
|
|||
SDL_USE= SDL=sdl2
|
||||
SDL_CONFIGURE_ENABLE= sdl2
|
||||
|
||||
# shaderc
|
||||
SHADERC_LIB_DEPENDS= libshaderc_shared.so:graphics/shaderc
|
||||
SHADERC_CONFIGURE_ENABLE= libshaderc
|
||||
SHADERC_PREVENTS= GLSLANG
|
||||
|
||||
# smbclient
|
||||
SMB_USES= samba:lib
|
||||
SMB_CONFIGURE_ENABLE= libsmbclient
|
||||
|
@ -536,6 +555,10 @@ VIDSTAB_CONFIGURE_ENABLE= libvidstab
|
|||
VORBIS_LIB_DEPENDS= libvorbisenc.so:audio/libvorbis
|
||||
VORBIS_CONFIGURE_ENABLE= libvorbis
|
||||
|
||||
# vpl
|
||||
VPL_LIB_DEPENDS= libvpl.so:multimedia/onevpl
|
||||
VPL_CONFIGURE_ENABLE= libvpl
|
||||
|
||||
# vp8
|
||||
VPX_LIB_DEPENDS= libvpx.so:multimedia/libvpx
|
||||
VPX_CONFIGURE_ENABLE= libvpx
|
||||
|
@ -544,7 +567,7 @@ VPX_CONFIGURE_ENABLE= libvpx
|
|||
VULKAN_BUILD_DEPENDS= vulkan-headers>0:graphics/vulkan-headers
|
||||
VULKAN_LIB_DEPENDS= libvulkan.so:graphics/vulkan-loader
|
||||
VULKAN_CONFIGURE_ENABLE= vulkan
|
||||
VULKAN_IMPLIES= GLSLANG
|
||||
VULKAN_IMPLIES= ${"${PORT_OPTIONS:MGLSLANG}":?GLSLANG:SHADERC}
|
||||
|
||||
# webp
|
||||
WEBP_LIB_DEPENDS= libwebp.so:graphics/webp
|
||||
|
@ -618,7 +641,6 @@ CONFIGURE_ARGS+=--prefix="${PREFIX}" \
|
|||
--enable-shared \
|
||||
--enable-pic \
|
||||
--enable-gpl \
|
||||
--enable-avresample \
|
||||
--cc="${CC}" \
|
||||
--cxx="${CXX}"
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
TIMESTAMP = 1681325571
|
||||
SHA256 (ffmpeg-4.4.4.tar.xz) = e80b380d595c809060f66f96a5d849511ef4a76a26b76eacf5778b94c3570309
|
||||
SIZE (ffmpeg-4.4.4.tar.xz) = 9565584
|
||||
TIMESTAMP = 1677530629
|
||||
SHA256 (ffmpeg-6.0.tar.xz) = 57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082
|
||||
SIZE (ffmpeg-6.0.tar.xz) = 10234012
|
||||
SHA256 (0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch) = 376ea23e9d876390fbca936c80cb437bb9daa6232ff65df0ea91673e18b739ff
|
||||
SIZE (0001-lavc-svt_hevc-add-libsvt-hevc-encoder-wrapper.patch) = 24259
|
||||
SHA256 (0002-doc-Add-libsvt_hevc-encoder-docs.patch) = d16589efc4be2602a9f436e9938cfee0cc7b5ccd7a4a6b41c0c9a59ae0859fda
|
||||
|
|
14
multimedia/ffmpeg/files/patch-libavutil_thread.h
Normal file
14
multimedia/ffmpeg/files/patch-libavutil_thread.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
pthread_setname_np is implemented on top of PR_SET_NAME on Linux
|
||||
and is also available on DragonFly, FreeBSD and Solaris
|
||||
|
||||
--- libavutil/thread.h.orig 2023-02-27 20:43:45 UTC
|
||||
+++ libavutil/thread.h
|
||||
@@ -196,6 +196,8 @@ static inline int ff_thread_setname(const char *name)
|
||||
{
|
||||
#if HAVE_PRCTL
|
||||
return AVERROR(prctl(PR_SET_NAME, name));
|
||||
+#elif HAVE_PTHREADS
|
||||
+ return AVERROR(pthread_setname_np(pthread_self(), name));
|
||||
#endif
|
||||
|
||||
return AVERROR(ENOSYS);
|
|
@ -1,437 +0,0 @@
|
|||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/04b89e8ae33b
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/64e2fb3f9d89
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/0463f5d6d56d
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/c5f314309067
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/c33b4048859a
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/a2b090da7932
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/1dddb930aaf0
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/4e47ebf38b97
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/50bc87263576
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/d794b36a7788
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/51c0b9e829be
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/e3c4442b249a
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/6fd1533057ff
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/ded0334d214f
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/70887d44ffa3
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/fe100bc556d7
|
||||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/fb70e0611bd7
|
||||
|
||||
--- configure.orig 2021-10-24 20:47:11 UTC
|
||||
+++ configure
|
||||
@@ -6430,7 +6430,7 @@ enabled libsrt && require_pkg_config libsrt
|
||||
enabled libssh && require_pkg_config libssh libssh libssh/sftp.h sftp_init
|
||||
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.8.4" EbSvtAv1Enc.h svt_av1_enc_init_handle
|
||||
+enabled libsvtav1 && require_pkg_config libsvtav1 "SvtAv1Enc >= 0.9.0" EbSvtAv1Enc.h svt_av1_enc_init_handle
|
||||
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
|
||||
--- doc/encoders.texi.orig 2021-10-24 20:47:07 UTC
|
||||
+++ doc/encoders.texi
|
||||
@@ -1754,28 +1754,15 @@ Set the operating point tier.
|
||||
@item tier
|
||||
Set the operating point tier.
|
||||
|
||||
-@item rc
|
||||
-Set the rate control mode to use.
|
||||
-
|
||||
-Possible modes:
|
||||
-@table @option
|
||||
-@item cqp
|
||||
-Constant quantizer: use fixed values of qindex (dependent on the frame type)
|
||||
-throughout the stream. This mode is the default.
|
||||
-
|
||||
-@item vbr
|
||||
-Variable bitrate: use a target bitrate for the whole stream.
|
||||
-
|
||||
-@item cvbr
|
||||
-Constrained variable bitrate: use a target bitrate for each GOP.
|
||||
-@end table
|
||||
-
|
||||
@item qmax
|
||||
Set the maximum quantizer to use when using a bitrate mode.
|
||||
|
||||
@item qmin
|
||||
Set the minimum quantizer to use when using a bitrate mode.
|
||||
|
||||
+@item crf
|
||||
+Constant rate factor value used in crf rate control mode (0-63).
|
||||
+
|
||||
@item qp
|
||||
Set the quantizer used in cqp rate control mode (0-63).
|
||||
|
||||
@@ -1786,14 +1773,18 @@ Set number of frames to look ahead (0-120).
|
||||
Set number of frames to look ahead (0-120).
|
||||
|
||||
@item preset
|
||||
-Set the quality-speed tradeoff, in the range 0 to 8. Higher values are
|
||||
-faster but lower quality. Defaults to 8 (highest speed).
|
||||
+Set the quality-speed tradeoff, in the range 0 to 13. Higher values are
|
||||
+faster but lower quality.
|
||||
|
||||
@item tile_rows
|
||||
Set log2 of the number of rows of tiles to use (0-6).
|
||||
|
||||
@item tile_columns
|
||||
Set log2 of the number of columns of tiles to use (0-4).
|
||||
+
|
||||
+@item svtav1-params
|
||||
+Set SVT-AV1 options using a list of @var{key}=@var{value} pairs separated
|
||||
+by ":". See the SVT-AV1 encoder user guide for a list of accepted parameters.
|
||||
|
||||
@end table
|
||||
|
||||
--- libavcodec/libsvtav1.c.orig 2021-10-24 20:47:07 UTC
|
||||
+++ libavcodec/libsvtav1.c
|
||||
@@ -60,17 +60,20 @@ typedef struct SvtContext {
|
||||
EOS_STATUS eos_flag;
|
||||
|
||||
// User options.
|
||||
+ AVDictionary *svtav1_opts;
|
||||
+#if FF_API_SVTAV1_OPTS
|
||||
int hierarchical_level;
|
||||
int la_depth;
|
||||
- int enc_mode;
|
||||
- int rc_mode;
|
||||
int scd;
|
||||
- int qp;
|
||||
|
||||
int tier;
|
||||
|
||||
int tile_columns;
|
||||
int tile_rows;
|
||||
+#endif
|
||||
+ int enc_mode;
|
||||
+ int crf;
|
||||
+ int qp;
|
||||
} SvtContext;
|
||||
|
||||
static const struct {
|
||||
@@ -151,11 +154,126 @@ static int config_enc_params(EbSvtAv1EncConfiguration
|
||||
{
|
||||
SvtContext *svt_enc = avctx->priv_data;
|
||||
const AVPixFmtDescriptor *desc;
|
||||
+ AVDictionaryEntry *en = NULL;
|
||||
|
||||
+ // Update param from options
|
||||
+#if FF_API_SVTAV1_OPTS
|
||||
+ param->hierarchical_levels = svt_enc->hierarchical_level;
|
||||
+ param->tier = svt_enc->tier;
|
||||
+ param->scene_change_detection = svt_enc->scd;
|
||||
+ param->tile_columns = svt_enc->tile_columns;
|
||||
+ param->tile_rows = svt_enc->tile_rows;
|
||||
+
|
||||
+ if (svt_enc->la_depth >= 0)
|
||||
+ param->look_ahead_distance = svt_enc->la_depth;
|
||||
+#endif
|
||||
+
|
||||
+ if (svt_enc->enc_mode >= 0)
|
||||
+ param->enc_mode = svt_enc->enc_mode;
|
||||
+
|
||||
+ if (avctx->bit_rate) {
|
||||
+ param->target_bit_rate = avctx->bit_rate;
|
||||
+ if (avctx->rc_max_rate != avctx->bit_rate)
|
||||
+ param->rate_control_mode = 1;
|
||||
+ else
|
||||
+ param->rate_control_mode = 2;
|
||||
+
|
||||
+ param->max_qp_allowed = avctx->qmax;
|
||||
+ param->min_qp_allowed = avctx->qmin;
|
||||
+ }
|
||||
+ param->max_bit_rate = avctx->rc_max_rate;
|
||||
+ param->vbv_bufsize = avctx->rc_buffer_size;
|
||||
+
|
||||
+ if (svt_enc->crf > 0) {
|
||||
+ param->qp = svt_enc->crf;
|
||||
+ param->rate_control_mode = 0;
|
||||
+ } else if (svt_enc->qp > 0) {
|
||||
+ param->qp = svt_enc->qp;
|
||||
+ param->rate_control_mode = 0;
|
||||
+ param->enable_adaptive_quantization = 0;
|
||||
+ }
|
||||
+
|
||||
+ desc = av_pix_fmt_desc_get(avctx->pix_fmt);
|
||||
+ param->color_primaries = avctx->color_primaries;
|
||||
+ param->matrix_coefficients = (desc->flags & AV_PIX_FMT_FLAG_RGB) ?
|
||||
+ AVCOL_SPC_RGB : avctx->colorspace;
|
||||
+ param->transfer_characteristics = avctx->color_trc;
|
||||
+
|
||||
+ if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED)
|
||||
+ param->color_range = avctx->color_range == AVCOL_RANGE_JPEG;
|
||||
+ else
|
||||
+ param->color_range = !!(desc->flags & AV_PIX_FMT_FLAG_RGB);
|
||||
+
|
||||
+#if SVT_AV1_CHECK_VERSION(1, 0, 0)
|
||||
+ if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) {
|
||||
+ const char *name =
|
||||
+ av_chroma_location_name(avctx->chroma_sample_location);
|
||||
+
|
||||
+ switch (avctx->chroma_sample_location) {
|
||||
+ case AVCHROMA_LOC_LEFT:
|
||||
+ param->chroma_sample_position = EB_CSP_VERTICAL;
|
||||
+ break;
|
||||
+ case AVCHROMA_LOC_TOPLEFT:
|
||||
+ param->chroma_sample_position = EB_CSP_COLOCATED;
|
||||
+ break;
|
||||
+ default:
|
||||
+ if (!name)
|
||||
+ break;
|
||||
+
|
||||
+ av_log(avctx, AV_LOG_WARNING,
|
||||
+ "Specified chroma sample location %s is unsupported "
|
||||
+ "on the AV1 bit stream level. Usage of a container that "
|
||||
+ "allows passing this information - such as Matroska - "
|
||||
+ "is recommended.\n",
|
||||
+ name);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ if (avctx->profile != FF_PROFILE_UNKNOWN)
|
||||
+ param->profile = avctx->profile;
|
||||
+
|
||||
+ if (avctx->level != FF_LEVEL_UNKNOWN)
|
||||
+ param->level = avctx->level;
|
||||
+
|
||||
+ if (avctx->gop_size > 0)
|
||||
+ param->intra_period_length = 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 * avctx->ticks_per_frame;
|
||||
+ }
|
||||
+
|
||||
+ /* 2 = IDR, closed GOP, 1 = CRA, open GOP */
|
||||
+ param->intra_refresh_type = avctx->flags & AV_CODEC_FLAG_CLOSED_GOP ? 2 : 1;
|
||||
+
|
||||
+#if SVT_AV1_CHECK_VERSION(0, 9, 1)
|
||||
+ while ((en = av_dict_get(svt_enc->svtav1_opts, "", en, AV_DICT_IGNORE_SUFFIX))) {
|
||||
+ EbErrorType ret = svt_av1_enc_parse_parameter(param, en->key, en->value);
|
||||
+ if (ret != EB_ErrorNone) {
|
||||
+ int level = (avctx->err_recognition & AV_EF_EXPLODE) ? AV_LOG_ERROR : AV_LOG_WARNING;
|
||||
+ av_log(avctx, level, "Error parsing option %s: %s.\n", en->key, en->value);
|
||||
+ if (avctx->err_recognition & AV_EF_EXPLODE)
|
||||
+ return AVERROR(EINVAL);
|
||||
+ }
|
||||
+ }
|
||||
+#else
|
||||
+ if ((en = av_dict_get(svt_enc->svtav1_opts, "", NULL, AV_DICT_IGNORE_SUFFIX))) {
|
||||
+ int level = (avctx->err_recognition & AV_EF_EXPLODE) ? AV_LOG_ERROR : AV_LOG_WARNING;
|
||||
+ av_log(avctx, level, "svt-params needs libavcodec to be compiled with SVT-AV1 "
|
||||
+ "headers >= 0.9.1.\n");
|
||||
+ if (avctx->err_recognition & AV_EF_EXPLODE)
|
||||
+ return AVERROR(ENOSYS);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
param->source_width = avctx->width;
|
||||
param->source_height = avctx->height;
|
||||
|
||||
- desc = av_pix_fmt_desc_get(avctx->pix_fmt);
|
||||
param->encoder_bit_depth = desc->comp[0].depth;
|
||||
|
||||
if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 1)
|
||||
@@ -169,12 +287,6 @@ static int config_enc_params(EbSvtAv1EncConfiguration
|
||||
return AVERROR(EINVAL);
|
||||
}
|
||||
|
||||
- if (avctx->profile != FF_PROFILE_UNKNOWN)
|
||||
- param->profile = avctx->profile;
|
||||
-
|
||||
- if (avctx->level != FF_LEVEL_UNKNOWN)
|
||||
- param->level = avctx->level;
|
||||
-
|
||||
if ((param->encoder_color_format == EB_YUV422 || param->encoder_bit_depth > 10)
|
||||
&& param->profile != FF_PROFILE_AV1_PROFESSIONAL ) {
|
||||
av_log(avctx, AV_LOG_WARNING, "Forcing Professional profile\n");
|
||||
@@ -184,40 +296,21 @@ static int config_enc_params(EbSvtAv1EncConfiguration
|
||||
param->profile = FF_PROFILE_AV1_HIGH;
|
||||
}
|
||||
|
||||
- // Update param from options
|
||||
- param->hierarchical_levels = svt_enc->hierarchical_level;
|
||||
- param->enc_mode = svt_enc->enc_mode;
|
||||
- param->tier = svt_enc->tier;
|
||||
- param->rate_control_mode = svt_enc->rc_mode;
|
||||
- param->scene_change_detection = svt_enc->scd;
|
||||
- param->qp = svt_enc->qp;
|
||||
+ avctx->bit_rate = param->rate_control_mode > 0 ?
|
||||
+ param->target_bit_rate : 0;
|
||||
+ avctx->rc_max_rate = param->max_bit_rate;
|
||||
+ avctx->rc_buffer_size = param->vbv_bufsize;
|
||||
|
||||
- param->target_bit_rate = avctx->bit_rate;
|
||||
+ if (avctx->bit_rate || avctx->rc_max_rate || avctx->rc_buffer_size) {
|
||||
+ AVCPBProperties *cpb_props = ff_add_cpb_side_data(avctx);
|
||||
+ if (!cpb_props)
|
||||
+ return AVERROR(ENOMEM);
|
||||
|
||||
- if (avctx->gop_size > 0)
|
||||
- param->intra_period_length = 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 * avctx->ticks_per_frame;
|
||||
+ cpb_props->buffer_size = avctx->rc_buffer_size;
|
||||
+ cpb_props->max_bitrate = avctx->rc_max_rate;
|
||||
+ cpb_props->avg_bitrate = avctx->bit_rate;
|
||||
}
|
||||
|
||||
- if (param->rate_control_mode) {
|
||||
- param->max_qp_allowed = avctx->qmax;
|
||||
- param->min_qp_allowed = avctx->qmin;
|
||||
- }
|
||||
-
|
||||
- param->intra_refresh_type = 2; /* Real keyframes only */
|
||||
-
|
||||
- if (svt_enc->la_depth >= 0)
|
||||
- param->look_ahead_distance = svt_enc->la_depth;
|
||||
-
|
||||
- param->tile_columns = svt_enc->tile_columns;
|
||||
- param->tile_rows = svt_enc->tile_rows;
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -330,11 +423,8 @@ static int eb_send_frame(AVCodecContext *avctx, const
|
||||
if (svt_enc->eos_flag == EOS_SENT)
|
||||
return 0;
|
||||
|
||||
- headerPtrLast.n_alloc_len = 0;
|
||||
- headerPtrLast.n_filled_len = 0;
|
||||
- headerPtrLast.n_tick_count = 0;
|
||||
- headerPtrLast.p_app_private = NULL;
|
||||
- headerPtrLast.p_buffer = NULL;
|
||||
+ memset(&headerPtrLast, 0, sizeof(headerPtrLast));
|
||||
+ headerPtrLast.pic_type = EB_AV1_INVALID_PICTURE;
|
||||
headerPtrLast.flags = EB_BUFFERFLAG_EOS;
|
||||
|
||||
svt_av1_enc_send_picture(svt_enc->svt_handle, &headerPtrLast);
|
||||
@@ -350,6 +440,16 @@ static int eb_send_frame(AVCodecContext *avctx, const
|
||||
headerPtr->p_app_private = NULL;
|
||||
headerPtr->pts = frame->pts;
|
||||
|
||||
+ switch (frame->pict_type) {
|
||||
+ case AV_PICTURE_TYPE_I:
|
||||
+ headerPtr->pic_type = EB_AV1_KEY_PICTURE;
|
||||
+ break;
|
||||
+ default:
|
||||
+ // Actually means auto, or default.
|
||||
+ headerPtr->pic_type = EB_AV1_INVALID_PICTURE;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
svt_av1_enc_send_picture(svt_enc->svt_handle, headerPtr);
|
||||
|
||||
return 0;
|
||||
@@ -472,21 +572,22 @@ static const AVOption options[] = {
|
||||
#define OFFSET(x) offsetof(SvtContext, x)
|
||||
#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
|
||||
static const AVOption options[] = {
|
||||
- { "hielevel", "Hierarchical prediction levels setting", OFFSET(hierarchical_level),
|
||||
- AV_OPT_TYPE_INT, { .i64 = 4 }, 3, 4, VE , "hielevel"},
|
||||
+#if FF_API_SVTAV1_OPTS
|
||||
+ { "hielevel", "Hierarchical prediction levels setting (Deprecated, use svtav1-params)", OFFSET(hierarchical_level),
|
||||
+ AV_OPT_TYPE_INT, { .i64 = 4 }, 3, 4, VE | AV_OPT_FLAG_DEPRECATED , "hielevel"},
|
||||
{ "3level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 3 }, INT_MIN, INT_MAX, VE, "hielevel" },
|
||||
{ "4level", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 4 }, INT_MIN, INT_MAX, VE, "hielevel" },
|
||||
|
||||
- { "la_depth", "Look ahead distance [0, 120]", OFFSET(la_depth),
|
||||
- AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 120, VE },
|
||||
+ { "la_depth", "Look ahead distance [0, 120] (Deprecated, use svtav1-params)", OFFSET(la_depth),
|
||||
+ AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 120, VE | AV_OPT_FLAG_DEPRECATED },
|
||||
|
||||
- { "preset", "Encoding preset [0, 8]",
|
||||
- OFFSET(enc_mode), AV_OPT_TYPE_INT, { .i64 = MAX_ENC_PRESET }, 0, MAX_ENC_PRESET, VE },
|
||||
-
|
||||
- { "tier", "Set operating point tier", OFFSET(tier),
|
||||
- AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE, "tier" },
|
||||
+ { "tier", "Set operating point tier (Deprecated, use svtav1-params)", OFFSET(tier),
|
||||
+ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE | AV_OPT_FLAG_DEPRECATED, "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" },
|
||||
+#endif
|
||||
+ { "preset", "Encoding preset",
|
||||
+ OFFSET(enc_mode), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, MAX_ENC_PRESET, VE },
|
||||
|
||||
FF_AV1_PROFILE_OPTS
|
||||
|
||||
@@ -518,21 +619,20 @@ static const AVOption options[] = {
|
||||
{ LEVEL("7.3", 73) },
|
||||
#undef LEVEL
|
||||
|
||||
- { "rc", "Bit rate control mode", OFFSET(rc_mode),
|
||||
- AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 3, VE , "rc"},
|
||||
- { "cqp", "Constant quantizer", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, VE, "rc" },
|
||||
- { "vbr", "Variable Bit Rate, use a target bitrate for the entire stream", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, VE, "rc" },
|
||||
- { "cvbr", "Constrained Variable Bit Rate, use a target bitrate for each GOP", 0, AV_OPT_TYPE_CONST,{ .i64 = 2 }, INT_MIN, INT_MAX, VE, "rc" },
|
||||
+ { "crf", "Constant Rate Factor value", OFFSET(crf),
|
||||
+ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 63, VE },
|
||||
+ { "qp", "Initial Quantizer level value", OFFSET(qp),
|
||||
+ AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 63, VE },
|
||||
+#if FF_API_SVTAV1_OPTS
|
||||
+ { "sc_detection", "Scene change detection (Deprecated, use svtav1-params)", OFFSET(scd),
|
||||
+ AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE | AV_OPT_FLAG_DEPRECATED },
|
||||
|
||||
- { "qp", "Quantizer to use with cqp rate control mode", OFFSET(qp),
|
||||
- AV_OPT_TYPE_INT, { .i64 = 50 }, 0, 63, VE },
|
||||
+ { "tile_columns", "Log2 of number of tile columns to use (Deprecated, use svtav1-params)", OFFSET(tile_columns), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 4, VE | AV_OPT_FLAG_DEPRECATED },
|
||||
+ { "tile_rows", "Log2 of number of tile rows to use (Deprecated, use svtav1-params)", OFFSET(tile_rows), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 6, VE | AV_OPT_FLAG_DEPRECATED },
|
||||
+#endif
|
||||
|
||||
- { "sc_detection", "Scene change detection", OFFSET(scd),
|
||||
- AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
|
||||
+ { "svtav1-params", "Set the SVT-AV1 configuration using a :-separated list of key=value parameters", OFFSET(svtav1_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE },
|
||||
|
||||
- { "tile_columns", "Log2 of number of tile columns to use", OFFSET(tile_columns), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4, VE},
|
||||
- { "tile_rows", "Log2 of number of tile rows to use", OFFSET(tile_rows), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 6, VE},
|
||||
-
|
||||
{NULL},
|
||||
};
|
||||
|
||||
@@ -544,9 +644,10 @@ static const AVCodecDefault eb_enc_defaults[] = {
|
||||
};
|
||||
|
||||
static const AVCodecDefault eb_enc_defaults[] = {
|
||||
- { "b", "7M" },
|
||||
+ { "b", "0" },
|
||||
+ { "flags", "+cgop" },
|
||||
{ "g", "-1" },
|
||||
- { "qmin", "0" },
|
||||
+ { "qmin", "1" },
|
||||
{ "qmax", "63" },
|
||||
{ NULL },
|
||||
};
|
||||
@@ -561,12 +662,11 @@ AVCodec ff_libsvtav1_encoder = {
|
||||
.receive_packet = eb_receive_packet,
|
||||
.close = eb_enc_close,
|
||||
.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS,
|
||||
- .caps_internal = FF_CODEC_CAP_AUTO_THREADS,
|
||||
+ .caps_internal = FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_INIT_CLEANUP,
|
||||
.pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P,
|
||||
AV_PIX_FMT_YUV420P10,
|
||||
AV_PIX_FMT_NONE },
|
||||
.priv_class = &class,
|
||||
.defaults = eb_enc_defaults,
|
||||
- .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
|
||||
.wrapper_name = "libsvtav1",
|
||||
};
|
||||
--- libavcodec/version.h.orig 2021-10-24 20:47:07 UTC
|
||||
+++ libavcodec/version.h
|
||||
@@ -168,5 +168,8 @@
|
||||
#ifndef FF_API_INIT_PACKET
|
||||
#define FF_API_INIT_PACKET (LIBAVCODEC_VERSION_MAJOR < 60)
|
||||
#endif
|
||||
+#ifndef FF_API_SVTAV1_OPTS
|
||||
+#define FF_API_SVTAV1_OPTS (LIBAVCODEC_VERSION_MAJOR < 60)
|
||||
+#endif
|
||||
|
||||
#endif /* AVCODEC_VERSION_H */
|
|
@ -1,951 +0,0 @@
|
|||
https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/3d29724c008d
|
||||
|
||||
--- configure.orig 2021-10-24 20:47:11 UTC
|
||||
+++ configure
|
||||
@@ -3663,7 +3663,7 @@ vidstabtransform_filter_deps="libvidstab"
|
||||
vaguedenoiser_filter_deps="gpl"
|
||||
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"
|
||||
@@ -6441,7 +6441,7 @@ enabled libvidstab && require_pkg_config libvid
|
||||
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
|
||||
--- doc/filters.texi.orig 2021-10-24 20:47:07 UTC
|
||||
+++ doc/filters.texi
|
||||
@@ -13867,66 +13867,58 @@ ffmpeg -i input.mov -vf lensfun=make=Canon:model="Cano
|
||||
|
||||
@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 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
|
||||
+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 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"}
|
||||
+Deprecated, use model='path=...'.
|
||||
|
||||
-@item log_path
|
||||
-Set the file path to be used to store logs.
|
||||
-
|
||||
-@item log_fmt
|
||||
-Set the format of the log file (csv, json or xml).
|
||||
-
|
||||
@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.
|
||||
@@ -13934,23 +13926,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 main.mpg -i ref.mpg -lavfi libvmaf -f null -
|
||||
+ffmpeg -i distorted.mpg -i reference.mpg -lavfi libvmaf=log_path=output.xml -f null -
|
||||
@end example
|
||||
|
||||
@item
|
||||
-Example with options:
|
||||
+Example with multiple models:
|
||||
@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='model=version=vmaf_v0.6.1\\:name=vmaf|version=vmaf_v0.6.1neg\\:name=vmaf_neg' -f null -
|
||||
@end example
|
||||
|
||||
@item
|
||||
+Example with multiple addtional features:
|
||||
+@example
|
||||
+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
|
||||
|
||||
--- libavfilter/vf_libvmaf.c.orig 2021-10-24 20:47:07 UTC
|
||||
+++ 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 {
|
||||
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,185 +51,488 @@ 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);
|
||||
|
||||
-static void compute_vmaf_score(LIBVMAFContext *s)
|
||||
+ 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 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);
|
||||
}
|
||||
|
||||
- format = (char *) s->desc->name;
|
||||
+ 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);
|
||||
+ }
|
||||
|
||||
- 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);
|
||||
+ 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);
|
||||
+ }
|
||||
+
|
||||
+ 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++;
|
||||
}
|
||||
- pthread_exit(NULL);
|
||||
+
|
||||
+ 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);
|
||||
+ }
|
||||
+
|
||||
+ 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;
|
||||
|
||||
- pthread_mutex_lock(&s->lock);
|
||||
+ 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);
|
||||
+ }
|
||||
|
||||
- while (s->frame_set && !s->error) {
|
||||
- pthread_cond_wait(&s->cond, &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;
|
||||
+ }
|
||||
}
|
||||
|
||||
- if (s->error) {
|
||||
+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;
|
||||
+
|
||||
+ 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);
|
||||
|
||||
- s->frame_set = 1;
|
||||
+ for (unsigned i = 0; i < dict_cnt; i++) {
|
||||
+ VmafModelConfig model_cfg = { 0 };
|
||||
+ AVDictionaryEntry *e = NULL;
|
||||
+ char *version = NULL;
|
||||
+ char *path = NULL;
|
||||
|
||||
- pthread_cond_signal(&s->cond);
|
||||
- pthread_mutex_unlock(&s->lock);
|
||||
+ 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;
|
||||
+ }
|
||||
|
||||
- return ff_filter_frame(ctx->outputs[0], master);
|
||||
+ 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;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+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,
|
||||
+ };
|
||||
|
||||
- s->error = 0;
|
||||
+ err = vmaf_init(&s->vmaf, cfg);
|
||||
+ if (err)
|
||||
+ return AVERROR(EINVAL);
|
||||
|
||||
- s->vmaf_thread_created = 0;
|
||||
- pthread_mutex_init(&s->lock, NULL);
|
||||
- pthread_cond_init (&s->cond, NULL);
|
||||
+ err = parse_deprecated_options(ctx);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
|
||||
+ err = parse_models(ctx);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = parse_features(ctx);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
s->fs.on_event = do_vmaf;
|
||||
return 0;
|
||||
}
|
||||
@@ -265,31 +554,36 @@ static int config_input_ref(AVFilterLink *inlink)
|
||||
|
||||
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);
|
||||
}
|
||||
if (ctx->inputs[0]->format != ctx->inputs[1]->format) {
|
||||
av_log(ctx, AV_LOG_ERROR, "Inputs must be of same pixel format.\n");
|
||||
return 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;
|
||||
}
|
||||
|
||||
@@ -320,28 +614,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");
|
||||
+ }
|
||||
|
||||
- pthread_mutex_destroy(&s->lock);
|
||||
- pthread_cond_destroy(&s->cond);
|
||||
+ 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);
|
||||
+ }
|
||||
+
|
||||
+ if (s->vmaf)
|
||||
+ vmaf_close(s->vmaf);
|
||||
}
|
||||
|
||||
static const AVFilterPad libvmaf_inputs[] = {
|
|
@ -12,6 +12,7 @@ include/libavcodec/codec_desc.h
|
|||
include/libavcodec/codec_id.h
|
||||
include/libavcodec/codec_par.h
|
||||
include/libavcodec/d3d11va.h
|
||||
include/libavcodec/defs.h
|
||||
include/libavcodec/dirac.h
|
||||
include/libavcodec/dv_profile.h
|
||||
include/libavcodec/dxva2.h
|
||||
|
@ -19,26 +20,28 @@ include/libavcodec/jni.h
|
|||
include/libavcodec/mediacodec.h
|
||||
include/libavcodec/packet.h
|
||||
include/libavcodec/qsv.h
|
||||
include/libavcodec/vaapi.h
|
||||
include/libavcodec/vdpau.h
|
||||
include/libavcodec/version.h
|
||||
include/libavcodec/version_major.h
|
||||
include/libavcodec/videotoolbox.h
|
||||
include/libavcodec/vorbis_parser.h
|
||||
include/libavcodec/xvmc.h
|
||||
include/libavdevice/avdevice.h
|
||||
include/libavdevice/version.h
|
||||
include/libavdevice/version_major.h
|
||||
include/libavfilter/avfilter.h
|
||||
include/libavfilter/buffersink.h
|
||||
include/libavfilter/buffersrc.h
|
||||
include/libavfilter/version.h
|
||||
include/libavfilter/version_major.h
|
||||
include/libavformat/avformat.h
|
||||
include/libavformat/avio.h
|
||||
include/libavformat/version.h
|
||||
include/libavresample/avresample.h
|
||||
include/libavresample/version.h
|
||||
include/libavformat/version_major.h
|
||||
include/libavutil/adler32.h
|
||||
include/libavutil/aes.h
|
||||
include/libavutil/aes_ctr.h
|
||||
include/libavutil/ambient_viewing_environment.h
|
||||
include/libavutil/attributes.h
|
||||
include/libavutil/audio_fifo.h
|
||||
include/libavutil/avassert.h
|
||||
|
@ -56,7 +59,9 @@ include/libavutil/channel_layout.h
|
|||
include/libavutil/common.h
|
||||
include/libavutil/cpu.h
|
||||
include/libavutil/crc.h
|
||||
include/libavutil/csp.h
|
||||
include/libavutil/des.h
|
||||
include/libavutil/detection_bbox.h
|
||||
include/libavutil/dict.h
|
||||
include/libavutil/display.h
|
||||
include/libavutil/dovi_meta.h
|
||||
|
@ -71,6 +76,7 @@ include/libavutil/film_grain_params.h
|
|||
include/libavutil/frame.h
|
||||
include/libavutil/hash.h
|
||||
include/libavutil/hdr_dynamic_metadata.h
|
||||
include/libavutil/hdr_dynamic_vivid_metadata.h
|
||||
include/libavutil/hmac.h
|
||||
include/libavutil/hwcontext.h
|
||||
include/libavutil/hwcontext_cuda.h
|
||||
|
@ -120,47 +126,47 @@ include/libavutil/timestamp.h
|
|||
include/libavutil/tree.h
|
||||
include/libavutil/twofish.h
|
||||
include/libavutil/tx.h
|
||||
include/libavutil/uuid.h
|
||||
include/libavutil/version.h
|
||||
include/libavutil/video_enc_params.h
|
||||
include/libavutil/xtea.h
|
||||
include/libpostproc/postprocess.h
|
||||
include/libpostproc/version.h
|
||||
include/libpostproc/version_major.h
|
||||
include/libswresample/swresample.h
|
||||
include/libswresample/version.h
|
||||
include/libswresample/version_major.h
|
||||
include/libswscale/swscale.h
|
||||
include/libswscale/version.h
|
||||
include/libswscale/version_major.h
|
||||
lib/libavcodec.so
|
||||
lib/libavcodec.so.58
|
||||
lib/libavcodec.so.58.134.100
|
||||
lib/libavcodec.so.60
|
||||
lib/libavcodec.so.60.3.100
|
||||
lib/libavdevice.so
|
||||
lib/libavdevice.so.58
|
||||
lib/libavdevice.so.58.13.100
|
||||
lib/libavdevice.so.60
|
||||
lib/libavdevice.so.60.1.100
|
||||
lib/libavfilter.so
|
||||
lib/libavfilter.so.7
|
||||
lib/libavfilter.so.7.110.100
|
||||
lib/libavfilter.so.9
|
||||
lib/libavfilter.so.9.3.100
|
||||
lib/libavformat.so
|
||||
lib/libavformat.so.58
|
||||
lib/libavformat.so.58.76.100
|
||||
lib/libavresample.so
|
||||
lib/libavresample.so.4
|
||||
lib/libavresample.so.4.0.0
|
||||
lib/libavformat.so.60
|
||||
lib/libavformat.so.60.3.100
|
||||
lib/libavutil.so
|
||||
lib/libavutil.so.56
|
||||
lib/libavutil.so.56.70.100
|
||||
lib/libavutil.so.58
|
||||
lib/libavutil.so.58.2.100
|
||||
lib/libpostproc.so
|
||||
lib/libpostproc.so.55
|
||||
lib/libpostproc.so.55.9.100
|
||||
lib/libpostproc.so.57
|
||||
lib/libpostproc.so.57.1.100
|
||||
lib/libswresample.so
|
||||
lib/libswresample.so.3
|
||||
lib/libswresample.so.3.9.100
|
||||
lib/libswresample.so.4
|
||||
lib/libswresample.so.4.10.100
|
||||
lib/libswscale.so
|
||||
lib/libswscale.so.5
|
||||
lib/libswscale.so.5.9.100
|
||||
lib/libswscale.so.7
|
||||
lib/libswscale.so.7.1.100
|
||||
libdata/pkgconfig/libavcodec.pc
|
||||
libdata/pkgconfig/libavdevice.pc
|
||||
libdata/pkgconfig/libavfilter.pc
|
||||
libdata/pkgconfig/libavformat.pc
|
||||
libdata/pkgconfig/libavresample.pc
|
||||
libdata/pkgconfig/libavutil.pc
|
||||
libdata/pkgconfig/libpostproc.pc
|
||||
libdata/pkgconfig/libswresample.pc
|
||||
|
@ -189,27 +195,28 @@ man/man3/libswresample.3.gz
|
|||
man/man3/libswscale.3.gz
|
||||
%%DATADIR%%/examples/Makefile
|
||||
%%DATADIR%%/examples/README
|
||||
%%DATADIR%%/examples/avio_http_serve_files.c
|
||||
%%DATADIR%%/examples/avio_list_dir.c
|
||||
%%DATADIR%%/examples/avio_reading.c
|
||||
%%DATADIR%%/examples/avio_read_callback.c
|
||||
%%DATADIR%%/examples/decode_audio.c
|
||||
%%DATADIR%%/examples/decode_filter_audio.c
|
||||
%%DATADIR%%/examples/decode_filter_video.c
|
||||
%%DATADIR%%/examples/decode_video.c
|
||||
%%DATADIR%%/examples/demuxing_decoding.c
|
||||
%%DATADIR%%/examples/demux_decode.c
|
||||
%%DATADIR%%/examples/encode_audio.c
|
||||
%%DATADIR%%/examples/encode_video.c
|
||||
%%DATADIR%%/examples/extract_mvs.c
|
||||
%%DATADIR%%/examples/filter_audio.c
|
||||
%%DATADIR%%/examples/filtering_audio.c
|
||||
%%DATADIR%%/examples/filtering_video.c
|
||||
%%DATADIR%%/examples/http_multiclient.c
|
||||
%%DATADIR%%/examples/hw_decode.c
|
||||
%%DATADIR%%/examples/metadata.c
|
||||
%%DATADIR%%/examples/muxing.c
|
||||
%%DATADIR%%/examples/qsvdec.c
|
||||
%%DATADIR%%/examples/remuxing.c
|
||||
%%DATADIR%%/examples/resampling_audio.c
|
||||
%%DATADIR%%/examples/scaling_video.c
|
||||
%%DATADIR%%/examples/mux.c
|
||||
%%DATADIR%%/examples/qsv_decode.c
|
||||
%%DATADIR%%/examples/qsv_transcode.c
|
||||
%%DATADIR%%/examples/remux.c
|
||||
%%DATADIR%%/examples/resample_audio.c
|
||||
%%DATADIR%%/examples/scale_video.c
|
||||
%%DATADIR%%/examples/show_metadata.c
|
||||
%%DATADIR%%/examples/transcode.c
|
||||
%%DATADIR%%/examples/transcode_aac.c
|
||||
%%DATADIR%%/examples/transcoding.c
|
||||
%%DATADIR%%/examples/vaapi_encode.c
|
||||
%%DATADIR%%/examples/vaapi_transcode.c
|
||||
%%DATADIR%%/ffprobe.xsd
|
||||
|
|
Loading…
Add table
Reference in a new issue