On 2017/8/12 21:47, Anton Khirnov wrote:

Quoting Huang, Zhengxu (2017-08-04 05:15:26)
>From 0d3fcc7322b86e236596aad21f704b5844d14446 Mon Sep 17 00:00:00 2001
From: "Huang, Zhengxu" <[email protected]>
Date: Wed, 26 Jul 2017 04:50:06 +0800
Subject: [PATCH 2/2] libavfilter/vf_vpp: Add common filters of the qsv vpp

Add common filters of the qsv vpp features including scale denosie deinterlace
frc crop and procAmp.

Performance will be significantly reduced in the test if using cascade mode just
like qsv framerate + qsv scale + qsv deinterlace + qsv denoise in separated way
no matter in system or video memmory cases. And the code is so redundant because
so much the same just as session and surface's creation and management. So we 
add
a common qsv filter.

Usage:
-hwaccel qsv -c:v h264_qsv -r 25 -i in -vf 
vpp_qsv=w=iw/2:h=400:deinterlace=1:framerate=60:detail=50:denoise=50
-b 2M -maxrate 3M -c:v h264_qsv -y out.h264

Signed-off-by: ChaoX A Liu <[email protected]>
Signed-off-by: Zhengxu Huang <[email protected]>
Signed-off-by: Andrew Zhang <[email protected]>
Change-Id: I130392ce722138c209ab658c5f03f0009b6e8024
---
configure                |   2 +
libavfilter/Makefile     |   1 +
libavfilter/allfilters.c |   1 +
libavfilter/vf_vpp_qsv.c | 405 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 409 insertions(+)
create mode 100644 libavfilter/vf_vpp_qsv.c

diff --git a/configure b/configure
index e6ea18a..70eee5e 100755
--- a/configure
+++ b/configure
@@ -2535,6 +2535,8 @@ resample_filter_deps="avresample"
scale_filter_deps="swscale"
scale_qsv_filter_deps="libmfx"
scale_vaapi_filter_deps="vaapi VAProcPipelineParameterBuffer"
+vpp_qsv_filter_deps="libmfx"
+vpp_qsv_filter_select="qsvvpp"

# examples
decode_audio_example_deps="avcodec avutil"
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 8d9ed6a..3f13d29 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -94,6 +94,7 @@ OBJS-$(CONFIG_TRANSPOSE_FILTER)              += vf_transpose.o
OBJS-$(CONFIG_TRIM_FILTER)                   += trim.o
OBJS-$(CONFIG_UNSHARP_FILTER)                += vf_unsharp.o
OBJS-$(CONFIG_VFLIP_FILTER)                  += vf_vflip.o
+OBJS-$(CONFIG_VPP_QSV_FILTER)                += qsvvpp.o vf_vpp_qsv.o
Needs the same changes you did to the overlay filter.

OBJS-$(CONFIG_YADIF_FILTER)                  += vf_yadif.o

OBJS-$(CONFIG_NULLSINK_FILTER)               += vsink_nullsink.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index dc59ccd..2b3a672 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -117,6 +117,7 @@ void avfilter_register_all(void)
     REGISTER_FILTER(TRIM,           trim,           vf);
     REGISTER_FILTER(UNSHARP,        unsharp,        vf);
     REGISTER_FILTER(VFLIP,          vflip,          vf);
+    REGISTER_FILTER(VPP_QSV,        vpp_qsv,        vf);
     REGISTER_FILTER(YADIF,          yadif,          vf);

     REGISTER_FILTER(COLOR,          color,          vsrc);
diff --git a/libavfilter/vf_vpp_qsv.c b/libavfilter/vf_vpp_qsv.c
new file mode 100644
index 0000000..4e14245
--- /dev/null
+++ b/libavfilter/vf_vpp_qsv.c
@@ -0,0 +1,405 @@
+/*
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <float.h>
+#include "internal.h"
+#include "formats.h"
+#include "libavutil/eval.h"
+#include "avfilter.h"
+#include "libavutil/avassert.h"
+#include "libavutil/opt.h"
+#include "libavcodec/avcodec.h"
+#include "libavformat/avformat.h"
+#include "libavutil/pixdesc.h"
+#include "qsvvpp.h"
+
+#define OFFSET(x) offsetof(VPPContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM
+
+/* number of video enhancement filters */
+#define ENH_FILTERS_COUNT (5)
+
+typedef struct VPPContext{
+    const AVClass *class;
+
+    FFQSVVPPContext *qsv;
+
+    /* Video Enhancement Algorithms */
+    mfxExtVPPDeinterlacing  deinterlace_conf;
+    mfxExtVPPFrameRateConversion frc_conf;
+    mfxExtVPPDenoise denoise_conf;
+    mfxExtVPPDetail detail_conf;
+    mfxExtVPPProcAmp procamp_conf;
+
+    int out_width;
+    int out_height;
+
+    AVRational framerate;       ///< target framerate
+    /**
+     * destination picture structure
+     * -1 = unkown
+     * 0 = interlaced top field first
+     * 1 = progressive
+     * 2 = interlaced bottom field first
+     */
+    int dpic;
+    int use_frc;                ///< use framerate conversion
+    int deinterlace;            ///< deinterlace mode : 0=off, 1=bob, 
2=advanced
+    int denoise;                ///< Enable Denoise algorithm. Level is the 
optional value from the interval [0; 100]
+    int detail;                 ///< Enable Detail Enhancement algorithm.
+                                ///< Level is the optional value from the 
interval [0; 100]
+    int use_crop;               ///< 1 = use crop; 0=none
+    int crop_w;
+    int crop_h;
+    int crop_x;
+    int crop_y;
+
+    /* param for the procamp */
+    int    procamp;            ///< enable the procamp
+    float  hue;
+    float  saturation;
+    float  contrast;
+    float  brightness;
+
+    char *cx, *cy, *cw, *ch;
+    char *ow, *oh;
+} VPPContext;
+
+static const AVOption options[] = {
+    { "deinterlace", "deinterlace mode: 0=off, 1=bob, 2=advanced",             
OFFSET(deinterlace),  AV_OPT_TYPE_INT, {.i64=0}, 0, MFX_DEINTERLACING_ADVANCED, .flags = FLAGS },
The values should be named constants. For their use see e.g. the overlay
filter (the eof_action option).

+    { "denoise",     "denoise level [0, 100]",                                 
OFFSET(denoise),      AV_OPT_TYPE_INT, {.i64=0}, 0, 100, .flags = FLAGS },
+    { "detail",      "detail enhancement level [0, 100]",                      
OFFSET(detail),       AV_OPT_TYPE_INT, {.i64=0}, 0, 100, .flags = FLAGS },
+    { "dpic",        "dest pic struct: 0=tff, 1=progressive [default], 2=bff", 
OFFSET(dpic),         AV_OPT_TYPE_INT, {.i64 = 1 }, 0, 2, .flags = FLAGS },
same

+    { "framerate",   "output framerate",                                       
OFFSET(framerate),    AV_OPT_TYPE_RATIONAL, { .dbl = 0.0 },0, DBL_MAX, .flags = FLAGS },
+    { "procamp",     "Enable ProcAmp",                                         
OFFSET(procamp),    AV_OPT_TYPE_INT,   {.i64 = 0}, 0, 1, .flags = FLAGS},
+    { "hue",         "ProcAmp hue",                                            
OFFSET(hue),        AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, -180.0, 180.0, .flags = FLAGS},
+    { "saturation",  "ProcAmp saturation",                                     
OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, 0.0, 10.0, .flags = FLAGS},
+    { "contrast",    "ProcAmp contrast",                                       
OFFSET(contrast),   AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, 0.0, 10.0, .flags = FLAGS},
+    { "brightness",  "ProcAmp brightness",                                     
OFFSET(brightness), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, -100.0, 100.0, .flags = FLAGS},
+
+    { "cw",   "set the width crop area expression",       OFFSET(cw), 
AV_OPT_TYPE_STRING, {.str = "iw"}, CHAR_MIN, CHAR_MAX, FLAGS },
+    { "ch",   "set the height crop area expression",      OFFSET(ch), 
AV_OPT_TYPE_STRING, {.str = "ih"}, CHAR_MIN, CHAR_MAX, FLAGS },
+    { "cx",   "set the x crop area expression",           OFFSET(cx), 
AV_OPT_TYPE_STRING, {.str = "(in_w-out_w)/2"}, CHAR_MIN, CHAR_MAX, FLAGS },
+    { "cy",   "set the y crop area expression",           OFFSET(cy), 
AV_OPT_TYPE_STRING, {.str = "(in_h-out_h)/2"}, CHAR_MIN, CHAR_MAX, FLAGS },
+
+    { "w",      "Output video width",  OFFSET(ow), AV_OPT_TYPE_STRING, 
{.str="cw"}, 0, 255, .flags = FLAGS },
+    { "width",  "Output video width",  OFFSET(ow), AV_OPT_TYPE_STRING, 
{.str="cw"}, 0, 255, .flags = FLAGS },
+    { "h",      "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, 
{.str="w*ch/cw"}, 0, 255, .flags = FLAGS },
+    { "height", "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, 
{.str="w*ch/cw"}, 0, 255, .flags = FLAGS },
+    { NULL }
+};
+
+static const char *const var_names[] = {
+    "iw", "in_w",
+    "ih", "in_h",
+    "ow", "out_w", "w",
+    "oh", "out_h", "h",
+    "cw",
+    "ch",
+    "cx",
+    "cy",
+    NULL
+};
+
+enum var_name {
+    VAR_iW, VAR_IN_W,
+    VAR_iH, VAR_IN_H,
+    VAR_oW, VAR_OUT_W, VAR_W,
+    VAR_oH, VAR_OUT_H, VAR_H,
+    CW,
+    CH,
+    CX,
+    CY,
+    VAR_VARS_NB
+};
+
+static int eval_expr(AVFilterContext *ctx)
+{
+#define PASS_EXPR(e, s) {\
+    ret = av_expr_parse(&e, s, var_names, NULL, NULL, NULL, NULL, 0, ctx); \
+    if (ret < 0) {\
+        av_log(ctx, AV_LOG_ERROR, "Error when passing '%s'.\n", s);\
+        return ret;\
Same leak as in the overlay filter.

+    }\
+}
+#define CALC_EXPR(e, v, i) {\
+    i = v = av_expr_eval(e, var_values, NULL); \
+}
+    VPPContext *vpp = ctx->priv;
+    double  var_values[VAR_VARS_NB] = { NAN };
+    AVExpr *w_expr = NULL, *h_expr = NULL;
+    AVExpr *cw_expr = NULL, *ch_expr = NULL;
+    AVExpr *cx_expr = NULL, *cy_expr = NULL;
+    int     ret = 0;
+
+    PASS_EXPR(cw_expr, vpp->cw);
+    PASS_EXPR(ch_expr, vpp->ch);
+
+    PASS_EXPR(w_expr, vpp->ow);
+    PASS_EXPR(h_expr, vpp->oh);
+
+    PASS_EXPR(cx_expr, vpp->cx);
+    PASS_EXPR(cy_expr, vpp->cy);
+
+    var_values[VAR_iW] =
+    var_values[VAR_IN_W] = ctx->inputs[0]->w;
+
+    var_values[VAR_iH] =
+    var_values[VAR_IN_H] = ctx->inputs[0]->h;
+
+    /* crop params */
+    CALC_EXPR(cw_expr, var_values[CW], vpp->crop_w);
+    CALC_EXPR(ch_expr, var_values[CH], vpp->crop_h);
+
+    /* calc again in case cw is relative to ch */
+    CALC_EXPR(cw_expr, var_values[CW], vpp->crop_w);
+
+    CALC_EXPR(w_expr,
+            var_values[VAR_OUT_W] = var_values[VAR_oW] = var_values[VAR_W],
+            vpp->out_width);
+    CALC_EXPR(h_expr,
+            var_values[VAR_OUT_H] = var_values[VAR_oH] = var_values[VAR_H],
+            vpp->out_height);
+
+    /* calc again in case ow is relative to oh */
+    CALC_EXPR(w_expr,
+            var_values[VAR_OUT_W] = var_values[VAR_oW] = var_values[VAR_W],
+            vpp->out_width);
+
+
+    CALC_EXPR(cx_expr, var_values[CX], vpp->crop_x);
+    CALC_EXPR(cy_expr, var_values[CY], vpp->crop_y);
+
+    /* calc again in case cx is relative to cy */
+    CALC_EXPR(cx_expr, var_values[CX], vpp->crop_x);
+
+    if((vpp->crop_w != var_values[VAR_iW]) || (vpp->crop_h != 
var_values[VAR_iH])) {
Why only width/height and not the x/y?
Now the cw/ch 's default value is iw and ih while the cx/cy default is (in_w-out_w)/2 , (in_h-out_h)/2. So if only cx /cy has been set, the cw and ch will be iw/ih.  The cx/cy 's value will be changed to 0 in
the blew code:
        if(vpp->crop_w + vpp->crop_x > inlink->w)
           vpp->crop_x = inlink->w - vpp->crop_w;
        if(vpp->crop_h + vpp->crop_y > inlink->h)
           vpp->crop_y = inlink->h - vpp->crop_h;

So now the code only check the width and height to judge whether using the crop.
Also, missing space.

+        vpp->use_crop = 1;
+        av_log(NULL, AV_LOG_INFO, "Using the crop feature \n");
This seems unnecessary. And in any case it should use a proper logging
context and have a lower verbosity level.

+     }
+
+    av_expr_free(w_expr);
+    av_expr_free(h_expr);
+    av_expr_free(cw_expr);
+    av_expr_free(ch_expr);
+    av_expr_free(cx_expr);
+    av_expr_free(cy_expr);
+#undef PASS_EXPR
+#undef CALC_EXPR
+
+    return ret;
+}
+
+static int config_input(AVFilterLink *inlink)
+{
+    AVFilterContext *ctx = inlink->dst;
+    VPPContext      *vpp = ctx->priv;
+    int              ret;
+
+    if (vpp->framerate.den == 0 || vpp->framerate.num == 0)
+        vpp->framerate = inlink->frame_rate;
The input framerate is not always set, the input could be VFR or its
framerate could be unknown. Can MSDK do VFR to CFR conversion?
The MSDK don't support the VFR to CFR.
If the inlink's frame_rate is unset,  later the VPP init will fail because the vpp needs default framerate to init.


+
+    if (av_q2d(vpp->framerate) != av_q2d(inlink->frame_rate))
Use av_cmp_q()

+        vpp->use_frc = 1;
+
+    ret = eval_expr(ctx);
+    if (ret != 0) {
+        av_log(ctx, AV_LOG_ERROR, "Fail to eval expr.\n");
+        return ret;
+    }
+
+    if (vpp->out_height == 0 || vpp->out_width == 0) {
+        vpp->out_width  = inlink->w;
+        vpp->out_height = inlink->h;
+    }
+
+    if (vpp->use_crop) {
+        if (vpp->crop_x < 0)  vpp->crop_x = 0;
Here and below use FFMIN/FFMAX for clipping, it's shorter and more
readable.

+        if (vpp->crop_y < 0)  vpp->crop_y = 0;
+
+        if(vpp->crop_w % 2)       vpp->crop_w++;
+        if(vpp->crop_h % 2)       vpp->crop_h++;
+        if(vpp->out_width % 2)    vpp->out_width++;
+        if(vpp->out_height % 2)   vpp->out_height++;
This should not silently do something different from what the caller
requested - it should at the very least warn.

+
+        if(vpp->crop_w + vpp->crop_x > inlink->w)
+           vpp->crop_x = inlink->w - vpp->crop_w;
+        if(vpp->crop_h + vpp->crop_y > inlink->h)
+           vpp->crop_y = inlink->h - vpp->crop_h;
+    }
+
+    return 0;
+}

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to