[FFmpeg-devel] [PATCH v2] lavfi: port IVTC filters from vapoursynth.

Paul B Mahol onemda at gmail.com
Wed Apr 10 10:15:13 CEST 2013


On 4/6/13, Clement Boesch <ubitux at gmail.com> wrote:
> TODO: Changelog, version bump
> ---
> Final version. Testing possible with ivtc branch on github/ubitux.
>
> Please comment.
> ---
>  doc/filters.texi            | 363 ++++++++++++++++
>  libavfilter/Makefile        |   2 +
>  libavfilter/allfilters.c    |   2 +
>  libavfilter/vf_decimate.c   | 406 ++++++++++++++++++
>  libavfilter/vf_fieldmatch.c | 998
> ++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 1771 insertions(+)
>  create mode 100644 libavfilter/vf_decimate.c
>  create mode 100644 libavfilter/vf_fieldmatch.c
>

[...]

> +static int query_formats(AVFilterContext *ctx)
> +{
> +    static const enum AVPixelFormat pix_fmts[] = {
> +        AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV420P,
> +        AV_PIX_FMT_YUV411P,  AV_PIX_FMT_YUV410P,
> +        AV_NE(AV_PIX_FMT_YUV420P9BE,  AV_PIX_FMT_YUV420P9LE),
> +        AV_NE(AV_PIX_FMT_YUV422P9BE,  AV_PIX_FMT_YUV422P9LE),
> +        AV_NE(AV_PIX_FMT_YUV444P9BE,  AV_PIX_FMT_YUV444P9LE),
> +        AV_NE(AV_PIX_FMT_YUV420P10BE, AV_PIX_FMT_YUV420P10LE),
> +        AV_NE(AV_PIX_FMT_YUV422P10BE, AV_PIX_FMT_YUV422P10LE),
> +        AV_NE(AV_PIX_FMT_YUV444P10BE, AV_PIX_FMT_YUV444P10LE),
> +        AV_NE(AV_PIX_FMT_YUV420P12BE, AV_PIX_FMT_YUV420P12LE),
> +        AV_NE(AV_PIX_FMT_YUV422P12BE, AV_PIX_FMT_YUV422P12LE),
> +        AV_NE(AV_PIX_FMT_YUV444P12BE, AV_PIX_FMT_YUV444P12LE),
> +        AV_NE(AV_PIX_FMT_YUV420P14BE, AV_PIX_FMT_YUV420P14LE),
> +        AV_NE(AV_PIX_FMT_YUV422P14BE, AV_PIX_FMT_YUV422P14LE),
> +        AV_NE(AV_PIX_FMT_YUV444P14BE, AV_PIX_FMT_YUV444P14LE),
> +        AV_NE(AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_YUV420P16LE),
> +        AV_NE(AV_PIX_FMT_YUV422P16BE, AV_PIX_FMT_YUV422P16LE),
> +        AV_NE(AV_PIX_FMT_YUV444P16BE, AV_PIX_FMT_YUV444P16LE),

gray and alpha versions of those above; also what about planar gbrp
(or even interleaved one)?

> +        AV_PIX_FMT_NONE
> +    };
> +    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
> +    return 0;
> +}

[...]

> diff --git a/libavfilter/vf_fieldmatch.c b/libavfilter/vf_fieldmatch.c
> new file mode 100644
> index 0000000..327b82b
> --- /dev/null
> +++ b/libavfilter/vf_fieldmatch.c
> @@ -0,0 +1,998 @@
> +/*
> + * Copyright (c) 2012 Fredrik Mellbin
> + * Copyright (c) 2013 Clement Boesch
> + *
> + * 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
> + * Fieldmatching filter, ported from VFM filter (VapouSsynth) by Clement.
> + * Fredrik Mellbin is the author of the VIVTC/VFM filter, which is itself a
> + * light clone of the TIVTC/TFM (AviSynth) filter written by Kevin Stone
> + * (tritical), the original author.
> + *
> + * @see http://bengal.missouri.edu/~kes25c/
> + * @see http://www.vapoursynth.com/about/
> + */
> +
> +#include <inttypes.h>
> +
> +#include "libavutil/avassert.h"
> +#include "libavutil/imgutils.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/timestamp.h"
> +#include "avfilter.h"
> +#include "internal.h"
> +
> +#define INPUT_MAIN     0
> +#define INPUT_CLEANSRC 1
> +
> +enum fieldmatch_parity {
> +    FM_PARITY_AUTO   = -1,
> +    FM_PARITY_BOTTOM =  0,
> +    FM_PARITY_TOP    =  1,
> +};
> +
> +enum matching_mode {
> +    MODE_PC,
> +    MODE_PC_N,
> +    MODE_PC_U,
> +    MODE_PC_N_UB,
> +    MODE_PCN,
> +    MODE_PCN_UB,
> +    NB_MODE
> +};
> +
> +enum comb_matching_mode {
> +    COMBMATCH_NONE,
> +    COMBMATCH_SC,
> +    COMBMATCH_FULL,
> +    NB_COMBMATCH
> +};
> +
> +enum comb_dbg {
> +    COMBDBG_NONE,
> +    COMBDBG_PCN,
> +    COMBDBG_PCNUB,
> +    NB_COMBDBG
> +};
> +
> +typedef struct {
> +    const AVClass *class;
> +
> +    AVFrame *prv,  *src,  *nxt;     ///< main sliding window of 3 frames
> +    AVFrame *prv2, *src2, *nxt2;    ///< sliding window of the optional
> second stream
> +    int64_t frame_count;            ///< output frame counter
> +    int got_frame[2];               ///< frame request flag for each input
> stream
> +    int hsub, vsub;                 ///< chroma subsampling values
> +    uint32_t eof;                   ///< bitmask for end of stream
> +    int64_t lastscdiff;
> +    int64_t lastn;
> +
> +    /* options */
> +    int order;
> +    int ppsrc;
> +    enum matching_mode mode;
> +    int field;
> +    int mchroma;
> +    int y0, y1;
> +    int64_t scthresh;
> +    double scthresh_flt;
> +    enum comb_matching_mode combmatch;
> +    int combdbg;
> +    int cthresh;
> +    int chroma;
> +    int blockx, blocky;
> +    int combpel;
> +
> +    /* misc buffers */
> +    uint8_t *map_data[4];
> +    int map_linesize[4];
> +    uint8_t *cmask_data[4];
> +    int cmask_linesize[4];
> +    int *c_array;
> +    int tpitchy, tpitchuv;
> +    uint8_t *tbuffer;
> +} FieldMatchContext;
> +
> +#define OFFSET(x) offsetof(FieldMatchContext, x)
> +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
> +
> +static const AVOption fieldmatch_options[] = {
> +    { "order", "specify the assumed field order", OFFSET(order),
> AV_OPT_TYPE_INT, {.i64=FM_PARITY_AUTO}, -1, 1, FLAGS, "order" },
> +        { "auto", "auto detect parity",        0, AV_OPT_TYPE_CONST,
> {.i64=FM_PARITY_AUTO},    INT_MIN, INT_MAX, FLAGS, "order" },
> +        { "bff",  "assume bottom field first", 0, AV_OPT_TYPE_CONST,
> {.i64=FM_PARITY_BOTTOM},  INT_MIN, INT_MAX, FLAGS, "order" },
> +        { "tff",  "assume top field first",    0, AV_OPT_TYPE_CONST,
> {.i64=FM_PARITY_TOP},     INT_MIN, INT_MAX, FLAGS, "order" },
> +    { "mode", "set the matching mode or strategy to use", OFFSET(mode),
> AV_OPT_TYPE_INT, {.i64=MODE_PC_N}, MODE_PC, NB_MODE-1, FLAGS, "mode" },
> +        { "pc",      "2-way match (p/c)",
>                                  0, AV_OPT_TYPE_CONST, {.i64=MODE_PC},
> INT_MIN, INT_MAX, FLAGS, "mode" },
> +        { "pc_n",    "2-way match + 3rd match on combed (p/c + u)",
>                                  0, AV_OPT_TYPE_CONST, {.i64=MODE_PC_N},
> INT_MIN, INT_MAX, FLAGS, "mode" },
> +        { "pc_u",    "2-way match + 3rd match (same order) on combed (p/c +
> u)",                             0, AV_OPT_TYPE_CONST, {.i64=MODE_PC_U},
> INT_MIN, INT_MAX, FLAGS, "mode" },
> +        { "pc_n_ub", "2-way match + 3rd match on combed + 4th/5th matches
> if still combed (p/c + u + u/b)",  0, AV_OPT_TYPE_CONST,
> {.i64=MODE_PC_N_UB}, INT_MIN, INT_MAX, FLAGS, "mode" },
> +        { "pcn",     "3-way match (p/c/n)",
>                                  0, AV_OPT_TYPE_CONST, {.i64=MODE_PCN},
> INT_MIN, INT_MAX, FLAGS, "mode" },
> +        { "pcn_ub",  "3-way match + 4th/5th matches on combed (p/c/n +
> u/b)",                                0, AV_OPT_TYPE_CONST,
> {.i64=MODE_PCN_UB},  INT_MIN, INT_MAX, FLAGS, "mode" },
> +    { "ppsrc", "mark main input as a pre-processed input and activate clean
> source input stream", OFFSET(ppsrc), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS
> },
> +    { "field", "set the field to match from", OFFSET(field),
> AV_OPT_TYPE_INT, {.i64=FM_PARITY_AUTO}, -1, 1, FLAGS, "field" },
> +        { "auto",   "automatic (same value as 'order')",    0,
> AV_OPT_TYPE_CONST, {.i64=FM_PARITY_AUTO},    INT_MIN, INT_MAX, FLAGS,
> "field" },
> +        { "bottom", "bottom field",                         0,
> AV_OPT_TYPE_CONST, {.i64=FM_PARITY_BOTTOM},  INT_MIN, INT_MAX, FLAGS,
> "field" },
> +        { "top",    "top field",                            0,
> AV_OPT_TYPE_CONST, {.i64=FM_PARITY_TOP},     INT_MIN, INT_MAX, FLAGS,
> "field" },
> +    { "mchroma", "set whether or not chroma is included during the match
> comparisons", OFFSET(mchroma), AV_OPT_TYPE_INT, {.i64=1}, 0, 1,  FLAGS },
> +    { "y0", "define an exclusion band which excludes the lines between y0
> and y1 from the field matching decision", OFFSET(y0), AV_OPT_TYPE_INT,
> {.i64=0}, 0, INT_MAX, FLAGS },
> +    { "y1", "define an exclusion band which excludes the lines between y0
> and y1 from the field matching decision", OFFSET(y1), AV_OPT_TYPE_INT,
> {.i64=0}, 0, INT_MAX, FLAGS },
> +    { "scthresh", "set scene change detection threshold",
> OFFSET(scthresh_flt), AV_OPT_TYPE_DOUBLE, {.dbl=12}, 0, 100, FLAGS },
> +    { "combmatch", "set combmatching mode", OFFSET(combmatch),
> AV_OPT_TYPE_INT, {.i64=COMBMATCH_SC}, COMBMATCH_NONE, NB_COMBMATCH-1, FLAGS,
> "combmatching" },
> +        { "none", "disable combmatching",                     0,
> AV_OPT_TYPE_CONST, {.i64=COMBMATCH_NONE}, INT_MIN, INT_MAX, FLAGS,
> "combmatching" },
> +        { "sc",   "enable combmatching only on scene change", 0,
> AV_OPT_TYPE_CONST, {.i64=COMBMATCH_SC},   INT_MIN, INT_MAX, FLAGS,
> "combmatching" },
> +        { "full", "enable combmatching all the time",         0,
> AV_OPT_TYPE_CONST, {.i64=COMBMATCH_FULL}, INT_MIN, INT_MAX, FLAGS,
> "combmatching" },
> +    { "combdbg",   "enable comb debug", OFFSET(combdbg), AV_OPT_TYPE_INT,
> {.i64=COMBDBG_NONE}, COMBDBG_NONE, NB_COMBDBG-1, FLAGS, "dbglvl" },
> +        { "none",  "no forced calculation", 0, AV_OPT_TYPE_CONST,
> {.i64=COMBDBG_NONE},  INT_MIN, INT_MAX, FLAGS, "dbglvl" },
> +        { "pcn",   "calculate p/c/n",       0, AV_OPT_TYPE_CONST,
> {.i64=COMBDBG_PCN},   INT_MIN, INT_MAX, FLAGS, "dbglvl" },
> +        { "pcnub", "calculate p/c/n/u/b",   0, AV_OPT_TYPE_CONST,
> {.i64=COMBDBG_PCNUB}, INT_MIN, INT_MAX, FLAGS, "dbglvl" },
> +    { "cthresh", "set the area combing threshold used for combed frame
> detection",       OFFSET(cthresh), AV_OPT_TYPE_INT, {.i64= 9}, -1, 0xff,
> FLAGS },
> +    { "chroma",  "set whether or not chroma is considered in the combed
> frame decision", OFFSET(chroma),  AV_OPT_TYPE_INT, {.i64= 0},  0,    1,
> FLAGS },
> +    { "blockx",  "set the x-axis size of the window used during combed
> frame detection", OFFSET(blockx),  AV_OPT_TYPE_INT, {.i64=16},  4, 1<<9,
> FLAGS },
> +    { "blocky",  "set the y-axis size of the window used during combed
> frame detection", OFFSET(blocky),  AV_OPT_TYPE_INT, {.i64=16},  4, 1<<9,
> FLAGS },
> +    { "combpel", "set the number of combed pixels inside any of the blocky
> by blockx size blocks on the frame for the frame to be detected as combed",
> OFFSET(combpel), AV_OPT_TYPE_INT, {.i64=80}, 0, INT_MAX, FLAGS },
> +    { NULL }
> +};
> +
> +AVFILTER_DEFINE_CLASS(fieldmatch);
> +
> +static int get_width(const FieldMatchContext *fm, const AVFrame *f, int
> plane)
> +{
> +    return plane ? f->width >> fm->hsub : f->width;
> +}
> +
> +static int get_height(const FieldMatchContext *fm, const AVFrame *f, int
> plane)
> +{
> +    return plane ? f->height >> fm->vsub : f->height;
> +}
> +
> +static int64_t luma_abs_diff(const AVFrame *f1, const AVFrame *f2)
> +{
> +    int x, y;
> +    const uint8_t *srcp1 = f1->data[0];
> +    const uint8_t *srcp2 = f2->data[0];
> +    const int src1_linesize = f1->linesize[0];
> +    const int src2_linesize = f2->linesize[0];
> +    const int width  = f1->width;
> +    const int height = f1->height;
> +    int64_t acc = 0;
> +
> +    for (y = 0; y < height; y++) {
> +        for (x = 0; x < width; x++)
> +            acc += abs(srcp1[x] - srcp2[x]);
> +        srcp1 += src1_linesize;
> +        srcp2 += src2_linesize;
> +    }
> +    return acc;
> +}
> +
> +static void fill_buf(uint8_t *data, int w, int h, int linesize, uint8_t v)
> +{
> +    int y;
> +
> +    for (y = 0; y < h; y++) {
> +        memset(data, v, w);
> +        data += linesize;
> +    }
> +}

unrelated: This so generic and probably could be used by other filters.

[...]

It would be extra if you did run it under valgrind and similar and it did not do
any of uninitialized reads, overreads and overwrites.


More information about the ffmpeg-devel mailing list