[FFmpeg-devel] [PATCH] Add "split" mode to tinterlace filter.

Brian Matherly code at brianmatherly.com
Sat Mar 28 23:35:29 CET 2015


From: Brian Matherly <pez4brian at yahoo.com>

This mode is the opposite of the "merge" mode.
---
This patch adds a new mode to tinterlace which performs the opposite operation 
as the "merge" mode. 

My primary motivation is that I have been working with Derek Buitenhuis to see 
about adding interlace support to the libx265 encoder. It turns out that this is
a complex situation since libx265 requires each field to be encoded separately 
but ffmpeg stores fields together as an interlaced frame. tinterlace can be used
with this new mode to provide each field as a separate frame to libx265 - and 
therefore perform valid interlaced h.265 encoding.

At first I considered this patch a hack and planned on keeping it to myself. But
now I think that it must be generally useful since it can produce the exact 
format of data that would be the input to the tinterlace "merge" mode.
As a test, I have checked: 
    ffmpeg -i input.file -vf "tinterlace=split,tinterlace=merge" output.file
And the image makes a successful round trip.
 doc/filters.texi            | 24 ++++++++++++++++++++++++
 libavfilter/tinterlace.h    |  1 +
 libavfilter/vf_tinterlace.c | 43 +++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index 15f8ed5..9b3fd02 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -9197,6 +9197,30 @@ Output:
  11111   11111   22222   22222   33333   33333   44444
 @end example
 
+ at item split, 7
+Perform the inverse operation as merge. Move upper field to odd frames, lower
+field to even frames, generating a half height frame at double frame rate.
+ at example
+ ------> time
+Input:
+Frame 1                         Frame 2
+11111                           33333
+22222                           44444
+11111                           33333
+22222                           44444
+11111                           33333
+22222                           44444
+11111                           33333
+22222                           44444
+
+Output:
+Frame 1         Frame 2         Frame 3         Frame 4
+11111           22222           33333           44444
+11111           22222           33333           44444
+11111           22222           33333           44444
+11111           22222           33333           44444
+ at end example
+
 
 @end table
 
diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h
index fa0a83a..ece8ce4 100644
--- a/libavfilter/tinterlace.h
+++ b/libavfilter/tinterlace.h
@@ -38,6 +38,7 @@ enum TInterlaceMode {
     MODE_INTERLEAVE_TOP,
     MODE_INTERLEAVE_BOTTOM,
     MODE_INTERLACEX2,
+    MODE_SPLIT,
     MODE_NB,
 };
 
diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c
index f3411f9..2c9047b 100644
--- a/libavfilter/vf_tinterlace.c
+++ b/libavfilter/vf_tinterlace.c
@@ -46,6 +46,7 @@ static const AVOption tinterlace_options[] = {
     {"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"},
+    {"split",             "split fields",                                 0, AV_OPT_TYPE_CONST, {.i64=MODE_SPLIT},             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" },
@@ -118,7 +119,8 @@ static int config_out_props(AVFilterLink *outlink)
     outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP;
     outlink->w = inlink->w;
     outlink->h = tinterlace->mode == MODE_MERGE || tinterlace->mode == MODE_PAD ?
-        inlink->h*2 : inlink->h;
+            inlink->h*2 : tinterlace->mode == MODE_SPLIT ?
+            inlink->h/2 : inlink->h;
 
     if (tinterlace->mode == MODE_PAD) {
         uint8_t black[4] = { 16, 128, 128, 16 };
@@ -145,7 +147,7 @@ static int config_out_props(AVFilterLink *outlink)
         tinterlace->flags &= ~TINTERLACE_FLAG_VLPF;
     }
     tinterlace->preout_time_base = inlink->time_base;
-    if (tinterlace->mode == MODE_INTERLACEX2) {
+    if (tinterlace->mode == MODE_INTERLACEX2 || tinterlace->mode == MODE_SPLIT) {
         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});
@@ -372,6 +374,43 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref)
                            tff ? FIELD_UPPER : FIELD_LOWER, 1, tff ? FIELD_UPPER : FIELD_LOWER,
                            tinterlace->flags);
         break;
+    case MODE_SPLIT: /* move the upper field into the new odd frame, lower into the new
+                      * even frame, generating a half-height video at double framerate */
+        /* output upper field first */
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+        if (!out)
+            return AVERROR(ENOMEM);
+        av_frame_copy_props(out, cur);
+        out->height = outlink->h;
+        out->interlaced_frame = 0;
+        if (cur->pts != AV_NOPTS_VALUE)
+            out->pts = cur->pts*2;
+        out->pts = av_rescale_q(out->pts, tinterlace->preout_time_base, outlink->time_base);
+        /* write upper field lines into the new odd frame */
+        copy_picture_field(tinterlace, out->data, out->linesize,
+                           (const uint8_t **)cur->data, cur->linesize,
+                           inlink->format, inlink->w, inlink->h,
+                           FIELD_UPPER, 0, FIELD_UPPER_AND_LOWER, tinterlace->flags);
+        if ((ret = ff_filter_frame(outlink, out)) < 0)
+            return ret;
+
+        /* output lower field */
+        out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
+        if (!out)
+            return AVERROR(ENOMEM);
+        av_frame_copy_props(out, cur);
+        out->height = outlink->h;
+        out->interlaced_frame = 0;
+        if (next->pts != AV_NOPTS_VALUE && cur->pts != AV_NOPTS_VALUE)
+            out->pts = cur->pts + next->pts;
+        else
+            out->pts = AV_NOPTS_VALUE;
+        /* write lower field lines into the new even frame */
+        copy_picture_field(tinterlace, out->data, out->linesize,
+                           (const uint8_t **)cur->data, cur->linesize,
+                           inlink->format, inlink->w, inlink->h,
+                           FIELD_LOWER, 0, FIELD_UPPER_AND_LOWER, tinterlace->flags);
+        break;
     default:
         av_assert0(0);
     }
-- 
1.9.1



More information about the ffmpeg-devel mailing list