diff mbox

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

Message ID CALGJd-LicyxpyCbBAd0QPd6ZNDj5B=WQLOexQwbHS71+LDCDzQ@mail.gmail.com
State New
Headers show

Commit Message

Vasile Toncu Aug. 16, 2018, 11:56 a.m. UTC
Hi,

Thank you for the additional testing effort.
Fixed the issue.

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

> Hi,
>
> 2018-08-14 18:53 GMT+02:00 Vasile Toncu <vasile.toncu@tremend.com>:
>
> > Hi Thomas,
> >
> > I added the log messages.
> >
> > Thanks for the review.
> >
>
> I found some more time for testing this evening. Unfortunately there are
> still issues.
> I get half green pictures with some modes at high bit depth.
> But the fix is easy.
> The bytewidth in all av_image_copy_plane functions need to be adapted for
> high bit depths.
>
> {....}
> >     const AVPixFmtDescriptor *fmt_desc = av_pix_fmt_desc_get(out->
> format);
> >     int mult = (fmt_desc->comp[0].depth > 8 ? 2 : 1);
> >
>
> You used the calculated "mult" in the av_image_copy_plane functions of
> MODE_MERGE and MODE_PAD only.
> And forgot the others:
>
>
> > {....}
> >
> +    case MODE_INTERLEAVE_BOTTOM:
> > +    case MODE_INTERLEAVE_TOP:
> > +        y = y * 2;
> > +
> > +        if (tinterlace->flags & FLAG_VLPF || tinterlace->flags &
> > FLAG_CVLPF) {
> > +            int clip_max = (1 << fmt_desc->comp[plane].depth) - 1;
> > +
> > +            interleave_filter_frame(tinterlace, first, out, plane,
> > !!(tinterlace->flags & FLAG_CVLPF), tinterlace_mode ==
> MODE_INTERLEAVE_TOP,
> > x, y, clip_max);
> > +            interleave_filter_frame(tinterlace, second, out, plane,
> > !!(tinterlace->flags & FLAG_CVLPF), tinterlace_mode ==
> > MODE_INTERLEAVE_BOTTOM, x, y, clip_max);
> >          } else {
> > -            if (tinterlace->csp->comp[plane].depth > 8)
> > -                cols *= 2;
> > -            av_image_copy_plane(dstp, dstp_linesize, srcp,
> srcp_linesize,
> > cols, lines);
> > +            offset1 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 :
> > out->linesize[plane];
> > +            offset2 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ? 0 :
> > first->linesize[plane];
> > +            offset3 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ?
> > out->linesize[plane]    : 0;
> > +            offset4 = (tinterlace_mode == MODE_INTERLEAVE_TOP) ?
> > second->linesize[plane] : 0;
> > +
> > +            av_image_copy_plane(out->data[plane] + offset1, 2 *
> > out->linesize[plane],
> > +                first->data[plane] + offset2, 2 *
> first->linesize[plane],
> > +                first->width / x, first->height / y);
> > +            av_image_copy_plane(out->data[plane] + offset3, 2 *
> > out->linesize[plane],
> > +                second->data[plane] + offset4, 2 *
> > second->linesize[plane],
> > +                second->width / x, second->height / y);
> >
>
> Here
>
>          }
> > +        break;
> > +
> > +    case MODE_INTERLACE_X2:
> > +        y = y * 2;
> > +
> > +        offset1 = 0; offset2 = 0;
> > +        offset3 = out->linesize[plane];
> > +        offset4 = second->linesize[plane];
> > +
> > +        if (second->interlaced_frame && second->top_field_first) {
> > +            offset1 = out->linesize[plane];
> > +            offset2 = first->linesize[plane];
> > +            offset3 = 0; offset4 = 0;
> > +        }
> > +
> > +        av_image_copy_plane(out->data[plane] + offset1, 2 *
> > out->linesize[plane],
> > +            first->data[plane] + offset2, 2 * first->linesize[plane],
> > +            first->width / x, first->height / y);
> > +        av_image_copy_plane(out->data[plane] + offset3, 2 *
> > out->linesize[plane],
> > +            second->data[plane] + offset4, 2 * second->linesize[plane],
> > +            second->width / x, second->height / y);
> >
>
>  Here
>
> +        break;
> > +
> > +    case MODE_MERGE_X2:
> > +        if (IS_ODD(tinterlace->current_frame_index - 1)) {
> > +            av_image_copy_plane(out->data[plane], 2 *
> > out->linesize[plane],
> > +                second->data[plane], second->linesize[plane],
> > second->width / x, second->height / y);
> > +            av_image_copy_plane(out->data[plane] +
> out->linesize[plane],
> > 2 * out->linesize[plane],
> > +                first->data[plane], first->linesize[plane], first->width
> > / x, first->height / y);
> > +        } else {
> > +            av_image_copy_plane(out->data[plane], 2 *
> > out->linesize[plane],
> > +                first->data[plane], first->linesize[plane], first->width
> > / x, first->height / y);
> > +            av_image_copy_plane(out->data[plane] +
> out->linesize[plane],
> > 2 * out->linesize[plane],
> > +                second->data[plane], second->linesize[plane],
> > second->width / x, second->height / y);
> >
>
> Here.
>
> Sorry for the piecemeal.
>
> Regards,
> Thomas
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>

Comments

Thomas Mundt Aug. 17, 2018, 3:24 p.m. UTC | #1
Hi,

2018-08-16 13:56 GMT+02:00 Vasile Toncu <vasile.toncu@tremend.com>:

> Hi,
>
> Thank you for the additional testing effort.
> Fixed the issue.
>
>
thanks, the patch looks good to me as far as I can judge.
It´s up to more experienced developers now to permit the license change.
Can anybody please have a look at this.

Regards,
Thomas
Vasile Toncu Sept. 17, 2018, 6:28 a.m. UTC | #2
Hello,

Thank you Thomas for the reviews and support!

The proposed actions, by Nicolas George in
https://ffmpeg.org/pipermail/ffmpeg-devel/2017-December/223072.html, were
taken.

>* Can one simply change the tinterlace from GPL to LGPL?
*
Of course not. There are two non-simple courses of action to achieve it:

- Get the approval of all copyright holders. It has been done in the
  past for other filters.

- Remove the GPL tinterlace and at the same time add a new LGPL filter
  that does the same thing and is also called tinterlace.


Only two contributors approved until now, Thomas Mundt and Stefano
Sebatini, while Baptiste Coudurier and Michael Zucchi could not be reached.
Also, the new implementation supports all the features from the old
tinterlace and conditionally (at compile time) the same ASM optimizations
are used, but only if CONFIG_GPL is defined.

Is there any way we can proceed with this patch?

Best regards.


On Fri, Aug 17, 2018 at 5:24 PM, Thomas Mundt <tmundt75@gmail.com> wrote:

> Hi,
>
> 2018-08-16 13:56 GMT+02:00 Vasile Toncu <vasile.toncu@tremend.com>:
>
> > Hi,
> >
> > Thank you for the additional testing effort.
> > Fixed the issue.
> >
> >
> thanks, the patch looks good to me as far as I can judge.
> It´s up to more experienced developers now to permit the license change.
> Can anybody please have a look at this.
>
> Regards,
> Thomas
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
Vasile Toncu Oct. 16, 2018, 4:40 p.m. UTC | #3
Hello,

Still Baptiste Coudurier and Michael Zucchi could not be reached, however
since the old GPL tinterlace was replaced with a new LGPL implementation
aren't we on the second course of action recommended by Nicolas George? And
by that means can we change the license of this implementation without the
approval of the original contributors whose code was removed?
Maybe someone else can have a look at the new implementation and provide
the necessary feedback in order to merge this patch and unblock the
development of the patches with new functionalities.

Thank you.
Best regards.



On Mon, Sep 17, 2018 at 8:28 AM, Vasile Toncu <vasile.toncu@tremend.com>
wrote:

> Hello,
>
> Thank you Thomas for the reviews and support!
>
> The proposed actions, by Nicolas George in https://ffmpeg.org/pipermail/
> ffmpeg-devel/2017-December/223072.html, were taken.
>
> >* Can one simply change the tinterlace from GPL to LGPL?
> *
> Of course not. There are two non-simple courses of action to achieve it:
>
> - Get the approval of all copyright holders. It has been done in the
>   past for other filters.
>
> - Remove the GPL tinterlace and at the same time add a new LGPL filter
>   that does the same thing and is also called tinterlace.
>
>
> Only two contributors approved until now, Thomas Mundt and Stefano
> Sebatini, while Baptiste Coudurier and Michael Zucchi could not be reached.
> Also, the new implementation supports all the features from the old
> tinterlace and conditionally (at compile time) the same ASM optimizations
> are used, but only if CONFIG_GPL is defined.
>
> Is there any way we can proceed with this patch?
>
> Best regards.
>
>
> On Fri, Aug 17, 2018 at 5:24 PM, Thomas Mundt <tmundt75@gmail.com> wrote:
>
>> Hi,
>>
>> 2018-08-16 13:56 GMT+02:00 Vasile Toncu <vasile.toncu@tremend.com>:
>>
>> > Hi,
>> >
>> > Thank you for the additional testing effort.
>> > Fixed the issue.
>> >
>> >
>> thanks, the patch looks good to me as far as I can judge.
>> It´s up to more experienced developers now to permit the license change.
>> Can anybody please have a look at this.
>>
>> Regards,
>> Thomas
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>
>
Vasile Toncu Dec. 6, 2018, 5:10 p.m. UTC | #4
Hi,

Since this patch is passing all the current tests, all the modification
required by Thomas were implemented and from our point of view it satisfies
all requirements for adding the double license to the filter, please
approve this patch for integration. Also, there are two more patches
blocked at the moment. This two patches add new features and improvements
for the filter.

Thank you. Regards.

On Tue, Oct 16, 2018 at 6:40 PM Vasile Toncu <vasile.toncu@tremend.com>
wrote:

> Hello,
>
> Still Baptiste Coudurier and Michael Zucchi could not be reached, however
> since the old GPL tinterlace was replaced with a new LGPL implementation
> aren't we on the second course of action recommended by Nicolas George? And
> by that means can we change the license of this implementation without the
> approval of the original contributors whose code was removed?
> Maybe someone else can have a look at the new implementation and provide
> the necessary feedback in order to merge this patch and unblock the
> development of the patches with new functionalities.
>
> Thank you.
> Best regards.
>
>
>
> On Mon, Sep 17, 2018 at 8:28 AM, Vasile Toncu <vasile.toncu@tremend.com>
> wrote:
>
>> Hello,
>>
>> Thank you Thomas for the reviews and support!
>>
>> The proposed actions, by Nicolas George in
>> https://ffmpeg.org/pipermail/ffmpeg-devel/2017-December/223072.html,
>> were taken.
>>
>> >* Can one simply change the tinterlace from GPL to LGPL?
>> *
>> Of course not. There are two non-simple courses of action to achieve it:
>>
>> - Get the approval of all copyright holders. It has been done in the
>>   past for other filters.
>>
>> - Remove the GPL tinterlace and at the same time add a new LGPL filter
>>   that does the same thing and is also called tinterlace.
>>
>>
>> Only two contributors approved until now, Thomas Mundt and Stefano
>> Sebatini, while Baptiste Coudurier and Michael Zucchi could not be reached.
>> Also, the new implementation supports all the features from the old
>> tinterlace and conditionally (at compile time) the same ASM optimizations
>> are used, but only if CONFIG_GPL is defined.
>>
>> Is there any way we can proceed with this patch?
>>
>> Best regards.
>>
>>
>> On Fri, Aug 17, 2018 at 5:24 PM, Thomas Mundt <tmundt75@gmail.com> wrote:
>>
>>> Hi,
>>>
>>> 2018-08-16 13:56 GMT+02:00 Vasile Toncu <vasile.toncu@tremend.com>:
>>>
>>> > Hi,
>>> >
>>> > Thank you for the additional testing effort.
>>> > Fixed the issue.
>>> >
>>> >
>>> thanks, the patch looks good to me as far as I can judge.
>>> It´s up to more experienced developers now to permit the license change.
>>> Can anybody please have a look at this.
>>>
>>> Regards,
>>> Thomas
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> ffmpeg-devel@ffmpeg.org
>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>>
>>
>>
>
Vasile Toncu Feb. 1, 2019, 4 p.m. UTC | #5
Hello,

Happy New Year.
Any news about this patch? Maybe Carl Eugen Hoyos could help us with this?

Best regards.

On Thu, Dec 6, 2018 at 6:10 PM Vasile Toncu <vasile.toncu@tremend.com>
wrote:

> Hi,
>
> Since this patch is passing all the current tests, all the modification
> required by Thomas were implemented and from our point of view it satisfies
> all requirements for adding the double license to the filter, please
> approve this patch for integration. Also, there are two more patches
> blocked at the moment. This two patches add new features and improvements
> for the filter.
>
> Thank you. Regards.
>
> On Tue, Oct 16, 2018 at 6:40 PM Vasile Toncu <vasile.toncu@tremend.com>
> wrote:
>
>> Hello,
>>
>> Still Baptiste Coudurier and Michael Zucchi could not be reached, however
>> since the old GPL tinterlace was replaced with a new LGPL implementation
>> aren't we on the second course of action recommended by Nicolas George? And
>> by that means can we change the license of this implementation without the
>> approval of the original contributors whose code was removed?
>> Maybe someone else can have a look at the new implementation and provide
>> the necessary feedback in order to merge this patch and unblock the
>> development of the patches with new functionalities.
>>
>> Thank you.
>> Best regards.
>>
>>
>>
>> On Mon, Sep 17, 2018 at 8:28 AM, Vasile Toncu <vasile.toncu@tremend.com>
>> wrote:
>>
>>> Hello,
>>>
>>> Thank you Thomas for the reviews and support!
>>>
>>> The proposed actions, by Nicolas George in
>>> https://ffmpeg.org/pipermail/ffmpeg-devel/2017-December/223072.html,
>>> were taken.
>>>
>>> >* Can one simply change the tinterlace from GPL to LGPL?
>>> *
>>> Of course not. There are two non-simple courses of action to achieve it:
>>>
>>> - Get the approval of all copyright holders. It has been done in the
>>>   past for other filters.
>>>
>>> - Remove the GPL tinterlace and at the same time add a new LGPL filter
>>>   that does the same thing and is also called tinterlace.
>>>
>>>
>>> Only two contributors approved until now, Thomas Mundt and Stefano
>>> Sebatini, while Baptiste Coudurier and Michael Zucchi could not be reached.
>>> Also, the new implementation supports all the features from the old
>>> tinterlace and conditionally (at compile time) the same ASM optimizations
>>> are used, but only if CONFIG_GPL is defined.
>>>
>>> Is there any way we can proceed with this patch?
>>>
>>> Best regards.
>>>
>>>
>>> On Fri, Aug 17, 2018 at 5:24 PM, Thomas Mundt <tmundt75@gmail.com>
>>> wrote:
>>>
>>>> Hi,
>>>>
>>>> 2018-08-16 13:56 GMT+02:00 Vasile Toncu <vasile.toncu@tremend.com>:
>>>>
>>>> > Hi,
>>>> >
>>>> > Thank you for the additional testing effort.
>>>> > Fixed the issue.
>>>> >
>>>> >
>>>> thanks, the patch looks good to me as far as I can judge.
>>>> It´s up to more experienced developers now to permit the license change.
>>>> Can anybody please have a look at this.
>>>>
>>>> Regards,
>>>> Thomas
>>>> _______________________________________________
>>>> ffmpeg-devel mailing list
>>>> ffmpeg-devel@ffmpeg.org
>>>> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>>>
>>>
>>>
>>
diff mbox

Patch

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

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

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