From ee33ed769207a99adb193eece32a5043ff0b6d94 Mon Sep 17 00:00:00 2001
From: Vasile Toncu <vasile.toncu@tremend.com>
Date: Wed, 25 Apr 2018 11:02:46 +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             | 125 -----
 libavfilter/tinterlace.h              | 155 +++++--
 libavfilter/vf_reinterlace.c          | 765 -------------------------------
 libavfilter/vf_tinterlace.c           | 831 +++++++++++++++++++++-------------
 libavfilter/x86/Makefile              |   1 -
 libavfilter/x86/vf_reinterlace_init.c | 102 -----
 libavfilter/x86/vf_tinterlace_init.c  |  42 +-
 10 files changed, 664 insertions(+), 1360 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 dee507c..d8bc940 100755
--- a/configure
+++ b/configure
@@ -3388,7 +3388,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 af702ba..8f41805 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -294,7 +294,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 5488ff4..643eec2 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -285,7 +285,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 f90b43a..0000000
--- a/libavfilter/reinterlace.h
+++ /dev/null
@@ -1,125 +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;
diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h
index b5c39aa..ca6ef3c 100644
--- a/libavfilter/tinterlace.h
+++ b/libavfilter/tinterlace.h
@@ -1,72 +1,139 @@
 /*
- * 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;
 
-#endif /* AVFILTER_TINTERLACE_H */
+} TInterlaceThreadData;
diff --git a/libavfilter/vf_reinterlace.c b/libavfilter/vf_reinterlace.c
deleted file mode 100644
index 8d1ef6d..0000000
--- a/libavfilter/vf_reinterlace.c
+++ /dev/null
@@ -1,765 +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)
-{
-
-    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_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
-        AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE
-    };
-
-    AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
-    if (!fmts_list)
-        return AVERROR(ENOMEM);
-
-    return ff_set_common_formats(ctx, fmts_list);
-}
-
-static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
-                           ptrdiff_t mref, ptrdiff_t pref, int clip_max)
-{
-    const uint8_t *srcp_above = srcp + mref;
-    const uint8_t *srcp_below = srcp + pref;
-    int i;
-    for (i = 0; i < width; i++) {
-        // this calculation is an integer representation of
-        // '0.5 * current + 0.25 * above + 0.25 * below'
-        // '1 +' is for rounding.
-        dstp[i] = (1 + srcp[i] + srcp[i] + srcp_above[i] + srcp_below[i]) >> 2;
-    }
-}
-
-static void lowpass_line_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8,
-                              ptrdiff_t mref, ptrdiff_t pref, int clip_max)
-{
-    uint16_t *dstp = (uint16_t *)dst8;
-    const uint16_t *srcp = (const uint16_t *)src8;
-    const uint16_t *srcp_above = srcp + mref / 2;
-    const uint16_t *srcp_below = srcp + pref / 2;
-    int i, src_x;
-    for (i = 0; i < width; i++) {
-        // this calculation is an integer representation of
-        // '0.5 * current + 0.25 * above + 0.25 * below'
-        // '1 +' is for rounding.
-        src_x   = av_le2ne16(srcp[i]) << 1;
-        dstp[i] = av_le2ne16((1 + src_x + av_le2ne16(srcp_above[i])
-                             + av_le2ne16(srcp_below[i])) >> 2);
-    }
-}
-
-static void lowpass_line_complex_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
-                                   ptrdiff_t mref, ptrdiff_t pref, int clip_max)
-{
-    const uint8_t *srcp_above = srcp + mref;
-    const uint8_t *srcp_below = srcp + pref;
-    const uint8_t *srcp_above2 = srcp + mref * 2;
-    const uint8_t *srcp_below2 = srcp + pref * 2;
-    int i, src_x, src_ab;
-    for (i = 0; i < width; i++) {
-        // this calculation is an integer representation of
-        // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
-        // '4 +' is for rounding.
-        src_x   = srcp[i] << 1;
-        src_ab  = srcp_above[i] + srcp_below[i];
-        dstp[i] = av_clip_uint8((4 + ((srcp[i] + src_x + src_ab) << 1)
-                                - srcp_above2[i] - srcp_below2[i]) >> 3);
-        // Prevent over-sharpening:
-        // dst must not exceed src when the average of above and below
-        // is less than src. And the other way around.
-        if (src_ab > src_x) {
-            if (dstp[i] < srcp[i])
-                dstp[i] = srcp[i];
-        } else if (dstp[i] > srcp[i])
-            dstp[i] = srcp[i];
-    }
-}
-
-static void lowpass_line_complex_c_16(uint8_t *dst8, ptrdiff_t width, const uint8_t *src8,
-                                      ptrdiff_t mref, ptrdiff_t pref, int clip_max)
-{
-    uint16_t *dstp = (uint16_t *)dst8;
-    const uint16_t *srcp = (const uint16_t *)src8;
-    const uint16_t *srcp_above = srcp + mref / 2;
-    const uint16_t *srcp_below = srcp + pref / 2;
-    const uint16_t *srcp_above2 = srcp + mref;
-    const uint16_t *srcp_below2 = srcp + pref;
-    int i, dst_le, src_le, src_x, src_ab;
-    for (i = 0; i < width; i++) {
-        // this calculation is an integer representation of
-        // '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
-        // '4 +' is for rounding.
-        src_le = av_le2ne16(srcp[i]);
-        src_x  = src_le << 1;
-        src_ab = av_le2ne16(srcp_above[i]) + av_le2ne16(srcp_below[i]);
-        dst_le = av_clip((4 + ((src_le + src_x + src_ab) << 1)
-                         - av_le2ne16(srcp_above2[i])
-                         - av_le2ne16(srcp_below2[i])) >> 3, 0, clip_max);
-        // Prevent over-sharpening:
-        // dst must not exceed src when the average of above and below
-        // is less than src. And the other way around.
-        if (src_ab > src_x) {
-            if (dst_le < src_le)
-                dstp[i] = av_le2ne16(src_le);
-            else
-                dstp[i] = av_le2ne16(dst_le);
-        } else if (dst_le > src_le) {
-            dstp[i] = av_le2ne16(src_le);
-        } else
-            dstp[i] = av_le2ne16(dst_le);
-    }
-}
-
-/** 
- * alocate memory for a black frame 
- */
-static int init_black_buffers(ReInterlaceContext *reinterlace, AVFilterLink *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 4f5c10d..6d20ea8 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -1,93 +1,48 @@
 /*
+ * 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 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" },
 
-   { NULL }
-};
-
-AVFILTER_DEFINE_CLASS(interlace);
+static av_cold int init(AVFilterContext *ctx)
+{
+    TInterlaceContext *tinterlace = ctx->priv;
+    int i;
 
-#define FULL_SCALE_YUVJ_FORMATS \
-    AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P
+    for (i = 0; i < 4; i++)
+        tinterlace->black_vec[i] = NULL;
 
-static const enum AVPixelFormat full_scale_yuvj_pix_fmts[] = {
-    FULL_SCALE_YUVJ_FORMATS, AV_PIX_FMT_NONE
-};
+    tinterlace->thread_data = av_malloc(4 * sizeof(TInterlaceThreadData));
 
-static const AVRational standard_tbs[] = {
-    {1, 25},
-    {1, 30},
-    {1001, 30000},
-};
+    return 0;
+}
 
 static int query_formats(AVFilterContext *ctx)
 {
+
     static const enum AVPixelFormat pix_fmts[] = {
         AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
         AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
@@ -97,14 +52,15 @@ static int query_formats(AVFilterContext *ctx)
         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
+        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
     };
 
     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 +158,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 +744,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 +753,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..47d1121 100644
--- a/libavfilter/x86/vf_tinterlace_init.c
+++ b/libavfilter/x86/vf_tinterlace_init.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2018 Vasile Toncu <toncuvasile@gmail.com>
  * Copyright (C) 2014 Kieran Kunhya <kierank@obe.tv>
  *
  * This file is part of FFmpeg.
@@ -27,6 +28,8 @@
 
 #include "libavfilter/tinterlace.h"
 
+#if CONFIG_GPL
+
 void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize,
                           const uint8_t *srcp, ptrdiff_t mref,
                           ptrdiff_t pref, int clip_max);
@@ -55,39 +58,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

