From 59f1f764d6cd07ff7d1bb113d423b3e62b3510c1 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Mon, 1 Dec 2014 20:52:10 +0100 Subject: [PATCH] avfilter/vf_tinterlace: Favor using standard timebases for the output Reported-by: Vittorio Giovara Inspired by discussion with Kieran Kunhya Signed-off-by: Michael Niedermayer --- libavfilter/tinterlace.h | 1 + libavfilter/vf_tinterlace.c | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h index 41b78c5e3c..fa0a83ae0c 100644 --- a/libavfilter/tinterlace.h +++ b/libavfilter/tinterlace.h @@ -44,6 +44,7 @@ enum TInterlaceMode { typedef struct { const AVClass *class; enum TInterlaceMode mode; ///< 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 diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c index 133f073631..c644895ee0 100644 --- a/libavfilter/vf_tinterlace.c +++ b/libavfilter/vf_tinterlace.c @@ -35,6 +35,7 @@ #define OFFSET(x) offsetof(TInterlaceContext, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM #define TINTERLACE_FLAG_VLPF 01 +#define TINTERLACE_FLAG_EXACT_TB 2 static const AVOption tinterlace_options[] = { {"mode", "select interlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_MERGE}, 0, MODE_NB-1, FLAGS, "mode"}, @@ -49,6 +50,7 @@ static const AVOption tinterlace_options[] = { {"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" }, + {"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} }; @@ -62,6 +64,12 @@ static const enum AVPixelFormat full_scale_yuvj_pix_fmts[] = { FULL_SCALE_YUVJ_FORMATS, AV_PIX_FMT_NONE }; +static const AVRational standard_tbs[] = { + {1, 25}, + {1, 30}, + {1001, 30000}, +}; + static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat pix_fmts[] = { @@ -104,6 +112,7 @@ static int config_out_props(AVFilterLink *outlink) AVFilterLink *inlink = outlink->src->inputs[0]; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); TInterlaceContext *tinterlace = ctx->priv; + int i; tinterlace->vsub = desc->log2_chroma_h; outlink->flags |= FF_LINK_FLAG_REQUEST_LOOP; @@ -135,14 +144,24 @@ static int config_out_props(AVFilterLink *outlink) tinterlace->mode); tinterlace->flags &= ~TINTERLACE_FLAG_VLPF; } + tinterlace->preout_time_base = inlink->time_base; if (tinterlace->mode == MODE_INTERLACEX2) { - outlink->time_base.num = inlink->time_base.num; - outlink->time_base.den = inlink->time_base.den * 2; + 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_PAD) { outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational){1,2}); + outlink->time_base = av_mul_q(inlink->time_base , (AVRational){2,1}); } + for (i = 0; itime_base)) + break; + } + if (i == FF_ARRAY_ELEMS(standard_tbs) || + (tinterlace->flags & TINTERLACE_FLAG_EXACT_TB)) + outlink->time_base = tinterlace->preout_time_base; + if (tinterlace->flags & TINTERLACE_FLAG_VLPF) { tinterlace->lowpass_line = lowpass_line_c; if (ARCH_X86) @@ -326,6 +345,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) 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); if ((ret = ff_filter_frame(outlink, out)) < 0) return ret; @@ -359,6 +379,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) 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++;