[FFmpeg-devel] [PATCH] avfilter: add VMAF filter

James Almer jamrial at gmail.com
Wed Jul 5 00:29:05 EEST 2017


On 7/3/2017 1:38 PM, Ashish Singh wrote:
> Added vmaf section in doc/filters.texi and Changelog.
> 
> ---
>  Changelog                |   1 +
>  configure                |   5 +
>  doc/filters.texi         |  33 ++++
>  libavfilter/Makefile     |   1 +
>  libavfilter/allfilters.c |   1 +
>  libavfilter/vf_vmaf.c    | 402 +++++++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 443 insertions(+)
>  create mode 100644 libavfilter/vf_vmaf.c
> 
> diff --git a/Changelog b/Changelog
> index 1778980..311b55b 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -10,6 +10,7 @@ version <next>:
>  - config.log and other configuration files moved into ffbuild/ directory
>  - update cuvid/nvenc headers to Video Codec SDK 8.0.14
>  - afir audio filter
> +- vmaf video filter
>  
>  version 3.3:
>  - CrystalHD decoder moved to new decode API
> diff --git a/configure b/configure
> index 5ae5227..bafcd07 100755
> --- a/configure
> +++ b/configure
> @@ -259,6 +259,7 @@ External library support:
>    --enable-libtwolame      enable MP2 encoding via libtwolame [no]
>    --enable-libv4l2         enable libv4l2/v4l-utils [no]
>    --enable-libvidstab      enable video stabilization using vid.stab [no]
> +  --enable-libvmaf         enable vmaf filter via libvmaf [no]
>    --enable-libvo-amrwbenc  enable AMR-WB encoding via libvo-amrwbenc [no]
>    --enable-libvorbis       enable Vorbis en/decoding via libvorbis,
>                             native implementation exists [no]
> @@ -1569,6 +1570,7 @@ EXTERNAL_LIBRARY_LIST="
>      libtheora
>      libtwolame
>      libv4l2
> +    libvmaf
>      libvorbis
>      libvpx
>      libwavpack
> @@ -3172,6 +3174,7 @@ uspp_filter_deps="gpl avcodec"
>  vaguedenoiser_filter_deps="gpl"
>  vidstabdetect_filter_deps="libvidstab"
>  vidstabtransform_filter_deps="libvidstab"
> +vmaf_filter_deps="libvmaf"
>  zmq_filter_deps="libzmq"
>  zoompan_filter_deps="swscale"
>  zscale_filter_deps="libzimg"
> @@ -5845,6 +5848,8 @@ enabled libtwolame        && require libtwolame twolame.h twolame_init -ltwolame
>                                 die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; }
>  enabled libv4l2           && require_pkg_config libv4l2 libv4l2.h v4l2_ioctl
>  enabled libvidstab        && require_pkg_config "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit
> +enabled libvmaf           && { check_lib libvmaf "libvmaf.h" "compute_vmaf" -lvmaf -lstdc++ -lpthread -lm ||
> +                               die "ERROR: libvmaf must be installed"; }
>  enabled libvo_amrwbenc    && require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_init -lvo-amrwbenc
>  enabled libvorbis         && require libvorbis vorbis/vorbisenc.h vorbis_info_init -lvorbisenc -lvorbis -logg
>  
> diff --git a/doc/filters.texi b/doc/filters.texi
> index 5985db6..792a11c 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -14701,6 +14701,39 @@ vignette='PI/4+random(1)*PI/50':eval=frame
>  
>  @end itemize
>  
> + at section vmaf
> +
> +Obtain the average VMAF (Video Multi-Method Assessment Fusion)
> +score between two input videos.
> +
> +This filter takes in input two input videos, the first input is
> +considered the "main" source and is passed unchanged to the
> +output. The second input is used as a "reference" video for computing
> +the VMAF score.
> +
> +Both video inputs must have the same resolution and pixel format for
> +this filter to work correctly. Also it assumes that both inputs
> +have the same number of frames, which are compared one by one.
> +
> +The obtained average VMAF score is printed through the logging system.
> +
> +Currently it requires Netflix's vmaf library (libvmaf) as a pre-requisite.
> +It can be enabled using --enable-libvmaf at ./configure ..
> +If no model path is not specified it uses default model.
> +
> +For example:
> + at example
> +ffmpeg -i main.mpg -i ref.mpg -lavfi vmaf -f null -
> + at end example
> +
> +Example with options:
> + at example
> +ffmpeg -i main.mpg -i ref.mpg -lavfi vmaf="psnr=1:enable-transform=1" -f null -
> + at end example
> +
> +On this example the input file @file{main.mpg} being processed is compared with the
> +reference file @file{ref.mpg}.
> +
>  @section vstack
>  Stack input videos vertically.
>  
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index f7dfe8a..1c4bd56 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -314,6 +314,7 @@ OBJS-$(CONFIG_VFLIP_FILTER)                  += vf_vflip.o
>  OBJS-$(CONFIG_VIDSTABDETECT_FILTER)          += vidstabutils.o vf_vidstabdetect.o
>  OBJS-$(CONFIG_VIDSTABTRANSFORM_FILTER)       += vidstabutils.o vf_vidstabtransform.o
>  OBJS-$(CONFIG_VIGNETTE_FILTER)               += vf_vignette.o
> +OBJS-$(CONFIG_VMAF_FILTER)                   += vf_vmaf.o dualinput.o framesync.o
>  OBJS-$(CONFIG_VSTACK_FILTER)                 += vf_stack.o framesync.o
>  OBJS-$(CONFIG_W3FDIF_FILTER)                 += vf_w3fdif.o
>  OBJS-$(CONFIG_WAVEFORM_FILTER)               += vf_waveform.o
> diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
> index cd35ae4..6894a6f 100644
> --- a/libavfilter/allfilters.c
> +++ b/libavfilter/allfilters.c
> @@ -325,6 +325,7 @@ static void register_all(void)
>      REGISTER_FILTER(VIDSTABDETECT,  vidstabdetect,  vf);
>      REGISTER_FILTER(VIDSTABTRANSFORM, vidstabtransform, vf);
>      REGISTER_FILTER(VIGNETTE,       vignette,       vf);
> +    REGISTER_FILTER(VMAF,           vmaf,           vf);
>      REGISTER_FILTER(VSTACK,         vstack,         vf);
>      REGISTER_FILTER(W3FDIF,         w3fdif,         vf);
>      REGISTER_FILTER(WAVEFORM,       waveform,       vf);
> diff --git a/libavfilter/vf_vmaf.c b/libavfilter/vf_vmaf.c
> new file mode 100644
> index 0000000..ce966e4
> --- /dev/null
> +++ b/libavfilter/vf_vmaf.c
> @@ -0,0 +1,402 @@
> +/*
> + * Copyright (c) 2017 Ronald S. Bultje <rsbultje at gmail.com>
> + * Copyright (c) 2017 Ashish Pratap Singh <ashk43712 at gmail.com>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +/**
> + * @file
> + * Calculate the VMAF between two input videos.
> + */
> +
> +#include <inttypes.h>
> +#include <pthread.h>
> +#include <string.h>
> +#include <libvmaf.h>
> +#include "libavutil/avstring.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/pixdesc.h"
> +#include "avfilter.h"
> +#include "dualinput.h"
> +#include "drawutils.h"
> +#include "formats.h"
> +#include "internal.h"
> +#include "video.h"
> +
> +typedef struct VMAFContext {
> +    const AVClass *class;
> +    FFDualInputContext dinput;
> +    char *format;
> +    int width;
> +    int height;
> +    double vmaf_score;
> +    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;
> +    int ssim;
> +    int ms_ssim;
> +    char *pool;
> +} VMAFContext;
> +
> +#define OFFSET(x) offsetof(VMAFContext, x)
> +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
> +
> +static const AVOption vmaf_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 (xml or json).",            OFFSET(log_fmt), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS},
> +    {"disable_clip",  "Disables clip for computing vmaf.",            OFFSET(disable_clip), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},
> +    {"disable avx",  "Disables avx for computing vmaf.",            OFFSET(disable_avx), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS},

Remove this option, and check for the AVX cpuflag instead.

That is, instead of passing s->disable_avx to compute_vmaf(), pass
!(av_get_cpu_flags() & AV_CPU_FLAG_AVX)


More information about the ffmpeg-devel mailing list