diff mbox

[FFmpeg-devel,3/5] reitnerlace - tinterlace-like filter under LGPL

Message ID a401b323-4b23-a25c-2639-467e705c1344@tremend.com
State Superseded
Headers show

Commit Message

Vasile Toncu April 23, 2018, 4:22 p.m. UTC
Hello,

Here is patch 3. Please review.

Thank you,
Vasile

Comments

Thomas Mundt April 25, 2018, 2:26 p.m. UTC | #1
Hi,

2018-04-23 18:22 GMT+02:00 Vasile Toncu <vasile.toncu@tremend.com>:

> Hello,
>
> Here is patch 3. Please review.
>
> Thank you,
> Vasile
>

Some fate tests fail when both patches are applied.
I also get lots of compiler warnings.
Please fix them and, as already said, run fate.
All tests must pass, otherwise there is something wrong with your filter.

Regards,
Thomas
diff mbox

Patch

From 180d0b61ca2d835bdc58a17db07d4c79532b1b1e Mon Sep 17 00:00:00 2001
From: Vasile Toncu <vasile.toncu@tremend.com>
Date: Mon, 23 Apr 2018 18:59:52 +0300
Subject: [PATCH] Patch3

Signed-off-by: Vasile Toncu <vasile.toncu@tremend.com>
---
 configure                             |   1 -
 libavfilter/Makefile                  |   1 -
 libavfilter/allfilters.c              |   1 -
 libavfilter/reinterlace.h             | 140 ------
 libavfilter/tinterlace.h              | 170 +++++--
 libavfilter/vf_reinterlace.c          | 754 ------------------------------
 libavfilter/vf_tinterlace.c           | 842 +++++++++++++++++++++-------------
 libavfilter/x86/Makefile              |   1 -
 libavfilter/x86/vf_reinterlace_init.c | 102 ----
 libavfilter/x86/vf_tinterlace_init.c  |  41 +-
 10 files changed, 678 insertions(+), 1375 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 a6f32f8..f1b4935 100755
--- a/configure
+++ b/configure
@@ -3387,7 +3387,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 5b503a1..cfb0f1d 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -291,7 +291,6 @@  OBJS-$(CONFIG_RANDOM_FILTER)                 += vf_random.o
 OBJS-$(CONFIG_READEIA608_FILTER)             += vf_readeia608.o
 OBJS-$(CONFIG_READVITC_FILTER)               += vf_readvitc.o
 OBJS-$(CONFIG_REALTIME_FILTER)               += f_realtime.o
-OBJS-$(CONFIG_REINTERLACE_FILTER)            += vf_reinterlace.o
 OBJS-$(CONFIG_REMAP_FILTER)                  += vf_remap.o framesync.o
 OBJS-$(CONFIG_REMOVEGRAIN_FILTER)            += vf_removegrain.o
 OBJS-$(CONFIG_REMOVELOGO_FILTER)             += bbox.o lswsutils.o lavfutils.o vf_removelogo.o
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 281eaa5..68b2992 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -282,7 +282,6 @@  extern AVFilter ff_vf_random;
 extern AVFilter ff_vf_readeia608;
 extern AVFilter ff_vf_readvitc;
 extern AVFilter ff_vf_realtime;
-extern AVFilter ff_vf_reinterlace;
 extern AVFilter ff_vf_remap;
 extern AVFilter ff_vf_removegrain;
 extern AVFilter ff_vf_removelogo;
diff --git a/libavfilter/reinterlace.h b/libavfilter/reinterlace.h
deleted file mode 100644
index 10832f5..0000000
--- a/libavfilter/reinterlace.h
+++ /dev/null
@@ -1,140 +0,0 @@ 
-/*
- * Copyright (c) 2018 Vasile Toncu <toncuvasile@gmail.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
- */
-
-#include <stdint.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
-};
-
-static const AVRational standard_tbs[] = {
-    {1, 25},
-    {1, 30},
-    {1001, 30000},
-};
-
-typedef struct {
-    const AVClass *class;
-    int mode;
-    int flags;
-
-    AVFrame *prev_frame, *current_frame;
-    int64_t current_frame_index;
-
-    void *black_vec[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
-
-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);
-
-#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;
-
-static enum AVPixelFormat all_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_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
-        AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
-};
-
diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h
index b5c39aa..702be3b 100644
--- a/libavfilter/tinterlace.h
+++ b/libavfilter/tinterlace.h
@@ -1,72 +1,154 @@ 
 /*
- * Copyright (c) 2011 Stefano Sabatini
- * Copyright (c) 2010 Baptiste Coudurier
- * Copyright (c) 2003 Michael Zucchi <notzed@ximian.com>
+ * Copyright (c) 2018 Vasile Toncu <toncuvasile@gmail.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
- */
-#ifndef AVFILTER_TINTERLACE_H
-#define AVFILTER_TINTERLACE_H
+#include <stdint.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_NB,
+    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
+};
+
+static const AVRational standard_tbs[] = {
+    {1, 25},
+    {1, 30},
+    {1001, 30000},
 };
 
-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 black_linesize[4];
-    FFDrawContext draw;
-    FFDrawColor color;
-    const AVPixFmtDescriptor *csp;
+    int mode;
+    int flags;
+
+    AVFrame *prev_frame, *current_frame;
+    int64_t current_frame_index;
+
+    void *black_vec[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;
+
 } TInterlaceContext;
 
-void ff_tinterlace_init_x86(TInterlaceContext *interlace);
+#if CONFIG_GPL
+void ff_tinterlace_init_x86(TInterlaceContext *tinterlace);
+#endif
+
+#define OFFSET(x) offsetof(TInterlaceContext, x)
+#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
+
+static const AVOption tinterlace_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 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);
+
+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 = 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 = 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 IS_ODD(value) (value & 1)
+
+typedef struct TInterlaceThreadData {
+    AVFrame *out, *first, *second;
+    int plane;
+    TInterlaceContext *tinterlace;
+
+    int scale_w_plane12_factor;
+    int scale_h_plane12_factor;
+
+} TInterlaceThreadData;
+
+static enum AVPixelFormat all_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_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
+        AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
+};
 
-#endif /* AVFILTER_TINTERLACE_H */
diff --git a/libavfilter/vf_reinterlace.c b/libavfilter/vf_reinterlace.c
deleted file mode 100644
index 7666a8d..0000000
--- a/libavfilter/vf_reinterlace.c
+++ /dev/null
@@ -1,754 +0,0 @@ 
-/*
- * Copyright (c) 2018 Vasile Toncu <toncuvasile@gmail.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 "reinterlace.h"
-
-
-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));
-
-    return 0;
-}
-
-static int query_formats(AVFilterContext *ctx)
-{
-
-    AVFilterFormats *fmts_list;
-
-    fmts_list = ff_make_format_list(all_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 *inlink, int format)
-{
-    int black_vec_size = inlink->w * inlink->h * 3 * ( (reinterlace->bit_depth > 8) ? 2 : 1 );
-    int val_black = 16;
-    int i;
-
-    if (format == AV_PIX_FMT_YUVJ420P ||
-        format == AV_PIX_FMT_YUVJ422P || 
-        format == AV_PIX_FMT_YUVJ440P || 
-        format == AV_PIX_FMT_YUVJ444P) {
-
-        val_black = 0;
-    
-    }
-
-    for (i = 0; i < 4; i++) {
-        if (reinterlace->bit_depth > 8) {
-            reinterlace->black_vec[i] = (uint16_t *) av_malloc(black_vec_size);
-        } else {
-            reinterlace->black_vec[i] = (uint8_t *) av_malloc(black_vec_size);
-        }
-        
-
-        if (!reinterlace->black_vec[i] )
-            return AVERROR(ENOMEM);
-
-        if (reinterlace->bit_depth > 8) {
-            memset( (uint16_t) reinterlace->black_vec[i], (i == 0 || i == 3 ? val_black : 128),  black_vec_size);
-        } else {
-            memset( (uint8_t) reinterlace->black_vec[i], (i == 0 || i == 3 ? val_black : 128),  black_vec_size);
-        }
-        
-    }
-
-    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;
-
-    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, inlink, outlink->format);
-
-        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);
-
-    }
-
-    int 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) || (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;
-
-    switch (reinterlace_mode) {
-    case MODE_MERGE:
-        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_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], 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], second->linesize[plane], 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;
-            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;
-
-            int 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);
-
-        filter_frame_plane(ctx, rtd, plane, desc->nb_components);
-    }
-}
-
-        
-
-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 = out->pts >> 1;
-        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;
-
-        //if (MODE_MERGE == reinterlace_mode) 
-        //    out->pts = out->pts >> 1;
-
-        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->pts = out->pts >> 1;
-        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;
-    int i;
-
-    for (i = 0; i < 4; i++)
-        if (reinterlace->black_vec[i])
-            av_free(reinterlace->black_vec[i]);
-
-    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 0e54fe3..581ec5e 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -1,110 +1,55 @@ 
 /*
+ * Copyright (c) 2018 Vasile Toncu <toncuvasile@gmail.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/imgutils.h"
-#include "libavutil/avassert.h"
-#include "avfilter.h"
-#include "internal.h"
 #include "tinterlace.h"
 
-#define OFFSET(x) offsetof(TInterlaceContext, x)
-#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
-
-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}
-};
 
-AVFILTER_DEFINE_CLASS(tinterlace);
+static av_cold int init(AVFilterContext *ctx)
+{
+    TInterlaceContext *tinterlace = ctx->priv;
+    int i;
 
-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" },
-   { "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" },
+    for (i = 0; i < 4; i++)
+        tinterlace->black_vec[i] = NULL;
 
-   { NULL }
-};
+    tinterlace->thread_data = av_malloc(4 * sizeof(TInterlaceThreadData));
 
-AVFILTER_DEFINE_CLASS(interlace);
+    return 0;
+}
 
-#define FULL_SCALE_YUVJ_FORMATS \
-    AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P
+static int query_formats(AVFilterContext *ctx)
+{
 
-static const enum AVPixelFormat full_scale_yuvj_pix_fmts[] = {
-    FULL_SCALE_YUVJ_FORMATS, AV_PIX_FMT_NONE
-};
+    AVFilterFormats *fmts_list;
 
-static const AVRational standard_tbs[] = {
-    {1, 25},
-    {1, 30},
-    {1001, 30000},
-};
+    fmts_list = ff_make_format_list(all_pix_fmts);
 
-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, FULL_SCALE_YUVJ_FORMATS,
-        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 +147,581 @@  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 *inlink, int format)
 {
-    TInterlaceContext *tinterlace = ctx->priv;
+    int black_vec_size = inlink->w * inlink->h * 3 * ( (tinterlace->bit_depth > 8) ? 2 : 1 );
+    int val_black = 16;
+    int i;
+
+    if (format == AV_PIX_FMT_YUVJ420P ||
+        format == AV_PIX_FMT_YUVJ422P || 
+        format == AV_PIX_FMT_YUVJ440P || 
+        format == AV_PIX_FMT_YUVJ444P) {
+
+        val_black = 0;
+    
+    }
+
+    for (i = 0; i < 4; i++) {
+        if (tinterlace->bit_depth > 8) {
+            tinterlace->black_vec[i] = (uint16_t *) av_malloc(black_vec_size);
+        } else {
+            tinterlace->black_vec[i] = (uint8_t *) av_malloc(black_vec_size);
+        }
+        
 
-    av_frame_free(&tinterlace->cur );
-    av_frame_free(&tinterlace->next);
-    av_freep(&tinterlace->black_data[0]);
+        if (!tinterlace->black_vec[i] )
+            return AVERROR(ENOMEM);
+
+        if (tinterlace->bit_depth > 8) {
+            memset( (uint16_t) tinterlace->black_vec[i], (i == 0 || i == 3 ? val_black : 128),  black_vec_size);
+        } else {
+            memset( (uint8_t) tinterlace->black_vec[i], (i == 0 || i == 3 ? val_black : 128),  black_vec_size);
+        }
+        
+    }
+
+    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;
+
+    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, inlink, outlink->format);
 
-    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);
         if (ret < 0)
-            return ret;
+           return ret;
 
-        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) {
+    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;
         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:
+    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++){
+    int 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);
-    }
 
-    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);
+    if (tinterlace->flags & FLAG_VLPF || tinterlace->flags & FLAG_CVLPF) {
 
+        if (tinterlace_mode != MODE_INTERLEAVE_TOP && tinterlace_mode != MODE_INTERLEAVE_BOTTOM) {
+            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
+        }
+
+    } 
+    
     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)
+static int filter_frame_plane(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
 {
-    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;
+    // jobnr is usualy plane number
+    TInterlaceThreadData *rtd = arg;
+    TInterlaceContext *tinterlace = rtd->tinterlace;
+    AVFrame *first = rtd->first;
+    AVFrame *second = rtd->second;
+    AVFrame *out = rtd->out;
+
+    int plane = rtd->plane;
+    int tinterlace_mode = tinterlace->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;
+
+    switch (tinterlace_mode) {
+    case MODE_MERGE:
+        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;
 
-    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;
+    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], 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], second->linesize[plane], 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 lines, cols;
+            AVFrame *from_frame;
+            uint8_t *from, *to;
+            int from_step, to_step;
+
+            lines = (tinterlace_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 (tinterlace_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
+            tinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], 0, clip_max);
+            to += to_step;
+            from += from_step;
+
+            int cvlfp = !!(tinterlace->flags & FLAG_CVLPF);
+            if (cvlfp) {
+                tinterlace->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--) {
+                tinterlace->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
+            tinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max);
+            to += to_step;
+            from += from_step;
+
+            if (cvlfp) {
+                tinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max);
+                to += to_step;
+                from += from_step;
+            }
+            
+
+            lines = (tinterlace_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 (tinterlace_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
+            tinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], 0, clip_max);
+            to += to_step;
+            from += from_step;
+
+            if (cvlfp) {
+                tinterlace->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--) {
+                tinterlace->lowpass_line(to, cols, from, from_frame->linesize[plane], -from_frame->linesize[plane], clip_max);
+                to += to_step;
+                from += from_step;
+            }
+
+            // when i == 1
+            tinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max);
+            to += to_step;
+            from += from_step;
+
+            if (cvlfp) {
+                tinterlace->lowpass_line(to, cols, from, 0, -from_frame->linesize[plane], clip_max);
+                to += to_step;
+                from += from_step;
             }
+
+        } else {
+            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 {
-            if (tinterlace->csp->comp[plane].depth > 8)
-                cols *= 2;
-            av_image_copy_plane(dstp, dstp_linesize, srcp, srcp_linesize, cols, lines);
+            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 = (tinterlace_mode == MODE_MERGE_TFF) ? 0 : out->linesize[plane];
+        offset2 = (tinterlace_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 TInterlaceThreadData *get_TInterlaceThreadData(AVFrame *out, AVFrame *first, AVFrame *second, 
+                int plane, TInterlaceContext *tinterlace, 
+                int scale_w_plane12_factor, 
+                int scale_h_plane12_factor)
+{
+    TInterlaceThreadData *rtd = &((TInterlaceThreadData *)tinterlace->thread_data)[plane];
+
+    if (!rtd)
+        return rtd;
+
+    rtd->out = out;
+    rtd->first = first;
+    rtd->second = second;
+    rtd->plane = plane;
+    rtd->tinterlace = tinterlace;
+    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, 
+    TInterlaceContext *tinterlace, 
+    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++) {
+
+        TInterlaceThreadData *rtd = get_TInterlaceThreadData(out, first, second, 
+            plane, tinterlace, scale_w_plane12_factor, scale_h_plane12_factor);
+
+        filter_frame_plane(ctx, rtd, plane, desc->nb_components);
     }
 }
 
-static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
+        
+
+static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
-    AVFilterContext *ctx = inlink->dst;
-    AVFilterLink *outlink = ctx->outputs[0];
+    AVFilterContext *ctx            = inlink->dst;
     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);
+    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 || tinterlace_mode == MODE_MERGE_BFF 
+            || tinterlace_mode == MODE_MERGE_TFF) {
+            // 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 = out->pts >> 1;
+        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:
+    case MODE_MERGE_TFF:
+    case MODE_MERGE_BFF:
+        if (tinterlace_mode == MODE_MERGE_X2 && tinterlace->current_frame_index == 1)
+            return 0;
+
+        if (tinterlace_mode == MODE_MERGE_BFF || tinterlace_mode == MODE_MERGE_TFF) {
+           if (!first)
+                return 0;
+
+            if (tinterlace->skip_next_frame) {
+                tinterlace->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 (tinterlace->mode == MODE_MERGE_BFF && first->top_field_first != 0)
+                    return 0;
+                else if (tinterlace->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_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        = tinterlace_mode == MODE_MERGE_BFF ? 0 : 1;
+        out->height                 = outlink->h;
+
+        //if (MODE_MERGE == tinterlace_mode) 
+        //    out->pts = out->pts >> 1;
+
+        copy_all_planes(ctx, tinterlace, desc, out, first, second);
+
+        if (tinterlace_mode == MODE_MERGE_BFF || tinterlace_mode == MODE_MERGE_TFF) 
+            tinterlace->skip_next_frame = 1;
+
+        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->pts = out->pts >> 1;
         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;
+    int i;
+
+    for (i = 0; i < 4; i++)
+        if (tinterlace->black_vec[i])
+            av_free(tinterlace->black_vec[i]);
+
+    av_free(tinterlace->thread_data);
+
+}
+
 static const AVFilterPad tinterlace_inputs[] = {
     {
         .name         = "default",
@@ -522,8 +733,8 @@  static const AVFilterPad tinterlace_inputs[] = {
 
 static const AVFilterPad tinterlace_outputs[] = {
     {
-        .name         = "default",
-        .type         = AVMEDIA_TYPE_VIDEO,
+        .name = "default",
+        .type = AVMEDIA_TYPE_VIDEO,
         .config_props = config_out_props,
     },
     { NULL }
@@ -531,16 +742,17 @@  static const AVFilterPad tinterlace_outputs[] = {
 
 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_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
 };
 
-
 AVFilter ff_vf_interlace = {
     .name          = "interlace",
     .description   = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."),
diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile
index 71cb1f5..f60de3b 100644
--- a/libavfilter/x86/Makefile
+++ b/libavfilter/x86/Makefile
@@ -16,7 +16,6 @@  OBJS-$(CONFIG_NOISE_FILTER)                  += x86/vf_noise.o
 OBJS-$(CONFIG_PP7_FILTER)                    += x86/vf_pp7_init.o
 OBJS-$(CONFIG_PSNR_FILTER)                   += x86/vf_psnr_init.o
 OBJS-$(CONFIG_PULLUP_FILTER)                 += x86/vf_pullup_init.o
-OBJS-$(CONFIG_REINTERLACE_FILTER)            += x86/vf_reinterlace_init.o
 OBJS-$(CONFIG_REMOVEGRAIN_FILTER)            += x86/vf_removegrain_init.o
 OBJS-$(CONFIG_SHOWCQT_FILTER)                += x86/avf_showcqt_init.o
 OBJS-$(CONFIG_SPP_FILTER)                    += x86/vf_spp.o
diff --git a/libavfilter/x86/vf_reinterlace_init.c b/libavfilter/x86/vf_reinterlace_init.c
deleted file mode 100644
index 5fba696..0000000
--- a/libavfilter/x86/vf_reinterlace_init.c
+++ /dev/null
@@ -1,102 +0,0 @@ 
-/*
- * 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
-
-av_cold void ff_reinterlace_init_x86(ReInterlaceContext *s) {}
-
-#endif
-
diff --git a/libavfilter/x86/vf_tinterlace_init.c b/libavfilter/x86/vf_tinterlace_init.c
index 2c9b1de..660d8d9 100644
--- a/libavfilter/x86/vf_tinterlace_init.c
+++ b/libavfilter/x86/vf_tinterlace_init.c
@@ -27,6 +27,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 +57,46 @@  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
+
+av_cold void ff_tinterlace_init_x86(TInterlaceContext *s) {}
+
+#endif
+
-- 
2.7.4