From: Brian Matherly <pez4br...@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 +@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. +@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 +@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 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel