diff --git a/libavfilter/bwdif.h b/libavfilter/bwdif.h
index 8b42c760a0..889ff772ed 100644
--- a/libavfilter/bwdif.h
+++ b/libavfilter/bwdif.h
@@ -21,36 +21,10 @@
 
 #include "libavutil/pixdesc.h"
 #include "avfilter.h"
-
-enum BWDIFMode {
-    BWDIF_MODE_SEND_FRAME = 0, ///< send 1 frame for each frame
-    BWDIF_MODE_SEND_FIELD = 1, ///< send 1 frame for each field
-};
-
-enum BWDIFParity {
-    BWDIF_PARITY_TFF  =  0, ///< top field first
-    BWDIF_PARITY_BFF  =  1, ///< bottom field first
-    BWDIF_PARITY_AUTO = -1, ///< auto detection
-};
-
-enum BWDIFDeint {
-    BWDIF_DEINT_ALL        = 0, ///< deinterlace all frames
-    BWDIF_DEINT_INTERLACED = 1, ///< only deinterlace frames marked as interlaced
-};
+#include "yadif.h"
 
 typedef struct BWDIFContext {
-    const AVClass *class;
-
-    int mode;           ///< BWDIFMode
-    int parity;         ///< BWDIFParity
-    int deint;          ///< BWDIFDeint
-
-    int frame_pending;
-
-    AVFrame *cur;
-    AVFrame *next;
-    AVFrame *prev;
-    AVFrame *out;
+    YADIFContext yadif;
 
     void (*filter_intra)(void *dst1, void *cur1, int w, int prefs, int mrefs,
                          int prefs3, int mrefs3, int parity, int clip_max);
@@ -61,10 +35,6 @@ typedef struct BWDIFContext {
     void (*filter_edge)(void *dst, void *prev, void *cur, void *next,
                         int w, int prefs, int mrefs, int prefs2, int mrefs2,
                         int parity, int clip_max, int spat);
-
-    const AVPixFmtDescriptor *csp;
-    int inter_field;
-    int eof;
 } BWDIFContext;
 
 void ff_bwdif_init_x86(BWDIFContext *bwdif);
diff --git a/libavfilter/vf_bwdif.c b/libavfilter/vf_bwdif.c
index b691983611..4ed9cd347d 100644
--- a/libavfilter/vf_bwdif.c
+++ b/libavfilter/vf_bwdif.c
@@ -216,10 +216,11 @@ static void filter_edge_16bit(void *dst1, void *prev1, void *cur1, void *next1,
 static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
 {
     BWDIFContext *s = ctx->priv;
+    YADIFContext *yadif = &s->yadif;
     ThreadData *td  = arg;
-    int linesize = s->cur->linesize[td->plane];
-    int clip_max = (1 << (s->csp->comp[td->plane].depth)) - 1;
-    int df = (s->csp->comp[td->plane].depth + 7) / 8;
+    int linesize = yadif->cur->linesize[td->plane];
+    int clip_max = (1 << (yadif->csp->comp[td->plane].depth)) - 1;
+    int df = (yadif->csp->comp[td->plane].depth + 7) / 8;
     int refs = linesize / df;
     int slice_start = (td->h *  jobnr   ) / nb_jobs;
     int slice_end   = (td->h * (jobnr+1)) / nb_jobs;
@@ -227,11 +228,11 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
 
     for (y = slice_start; y < slice_end; y++) {
         if ((y ^ td->parity) & 1) {
-            uint8_t *prev = &s->prev->data[td->plane][y * linesize];
-            uint8_t *cur  = &s->cur ->data[td->plane][y * linesize];
-            uint8_t *next = &s->next->data[td->plane][y * linesize];
+            uint8_t *prev = &yadif->prev->data[td->plane][y * linesize];
+            uint8_t *cur  = &yadif->cur ->data[td->plane][y * linesize];
+            uint8_t *next = &yadif->next->data[td->plane][y * linesize];
             uint8_t *dst  = &td->frame->data[td->plane][y * td->frame->linesize[td->plane]];
-            if (!s->inter_field) {
+            if (yadif->current_field == YADIF_FIELD_FIRST) {
                 s->filter_intra(dst, cur, td->w, (y + df) < td->h ? refs : -refs,
                                 y > (df - 1) ? -refs : refs,
                                 (y + 3*df) < td->h ? 3 * refs : -refs,
@@ -252,7 +253,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
             }
         } else {
             memcpy(&td->frame->data[td->plane][y * td->frame->linesize[td->plane]],
-                   &s->cur->data[td->plane][y * linesize], td->w * df);
+                   &yadif->cur->data[td->plane][y * linesize], td->w * df);
         }
     }
     return 0;
@@ -262,16 +263,17 @@ static void filter(AVFilterContext *ctx, AVFrame *dstpic,
                    int parity, int tff)
 {
     BWDIFContext *bwdif = ctx->priv;
+    YADIFContext *yadif = &bwdif->yadif;
     ThreadData td = { .frame = dstpic, .parity = parity, .tff = tff };
     int i;
 
-    for (i = 0; i < bwdif->csp->nb_components; i++) {
+    for (i = 0; i < yadif->csp->nb_components; i++) {
         int w = dstpic->width;
         int h = dstpic->height;
 
         if (i == 1 || i == 2) {
-            w = AV_CEIL_RSHIFT(w, bwdif->csp->log2_chroma_w);
-            h = AV_CEIL_RSHIFT(h, bwdif->csp->log2_chroma_h);
+            w = AV_CEIL_RSHIFT(w, yadif->csp->log2_chroma_w);
+            h = AV_CEIL_RSHIFT(h, yadif->csp->log2_chroma_h);
         }
 
         td.w     = w;
@@ -280,186 +282,21 @@ static void filter(AVFilterContext *ctx, AVFrame *dstpic,
 
         ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(h, ff_filter_get_nb_threads(ctx)));
     }
-    if (!bwdif->inter_field) {
-        bwdif->inter_field = 1;
+    if (yadif->current_field == YADIF_FIELD_FIRST) {
+        yadif->current_field = YADIF_FIELD_NORMAL;
     }
 
     emms_c();
 }
 
-static int return_frame(AVFilterContext *ctx, int is_second)
-{
-    BWDIFContext *bwdif = ctx->priv;
-    AVFilterLink *link  = ctx->outputs[0];
-    int tff, ret;
-
-    if (bwdif->parity == -1) {
-        tff = bwdif->cur->interlaced_frame ?
-              bwdif->cur->top_field_first : 1;
-    } else {
-        tff = bwdif->parity ^ 1;
-    }
-
-    if (is_second) {
-        bwdif->out = ff_get_video_buffer(link, link->w, link->h);
-        if (!bwdif->out)
-            return AVERROR(ENOMEM);
-
-        av_frame_copy_props(bwdif->out, bwdif->cur);
-        bwdif->out->interlaced_frame = 0;
-        if (bwdif->inter_field < 0)
-            bwdif->inter_field = 0;
-    }
-
-    filter(ctx, bwdif->out, tff ^ !is_second, tff);
-
-    if (is_second) {
-        int64_t cur_pts  = bwdif->cur->pts;
-        int64_t next_pts = bwdif->next->pts;
-
-        if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) {
-            bwdif->out->pts = cur_pts + next_pts;
-        } else {
-            bwdif->out->pts = AV_NOPTS_VALUE;
-        }
-    }
-    ret = ff_filter_frame(ctx->outputs[0], bwdif->out);
-
-    bwdif->frame_pending = (bwdif->mode&1) && !is_second;
-    return ret;
-}
-
-static int checkstride(BWDIFContext *bwdif, const AVFrame *a, const AVFrame *b)
-{
-    int i;
-    for (i = 0; i < bwdif->csp->nb_components; i++)
-        if (a->linesize[i] != b->linesize[i])
-            return 1;
-    return 0;
-}
-
-static void fixstride(AVFilterLink *link, AVFrame *f)
-{
-    AVFrame *dst = ff_default_get_video_buffer(link, f->width, f->height);
-    if(!dst)
-        return;
-    av_frame_copy_props(dst, f);
-    av_image_copy(dst->data, dst->linesize,
-                  (const uint8_t **)f->data, f->linesize,
-                  dst->format, dst->width, dst->height);
-    av_frame_unref(f);
-    av_frame_move_ref(f, dst);
-    av_frame_free(&dst);
-}
-
-static int filter_frame(AVFilterLink *link, AVFrame *frame)
-{
-    AVFilterContext *ctx = link->dst;
-    BWDIFContext *bwdif = ctx->priv;
-
-    av_assert0(frame);
-
-    if (bwdif->frame_pending)
-        return_frame(ctx, 1);
-
-    if (bwdif->prev)
-        av_frame_free(&bwdif->prev);
-    bwdif->prev = bwdif->cur;
-    bwdif->cur  = bwdif->next;
-    bwdif->next = frame;
-
-    if (!bwdif->cur) {
-        bwdif->cur = av_frame_clone(bwdif->next);
-        if (!bwdif->cur)
-            return AVERROR(ENOMEM);
-        bwdif->inter_field = 0;
-    }
-
-    if (checkstride(bwdif, bwdif->next, bwdif->cur)) {
-        av_log(ctx, AV_LOG_VERBOSE, "Reallocating frame due to differing stride\n");
-        fixstride(link, bwdif->next);
-    }
-    if (checkstride(bwdif, bwdif->next, bwdif->cur))
-        fixstride(link, bwdif->cur);
-    if (bwdif->prev && checkstride(bwdif, bwdif->next, bwdif->prev))
-        fixstride(link, bwdif->prev);
-    if (checkstride(bwdif, bwdif->next, bwdif->cur) || (bwdif->prev && checkstride(bwdif, bwdif->next, bwdif->prev))) {
-        av_log(ctx, AV_LOG_ERROR, "Failed to reallocate frame\n");
-        return -1;
-    }
-
-    if (!bwdif->prev)
-        return 0;
-
-    if ((bwdif->deint && !bwdif->cur->interlaced_frame) ||
-        ctx->is_disabled ||
-        (bwdif->deint && !bwdif->prev->interlaced_frame && bwdif->prev->repeat_pict) ||
-        (bwdif->deint && !bwdif->next->interlaced_frame && bwdif->next->repeat_pict)
-    ) {
-        bwdif->out  = av_frame_clone(bwdif->cur);
-        if (!bwdif->out)
-            return AVERROR(ENOMEM);
-
-        av_frame_free(&bwdif->prev);
-        if (bwdif->out->pts != AV_NOPTS_VALUE)
-            bwdif->out->pts *= 2;
-        return ff_filter_frame(ctx->outputs[0], bwdif->out);
-    }
-
-    bwdif->out = ff_get_video_buffer(ctx->outputs[0], link->w, link->h);
-    if (!bwdif->out)
-        return AVERROR(ENOMEM);
-
-    av_frame_copy_props(bwdif->out, bwdif->cur);
-    bwdif->out->interlaced_frame = 0;
-
-    if (bwdif->out->pts != AV_NOPTS_VALUE)
-        bwdif->out->pts *= 2;
-
-    return return_frame(ctx, 0);
-}
-
-static int request_frame(AVFilterLink *link)
-{
-    AVFilterContext *ctx = link->src;
-    BWDIFContext *bwdif = ctx->priv;
-    int ret;
-
-    if (bwdif->frame_pending) {
-        return_frame(ctx, 1);
-        return 0;
-    }
-
-    if (bwdif->eof)
-        return AVERROR_EOF;
-
-    ret  = ff_request_frame(link->src->inputs[0]);
-
-    if (ret == AVERROR_EOF && bwdif->cur) {
-        AVFrame *next = av_frame_clone(bwdif->next);
-
-        if (!next)
-            return AVERROR(ENOMEM);
-
-        bwdif->inter_field = -1;
-        next->pts = bwdif->next->pts * 2 - bwdif->cur->pts;
-
-        filter_frame(link->src->inputs[0], next);
-        bwdif->eof = 1;
-    } else if (ret < 0) {
-        return ret;
-    }
-
-    return 0;
-}
-
 static av_cold void uninit(AVFilterContext *ctx)
 {
     BWDIFContext *bwdif = ctx->priv;
+    YADIFContext *yadif = &bwdif->yadif;
 
-    av_frame_free(&bwdif->prev);
-    av_frame_free(&bwdif->cur );
-    av_frame_free(&bwdif->next);
+    av_frame_free(&yadif->prev);
+    av_frame_free(&yadif->cur );
+    av_frame_free(&yadif->next);
 }
 
 static int query_formats(AVFilterContext *ctx)
@@ -496,13 +333,14 @@ static int config_props(AVFilterLink *link)
 {
     AVFilterContext *ctx = link->src;
     BWDIFContext *s = link->src->priv;
+    YADIFContext *yadif = &s->yadif;
 
     link->time_base.num = link->src->inputs[0]->time_base.num;
     link->time_base.den = link->src->inputs[0]->time_base.den * 2;
     link->w             = link->src->inputs[0]->w;
     link->h             = link->src->inputs[0]->h;
 
-    if(s->mode&1)
+    if(yadif->mode&1)
         link->frame_rate = av_mul_q(link->src->inputs[0]->frame_rate, (AVRational){2,1});
 
     if (link->w < 3 || link->h < 3) {
@@ -510,8 +348,9 @@ static int config_props(AVFilterLink *link)
         return AVERROR(EINVAL);
     }
 
-    s->csp = av_pix_fmt_desc_get(link->format);
-    if (s->csp->comp[0].depth > 8) {
+    yadif->csp = av_pix_fmt_desc_get(link->format);
+    yadif->filter = filter;
+    if (yadif->csp->comp[0].depth > 8) {
         s->filter_intra = filter_intra_16bit;
         s->filter_line  = filter_line_c_16bit;
         s->filter_edge  = filter_edge_16bit;
@@ -528,24 +367,24 @@ static int config_props(AVFilterLink *link)
 }
 
 
-#define OFFSET(x) offsetof(BWDIFContext, x)
+#define OFFSET(x) offsetof(YADIFContext, x)
 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
 
 #define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, INT_MIN, INT_MAX, FLAGS, unit }
 
 static const AVOption bwdif_options[] = {
-    { "mode",   "specify the interlacing mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=BWDIF_MODE_SEND_FIELD}, 0, 1, FLAGS, "mode"},
-    CONST("send_frame", "send one frame for each frame", BWDIF_MODE_SEND_FRAME, "mode"),
-    CONST("send_field", "send one frame for each field", BWDIF_MODE_SEND_FIELD, "mode"),
+    { "mode",   "specify the interlacing mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=YADIF_MODE_SEND_FIELD}, 0, 1, FLAGS, "mode"},
+    CONST("send_frame", "send one frame for each frame", YADIF_MODE_SEND_FRAME, "mode"),
+    CONST("send_field", "send one frame for each field", YADIF_MODE_SEND_FIELD, "mode"),
 
-    { "parity", "specify the assumed picture field parity", OFFSET(parity), AV_OPT_TYPE_INT, {.i64=BWDIF_PARITY_AUTO}, -1, 1, FLAGS, "parity" },
-    CONST("tff",  "assume top field first",    BWDIF_PARITY_TFF,  "parity"),
-    CONST("bff",  "assume bottom field first", BWDIF_PARITY_BFF,  "parity"),
-    CONST("auto", "auto detect parity",        BWDIF_PARITY_AUTO, "parity"),
+    { "parity", "specify the assumed picture field parity", OFFSET(parity), AV_OPT_TYPE_INT, {.i64=YADIF_PARITY_AUTO}, -1, 1, FLAGS, "parity" },
+    CONST("tff",  "assume top field first",    YADIF_PARITY_TFF,  "parity"),
+    CONST("bff",  "assume bottom field first", YADIF_PARITY_BFF,  "parity"),
+    CONST("auto", "auto detect parity",        YADIF_PARITY_AUTO, "parity"),
 
-    { "deint", "specify which frames to deinterlace", OFFSET(deint), AV_OPT_TYPE_INT, {.i64=BWDIF_DEINT_ALL}, 0, 1, FLAGS, "deint" },
-    CONST("all",        "deinterlace all frames",                       BWDIF_DEINT_ALL,        "deint"),
-    CONST("interlaced", "only deinterlace frames marked as interlaced", BWDIF_DEINT_INTERLACED, "deint"),
+    { "deint", "specify which frames to deinterlace", OFFSET(deint), AV_OPT_TYPE_INT, {.i64=YADIF_DEINT_ALL}, 0, 1, FLAGS, "deint" },
+    CONST("all",        "deinterlace all frames",                       YADIF_DEINT_ALL,        "deint"),
+    CONST("interlaced", "only deinterlace frames marked as interlaced", YADIF_DEINT_INTERLACED, "deint"),
 
     { NULL }
 };
@@ -556,7 +395,7 @@ static const AVFilterPad avfilter_vf_bwdif_inputs[] = {
     {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
-        .filter_frame  = filter_frame,
+        .filter_frame  = ff_yadif_filter_frame,
     },
     { NULL }
 };
@@ -565,7 +404,7 @@ static const AVFilterPad avfilter_vf_bwdif_outputs[] = {
     {
         .name          = "default",
         .type          = AVMEDIA_TYPE_VIDEO,
-        .request_frame = request_frame,
+        .request_frame = ff_yadif_request_frame,
         .config_props  = config_props,
     },
     { NULL }
diff --git a/libavfilter/x86/vf_bwdif_init.c b/libavfilter/x86/vf_bwdif_init.c
index 1cb8438e5f..b1e70b3bc6 100644
--- a/libavfilter/x86/vf_bwdif_init.c
+++ b/libavfilter/x86/vf_bwdif_init.c
@@ -53,8 +53,9 @@ void ff_bwdif_filter_line_12bit_ssse3(void *dst, void *prev, void *cur, void *ne
 
 av_cold void ff_bwdif_init_x86(BWDIFContext *bwdif)
 {
+    YADIFContext *yadif = &bwdif->yadif;
     int cpu_flags = av_get_cpu_flags();
-    int bit_depth = (!bwdif->csp) ? 8 : bwdif->csp->comp[0].depth;
+    int bit_depth = (!yadif->csp) ? 8 : yadif->csp->comp[0].depth;
 
     if (bit_depth <= 8) {
 #if ARCH_X86_32
