[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