diff mbox

[FFmpeg-devel,3/5] Renamed reinterlace to tinterlace

Message ID CALGJd-+oBTWe8MU0W-y4+37S0ANftX-X1xW3BK3O0k1iVdfVTQ@mail.gmail.com
State Superseded
Headers show

Commit Message

Vasile Toncu Aug. 14, 2018, 4:53 p.m. UTC
Hi Thomas,

I added the log messages.

Thanks for the review.

On Tue, Aug 14, 2018 at 3:23 PM, Thomas Mundt <tmundt75@gmail.com> wrote:

> Hi,
>
> 2018-08-13 0:02 GMT+02:00 Vasile Toncu <vasile.toncu@tremend.com>:
>
> > Hello,
> >
> > I have updated patch 3 according to review, removed all code related to
> the
> > new flags (MERGE_TFF, MERGE_BFF) and threading functionality.
> >
> >
> Thanks, your patch looks fine to me now.
> There is just one thing, I forgot to mention last review:
>
>
> > {....}
> > -    if (tinterlace->flags & (TINTERLACE_FLAG_VLPF |
> TINTERLACE_FLAG_CVLPF)
> > -            && !(tinterlace->mode == MODE_INTERLEAVE_TOP
> > -              || tinterlace->mode == MODE_INTERLEAVE_BOTTOM)) {
> > -        av_log(ctx, AV_LOG_WARNING, "low_pass_filter flags ignored with
> > mode %d\n",
> > -                tinterlace->mode);
> >
> > {....}
> > +    if (tinterlace->flags & FLAG_VLPF || tinterlace->flags &
> FLAG_CVLPF) {
> >
> > -    av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n",
> > tinterlace->mode,
> > -           (tinterlace->flags & TINTERLACE_FLAG_CVLPF) ? "complex" :
> > -           (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "linear" :
> "off",
> > -           inlink->h, outlink->h);
> >
>
> Please keep the log messages. Nothing should change for the user.
>
> Regards,
> Thomas
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>

Comments

Thomas Mundt Aug. 14, 2018, 8:25 p.m. UTC | #1
Hi,

2018-08-14 18:53 GMT+02:00 Vasile Toncu <vasile.toncu@tremend.com>:

> Hi Thomas,
>
> I added the log messages.
>
> Thanks for the review.
>

I found some more time for testing this evening. Unfortunately there are
still issues.
I get half green pictures with some modes at high bit depth.
But the fix is easy.
The bytewidth in all av_image_copy_plane functions need to be adapted for
high bit depths.

{....}
>     const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(out->format);
>     int mult = (fmt_desc->comp[0].depth > 8 ? 2 : 1);
>

You used the calculated "mult" in the av_image_copy_plane functions of
MODE_MERGE and MODE_PAD only.
And forgot the others:


> {....}
>
+    case MODE_INTERLEAVE_BOTTOM:
> +    case MODE_INTERLEAVE_TOP:
> +        y = y * 2;
> +
> +        if (tinterlace->flags & FLAG_VLPF || tinterlace->flags &
> FLAG_CVLPF) {
> +            int clip_max = (1 << fmt_desc->comp[plane].depth) - 1;
> +
> +            interleave_filter_frame(tinterlace, first, out, plane,
> !!(tinterlace->flags & FLAG_CVLPF), tinterlace_mode == MODE_INTERLEAVE_TOP,
> x, y, clip_max);
> +            interleave_filter_frame(tinterlace, second, out, plane,
> !!(tinterlace->flags & FLAG_CVLPF), tinterlace_mode ==
> MODE_INTERLEAVE_BOTTOM, x, y, clip_max);
>          } else {
> -            if (tinterlace->csp->comp[plane].depth > 8)
> -                cols *= 2;
> -            av_image_copy_plane(dstp, dstp_linesize, srcp, srcp_linesize,
> cols, lines);
> +            offset1 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 :
> out->linesize[plane];
> +            offset2 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 :
> first->linesize[plane];
> +            offset3 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ?
> out->linesize[plane]    : 0;
> +            offset4 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ?
> second->linesize[plane] : 0;
> +
> +            av_image_copy_plane(out->data[plane] + offset1, 2 *
> out->linesize[plane],
> +                first->data[plane] + offset2, 2 * first->linesize[plane],
> +                first->width / x, first->height / y);
> +            av_image_copy_plane(out->data[plane] + offset3, 2 *
> out->linesize[plane],
> +                second->data[plane] + offset4, 2 *
> second->linesize[plane],
> +                second->width / x, second->height / y);
>

Here

         }
> +        break;
> +
> +    case MODE_INTERLACE_X2:
> +        y = y * 2;
> +
> +        offset1 = 0; offset2 = 0;
> +        offset3 = out->linesize[plane];
> +        offset4 = second->linesize[plane];
> +
> +        if (second->interlaced_frame && second->top_field_first) {
> +            offset1 = out->linesize[plane];
> +            offset2 = first->linesize[plane];
> +            offset3 = 0; offset4 = 0;
> +        }
> +
> +        av_image_copy_plane(out->data[plane] + offset1, 2 *
> out->linesize[plane],
> +            first->data[plane] + offset2, 2 * first->linesize[plane],
> +            first->width / x, first->height / y);
> +        av_image_copy_plane(out->data[plane] + offset3, 2 *
> out->linesize[plane],
> +            second->data[plane] + offset4, 2 * second->linesize[plane],
> +            second->width / x, second->height / y);
>

 Here

+        break;
> +
> +    case MODE_MERGE_X2:
> +        if (IS_ODD(tinterlace->current_frame_index - 1)) {
> +            av_image_copy_plane(out->data[plane], 2 *
> out->linesize[plane],
> +                second->data[plane], second->linesize[plane],
> second->width / x, second->height / y);
> +            av_image_copy_plane(out->data[plane] + out->linesize[plane],
> 2 * out->linesize[plane],
> +                first->data[plane], first->linesize[plane], first->width
> / x, first->height / y);
> +        } else {
> +            av_image_copy_plane(out->data[plane], 2 *
> out->linesize[plane],
> +                first->data[plane], first->linesize[plane], first->width
> / x, first->height / y);
> +            av_image_copy_plane(out->data[plane] + out->linesize[plane],
> 2 * out->linesize[plane],
> +                second->data[plane], second->linesize[plane],
> second->width / x, second->height / y);
>

Here.

Sorry for the piecemeal.

Regards,
Thomas
diff mbox

Patch

From b2f8fc595312b4b89017c3689dfb80e30b3472ed Mon Sep 17 00:00:00 2001
From: Vasile Toncu <vasile.toncu@tremend.com>
Date: Tue, 24 Jul 2018 12:02:16 +0200
Subject: [PATCH] Patch 3 - Move reinterlace to tinterlace

---
 configure                             |   1 -
 libavfilter/Makefile                  |   1 -
 libavfilter/allfilters.c              |   1 -
 libavfilter/reinterlace.h             | 105 ----
 libavfilter/tinterlace.h              |  96 ++--
 libavfilter/vf_reinterlace.c          | 775 --------------------------
 libavfilter/vf_tinterlace.c           | 689 +++++++++++++----------
 libavfilter/x86/Makefile              |   1 -
 libavfilter/x86/vf_reinterlace_init.c | 102 ----
 libavfilter/x86/vf_tinterlace_init.c  |  41 +-
 10 files changed, 484 insertions(+), 1328 deletions(-)
 delete mode 100644 libavfilter/reinterlace.h
 delete mode 100644 libavfilter/vf_reinterlace.c
 delete mode 100644 libavfilter/x86/vf_reinterlace_init.c

diff --git a/configure b/configure
index e718c1531c..8f42a86f8f 100755
--- a/configure
+++ b/configure
@@ -3420,7 +3420,6 @@  stereo3d_filter_deps="gpl"
 subtitles_filter_deps="avformat avcodec libass"
 super2xsai_filter_deps="gpl"
 pixfmts_super2xsai_test_deps="super2xsai_filter"
-tinterlace_filter_deps="gpl"
 tinterlace_merge_test_deps="tinterlace_filter"
 tinterlace_pad_test_deps="tinterlace_filter"
 tonemap_filter_deps="const_nan"
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index c8ba079750..245302bbe8 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -246,7 +246,6 @@  OBJS-$(CONFIG_IDET_FILTER)                   += vf_idet.o
 OBJS-$(CONFIG_IL_FILTER)                     += vf_il.o
 OBJS-$(CONFIG_INFLATE_FILTER)                += vf_neighbor.o
 OBJS-$(CONFIG_INTERLACE_FILTER)              += vf_tinterlace.o
-OBJS-$(CONFIG_REINTERLACE_FILTER)            += vf_reinterlace.o
 OBJS-$(CONFIG_INTERLEAVE_FILTER)             += f_interleave.o
 OBJS-$(CONFIG_KERNDEINT_FILTER)              += vf_kerndeint.o
 OBJS-$(CONFIG_LENSCORRECTION_FILTER)         += vf_lenscorrection.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 9956776938..2d19929bdc 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -348,7 +348,6 @@  extern AVFilter ff_vf_thumbnail;
 extern AVFilter ff_vf_thumbnail_cuda;
 extern AVFilter ff_vf_tile;
 extern AVFilter ff_vf_tinterlace;
-extern AVFilter ff_vf_reinterlace;
 extern AVFilter ff_vf_tlut2;
 extern AVFilter ff_vf_tmix;
 extern AVFilter ff_vf_tonemap;
diff --git a/libavfilter/reinterlace.h b/libavfilter/reinterlace.h
deleted file mode 100644
index cb512c7639..0000000000
--- a/libavfilter/reinterlace.h
+++ /dev/null
@@ -1,105 +0,0 @@ 
-/*
- * Copyright (c) 2017 Vasile Toncu <vasile.toncu@tremend.com>
- * Copyright (c) 2017 Thomas Mundt <tmundt75@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
- * Reinterlace filter
- */
-
-#ifndef AVFILTER_REINTERLACE_H
-#define AVFILTER_REINTERLACE_H
-
-#include "avfilter.h"
-#include "formats.h"
-#include "internal.h"
-#include "video.h"
-#include "libavutil/avassert.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/opt.h"
-#include "libavutil/pixdesc.h"
-#include "libavutil/bswap.h"
-
-enum FilterMode {
-    MODE_MERGE,
-    MODE_DROP_EVEN,
-    MODE_DROP_ODD,
-    MODE_PAD,
-    MODE_INTERLEAVE_TOP,
-    MODE_INTERLEAVE_BOTTOM,
-    MODE_INTERLACE_X2,
-    MODE_MERGE_X2,
-    MODE_MERGE_TFF,
-    MODE_MERGE_BFF,
-    MODE_NB,
- };
-
-enum FilterFlags {
-    FLAG_NOTHING    = 0x00,
-    FLAG_VLPF       = 0x01,
-    FLAG_EXACT_TB   = 0x02,
-    FLAG_CVLPF      = 0x04,
-    FLAG_NB
-};
-
-typedef struct {
-    const AVClass *class;
-    int mode;
-    int flags;
-
-    AVFrame *prev_frame, *current_frame;
-    int64_t current_frame_index;
-
-    uint8_t *black_vec[4];
-    int black_linesize[4];
-
-    int skip_next_frame;
-
-    void *thread_data;
-
-    uint8_t bit_depth;
-
-    void (*lowpass_line)(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
-                          ptrdiff_t mref, ptrdiff_t pref, int clip_max);
-
-    AVRational preout_time_base;
-
- } ReInterlaceContext;
-
-#if CONFIG_GPL
-void ff_reinterlace_init_x86(ReInterlaceContext *reinterlace);
-#endif
-
-#define OFFSET(x) offsetof(ReInterlaceContext, x)
-#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
-
-#define IS_ODD(value) (value & 1)
-
-typedef struct ReInterlaceThreadData {
-    AVFrame *out, *first, *second;
-    int plane;
-    ReInterlaceContext *reinterlace;
-
-    int scale_w_plane12_factor;
-    int scale_h_plane12_factor;
-
-} ReInterlaceThreadData;
-
-#endif /* AVFILTER_REINTERLACE_H */
diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h
index b5c39aac52..19381985a3 100644
--- a/libavfilter/tinterlace.h
+++ b/libavfilter/tinterlace.h
@@ -1,72 +1,90 @@ 
 /*
- * Copyright (c) 2011 Stefano Sabatini
- * Copyright (c) 2010 Baptiste Coudurier
- * Copyright (c) 2003 Michael Zucchi <notzed@ximian.com>
+ * Copyright (c) 2017 Vasile Toncu <vasile.toncu@tremend.com>
+ * Copyright (c) 2017 Thomas Mundt <tmundt75@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 General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * 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 General Public License for more details.
+ * 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 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.
+ * 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
- * temporal field interlace filter, ported from MPlayer/libmpcodecs
+ * TInterlace filter
  */
+
 #ifndef AVFILTER_TINTERLACE_H
 #define AVFILTER_TINTERLACE_H
 
-#include "libavutil/bswap.h"
+#include "avfilter.h"
+#include "formats.h"
+#include "internal.h"
+#include "video.h"
+#include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
 #include "libavutil/opt.h"
 #include "libavutil/pixdesc.h"
-#include "drawutils.h"
-#include "avfilter.h"
-
-#define TINTERLACE_FLAG_VLPF 01
-#define TINTERLACE_FLAG_EXACT_TB 2
-#define TINTERLACE_FLAG_CVLPF 4
+#include "libavutil/bswap.h"
 
-enum TInterlaceMode {
-    MODE_MERGE = 0,
+enum FilterMode {
+    MODE_MERGE,
     MODE_DROP_EVEN,
     MODE_DROP_ODD,
     MODE_PAD,
     MODE_INTERLEAVE_TOP,
     MODE_INTERLEAVE_BOTTOM,
-    MODE_INTERLACEX2,
-    MODE_MERGEX2,
+    MODE_INTERLACE_X2,
+    MODE_MERGE_X2,
     MODE_NB,
+ };
+
+enum FilterFlags {
+    FLAG_NOTHING    = 0x00,
+    FLAG_VLPF       = 0x01,
+    FLAG_EXACT_TB   = 0x02,
+    FLAG_CVLPF      = 0x04,
+    FLAG_NB
 };
 
-typedef struct TInterlaceContext {
+typedef struct {
     const AVClass *class;
-    int mode;                   ///< TInterlaceMode, interlace mode selected
-    AVRational preout_time_base;
-    int flags;                  ///< flags affecting interlacing algorithm
-    int frame;                  ///< number of the output frame
-    int vsub;                   ///< chroma vertical subsampling
-    AVFrame *cur;
-    AVFrame *next;
-    uint8_t *black_data[4];     ///< buffer used to fill padded lines
+    int mode;
+    int flags;
+
+    AVFrame *prev_frame, *current_frame;
+    int64_t current_frame_index;
+
+    uint8_t *black_vec[4];
     int black_linesize[4];
-    FFDrawContext draw;
-    FFDrawColor color;
-    const AVPixFmtDescriptor *csp;
+
+    int skip_next_frame;
+
+    uint8_t bit_depth;
+
     void (*lowpass_line)(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
-                         ptrdiff_t mref, ptrdiff_t pref, int clip_max);
-} TInterlaceContext;
+                          ptrdiff_t mref, ptrdiff_t pref, int clip_max);
+
+    AVRational preout_time_base;
+
+ } TInterlaceContext;
+
+#if CONFIG_GPL
+void ff_tinterlace_init_x86(TInterlaceContext *tinterlace);
+#endif
 
-void ff_tinterlace_init_x86(TInterlaceContext *interlace);
+#define IS_ODD(value) (value & 1)
+#define OFFSET(x) offsetof(TInterlaceContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
 
 #endif /* AVFILTER_TINTERLACE_H */
diff --git a/libavfilter/vf_reinterlace.c b/libavfilter/vf_reinterlace.c
deleted file mode 100644
index d3f8f374ae..0000000000
--- a/libavfilter/vf_reinterlace.c
+++ /dev/null
@@ -1,775 +0,0 @@ 
-/*
- * Copyright (c) 2018 Vasile Toncu <vasile.toncu@tremend.com>
- * Copyright (c) 2017 Thomas Mundt <tmundt75@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
- * Reinterlace filter
- */
-
-#include "libavutil/pixdesc.h"
-#include "libavutil/imgutils.h"
-#include "drawutils.h"
-#include "reinterlace.h"
-
-static const AVRational standard_tbs[] = {
-    {1, 25},
-    {1, 30},
-    {1001, 30000},
-};
-
-static const AVOption reinterlace_options[] = {
-    { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE},     0, MODE_NB - 1, FLAGS, "mode" },
-    { "merge",             "merge frames",                0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE},                INT_MIN, INT_MAX, FLAGS, "mode"},
-    { "drop_even",         "drop even frames",            0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_EVEN},            INT_MIN, INT_MAX, FLAGS, "mode"},
-    { "drop_odd",          "drop odd frames",             0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_ODD},             INT_MIN, INT_MAX, FLAGS, "mode"},
-    { "pad",               "pad lines of a frame with black lines",                  0, AV_OPT_TYPE_CONST, {.i64=MODE_PAD},                  INT_MIN, INT_MAX, FLAGS, "mode"},
-    { "interleave_top",    "interleave top and bottom frames",       0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP},       INT_MIN, INT_MAX, FLAGS, "mode"},
-    { "interleave_bottom", "interleave bottom and top frames",    0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM},    INT_MIN, INT_MAX, FLAGS, "mode"},
-    { "interlacex2",       "interlace consecutive frames",         0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLACE_X2},         INT_MIN, INT_MAX, FLAGS, "mode"},
-    { "mergex2",           "just like merge, but at the same frame rate",             0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE_X2},             INT_MIN, INT_MAX, FLAGS, "mode"},
-
-    { "flags", "add flag for reinterlace", OFFSET(flags), AV_OPT_TYPE_INT, {.i64=FLAG_NOTHING}, 0, 0xFF, FLAGS, "flags" },
-    { "low_pass_filter",   "low pass fitler",                 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags"},
-    { "vlpf",              "low pass filter",                 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags"},
-    { "complex_filter",    "enable complex vertical low-pass filter",      0, AV_OPT_TYPE_CONST, {.i64 = FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
-    { "cvlpf",             "enable complex vertical low-pass filter",      0, AV_OPT_TYPE_CONST, {.i64 = FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
-    { "exact_tb",          "force a timebase which can represent timestamps exactly", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_EXACT_TB}, INT_MIN, INT_MAX, FLAGS, "flags" },
-    { NULL }
-};
-
-AVFILTER_DEFINE_CLASS(reinterlace);
-
-static av_cold int init(AVFilterContext *ctx)
-{
-    ReInterlaceContext *reinterlace = ctx->priv;
-    int i;
-
-    for (i = 0; i < 4; i++)
-        reinterlace->black_vec[i] = NULL;
-
-    reinterlace->thread_data = av_malloc(4 * sizeof(ReInterlaceThreadData));
-    if (!reinterlace->thread_data)
-        return AVERROR(ENOMEM);
-
-    return 0;
-}
-
-static int query_formats(AVFilterContext *ctx)
-{
-    static const enum AVPixelFormat pix_fmts[] = {
-        AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
-        AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
-        AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
-        AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUV422P10LE,
-        AV_PIX_FMT_YUV440P10LE, AV_PIX_FMT_YUV444P10LE,
-        AV_PIX_FMT_YUV420P12LE, AV_PIX_FMT_YUV422P12LE,
-        AV_PIX_FMT_YUV440P12LE, AV_PIX_FMT_YUV444P12LE,
-        AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
-        AV_PIX_FMT_YUVA420P10LE, AV_PIX_FMT_YUVA422P10LE, AV_PIX_FMT_YUVA444P10LE,
-        AV_PIX_FMT_GRAY8, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
-        AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P,
-        AV_PIX_FMT_NONE
-    };
-
-    AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
-
-    if (!fmts_list)
-        return AVERROR(ENOMEM);
-
-    return ff_set_common_formats(ctx, fmts_list);
-}
-
-static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
-                           ptrdiff_t mref, ptrdiff_t pref, int clip_max)
-{
-    const uint8_t *srcp_above = srcp + mref;
-    const uint8_t *srcp_below = srcp + pref;
-    int i;
-    for (i = 0; i < width; i++) {
-        // this calculation is an integer representation of
-        // '0.5 * current + 0.25 * above + 0.25 * below'
-        // '1 +' is for rounding.
-        dstp[i] = (1 + srcp[i] + srcp[i] + srcp_above[i] + srcp_below[i]) >> 2;
-    }
-}
-
-static void lowpass_line_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8,
-                              ptrdiff_t mref, ptrdiff_t pref, int clip_max)
-{
-    uint16_t *dstp = (uint16_t *)dst8;
-    const uint16_t *srcp = (const uint16_t *)src8;
-    const uint16_t *srcp_above = srcp + mref / 2;
-    const uint16_t *srcp_below = srcp + pref / 2;
-    int i, src_x;
-    for (i = 0; i < width; i++) {
-        // this calculation is an integer representation of
-        // '0.5 * current + 0.25 * above + 0.25 * below'
-        // '1 +' is for rounding.
-        src_x   = av_le2ne16(srcp[i]) << 1;
-        dstp[i] = av_le2ne16((1 + src_x + av_le2ne16(srcp_above[i])
-                             + av_le2ne16(srcp_below[i])) >> 2);
-    }
-}
-
-static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
-                                   ptrdiff_t mref, ptrdiff_t pref, int clip_max)
-{
-    const uint8_t *srcp_above = srcp + mref;
-    const uint8_t *srcp_below = srcp + pref;
-    const uint8_t *srcp_above2 = srcp + mref * 2;
-    const uint8_t *srcp_below2 = srcp + pref * 2;
-    int i, src_x, src_ab;
-    for (i = 0; i < width; i++) {
-        // this calculation is an integer representation of
-        // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
-        // '4 +' is for rounding.
-        src_x   = srcp[i] << 1;
-        src_ab  = srcp_above[i] + srcp_below[i];
-        dstp[i] = av_clip_uint8((4 + ((srcp[i] + src_x + src_ab) << 1)
-                                - srcp_above2[i] - srcp_below2[i]) >> 3);
-        // Prevent over-sharpening:
-        // dst must not exceed src when the average of above and below
-        // is less than src. And the other way around.
-        if (src_ab > src_x) {
-            if (dstp[i] < srcp[i])
-                dstp[i] = srcp[i];
-        } else if (dstp[i] > srcp[i])
-            dstp[i] = srcp[i];
-    }
-}
-
-static void lowpass_line_complex_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8,
-                                      ptrdiff_t mref, ptrdiff_t pref, int clip_max)
-{
-    uint16_t *dstp = (uint16_t *)dst8;
-    const uint16_t *srcp = (const uint16_t *)src8;
-    const uint16_t *srcp_above = srcp + mref / 2;
-    const uint16_t *srcp_below = srcp + pref / 2;
-    const uint16_t *srcp_above2 = srcp + mref;
-    const uint16_t *srcp_below2 = srcp + pref;
-    int i, dst_le, src_le, src_x, src_ab;
-    for (i = 0; i < width; i++) {
-        // this calculation is an integer representation of
-        // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
-        // '4 +' is for rounding.
-        src_le = av_le2ne16(srcp[i]);
-        src_x  = src_le << 1;
-        src_ab = av_le2ne16(srcp_above[i]) + av_le2ne16(srcp_below[i]);
-        dst_le = av_clip((4 + ((src_le + src_x + src_ab) << 1)
-                         - av_le2ne16(srcp_above2[i])
-                         - av_le2ne16(srcp_below2[i])) >> 3, 0, clip_max);
-        // Prevent over-sharpening:
-        // dst must not exceed src when the average of above and below
-        // is less than src. And the other way around.
-        if (src_ab > src_x) {
-            if (dst_le < src_le)
-                dstp[i] = av_le2ne16(src_le);
-            else
-                dstp[i] = av_le2ne16(dst_le);
-        } else if (dst_le > src_le) {
-            dstp[i] = av_le2ne16(src_le);
-        } else
-            dstp[i] = av_le2ne16(dst_le);
-    }
-}
-
-/**
- * alocate memory for a black frame
- */
-static int init_black_buffers(ReInterlaceContext *reinterlace, AVFilterLink *outlink)
-{
-    FFDrawContext ctx;
-    FFDrawColor color;
-    int ret;
-    int format = outlink->format;
-
-    if ((ret = av_image_alloc(reinterlace->black_vec, reinterlace->black_linesize,
-                         outlink->w, outlink->h, outlink->format, 16)) < 0)
-        return ret;
-
-    ff_draw_init(&ctx, outlink->format, 0);
-    ff_draw_color(&ctx, &color, (uint8_t[]){0, 0, 0, 16});
-    if (format == AV_PIX_FMT_YUVJ420P ||
-        format == AV_PIX_FMT_YUVJ422P ||
-        format == AV_PIX_FMT_YUVJ440P ||
-        format == AV_PIX_FMT_YUVJ444P)
-        color.comp[0].u8[0] = 0;
-    ff_fill_rectangle(&ctx, &color, reinterlace->black_vec,
-                      reinterlace->black_linesize, 0, 0, outlink->w, outlink->h);
-
-    return 0;
-}
-
-static int config_out_props(AVFilterLink *outlink)
-{
-    AVFilterContext *ctx = outlink->src;
-    AVFilterLink *inlink = outlink->src->inputs[0];
-    ReInterlaceContext *reinterlace = ctx->priv;
-    const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(outlink->format);
-    int reinterlace_mode = reinterlace->mode;
-    int ret, i;
-
-    reinterlace->bit_depth = fmt_desc->comp[0].depth;
-    reinterlace->preout_time_base = inlink->time_base;
-
-    switch (reinterlace_mode) {
-    case MODE_PAD:
-        outlink->w = inlink->w;
-        outlink->h = 2 * inlink->h;
-        outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1));
-
-        ret = init_black_buffers(reinterlace, outlink);
-        if (ret < 0)
-            return ret;
-        break;
-
-    case MODE_DROP_EVEN:
-    case MODE_DROP_ODD:
-        outlink->w = inlink->w;
-        outlink->h = inlink->h;
-        outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
-        outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){2,1});
-        break;
-
-    case MODE_INTERLEAVE_TOP:
-    case MODE_INTERLEAVE_BOTTOM:
-        outlink->w = inlink->w;
-        outlink->h = inlink->h;
-        outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
-        outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){2,1});
-        break;
-
-    case MODE_INTERLACE_X2:
-        outlink->w = inlink->w;
-        outlink->h = inlink->h;
-        reinterlace->preout_time_base.den *= 2;
-        outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2,1});
-        outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){1,2});
-        break;
-
-    case MODE_MERGE_X2:
-        outlink->w = inlink->w;
-        outlink->h = 2 * inlink->h;
-        outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1));
-        outlink->frame_rate = inlink->frame_rate;
-        outlink->time_base  = inlink->time_base;
-        break;
-
-    case MODE_MERGE:
-    case MODE_MERGE_BFF:
-    case MODE_MERGE_TFF:
-        outlink->w = inlink->w;
-        outlink->h = 2 * inlink->h;
-        outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1));
-        outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
-        outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){2,1});
-        break;
-
-    default:
-        av_log(ctx, AV_LOG_VERBOSE, "invalid value for mode");
-        av_assert0(0);
-
-    }
-
-    for (i = 0; i < FF_ARRAY_ELEMS(standard_tbs); i++) {
-        if (!av_cmp_q(standard_tbs[i], outlink->time_base))
-            break;
-    }
-    if (i == FF_ARRAY_ELEMS(standard_tbs) || (reinterlace->flags & FLAG_EXACT_TB) )
-        outlink->time_base = reinterlace->preout_time_base;
-
-    if (reinterlace->flags & FLAG_VLPF || reinterlace->flags & FLAG_CVLPF) {
-
-        if (reinterlace_mode != MODE_INTERLEAVE_TOP && reinterlace_mode != MODE_INTERLEAVE_BOTTOM) {
-            reinterlace->flags &= ~(FLAG_VLPF | FLAG_CVLPF);
-        } else {
-            reinterlace->lowpass_line = (reinterlace->flags & FLAG_VLPF) ? lowpass_line_c : lowpass_line_complex_c;
-
-            if (reinterlace->bit_depth > 8) {
-                reinterlace->lowpass_line = (reinterlace->flags & FLAG_VLPF) ? lowpass_line_c_16 : lowpass_line_complex_c_16;
-            }
-
-#if CONFIG_GPL
-            if (ARCH_X86) {
-                ff_reinterlace_init_x86(reinterlace);
-            }
-#endif
-        }
-
-    }
-
-    return 0;
-}
-
-static int filter_frame_plane(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
-{
-    // jobnr is usualy plane number
-    ReInterlaceThreadData *rtd = arg;
-    ReInterlaceContext *reinterlace = rtd->reinterlace;
-    AVFrame *first = rtd->first;
-    AVFrame *second = rtd->second;
-    AVFrame *out = rtd->out;
-
-    int plane = rtd->plane;
-    int reinterlace_mode = reinterlace->mode;
-
-    int x = (plane == 1 || plane == 2) ? rtd->scale_w_plane12_factor : 1;
-    int y = (plane == 1 || plane == 2) ? rtd->scale_h_plane12_factor : 1;
-    int i, ls_offset;
-    int offset1, offset2, offset3, offset4;
-
-    const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(out->format);
-    int clip_max = (1 << fmt_desc->comp[plane].depth) - 1;
-    int mult = (fmt_desc->comp[0].depth > 8 ? 2 : 1);
-
-    switch (reinterlace_mode) {
-    case MODE_MERGE:
-        av_image_copy_plane(out->data[plane], 2 * out->linesize[plane],
-            first->data[plane], first->linesize[plane], mult * first->width / x, first->height / y);
-        av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane],
-            second->data[plane], second->linesize[plane], mult * second->width / x, second->height / y);
-        break;
-
-    case MODE_PAD:
-        ls_offset = (reinterlace->current_frame_index & 1) ? 0 : out->linesize[plane];
-        av_image_copy_plane(out->data[plane] + ls_offset, 2 * out->linesize[plane],
-            second->data[plane], second->linesize[plane], mult * second->width / x, second->height / y);
-        av_image_copy_plane(out->data[plane] + out->linesize[plane] - ls_offset, 2 * out->linesize[plane],
-            reinterlace->black_vec[plane], reinterlace->black_linesize[plane], mult * second->width / x, second->height / y);
-        break;
-
-    case MODE_INTERLEAVE_BOTTOM:
-    case MODE_INTERLEAVE_TOP:
-        y = y * 2;
-
-        if (reinterlace->flags & FLAG_VLPF || reinterlace->flags & FLAG_CVLPF) {
-
-            int lines, cols, cvlfp;
-            AVFrame *from_frame;
-            uint8_t *from, *to;
-            int from_step, to_step;
-
-            lines = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? (2 * out->height / y + 1) / 2 : (2 * out->height / y + 0) / 2;
-            cols = out->width / x;
-            from_frame = first;
-            from = from_frame->data[plane];
-            to = out->data[plane];
-
-            if (reinterlace_mode == MODE_INTERLEAVE_BOTTOM) {
-                from = from + from_frame->linesize[plane];
-                to = to + out->linesize[plane];
-            }
-
-            from_step = 2 * from_frame->linesize[plane];
-            to_step = 2 * out->linesize[plane];
-
-            // when i = lines - aka first line
-            reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], 0, clip_max);
-            to += to_step;
-            from += from_step;
-
-            cvlfp = !!(reinterlace->flags & FLAG_CVLPF);
-            if (cvlfp) {
-                reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], 0, clip_max);
-                to += to_step;
-                from += from_step;
-            }
-
-            for (i = lines - 2 - 2 * cvlfp; i; i--) {
-                reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], -from_frame->linesize[plane], clip_max);
-                to += to_step;
-                from += from_step;
-            }
-
-            // when i == 1 - aka last line
-            reinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max);
-            to += to_step;
-            from += from_step;
-
-            if (cvlfp) {
-                reinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max);
-                to += to_step;
-                from += from_step;
-            }
-
-
-            lines = (reinterlace_mode == MODE_INTERLEAVE_BOTTOM) ? ((2 * out->height / y) + 1) / 2 : (2 * out->height / y + 0) / 2;
-            cols = out->width / x;
-            from_frame = second;
-            from = from_frame->data[plane];
-            to = out->data[plane];
-
-            if (reinterlace_mode == MODE_INTERLEAVE_TOP) {
-                from = from + from_frame->linesize[plane];
-                to = to + out->linesize[plane];
-            }
-
-            from_step = 2 * from_frame->linesize[plane];
-            to_step = 2 * out->linesize[plane];
-
-            // when i = lines
-            reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], 0, clip_max);
-            to += to_step;
-            from += from_step;
-
-            if (cvlfp) {
-                reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], 0, clip_max);
-                to += to_step;
-                from += from_step;
-            }
-
-
-            for (i = lines - 2 - 2 * cvlfp; i; i--) {
-                reinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], -from_frame->linesize[plane], clip_max);
-                to += to_step;
-                from += from_step;
-            }
-
-            // when i == 1
-            reinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max);
-            to += to_step;
-            from += from_step;
-
-            if (cvlfp) {
-                reinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max);
-                to += to_step;
-                from += from_step;
-            }
-
-        } else {
-            offset1 = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 : out->linesize[plane];
-            offset2 = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 : first->linesize[plane];
-            offset3 = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? out->linesize[plane]    : 0;
-            offset4 = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? second->linesize[plane] : 0;
-
-            av_image_copy_plane(out->data[plane] + offset1, 2 * out->linesize[plane],
-                first->data[plane] + offset2, 2 * first->linesize[plane],
-                first->width / x, first->height / y);
-            av_image_copy_plane(out->data[plane] + offset3, 2 * out->linesize[plane],
-                second->data[plane] + offset4, 2 * second->linesize[plane],
-                second->width / x, second->height / y);
-        }
-        break;
-
-    case MODE_INTERLACE_X2:
-        y = y * 2;
-
-        offset1 = 0; offset2 = 0;
-        offset3 = out->linesize[plane];
-        offset4 = second->linesize[plane];
-
-        if (second->interlaced_frame && second->top_field_first) {
-            offset1 = out->linesize[plane];
-            offset2 = first->linesize[plane];
-            offset3 = 0; offset4 = 0;
-        }
-
-        av_image_copy_plane(out->data[plane] + offset1, 2 * out->linesize[plane],
-            first->data[plane] + offset2, 2 * first->linesize[plane],
-            first->width / x, first->height / y);
-        av_image_copy_plane(out->data[plane] + offset3, 2 * out->linesize[plane],
-            second->data[plane] + offset4, 2 * second->linesize[plane],
-            second->width / x, second->height / y);
-        break;
-
-    case MODE_MERGE_X2:
-        if (IS_ODD(reinterlace->current_frame_index - 1)) {
-            av_image_copy_plane(out->data[plane], 2 * out->linesize[plane],
-                second->data[plane], second->linesize[plane], second->width / x, second->height / y);
-            av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane],
-                first->data[plane], first->linesize[plane], first->width / x, first->height / y);
-        } else {
-            av_image_copy_plane(out->data[plane], 2 * out->linesize[plane],
-                first->data[plane], first->linesize[plane], first->width / x, first->height / y);
-            av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane],
-                second->data[plane], second->linesize[plane], second->width / x, second->height / y);
-        }
-        break;
-
-    case MODE_MERGE_TFF:
-    case MODE_MERGE_BFF:
-        offset1 = (reinterlace_mode == MODE_MERGE_TFF) ? 0 : out->linesize[plane];
-        offset2 = (reinterlace_mode == MODE_MERGE_TFF) ? out->linesize[plane] : 0;
-
-        av_image_copy_plane(out->data[plane] + offset1, 2 * out->linesize[plane],
-            first->data[plane], first->linesize[plane], first->width / x, first->height / y);
-        av_image_copy_plane(out->data[plane] + offset2, 2 * out->linesize[plane],
-            second->data[plane], second->linesize[plane], second->width / x, second->height / y);
-        break;
-
-    default:
-        break;
-    }
-
-    return 0;
-}
-
-static ReInterlaceThreadData *get_ReInterlaceThreadData(AVFrame *out, AVFrame *first, AVFrame *second,
-                int plane, ReInterlaceContext *reinterlace,
-                int scale_w_plane12_factor,
-                int scale_h_plane12_factor)
-{
-    ReInterlaceThreadData *rtd = &((ReInterlaceThreadData *)reinterlace->thread_data)[plane];
-
-    if (!rtd)
-        return rtd;
-
-    rtd->out = out;
-    rtd->first = first;
-    rtd->second = second;
-    rtd->plane = plane;
-    rtd->reinterlace = reinterlace;
-    rtd->scale_h_plane12_factor = scale_h_plane12_factor;
-    rtd->scale_w_plane12_factor = scale_w_plane12_factor;
-
-    return rtd;
-}
-
-static void copy_all_planes(AVFilterContext *ctx,
-    ReInterlaceContext *reinterlace,
-    const AVPixFmtDescriptor *desc,
-    AVFrame *out, AVFrame *first, AVFrame *second)
-{
-    int scale_w_plane12_factor = 1 << desc->log2_chroma_w;
-    int scale_h_plane12_factor = 1 << desc->log2_chroma_h;
-    int plane;
-
-    for (plane = 0; plane < desc->nb_components; plane++) {
-
-        ReInterlaceThreadData *rtd = get_ReInterlaceThreadData(out, first, second,
-            plane, reinterlace, scale_w_plane12_factor, scale_h_plane12_factor);
-
-        ctx->internal->execute(ctx, filter_frame_plane, rtd, NULL, FFMIN(desc->nb_components, ctx->graph->nb_threads));
-    }
-}
-
-static int filter_frame(AVFilterLink *inlink, AVFrame *in)
-{
-    AVFilterContext *ctx            = inlink->dst;
-    ReInterlaceContext *reinterlace = ctx->priv;
-    AVFilterLink *outlink           = ctx->outputs[0];
-    const AVPixFmtDescriptor *desc  = av_pix_fmt_desc_get(outlink->format);
-    AVFrame *out, *first, *second;
-    int ret;
-
-    int reinterlace_mode = reinterlace->mode;
-
-    av_frame_free(&(reinterlace->prev_frame));
-    reinterlace->prev_frame = reinterlace->current_frame;
-    reinterlace->current_frame = in;
-    reinterlace->current_frame_index++;
-
-    // we process two frames at a time, thus only even frame indexes are considered
-    if (IS_ODD(reinterlace->current_frame_index)) {
-        if (reinterlace_mode == MODE_PAD || reinterlace_mode == MODE_MERGE_X2
-            || reinterlace_mode == MODE_INTERLACE_X2 || reinterlace_mode == MODE_MERGE_BFF
-            || reinterlace_mode == MODE_MERGE_TFF) {
-            // continue
-        } else {
-            return 0;
-        }
-    }
-
-    first   = reinterlace->prev_frame;
-    second  = reinterlace->current_frame;
-
-    switch (reinterlace_mode) {
-    case MODE_DROP_EVEN:
-    case MODE_DROP_ODD:
-        out = (reinterlace_mode == MODE_DROP_ODD) ? reinterlace->current_frame : reinterlace->prev_frame;
-        out = av_frame_clone(out);
-
-        if (!out)
-            return AVERROR(ENOMEM);
-
-        out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base);
-        ret = ff_filter_frame(outlink, out);
-        break;
-
-    case MODE_MERGE:
-    case MODE_MERGE_X2:
-    case MODE_MERGE_TFF:
-    case MODE_MERGE_BFF:
-        if (reinterlace_mode == MODE_MERGE_X2 && reinterlace->current_frame_index == 1)
-            return 0;
-
-        if (reinterlace_mode == MODE_MERGE_BFF || reinterlace_mode == MODE_MERGE_TFF) {
-           if (!first)
-                return 0;
-
-            if (reinterlace->skip_next_frame) {
-                reinterlace->skip_next_frame = 0;
-                return 0;
-            }
-
-            if (first->interlaced_frame == 1 && second->interlaced_frame == 1)
-            {
-                if (first->top_field_first == second->top_field_first)
-                    return 0;
-                else if (reinterlace->mode == MODE_MERGE_BFF && first->top_field_first != 0)
-                    return 0;
-                else if (reinterlace->mode == MODE_MERGE_TFF && first->top_field_first != 1)
-                    return 0;
-            }
-        }
-
-        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
-
-        if (!out)
-            return AVERROR(ENOMEM);
-
-        av_frame_copy_props(out, first);
-        out->sample_aspect_ratio    = av_mul_q(first->sample_aspect_ratio, av_make_q(2, 1));
-        out->interlaced_frame       = 1;
-        out->top_field_first        = reinterlace_mode == MODE_MERGE_BFF ? 0 : 1;
-        out->height                 = outlink->h;
-
-        copy_all_planes(ctx, reinterlace, desc, out, first, second);
-
-        if (reinterlace_mode == MODE_MERGE_BFF || reinterlace_mode == MODE_MERGE_TFF)
-            reinterlace->skip_next_frame = 1;
-
-        out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base);
-        ret = ff_filter_frame(outlink, out);
-        break;
-
-    case MODE_PAD:
-        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
-
-        if (!out)
-            return AVERROR(ENOMEM);
-
-        av_frame_copy_props(out, second);
-        out->sample_aspect_ratio = av_mul_q(second->sample_aspect_ratio, av_make_q(2, 1));
-        out->height = outlink->h;
-
-        copy_all_planes(ctx, reinterlace, desc, out, first, second);
-
-        out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base);
-        ret = ff_filter_frame(outlink, out);
-        break;
-
-    case MODE_INTERLEAVE_BOTTOM:
-    case MODE_INTERLEAVE_TOP:
-        out  = ff_get_video_buffer(outlink, outlink->w, outlink->h);
-
-        if (!out)
-            return AVERROR(ENOMEM);
-
-        av_frame_copy_props(out, first);
-
-        copy_all_planes(ctx, reinterlace, desc, out, first, second);
-
-        out->interlaced_frame = 1;
-        out->top_field_first = (reinterlace_mode == MODE_INTERLEAVE_TOP) ? 1 : 0;
-
-        out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base);
-        ret = ff_filter_frame(outlink, out);
-        break;
-
-    case MODE_INTERLACE_X2:
-        if (reinterlace->current_frame_index == 1)
-            return 0;
-
-        out = av_frame_clone(first);
-
-        if (!out)
-            return AVERROR(ENOMEM);
-
-        // output first frame
-        out->pts = (AV_NOPTS_VALUE != first->pts ) ? first->pts * 2 : AV_NOPTS_VALUE;
-        out->interlaced_frame = 1;
-        out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base);
-        ret = ff_filter_frame(outlink, out);
-
-        if (ret < 0)
-            return ret;
-
-        // output the second frame interlaced with first frame
-        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
-
-        if (!out)
-            return AVERROR(ENOMEM);
-
-        av_frame_copy_props(out, second);
-        out->interlaced_frame = 1;
-        out->top_field_first = !out->top_field_first;
-        out->pts = first->pts + second->pts;
-        out->pts = ( first->pts == AV_NOPTS_VALUE || second->pts == AV_NOPTS_VALUE) ? AV_NOPTS_VALUE : out->pts;
-
-        copy_all_planes(ctx, reinterlace, desc, out, first, second);
-
-        out->pts = av_rescale_q(out->pts, reinterlace->preout_time_base, outlink->time_base);
-        ret = ff_filter_frame(outlink, out);
-        break;
-
-    default:
-        av_assert0(0);
-    }
-
-    return ret;
-}
-
-static av_cold void uninit(AVFilterContext *ctx)
-{
-    ReInterlaceContext *reinterlace = ctx->priv;
-
-    av_frame_free(&reinterlace->prev_frame);
-    av_frame_free(&reinterlace->current_frame);
-
-    if (reinterlace->black_vec[0] != NULL)
-    {
-        av_freep(&reinterlace->black_vec[0]);
-    }
-
-    av_free(reinterlace->thread_data);
-}
-
-static const AVFilterPad reinterlace_inputs[] = {
-    {
-        .name         = "default",
-        .type         = AVMEDIA_TYPE_VIDEO,
-        .filter_frame = filter_frame,
-    },
-    { NULL }
-};
-
-static const AVFilterPad reinterlace_outputs[] = {
-    {
-        .name = "default",
-        .type = AVMEDIA_TYPE_VIDEO,
-        .config_props = config_out_props,
-    },
-    { NULL }
-};
-
-AVFilter ff_vf_reinterlace = {
-    .name          = "reinterlace",
-    .description   = NULL_IF_CONFIG_SMALL("Various interlace frame manipulations"),
-    .priv_size     = sizeof(ReInterlaceContext),
-    .init          = init,
-    .uninit        = uninit,
-    .query_formats = query_formats,
-    .inputs        = reinterlace_inputs,
-    .outputs       = reinterlace_outputs,
-    .priv_class    = &reinterlace_class,
-    .flags         = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
-};
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
index 4f5c10d7ac..501f1f483e 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -1,60 +1,58 @@ 
 /*
+ * Copyright (c) 2018 Vasile Toncu <vasile.toncu@tremend.com>
  * Copyright (c) 2017 Thomas Mundt <tmundt75@gmail.com>
- * Copyright (c) 2011 Stefano Sabatini
- * Copyright (c) 2010 Baptiste Coudurier
- * Copyright (c) 2003 Michael Zucchi <notzed@ximian.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 General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * 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 General Public License for more details.
+ * 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 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.
+ * 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
- * temporal field interlace filter, ported from MPlayer/libmpcodecs
+ * TInterlace filter
  */
 
-#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
 #include "libavutil/imgutils.h"
-#include "libavutil/avassert.h"
-#include "avfilter.h"
-#include "internal.h"
+#include "drawutils.h"
 #include "tinterlace.h"
 
-#define OFFSET(x) offsetof(TInterlaceContext, x)
-#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+static const AVRational standard_tbs[] = {
+    {1, 25},
+    {1, 30},
+    {1001, 30000},
+};
 
 static const AVOption tinterlace_options[] = {
-    {"mode",              "select interlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE}, 0, MODE_NB-1, FLAGS, "mode"},
-    {"merge",             "merge fields",                                 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE},             INT_MIN, INT_MAX, FLAGS, "mode"},
-    {"drop_even",         "drop even fields",                             0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_EVEN},         INT_MIN, INT_MAX, FLAGS, "mode"},
-    {"drop_odd",          "drop odd fields",                              0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_ODD},          INT_MIN, INT_MAX, FLAGS, "mode"},
-    {"pad",               "pad alternate lines with black",               0, AV_OPT_TYPE_CONST, {.i64=MODE_PAD},               INT_MIN, INT_MAX, FLAGS, "mode"},
-    {"interleave_top",    "interleave top and bottom fields",             0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP},    INT_MIN, INT_MAX, FLAGS, "mode"},
-    {"interleave_bottom", "interleave bottom and top fields",             0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, "mode"},
-    {"interlacex2",       "interlace fields from two consecutive frames", 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLACEX2},       INT_MIN, INT_MAX, FLAGS, "mode"},
-    {"mergex2",           "merge fields keeping same frame rate",         0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGEX2},           INT_MIN, INT_MAX, FLAGS, "mode"},
-
-    {"flags",             "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, 0, INT_MAX, 0, "flags" },
-    {"low_pass_filter",   "enable vertical low-pass filter",              0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
-    {"vlpf",              "enable vertical low-pass filter",              0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
-    {"complex_filter",    "enable complex vertical low-pass filter",      0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
-    {"cvlpf",             "enable complex vertical low-pass filter",      0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
-    {"exact_tb",          "force a timebase which can represent timestamps exactly", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_EXACT_TB}, INT_MIN, INT_MAX, FLAGS, "flags" },
-
-    {NULL}
+    { "mode",               "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE},     0, MODE_NB - 1, FLAGS, "mode" },
+    { "merge",              "merge frames",                                 0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE},                INT_MIN, INT_MAX, FLAGS, "mode"},
+    { "drop_even",          "drop even frames",                             0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_EVEN},            INT_MIN, INT_MAX, FLAGS, "mode"},
+    { "drop_odd",           "drop odd frames",                              0, AV_OPT_TYPE_CONST, {.i64=MODE_DROP_ODD},             INT_MIN, INT_MAX, FLAGS, "mode"},
+    { "pad",                "pad lines of a frame with black lines",        0, AV_OPT_TYPE_CONST, {.i64=MODE_PAD},                  INT_MIN, INT_MAX, FLAGS, "mode"},
+    { "interleave_top",     "interleave top and bottom frames",             0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP},       INT_MIN, INT_MAX, FLAGS, "mode"},
+    { "interleave_bottom",  "interleave bottom and top frames",             0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM},    INT_MIN, INT_MAX, FLAGS, "mode"},
+    { "interlacex2",        "interlace consecutive frames",                 0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLACE_X2},         INT_MIN, INT_MAX, FLAGS, "mode"},
+    { "mergex2",            "just like merge, but at the same frame rate",  0, AV_OPT_TYPE_CONST, {.i64=MODE_MERGE_X2},             INT_MIN, INT_MAX, FLAGS, "mode"},
+
+    { "flags",              "add flag for tinterlace", OFFSET(flags), AV_OPT_TYPE_INT, {.i64=FLAG_NOTHING}, 0, 0xFF, FLAGS, "flags" },
+    { "low_pass_filter",    "low pass fitler",                              0, AV_OPT_TYPE_CONST, {.i64 = FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags"},
+    { "vlpf",               "low pass filter",                              0, AV_OPT_TYPE_CONST, {.i64 = FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags"},
+    { "complex_filter",     "enable complex vertical low-pass filter",      0, AV_OPT_TYPE_CONST, {.i64 = FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
+    { "cvlpf",              "enable complex vertical low-pass filter",      0, AV_OPT_TYPE_CONST, {.i64 = FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
+    { "exact_tb",           "force a timebase which can represent timestamps exactly", 0, AV_OPT_TYPE_CONST, {.i64 = FLAG_EXACT_TB}, INT_MIN, INT_MAX, FLAGS, "flags" },
+    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(tinterlace);
@@ -63,28 +61,26 @@  static const AVOption interlace_options[] = {
    { "scan",              "scanning mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_INTERLEAVE_TOP}, 0, MODE_NB-1, FLAGS, "mode"},
    { "tff",               "top field first",                              0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_TOP},    INT_MIN, INT_MAX, FLAGS, .unit = "mode" },
    { "bff",               "bottom field first",                           0, AV_OPT_TYPE_CONST, {.i64=MODE_INTERLEAVE_BOTTOM}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"},
-   { "lowpass",           "set vertical low-pass filter", OFFSET(flags), AV_OPT_TYPE_FLAGS,   {.i64 = TINTERLACE_FLAG_VLPF}, 0,INT_MAX, 0, "flags" },
+   { "lowpass",           "set vertical low-pass filter", OFFSET(flags), AV_OPT_TYPE_FLAGS,   {.i64 = FLAG_VLPF}, 0,INT_MAX, 0, "flags" },
    { "off",               "disable vertical low-pass filter",             0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, FLAGS, "flags" },
-   { "linear",            "linear vertical low-pass filter",              0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
-   { "complex",           "complex vertical low-pass filter",             0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
+   { "linear",            "linear vertical low-pass filter",              0, AV_OPT_TYPE_CONST, {.i64 = FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" },
+   { "complex",           "complex vertical low-pass filter",             0, AV_OPT_TYPE_CONST, {.i64 = FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" },
 
    { NULL }
 };
 
 AVFILTER_DEFINE_CLASS(interlace);
 
-#define FULL_SCALE_YUVJ_FORMATS \
-    AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P
+static av_cold int init(AVFilterContext *ctx)
+{
+    TInterlaceContext *tinterlace = ctx->priv;
+    int i;
 
-static const enum AVPixelFormat full_scale_yuvj_pix_fmts[] = {
-    FULL_SCALE_YUVJ_FORMATS, AV_PIX_FMT_NONE
-};
+    for (i = 0; i < 4; i++)
+        tinterlace->black_vec[i] = NULL;
 
-static const AVRational standard_tbs[] = {
-    {1, 25},
-    {1, 30},
-    {1001, 30000},
-};
+    return 0;
+}
 
 static int query_formats(AVFilterContext *ctx)
 {
@@ -98,13 +94,16 @@  static int query_formats(AVFilterContext *ctx)
         AV_PIX_FMT_YUV440P12LE, AV_PIX_FMT_YUV444P12LE,
         AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
         AV_PIX_FMT_YUVA420P10LE, AV_PIX_FMT_YUVA422P10LE, AV_PIX_FMT_YUVA444P10LE,
-        AV_PIX_FMT_GRAY8, FULL_SCALE_YUVJ_FORMATS,
+        AV_PIX_FMT_GRAY8, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
+        AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P,
         AV_PIX_FMT_NONE
     };
 
     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
+
     if (!fmts_list)
         return AVERROR(ENOMEM);
+
     return ff_set_common_formats(ctx, fmts_list);
 }
 
@@ -202,315 +201,428 @@  static void lowpass_line_complex_c_16(uint8_t *dst8, ptrdiff_t width, const uint
     }
 }
 
-static av_cold void uninit(AVFilterContext *ctx)
+/**
+ * alocate memory for a black frame
+ */
+static int init_black_buffers(TInterlaceContext *tinterlace, AVFilterLink *outlink)
 {
-    TInterlaceContext *tinterlace = ctx->priv;
+    FFDrawContext ctx;
+    FFDrawColor color;
+    int ret;
+    int format = outlink->format;
+
+    if ((ret = av_image_alloc(tinterlace->black_vec, tinterlace->black_linesize,
+                         outlink->w, outlink->h, format, 16)) < 0)
+        return ret;
+
+    ff_draw_init(&ctx, outlink->format, 0);
+    ff_draw_color(&ctx, &color, (uint8_t[]){0, 0, 0, 16});
+    if (format == AV_PIX_FMT_YUVJ420P ||
+        format == AV_PIX_FMT_YUVJ422P ||
+        format == AV_PIX_FMT_YUVJ440P ||
+        format == AV_PIX_FMT_YUVJ444P)
+        color.comp[0].u8[0] = 0;
+    ff_fill_rectangle(&ctx, &color, tinterlace->black_vec,
+                      tinterlace->black_linesize, 0, 0, outlink->w, outlink->h);
 
-    av_frame_free(&tinterlace->cur );
-    av_frame_free(&tinterlace->next);
-    av_freep(&tinterlace->black_data[0]);
+    return 0;
 }
 
 static int config_out_props(AVFilterLink *outlink)
 {
     AVFilterContext *ctx = outlink->src;
     AVFilterLink *inlink = outlink->src->inputs[0];
-    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format);
     TInterlaceContext *tinterlace = ctx->priv;
-    int i;
+    const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(outlink->format);
+    int tinterlace_mode = tinterlace->mode;
+    int ret, i;
 
-    tinterlace->vsub = desc->log2_chroma_h;
-    outlink->w = inlink->w;
-    outlink->h = tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2?
-        inlink->h*2 : inlink->h;
-    if (tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD || tinterlace->mode == MODE_MERGEX2)
-        outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio,
-                                                av_make_q(2, 1));
-
-    if (tinterlace->mode == MODE_PAD) {
-        uint8_t black[4] = { 0, 0, 0, 16 };
-        int ret;
-        ff_draw_init(&tinterlace->draw, outlink->format, 0);
-        ff_draw_color(&tinterlace->draw, &tinterlace->color, black);
-        if (ff_fmt_is_in(outlink->format, full_scale_yuvj_pix_fmts))
-            tinterlace->color.comp[0].u8[0] = 0;
-        ret = av_image_alloc(tinterlace->black_data, tinterlace->black_linesize,
-                             outlink->w, outlink->h, outlink->format, 16);
+    tinterlace->bit_depth = fmt_desc->comp[0].depth;
+    tinterlace->preout_time_base = inlink->time_base;
+
+    switch (tinterlace_mode) {
+    case MODE_PAD:
+        outlink->w = inlink->w;
+        outlink->h = 2 * inlink->h;
+        outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1));
+
+        ret = init_black_buffers(tinterlace, outlink);
         if (ret < 0)
             return ret;
+        break;
 
-        ff_fill_rectangle(&tinterlace->draw, &tinterlace->color, tinterlace->black_data,
-                          tinterlace->black_linesize, 0, 0, outlink->w, outlink->h);
-    }
-    if (tinterlace->flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF)
-            && !(tinterlace->mode == MODE_INTERLEAVE_TOP
-              || tinterlace->mode == MODE_INTERLEAVE_BOTTOM)) {
-        av_log(ctx, AV_LOG_WARNING, "low_pass_filter flags ignored with mode %d\n",
-                tinterlace->mode);
-        tinterlace->flags &= ~(TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF);
-    }
-    tinterlace->preout_time_base = inlink->time_base;
-    if (tinterlace->mode == MODE_INTERLACEX2) {
+    case MODE_DROP_EVEN:
+    case MODE_DROP_ODD:
+        outlink->w = inlink->w;
+        outlink->h = inlink->h;
+        outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
+        outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){2,1});
+        break;
+
+    case MODE_INTERLEAVE_TOP:
+    case MODE_INTERLEAVE_BOTTOM:
+        outlink->w = inlink->w;
+        outlink->h = inlink->h;
+        outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
+        outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){2,1});
+        break;
+
+    case MODE_INTERLACE_X2:
+        outlink->w = inlink->w;
+        outlink->h = inlink->h;
         tinterlace->preout_time_base.den *= 2;
         outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){2,1});
         outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){1,2});
-    } else if (tinterlace->mode == MODE_MERGEX2) {
+        break;
+
+    case MODE_MERGE_X2:
+        outlink->w = inlink->w;
+        outlink->h = 2 * inlink->h;
+        outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1));
         outlink->frame_rate = inlink->frame_rate;
         outlink->time_base  = inlink->time_base;
-    } else if (tinterlace->mode != MODE_PAD) {
+        break;
+
+    case MODE_MERGE:
+        outlink->w = inlink->w;
+        outlink->h = 2 * inlink->h;
+        outlink->sample_aspect_ratio = av_mul_q(inlink->sample_aspect_ratio, av_make_q(2, 1));
         outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2});
         outlink->time_base  = av_mul_q(inlink->time_base , (AVRational){2,1});
+        break;
+
+    default:
+        av_log(ctx, AV_LOG_VERBOSE, "invalid value for mode");
+        av_assert0(0);
+
     }
 
-    for (i = 0; i<FF_ARRAY_ELEMS(standard_tbs); i++){
+    for (i = 0; i < FF_ARRAY_ELEMS(standard_tbs); i++) {
         if (!av_cmp_q(standard_tbs[i], outlink->time_base))
             break;
     }
-    if (i == FF_ARRAY_ELEMS(standard_tbs) ||
-        (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB))
+    if (i == FF_ARRAY_ELEMS(standard_tbs) || (tinterlace->flags & FLAG_EXACT_TB) )
         outlink->time_base = tinterlace->preout_time_base;
 
-    tinterlace->csp = av_pix_fmt_desc_get(outlink->format);
-    if (tinterlace->flags & TINTERLACE_FLAG_CVLPF) {
-        if (tinterlace->csp->comp[0].depth > 8)
-            tinterlace->lowpass_line = lowpass_line_complex_c_16;
-        else
-            tinterlace->lowpass_line = lowpass_line_complex_c;
-        if (ARCH_X86)
-            ff_tinterlace_init_x86(tinterlace);
-    } else if (tinterlace->flags & TINTERLACE_FLAG_VLPF) {
-        if (tinterlace->csp->comp[0].depth > 8)
-            tinterlace->lowpass_line = lowpass_line_c_16;
-        else
-            tinterlace->lowpass_line = lowpass_line_c;
-        if (ARCH_X86)
-            ff_tinterlace_init_x86(tinterlace);
+    if (tinterlace->flags & FLAG_VLPF || tinterlace->flags & FLAG_CVLPF) {
+
+        if (tinterlace_mode != MODE_INTERLEAVE_TOP && tinterlace_mode != MODE_INTERLEAVE_BOTTOM) {
+            av_log(ctx, AV_LOG_WARNING, "low_pass_filter flags ignored with mode %d\n", tinterlace_mode);
+            tinterlace->flags &= ~(FLAG_VLPF | FLAG_CVLPF);
+        } else {
+            tinterlace->lowpass_line = (tinterlace->flags & FLAG_VLPF) ? lowpass_line_c : lowpass_line_complex_c;
+
+            if (tinterlace->bit_depth > 8) {
+                tinterlace->lowpass_line = (tinterlace->flags & FLAG_VLPF) ? lowpass_line_c_16 : lowpass_line_complex_c_16;
+            }
+
+#if CONFIG_GPL
+            if (ARCH_X86) {
+                ff_tinterlace_init_x86(tinterlace);
+            }
+#endif
+        }
+
     }
 
-    av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n", tinterlace->mode,
-           (tinterlace->flags & TINTERLACE_FLAG_CVLPF) ? "complex" :
-           (tinterlace->flags & TINTERLACE_FLAG_VLPF) ? "linear" : "off",
-           inlink->h, outlink->h);
+    av_log(ctx, AV_LOG_VERBOSE, "mode:%d filter:%s h:%d -> h:%d\n", tinterlace_mode,
+            (tinterlace->flags & FLAG_CVLPF) ? "complex" :
+                (tinterlace->flags & FLAG_VLPF) ? "linear" : "off",
+            inlink->h, outlink->h);
 
     return 0;
 }
 
-#define FIELD_UPPER           0
-#define FIELD_LOWER           1
-#define FIELD_UPPER_AND_LOWER 2
-
-/**
- * Copy picture field from src to dst.
- *
- * @param src_field copy from upper, lower field or both
- * @param interleave leave a padding line between each copied line
- * @param dst_field copy to upper or lower field,
- *        only meaningful when interleave is selected
- * @param flags context flags
- */
 static inline
-void copy_picture_field(TInterlaceContext *tinterlace,
-                        uint8_t *dst[4], int dst_linesize[4],
-                        const uint8_t *src[4], int src_linesize[4],
-                        enum AVPixelFormat format, int w, int src_h,
-                        int src_field, int interleave, int dst_field,
-                        int flags)
+void interleave_filter_frame(TInterlaceContext *tinterlace, AVFrame *from_frame, AVFrame *out,
+                            int plane, int cvlfp, int mode, int x, int y, int clip_max)
 {
-    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(format);
-    int hsub = desc->log2_chroma_w;
-    int plane, vsub = desc->log2_chroma_h;
-    int k = src_field == FIELD_UPPER_AND_LOWER ? 1 : 2;
-    int h;
+    int lines = mode ? (2 * out->height / y + 1) / 2 : (2 * out->height / y) / 2;
+    int i = lines;
+    int cols = out->width / x;
+    uint8_t *from = from_frame->data[plane];
+    uint8_t *to = out->data[plane];
+    int from_step = 2 * from_frame->linesize[plane];
+    int to_step = 2 * out->linesize[plane];
+
+    if (!mode) {
+        from = from + from_frame->linesize[plane];
+        to = to + out->linesize[plane];
+    }
 
-    for (plane = 0; plane < desc->nb_components; plane++) {
-        int lines = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT(src_h, vsub) : src_h;
-        int cols  = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT(    w, hsub) : w;
-        uint8_t *dstp = dst[plane];
-        const uint8_t *srcp = src[plane];
-        int srcp_linesize = src_linesize[plane] * k;
-        int dstp_linesize = dst_linesize[plane] * (interleave ? 2 : 1);
-        int clip_max = (1 << tinterlace->csp->comp[plane].depth) - 1;
-
-        lines = (lines + (src_field == FIELD_UPPER)) / k;
-        if (src_field == FIELD_LOWER)
-            srcp += src_linesize[plane];
-        if (interleave && dst_field == FIELD_LOWER)
-            dstp += dst_linesize[plane];
-        // Low-pass filtering is required when creating an interlaced destination from
-        // a progressive source which contains high-frequency vertical detail.
-        // Filtering will reduce interlace 'twitter' and Moire patterning.
-        if (flags & (TINTERLACE_FLAG_VLPF | TINTERLACE_FLAG_CVLPF)) {
-            int x = !!(flags & TINTERLACE_FLAG_CVLPF);
-            for (h = lines; h > 0; h--) {
-                ptrdiff_t pref = src_linesize[plane];
-                ptrdiff_t mref = -pref;
-                if (h >= (lines - x))  mref = 0; // there is no line above
-                else if (h <= (1 + x)) pref = 0; // there is no line below
-
-                tinterlace->lowpass_line(dstp, cols, srcp, mref, pref, clip_max);
-                dstp += dstp_linesize;
-                srcp += srcp_linesize;
-            }
+    for (; i >= (lines - cvlfp); --i, from += from_step, to += to_step)
+        tinterlace->lowpass_line(to, cols, from, 0, from_frame->linesize[plane], clip_max);
+
+    for (; i > (1 + cvlfp); --i, from += from_step, to += to_step)
+        tinterlace->lowpass_line(to, cols, from, -from_frame->linesize[plane], from_frame->linesize[plane], clip_max);
+
+    for (; i > 0; --i, from += from_step, to += to_step)
+        tinterlace->lowpass_line(to, cols, from, -from_frame->linesize[plane], 0, clip_max);
+}
+
+static int filter_frame_plane(TInterlaceContext *tinterlace, AVFrame *first, AVFrame *second, AVFrame *out,
+                            int plane, int scale_w_plane12_factor, int scale_h_plane12_factor)
+{
+    int tinterlace_mode = tinterlace->mode;
+
+    int x = (plane == 1 || plane == 2) ? scale_w_plane12_factor : 1;
+    int y = (plane == 1 || plane == 2) ? scale_h_plane12_factor : 1;
+    int ls_offset, offset1, offset2, offset3, offset4;
+
+    const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(out->format);
+    int mult = (fmt_desc->comp[0].depth > 8 ? 2 : 1);
+
+    switch (tinterlace_mode) {
+    case MODE_MERGE:
+        av_image_copy_plane(out->data[plane], 2 * out->linesize[plane],
+            first->data[plane], first->linesize[plane], mult * first->width / x, first->height / y);
+        av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane],
+            second->data[plane], second->linesize[plane], mult * second->width / x, second->height / y);
+        break;
+
+    case MODE_PAD:
+        ls_offset = (tinterlace->current_frame_index & 1) ? 0 : out->linesize[plane];
+        av_image_copy_plane(out->data[plane] + ls_offset, 2 * out->linesize[plane],
+            second->data[plane], second->linesize[plane], mult * second->width / x, second->height / y);
+        av_image_copy_plane(out->data[plane] + out->linesize[plane] - ls_offset, 2 * out->linesize[plane],
+            tinterlace->black_vec[plane], tinterlace->black_linesize[plane], mult * second->width / x, second->height / y);
+        break;
+
+    case MODE_INTERLEAVE_BOTTOM:
+    case MODE_INTERLEAVE_TOP:
+        y = y * 2;
+
+        if (tinterlace->flags & FLAG_VLPF || tinterlace->flags & FLAG_CVLPF) {
+            int clip_max = (1 << fmt_desc->comp[plane].depth) - 1;
+
+            interleave_filter_frame(tinterlace, first, out, plane, !!(tinterlace->flags & FLAG_CVLPF), tinterlace_mode == MODE_INTERLEAVE_TOP, x, y, clip_max);
+            interleave_filter_frame(tinterlace, second, out, plane, !!(tinterlace->flags & FLAG_CVLPF), tinterlace_mode == MODE_INTERLEAVE_BOTTOM, x, y, clip_max);
         } else {
-            if (tinterlace->csp->comp[plane].depth > 8)
-                cols *= 2;
-            av_image_copy_plane(dstp, dstp_linesize, srcp, srcp_linesize, cols, lines);
+            offset1 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 : out->linesize[plane];
+            offset2 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 : first->linesize[plane];
+            offset3 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? out->linesize[plane]    : 0;
+            offset4 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? second->linesize[plane] : 0;
+
+            av_image_copy_plane(out->data[plane] + offset1, 2 * out->linesize[plane],
+                first->data[plane] + offset2, 2 * first->linesize[plane],
+                first->width / x, first->height / y);
+            av_image_copy_plane(out->data[plane] + offset3, 2 * out->linesize[plane],
+                second->data[plane] + offset4, 2 * second->linesize[plane],
+                second->width / x, second->height / y);
         }
+        break;
+
+    case MODE_INTERLACE_X2:
+        y = y * 2;
+
+        offset1 = 0; offset2 = 0;
+        offset3 = out->linesize[plane];
+        offset4 = second->linesize[plane];
+
+        if (second->interlaced_frame && second->top_field_first) {
+            offset1 = out->linesize[plane];
+            offset2 = first->linesize[plane];
+            offset3 = 0; offset4 = 0;
+        }
+
+        av_image_copy_plane(out->data[plane] + offset1, 2 * out->linesize[plane],
+            first->data[plane] + offset2, 2 * first->linesize[plane],
+            first->width / x, first->height / y);
+        av_image_copy_plane(out->data[plane] + offset3, 2 * out->linesize[plane],
+            second->data[plane] + offset4, 2 * second->linesize[plane],
+            second->width / x, second->height / y);
+        break;
+
+    case MODE_MERGE_X2:
+        if (IS_ODD(tinterlace->current_frame_index - 1)) {
+            av_image_copy_plane(out->data[plane], 2 * out->linesize[plane],
+                second->data[plane], second->linesize[plane], second->width / x, second->height / y);
+            av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane],
+                first->data[plane], first->linesize[plane], first->width / x, first->height / y);
+        } else {
+            av_image_copy_plane(out->data[plane], 2 * out->linesize[plane],
+                first->data[plane], first->linesize[plane], first->width / x, first->height / y);
+            av_image_copy_plane(out->data[plane] + out->linesize[plane], 2 * out->linesize[plane],
+                second->data[plane], second->linesize[plane], second->width / x, second->height / y);
+        }
+        break;
+
+    default:
+        break;
     }
+
+    return 0;
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
+static void copy_all_planes(AVFilterContext *ctx,
+    TInterlaceContext *tinterlace,
+    const AVPixFmtDescriptor *desc,
+    AVFrame *out, AVFrame *first, AVFrame *second)
 {
-    AVFilterContext *ctx = inlink->dst;
-    AVFilterLink *outlink = ctx->outputs[0];
-    TInterlaceContext *tinterlace = ctx->priv;
-    AVFrame *cur, *next, *out;
-    int field, tff, ret;
-
-    av_frame_free(&tinterlace->cur);
-    tinterlace->cur  = tinterlace->next;
-    tinterlace->next = picref;
-
-    cur = tinterlace->cur;
-    next = tinterlace->next;
-    /* we need at least two frames */
-    if (!tinterlace->cur)
-        return 0;
-
-    switch (tinterlace->mode) {
-    case MODE_MERGEX2: /* move the odd frame into the upper field of the new image, even into
-                        * the lower field, generating a double-height video at same framerate */
-    case MODE_MERGE: /* move the odd frame into the upper field of the new image, even into
-             * the lower field, generating a double-height video at half framerate */
-        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+    int scale_w_plane12_factor = 1 << desc->log2_chroma_w;
+    int scale_h_plane12_factor = 1 << desc->log2_chroma_h;
+    int plane;
+
+    for (plane = 0; plane < desc->nb_components; plane++) {
+        filter_frame_plane(tinterlace, first, second, out, plane,
+            scale_w_plane12_factor, scale_h_plane12_factor);
+    }
+}
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
+{
+    AVFilterContext *ctx            = inlink->dst;
+    TInterlaceContext *tinterlace   = ctx->priv;
+    AVFilterLink *outlink           = ctx->outputs[0];
+    const AVPixFmtDescriptor *desc  = av_pix_fmt_desc_get(outlink->format);
+    AVFrame *out, *first, *second;
+    int ret;
+
+    int tinterlace_mode = tinterlace->mode;
+
+    av_frame_free(&(tinterlace->prev_frame));
+    tinterlace->prev_frame = tinterlace->current_frame;
+    tinterlace->current_frame = in;
+    tinterlace->current_frame_index++;
+
+    // we process two frames at a time, thus only even frame indexes are considered
+    if (IS_ODD(tinterlace->current_frame_index)) {
+        if (tinterlace_mode == MODE_PAD || tinterlace_mode == MODE_MERGE_X2
+            || tinterlace_mode == MODE_INTERLACE_X2) {
+            // continue
+        } else {
+            return 0;
+        }
+    }
+
+    first   = tinterlace->prev_frame;
+    second  = tinterlace->current_frame;
+
+    switch (tinterlace_mode) {
+    case MODE_DROP_EVEN:
+    case MODE_DROP_ODD:
+        out = (tinterlace_mode == MODE_DROP_ODD) ? tinterlace->current_frame : tinterlace->prev_frame;
+        out = av_frame_clone(out);
+
         if (!out)
             return AVERROR(ENOMEM);
-        av_frame_copy_props(out, cur);
-        out->height = outlink->h;
-        out->interlaced_frame = 1;
-        out->top_field_first = 1;
-        out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1));
-
-        /* write odd frame lines into the upper field of the new frame */
-        copy_picture_field(tinterlace, out->data, out->linesize,
-                           (const uint8_t **)cur->data, cur->linesize,
-                           inlink->format, inlink->w, inlink->h,
-                           FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? inlink->frame_count_out & 1 ? FIELD_LOWER : FIELD_UPPER : FIELD_UPPER, tinterlace->flags);
-        /* write even frame lines into the lower field of the new frame */
-        copy_picture_field(tinterlace, out->data, out->linesize,
-                           (const uint8_t **)next->data, next->linesize,
-                           inlink->format, inlink->w, inlink->h,
-                           FIELD_UPPER_AND_LOWER, 1, tinterlace->mode == MODE_MERGEX2 ? inlink->frame_count_out & 1 ? FIELD_UPPER : FIELD_LOWER : FIELD_LOWER, tinterlace->flags);
-        if (tinterlace->mode != MODE_MERGEX2)
-            av_frame_free(&tinterlace->next);
+
+        out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
+        ret = ff_filter_frame(outlink, out);
         break;
 
-    case MODE_DROP_ODD:  /* only output even frames, odd  frames are dropped; height unchanged, half framerate */
-    case MODE_DROP_EVEN: /* only output odd  frames, even frames are dropped; height unchanged, half framerate */
-        out = av_frame_clone(tinterlace->mode == MODE_DROP_EVEN ? cur : next);
+    case MODE_MERGE:
+    case MODE_MERGE_X2:
+        if (tinterlace_mode == MODE_MERGE_X2 && tinterlace->current_frame_index == 1)
+            return 0;
+
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+
         if (!out)
             return AVERROR(ENOMEM);
-        av_frame_free(&tinterlace->next);
+
+        av_frame_copy_props(out, first);
+        out->sample_aspect_ratio    = av_mul_q(first->sample_aspect_ratio, av_make_q(2, 1));
+        out->interlaced_frame       = 1;
+        out->top_field_first        = 1;
+        out->height                 = outlink->h;
+
+        copy_all_planes(ctx, tinterlace, desc, out, first, second);
+
+        out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
+        ret = ff_filter_frame(outlink, out);
         break;
 
-    case MODE_PAD: /* expand each frame to double height, but pad alternate
-                    * lines with black; framerate unchanged */
+    case MODE_PAD:
         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+
         if (!out)
             return AVERROR(ENOMEM);
-        av_frame_copy_props(out, cur);
+
+        av_frame_copy_props(out, second);
+        out->sample_aspect_ratio = av_mul_q(second->sample_aspect_ratio, av_make_q(2, 1));
         out->height = outlink->h;
-        out->sample_aspect_ratio = av_mul_q(cur->sample_aspect_ratio, av_make_q(2, 1));
-
-        field = (1 + tinterlace->frame) & 1 ? FIELD_UPPER : FIELD_LOWER;
-        /* copy upper and lower fields */
-        copy_picture_field(tinterlace, out->data, out->linesize,
-                           (const uint8_t **)cur->data, cur->linesize,
-                           inlink->format, inlink->w, inlink->h,
-                           FIELD_UPPER_AND_LOWER, 1, field, tinterlace->flags);
-        /* pad with black the other field */
-        copy_picture_field(tinterlace, out->data, out->linesize,
-                           (const uint8_t **)tinterlace->black_data, tinterlace->black_linesize,
-                           inlink->format, inlink->w, inlink->h,
-                           FIELD_UPPER_AND_LOWER, 1, !field, tinterlace->flags);
+
+        copy_all_planes(ctx, tinterlace, desc, out, first, second);
+
+        out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
+        ret = ff_filter_frame(outlink, out);
         break;
 
-        /* interleave upper/lower lines from odd frames with lower/upper lines from even frames,
-         * halving the frame rate and preserving image height */
-    case MODE_INTERLEAVE_TOP:    /* top    field first */
-    case MODE_INTERLEAVE_BOTTOM: /* bottom field first */
-        tff = tinterlace->mode == MODE_INTERLEAVE_TOP;
-        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+    case MODE_INTERLEAVE_BOTTOM:
+    case MODE_INTERLEAVE_TOP:
+        out  = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+
         if (!out)
             return AVERROR(ENOMEM);
-        av_frame_copy_props(out, cur);
+
+        av_frame_copy_props(out, first);
+
+        copy_all_planes(ctx, tinterlace, desc, out, first, second);
+
         out->interlaced_frame = 1;
-        out->top_field_first = tff;
-
-        /* copy upper/lower field from cur */
-        copy_picture_field(tinterlace, out->data, out->linesize,
-                           (const uint8_t **)cur->data, cur->linesize,
-                           inlink->format, inlink->w, inlink->h,
-                           tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER,
-                           tinterlace->flags);
-        /* copy lower/upper field from next */
-        copy_picture_field(tinterlace, out->data, out->linesize,
-                           (const uint8_t **)next->data, next->linesize,
-                           inlink->format, inlink->w, inlink->h,
-                           tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER,
-                           tinterlace->flags);
-        av_frame_free(&tinterlace->next);
+        out->top_field_first = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 1 : 0;
+
+        out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
+        ret = ff_filter_frame(outlink, out);
         break;
-    case MODE_INTERLACEX2: /* re-interlace preserving image height, double frame rate */
-        /* output current frame first */
-        out = av_frame_clone(cur);
+
+    case MODE_INTERLACE_X2:
+        if (tinterlace->current_frame_index == 1)
+            return 0;
+
+        out = av_frame_clone(first);
+
         if (!out)
             return AVERROR(ENOMEM);
-        out->interlaced_frame = 1;
-        if (cur->pts != AV_NOPTS_VALUE)
-            out->pts = cur->pts*2;
 
+        // output first frame
+        out->pts = (AV_NOPTS_VALUE != first->pts ) ? first->pts * 2 : AV_NOPTS_VALUE;
+        out->interlaced_frame = 1;
         out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
-        if ((ret = ff_filter_frame(outlink, out)) < 0)
+        ret = ff_filter_frame(outlink, out);
+
+        if (ret < 0)
             return ret;
 
-        /* output mix of current and next frame */
-        tff = next->top_field_first;
+        // output the second frame interlaced with first frame
         out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+
         if (!out)
             return AVERROR(ENOMEM);
-        av_frame_copy_props(out, next);
+
+        av_frame_copy_props(out, second);
         out->interlaced_frame = 1;
-        out->top_field_first = !tff;
-
-        if (next->pts != AV_NOPTS_VALUE && cur->pts != AV_NOPTS_VALUE)
-            out->pts = cur->pts + next->pts;
-        else
-            out->pts = AV_NOPTS_VALUE;
-        /* write current frame second field lines into the second field of the new frame */
-        copy_picture_field(tinterlace, out->data, out->linesize,
-                           (const uint8_t **)cur->data, cur->linesize,
-                           inlink->format, inlink->w, inlink->h,
-                           tff ? FIELD_LOWER : FIELD_UPPER, 1, tff ? FIELD_LOWER : FIELD_UPPER,
-                           tinterlace->flags);
-        /* write next frame first field lines into the first field of the new frame */
-        copy_picture_field(tinterlace, out->data, out->linesize,
-                           (const uint8_t **)next->data, next->linesize,
-                           inlink->format, inlink->w, inlink->h,
-                           tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER,
-                           tinterlace->flags);
+        out->top_field_first = !out->top_field_first;
+        out->pts = first->pts + second->pts;
+        out->pts = ( first->pts == AV_NOPTS_VALUE || second->pts == AV_NOPTS_VALUE) ? AV_NOPTS_VALUE : out->pts;
+
+        copy_all_planes(ctx, tinterlace, desc, out, first, second);
+
+        out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
+        ret = ff_filter_frame(outlink, out);
         break;
+
     default:
         av_assert0(0);
     }
 
-    out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
-    ret = ff_filter_frame(outlink, out);
-    tinterlace->frame++;
-
     return ret;
 }
 
+static av_cold void uninit(AVFilterContext *ctx)
+{
+    TInterlaceContext *tinterlace = ctx->priv;
+
+    av_frame_free(&tinterlace->prev_frame);
+    av_frame_free(&tinterlace->current_frame);
+
+    if (tinterlace->black_vec[0] != NULL)
+    {
+        av_freep(&tinterlace->black_vec[0]);
+    }
+}
+
 static const AVFilterPad tinterlace_inputs[] = {
     {
         .name         = "default",
@@ -522,32 +634,35 @@  static const AVFilterPad tinterlace_inputs[] = {
 
 static const AVFilterPad tinterlace_outputs[] = {
     {
-        .name         = "default",
-        .type         = AVMEDIA_TYPE_VIDEO,
-        .config_props = config_out_props,
+        .name           = "default",
+        .type           = AVMEDIA_TYPE_VIDEO,
+        .config_props   = config_out_props,
     },
     { NULL }
 };
 
 AVFilter ff_vf_tinterlace = {
     .name          = "tinterlace",
-    .description   = NULL_IF_CONFIG_SMALL("Perform temporal field interlacing."),
+    .description   = NULL_IF_CONFIG_SMALL("Various interlace frame manipulations"),
     .priv_size     = sizeof(TInterlaceContext),
+    .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
     .inputs        = tinterlace_inputs,
     .outputs       = tinterlace_outputs,
     .priv_class    = &tinterlace_class,
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
 
-
 AVFilter ff_vf_interlace = {
     .name          = "interlace",
     .description   = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."),
     .priv_size     = sizeof(TInterlaceContext),
+    .init          = init,
     .uninit        = uninit,
     .query_formats = query_formats,
     .inputs        = tinterlace_inputs,
     .outputs       = tinterlace_outputs,
     .priv_class    = &interlace_class,
+    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile
index e31884aec0..b484c8bd1c 100644
--- a/libavfilter/x86/Makefile
+++ b/libavfilter/x86/Makefile
@@ -10,7 +10,6 @@  OBJS-$(CONFIG_HFLIP_FILTER)                  += x86/vf_hflip_init.o
 OBJS-$(CONFIG_HQDN3D_FILTER)                 += x86/vf_hqdn3d_init.o
 OBJS-$(CONFIG_IDET_FILTER)                   += x86/vf_idet_init.o
 OBJS-$(CONFIG_INTERLACE_FILTER)              += x86/vf_tinterlace_init.o
-OBJS-$(CONFIG_INTERLACE_FILTER)              += x86/vf_reinterlace_init.o
 OBJS-$(CONFIG_LIMITER_FILTER)                += x86/vf_limiter_init.o
 OBJS-$(CONFIG_MASKEDMERGE_FILTER)            += x86/vf_maskedmerge_init.o
 OBJS-$(CONFIG_NOISE_FILTER)                  += x86/vf_noise.o
diff --git a/libavfilter/x86/vf_reinterlace_init.c b/libavfilter/x86/vf_reinterlace_init.c
deleted file mode 100644
index 144db23beb..0000000000
--- a/libavfilter/x86/vf_reinterlace_init.c
+++ /dev/null
@@ -1,102 +0,0 @@ 
-/*
- * Copyright (c) 2018 Vasile Toncu <vasile.toncu@tremend.com>
- * Copyright (C) 2014 Kieran Kunhya <kierank@obe.tv>
- *
- * This file is part of FFmpeg.
- *
- * FFmpeg is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 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 General Public License for more details.
- *
- * You should have received a copy of the GNU 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.
- */
-
-#include "libavutil/attributes.h"
-#include "libavutil/cpu.h"
-#include "libavutil/internal.h"
-#include "libavutil/mem.h"
-#include "libavutil/x86/asm.h"
-#include "libavutil/x86/cpu.h"
-
-#include "libavfilter/reinterlace.h"
-
-#if CONFIG_GPL
-
-void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize,
-                          const uint8_t *srcp, ptrdiff_t mref,
-                          ptrdiff_t pref, int clip_max);
-void ff_lowpass_line_avx (uint8_t *dstp, ptrdiff_t linesize,
-                          const uint8_t *srcp, ptrdiff_t mref,
-                          ptrdiff_t pref, int clip_max);
-void ff_lowpass_line_avx2 (uint8_t *dstp, ptrdiff_t linesize,
-                          const uint8_t *srcp, ptrdiff_t mref,
-                          ptrdiff_t pref, int clip_max);
-
-void ff_lowpass_line_16_sse2(uint8_t *dstp, ptrdiff_t linesize,
-                             const uint8_t *srcp, ptrdiff_t mref,
-                             ptrdiff_t pref, int clip_max);
-void ff_lowpass_line_16_avx (uint8_t *dstp, ptrdiff_t linesize,
-                             const uint8_t *srcp, ptrdiff_t mref,
-                             ptrdiff_t pref, int clip_max);
-void ff_lowpass_line_16_avx2 (uint8_t *dstp, ptrdiff_t linesize,
-                             const uint8_t *srcp, ptrdiff_t mref,
-                             ptrdiff_t pref, int clip_max);
-
-void ff_lowpass_line_complex_sse2(uint8_t *dstp, ptrdiff_t linesize,
-                                  const uint8_t *srcp, ptrdiff_t mref,
-                                  ptrdiff_t pref, int clip_max);
-
-void ff_lowpass_line_complex_12_sse2(uint8_t *dstp, ptrdiff_t linesize,
-                                     const uint8_t *srcp, ptrdiff_t mref,
-                                     ptrdiff_t pref, int clip_max);
-
-av_cold void ff_reinterlace_init_x86(ReInterlaceContext *reinterlace)
-{
-    int cpu_flags = av_get_cpu_flags();
-
-    if (reinterlace->bit_depth > 8) {
-        if (EXTERNAL_SSE2(cpu_flags)) {
-            if (!(reinterlace->flags & FLAG_CVLPF))
-                reinterlace->lowpass_line = ff_lowpass_line_16_sse2;
-            else
-                reinterlace->lowpass_line = ff_lowpass_line_complex_12_sse2;
-        }
-        if (EXTERNAL_AVX(cpu_flags))
-            if (!(reinterlace->flags & FLAG_CVLPF))
-                reinterlace->lowpass_line = ff_lowpass_line_16_avx;
-        if (EXTERNAL_AVX2_FAST(cpu_flags)) {
-            if (!(reinterlace->flags & FLAG_CVLPF)) {
-                reinterlace->lowpass_line = ff_lowpass_line_16_avx2;
-            }
-        }
-    } else {
-        if (EXTERNAL_SSE2(cpu_flags)) {
-            if (!(reinterlace->flags & FLAG_CVLPF))
-                reinterlace->lowpass_line = ff_lowpass_line_sse2;
-            else
-                reinterlace->lowpass_line = ff_lowpass_line_complex_sse2;
-        }
-        if (EXTERNAL_AVX(cpu_flags))
-            if (!(reinterlace->flags & FLAG_CVLPF))
-                reinterlace->lowpass_line = ff_lowpass_line_avx;
-        if (EXTERNAL_AVX2_FAST(cpu_flags)) {
-            if (!(reinterlace->flags & FLAG_CVLPF)) {
-                reinterlace->lowpass_line = ff_lowpass_line_avx2;
-            }
-        }
-    }
-}
-
-#elif /* CONFIG_GPL */
-
-av_cold void ff_reinterlace_init_x86(ReInterlaceContext *s) {}
-
-#endif /* CONFIG_GPL */
diff --git a/libavfilter/x86/vf_tinterlace_init.c b/libavfilter/x86/vf_tinterlace_init.c
index 2c9b1de581..c14f62991d 100644
--- a/libavfilter/x86/vf_tinterlace_init.c
+++ b/libavfilter/x86/vf_tinterlace_init.c
@@ -1,4 +1,5 @@ 
 /*
+ * Copyright (c) 2018 Vasile Toncu <vasile.toncu@tremend.com>
  * Copyright (C) 2014 Kieran Kunhya <kierank@obe.tv>
  *
  * This file is part of FFmpeg.
@@ -27,6 +28,8 @@ 
 
 #include "libavfilter/tinterlace.h"
 
+#if CONFIG_GPL
+
 void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize,
                           const uint8_t *srcp, ptrdiff_t mref,
                           ptrdiff_t pref, int clip_max);
@@ -55,39 +58,45 @@  void ff_lowpass_line_complex_12_sse2(uint8_t *dstp, ptrdiff_t linesize,
                                      const uint8_t *srcp, ptrdiff_t mref,
                                      ptrdiff_t pref, int clip_max);
 
-av_cold void ff_tinterlace_init_x86(TInterlaceContext *s)
+av_cold void ff_tinterlace_init_x86(TInterlaceContext *tinterlace)
 {
     int cpu_flags = av_get_cpu_flags();
 
-    if (s->csp->comp[0].depth > 8) {
+    if (tinterlace->bit_depth > 8) {
         if (EXTERNAL_SSE2(cpu_flags)) {
-            if (!(s->flags & TINTERLACE_FLAG_CVLPF))
-                s->lowpass_line = ff_lowpass_line_16_sse2;
+            if (!(tinterlace->flags & FLAG_CVLPF))
+                tinterlace->lowpass_line = ff_lowpass_line_16_sse2;
             else
-                s->lowpass_line = ff_lowpass_line_complex_12_sse2;
+                tinterlace->lowpass_line = ff_lowpass_line_complex_12_sse2;
         }
         if (EXTERNAL_AVX(cpu_flags))
-            if (!(s->flags & TINTERLACE_FLAG_CVLPF))
-                s->lowpass_line = ff_lowpass_line_16_avx;
+            if (!(tinterlace->flags & FLAG_CVLPF))
+                tinterlace->lowpass_line = ff_lowpass_line_16_avx;
         if (EXTERNAL_AVX2_FAST(cpu_flags)) {
-            if (!(s->flags & TINTERLACE_FLAG_CVLPF)) {
-                s->lowpass_line = ff_lowpass_line_16_avx2;
+            if (!(tinterlace->flags & FLAG_CVLPF)) {
+                tinterlace->lowpass_line = ff_lowpass_line_16_avx2;
             }
         }
     } else {
         if (EXTERNAL_SSE2(cpu_flags)) {
-            if (!(s->flags & TINTERLACE_FLAG_CVLPF))
-                s->lowpass_line = ff_lowpass_line_sse2;
+            if (!(tinterlace->flags & FLAG_CVLPF))
+                tinterlace->lowpass_line = ff_lowpass_line_sse2;
             else
-                s->lowpass_line = ff_lowpass_line_complex_sse2;
+                tinterlace->lowpass_line = ff_lowpass_line_complex_sse2;
         }
         if (EXTERNAL_AVX(cpu_flags))
-            if (!(s->flags & TINTERLACE_FLAG_CVLPF))
-                s->lowpass_line = ff_lowpass_line_avx;
+            if (!(tinterlace->flags & FLAG_CVLPF))
+                tinterlace->lowpass_line = ff_lowpass_line_avx;
         if (EXTERNAL_AVX2_FAST(cpu_flags)) {
-            if (!(s->flags & TINTERLACE_FLAG_CVLPF)) {
-                s->lowpass_line = ff_lowpass_line_avx2;
+            if (!(tinterlace->flags & FLAG_CVLPF)) {
+                tinterlace->lowpass_line = ff_lowpass_line_avx2;
             }
         }
     }
 }
+
+#elif /* CONFIG_GPL */
+
+av_cold void ff_tinterlace_init_x86(TInterlaceContext *s) {}
+
+#endif /* CONFIG_GPL */
-- 
2.17.1