[FFmpeg-devel] [PATCH] avfilter/tinterlace: merge code with interlace

Clément Bœsch u at pkh.me
Tue Dec 2 19:43:47 CET 2014


---
After this commit, interlace doesn't behave the same if the input frames
are already interlaced. Does anyone wants me to keep this behaviour?

Also, the PTS adjustments might be different, but I didn't follow the
current discussions about it so I can't tell what people want.
---
 libavfilter/Makefile                |   2 +-
 libavfilter/interlace.h             |  58 ---------
 libavfilter/tinterlace.h            |   5 +-
 libavfilter/vf_interlace.c          | 250 ------------------------------------
 libavfilter/vf_tinterlace.c         |  44 +++++++
 libavfilter/x86/Makefile            |   2 +-
 libavfilter/x86/vf_interlace_init.c |  47 -------
 7 files changed, 49 insertions(+), 359 deletions(-)
 delete mode 100644 libavfilter/interlace.h
 delete mode 100644 libavfilter/vf_interlace.c
 delete mode 100644 libavfilter/x86/vf_interlace_init.c

diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 2c56e38..36676aa 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -136,7 +136,7 @@ OBJS-$(CONFIG_HQX_FILTER)                    += vf_hqx.o
 OBJS-$(CONFIG_HUE_FILTER)                    += vf_hue.o
 OBJS-$(CONFIG_IDET_FILTER)                   += vf_idet.o
 OBJS-$(CONFIG_IL_FILTER)                     += vf_il.o
-OBJS-$(CONFIG_INTERLACE_FILTER)              += vf_interlace.o
+OBJS-$(CONFIG_INTERLACE_FILTER)              += vf_tinterlace.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/interlace.h b/libavfilter/interlace.h
deleted file mode 100644
index 44f1e06..0000000
--- a/libavfilter/interlace.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * @file
- * progressive to interlaced content filter, inspired by heavy debugging of
- * tinterlace filter.
- */
-
-#ifndef AVFILTER_INTERLACE_H
-#define AVFILTER_INTERLACE_H
-
-#include "libavutil/common.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/opt.h"
-
-#include "avfilter.h"
-#include "formats.h"
-#include "internal.h"
-#include "video.h"
-
-enum ScanMode {
-    MODE_TFF = 0,
-    MODE_BFF = 1,
-};
-
-enum FieldType {
-    FIELD_UPPER = 0,
-    FIELD_LOWER = 1,
-};
-
-typedef struct InterlaceContext {
-    const AVClass *class;
-    enum ScanMode scan;    // top or bottom field first scanning
-    int lowpass;           // enable or disable low pass filterning
-    AVFrame *cur, *next;   // the two frames from which the new one is obtained
-    void (*lowpass_line)(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp,
-                         const uint8_t *srcp_above, const uint8_t *srcp_below);
-} InterlaceContext;
-
-void ff_interlace_init_x86(InterlaceContext *interlace);
-
-#endif /* AVFILTER_INTERLACE_H */
diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h
index fa0a83a..846c426 100644
--- a/libavfilter/tinterlace.h
+++ b/libavfilter/tinterlace.h
@@ -44,12 +44,13 @@ enum TInterlaceMode {
 typedef struct {
     const AVClass *class;
     enum TInterlaceMode mode;   ///< interlace mode selected
+    int scan;                   ///< top (0) or bottom (1) field first scanning
     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;
+    int lowpass;                ///< enable or disable low pass filterning
+    AVFrame *cur, *next;        ///< the two frames from which the new one is obtained
     uint8_t *black_data[4];     ///< buffer used to fill padded lines
     int black_linesize[4];
     void (*lowpass_line)(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
diff --git a/libavfilter/vf_interlace.c b/libavfilter/vf_interlace.c
deleted file mode 100644
index 2828e36..0000000
--- a/libavfilter/vf_interlace.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * Copyright (c) 2003 Michael Zucchi <notzed at ximian.com>
- * Copyright (c) 2010 Baptiste Coudurier
- * Copyright (c) 2011 Stefano Sabatini
- * Copyright (c) 2013 Vittorio Giovara <vittorio.giovara at 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 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.
- */
-
-/**
- * @file
- * progressive to interlaced content filter, inspired by heavy debugging of tinterlace filter
- */
-
-#include "libavutil/common.h"
-#include "libavutil/opt.h"
-#include "libavutil/imgutils.h"
-#include "libavutil/avassert.h"
-
-#include "formats.h"
-#include "avfilter.h"
-#include "interlace.h"
-#include "internal.h"
-#include "video.h"
-
-#define OFFSET(x) offsetof(InterlaceContext, x)
-#define V AV_OPT_FLAG_VIDEO_PARAM
-static const AVOption interlace_options[] = {
-    { "scan", "scanning mode", OFFSET(scan),
-        AV_OPT_TYPE_INT,   {.i64 = MODE_TFF }, 0, 1, .flags = V, .unit = "scan" },
-    { "tff", "top field first", 0,
-        AV_OPT_TYPE_CONST, {.i64 = MODE_TFF }, INT_MIN, INT_MAX, .flags = V, .unit = "scan" },
-    { "bff", "bottom field first", 0,
-        AV_OPT_TYPE_CONST, {.i64 = MODE_BFF }, INT_MIN, INT_MAX, .flags = V, .unit = "scan" },
-    { "lowpass", "enable vertical low-pass filter", OFFSET(lowpass),
-        AV_OPT_TYPE_INT,   {.i64 = 1 },        0, 1, .flags = V },
-    { NULL }
-};
-
-AVFILTER_DEFINE_CLASS(interlace);
-
-static void lowpass_line_c(uint8_t *dstp, ptrdiff_t linesize,
-                           const uint8_t *srcp,
-                           const uint8_t *srcp_above,
-                           const uint8_t *srcp_below)
-{
-    int i;
-    for (i = 0; i < linesize; 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 const enum AVPixelFormat formats_supported[] = {
-    AV_PIX_FMT_YUV420P,  AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV444P,
-    AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV410P,  AV_PIX_FMT_YUVA420P,
-    AV_PIX_FMT_GRAY8,    AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
-    AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_NONE
-};
-
-static int query_formats(AVFilterContext *ctx)
-{
-    ff_set_common_formats(ctx, ff_make_format_list(formats_supported));
-    return 0;
-}
-
-static av_cold void uninit(AVFilterContext *ctx)
-{
-    InterlaceContext *s = ctx->priv;
-
-    av_frame_free(&s->cur);
-    av_frame_free(&s->next);
-}
-
-static int config_out_props(AVFilterLink *outlink)
-{
-    AVFilterContext *ctx = outlink->src;
-    AVFilterLink *inlink = outlink->src->inputs[0];
-    InterlaceContext *s = ctx->priv;
-
-    if (inlink->h < 2) {
-        av_log(ctx, AV_LOG_ERROR, "input video height is too small\n");
-        return AVERROR_INVALIDDATA;
-    }
-
-    if (!s->lowpass)
-        av_log(ctx, AV_LOG_WARNING, "***warning*** Lowpass filter is disabled, "
-               "the resulting video will be aliased rather than interlaced.\n");
-
-    // same input size
-    outlink->w = inlink->w;
-    outlink->h = inlink->h;
-    outlink->time_base = inlink->time_base;
-    outlink->frame_rate = inlink->frame_rate;
-    // half framerate
-    outlink->time_base.num *= 2;
-    outlink->frame_rate.den *= 2;
-    outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
-
-
-    if (s->lowpass) {
-        s->lowpass_line = lowpass_line_c;
-        if (ARCH_X86)
-            ff_interlace_init_x86(s);
-    }
-
-    av_log(ctx, AV_LOG_VERBOSE, "%s interlacing %s lowpass filter\n",
-           s->scan == MODE_TFF ? "tff" : "bff", (s->lowpass) ? "with" : "without");
-
-    return 0;
-}
-
-static void copy_picture_field(InterlaceContext *s,
-                               AVFrame *src_frame, AVFrame *dst_frame,
-                               AVFilterLink *inlink, enum FieldType field_type,
-                               int lowpass)
-{
-    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
-    int vsub = desc->log2_chroma_h;
-    int plane, j;
-
-    for (plane = 0; plane < desc->nb_components; plane++) {
-        int lines = (plane == 1 || plane == 2) ? FF_CEIL_RSHIFT(inlink->h, vsub) : inlink->h;
-        ptrdiff_t linesize = av_image_get_linesize(inlink->format, inlink->w, plane);
-        uint8_t *dstp = dst_frame->data[plane];
-        const uint8_t *srcp = src_frame->data[plane];
-
-        av_assert0(linesize >= 0);
-
-        lines = (lines + (field_type == FIELD_UPPER)) / 2;
-        if (field_type == FIELD_LOWER)
-            srcp += src_frame->linesize[plane];
-        if (field_type == FIELD_LOWER)
-            dstp += dst_frame->linesize[plane];
-        if (lowpass) {
-            int srcp_linesize = src_frame->linesize[plane] * 2;
-            int dstp_linesize = dst_frame->linesize[plane] * 2;
-            for (j = lines; j > 0; j--) {
-                const uint8_t *srcp_above = srcp - src_frame->linesize[plane];
-                const uint8_t *srcp_below = srcp + src_frame->linesize[plane];
-                if (j == lines)
-                    srcp_above = srcp; // there is no line above
-                if (j == 1)
-                    srcp_below = srcp; // there is no line below
-                s->lowpass_line(dstp, linesize, srcp, srcp_above, srcp_below);
-                dstp += dstp_linesize;
-                srcp += srcp_linesize;
-            }
-        } else {
-            av_image_copy_plane(dstp, dst_frame->linesize[plane] * 2,
-                                srcp, src_frame->linesize[plane] * 2,
-                                linesize, lines);
-        }
-    }
-}
-
-static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
-{
-    AVFilterContext *ctx = inlink->dst;
-    AVFilterLink *outlink = ctx->outputs[0];
-    InterlaceContext *s = ctx->priv;
-    AVFrame *out;
-    int tff, ret;
-
-    av_frame_free(&s->cur);
-    s->cur  = s->next;
-    s->next = buf;
-
-    /* we need at least two frames */
-    if (!s->cur || !s->next)
-        return 0;
-
-    if (s->cur->interlaced_frame) {
-        av_log(ctx, AV_LOG_WARNING,
-               "video is already interlaced, adjusting framerate only\n");
-        out = av_frame_clone(s->cur);
-        if (!out)
-            return AVERROR(ENOMEM);
-        out->pts /= 2;  // adjust pts to new framerate
-        ret = ff_filter_frame(outlink, out);
-        return ret;
-    }
-
-    tff = (s->scan == MODE_TFF);
-    out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
-    if (!out)
-        return AVERROR(ENOMEM);
-
-    av_frame_copy_props(out, s->cur);
-    out->interlaced_frame = 1;
-    out->top_field_first  = tff;
-    out->pts             /= 2;  // adjust pts to new framerate
-
-    /* copy upper/lower field from cur */
-    copy_picture_field(s, s->cur, out, inlink, tff ? FIELD_UPPER : FIELD_LOWER, s->lowpass);
-    av_frame_free(&s->cur);
-
-    /* copy lower/upper field from next */
-    copy_picture_field(s, s->next, out, inlink, tff ? FIELD_LOWER : FIELD_UPPER, s->lowpass);
-    av_frame_free(&s->next);
-
-    ret = ff_filter_frame(outlink, out);
-
-    return ret;
-}
-
-static const AVFilterPad inputs[] = {
-    {
-        .name         = "default",
-        .type         = AVMEDIA_TYPE_VIDEO,
-        .filter_frame = filter_frame,
-    },
-    { NULL }
-};
-
-static const AVFilterPad outputs[] = {
-    {
-        .name         = "default",
-        .type         = AVMEDIA_TYPE_VIDEO,
-        .config_props = config_out_props,
-    },
-    { NULL }
-};
-
-AVFilter ff_vf_interlace = {
-    .name          = "interlace",
-    .description   = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."),
-    .uninit        = uninit,
-    .priv_class    = &interlace_class,
-    .priv_size     = sizeof(InterlaceContext),
-    .query_formats = query_formats,
-    .inputs        = inputs,
-    .outputs       = outputs,
-};
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
index c644895..f8f865a 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2011 Stefano Sabatini
  * Copyright (c) 2010 Baptiste Coudurier
  * Copyright (c) 2003 Michael Zucchi <notzed at ximian.com>
+ * Copyright (c) 2013 Vittorio Giovara <vittorio.giovara at gmail.com>
  *
  * This file is part of FFmpeg.
  *
@@ -57,6 +58,16 @@ static const AVOption tinterlace_options[] = {
 
 AVFILTER_DEFINE_CLASS(tinterlace);
 
+static const AVOption interlace_options[] = {
+    {"scan", "scanning mode", OFFSET(scan), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, FLAGS, "scan"},
+        { "tff", "top field first",    0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, FLAGS, "scan"},
+        { "bff", "bottom field first", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, FLAGS, "scan"},
+    {"lowpass", "enable vertical low-pass filter", OFFSET(lowpass), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, 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
 
@@ -114,6 +125,11 @@ static int config_out_props(AVFilterLink *outlink)
     TInterlaceContext *tinterlace = ctx->priv;
     int i;
 
+    if (inlink->h < 2) {
+        av_log(ctx, AV_LOG_ERROR, "input video height is too small\n");
+        return AVERROR_INVALIDDATA;
+    }
+
     tinterlace->vsub = desc->log2_chroma_h;
     outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
     outlink->w = inlink->w;
@@ -162,6 +178,13 @@ static int config_out_props(AVFilterLink *outlink)
         (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB))
         outlink->time_base = tinterlace->preout_time_base;
 
+    if (tinterlace->mode == MODE_INTERLEAVE_TOP ||
+        tinterlace->mode == MODE_INTERLEAVE_BOTTOM) {
+        if (!(tinterlace->flags & TINTERLACE_FLAG_VLPF))
+            av_log(ctx, AV_LOG_WARNING, "Vertical lowpass filter is disabled, "
+                   "the resulting video will be aliased rather than interlaced.\n");
+    }
+
     if (tinterlace->flags & TINTERLACE_FLAG_VLPF) {
         tinterlace->lowpass_line = lowpass_line_c;
         if (ARCH_X86)
@@ -414,3 +437,24 @@ AVFilter ff_vf_tinterlace = {
     .outputs       = tinterlace_outputs,
     .priv_class    = &tinterlace_class,
 };
+
+static av_cold int interlace_init(AVFilterContext *ctx)
+{
+    TInterlaceContext *s = ctx->priv;
+
+    s->mode = MODE_INTERLEAVE_TOP + s->scan;
+    s->flags |= s->lowpass ? TINTERLACE_FLAG_VLPF : 0;
+    return 0;
+}
+
+AVFilter ff_vf_interlace = {
+    .name          = "interlace",
+    .description   = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."),
+    .priv_size     = sizeof(TInterlaceContext),
+    .init          = interlace_init,
+    .uninit        = uninit,
+    .query_formats = query_formats,
+    .inputs        = tinterlace_inputs,
+    .outputs       = tinterlace_outputs,
+    .priv_class    = &interlace_class,
+};
diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile
index 44765d2..d77c420 100644
--- a/libavfilter/x86/Makefile
+++ b/libavfilter/x86/Makefile
@@ -1,7 +1,7 @@
 OBJS-$(CONFIG_GRADFUN_FILTER)                += x86/vf_gradfun_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_interlace_init.o
+OBJS-$(CONFIG_INTERLACE_FILTER)              += x86/vf_tinterlace_init.o
 OBJS-$(CONFIG_NOISE_FILTER)                  += x86/vf_noise.o
 OBJS-$(CONFIG_PULLUP_FILTER)                 += x86/vf_pullup_init.o
 OBJS-$(CONFIG_SPP_FILTER)                    += x86/vf_spp.o
diff --git a/libavfilter/x86/vf_interlace_init.c b/libavfilter/x86/vf_interlace_init.c
deleted file mode 100644
index 68ee47d..0000000
--- a/libavfilter/x86/vf_interlace_init.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2014 Kieran Kunhya <kierank at 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/interlace.h"
-
-void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize,
-                          const uint8_t *srcp,
-                          const uint8_t *srcp_above,
-                          const uint8_t *srcp_below);
-void ff_lowpass_line_avx (uint8_t *dstp, ptrdiff_t linesize,
-                          const uint8_t *srcp,
-                          const uint8_t *srcp_above,
-                          const uint8_t *srcp_below);
-
-av_cold void ff_interlace_init_x86(InterlaceContext *s)
-{
-    int cpu_flags = av_get_cpu_flags();
-
-    if (EXTERNAL_SSE2(cpu_flags))
-        s->lowpass_line = ff_lowpass_line_sse2;
-    if (EXTERNAL_AVX(cpu_flags))
-        s->lowpass_line = ff_lowpass_line_avx;
-}
-- 
2.1.3



More information about the ffmpeg-devel mailing list