From 2b06f2d2e24ccc4098f3ab40efd68e8f3f02b273 Mon Sep 17 00:00:00 2001 From: erankor Date: Wed, 3 May 2017 11:50:15 +0300 Subject: [PATCH] ffmpeg: add enc_time_base option add a per-stream option for setting the encoder timebase. the following values are allowed: 0 - for video, use 1/frame_rate, for audio use 1/sample_rate (this is the default) -1 - match the input timebase (when possible) >0 - set the timebase to provided number Signed-off-by: Michael Niedermayer --- doc/ffmpeg.texi | 24 ++++++++++++++++++++++++ ffmpeg.c | 31 +++++++++++++++++++++++++++++-- ffmpeg.h | 3 +++ ffmpeg_opt.c | 16 ++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index e72da8c473..dcc0cfb341 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -1176,6 +1176,30 @@ Try to make the choice automatically, in order to generate a sane output. Default value is -1. +@item -enc_time_base[:@var{stream_specifier}] @var{timebase} (@emph{output,per-stream}) +Set the encoder timebase. @var{timebase} is a floating point number, +and can assume one of the following values: + +@table @option +@item 0 +Assign a default value according to the media type. + +For video - use 1/framerate, for audio - use 1/samplerate. + +@item -1 +Use the input stream timebase when possible. + +If an input stream is not available, the default timebase will be used. + +@item >0 +Use the provided number as the timebase. + +This field can be provided as a ratio of two integers (e.g. 1:24, 1:48000) +or as a floating point number (e.g. 0.04166, 2.0833e-5) +@end table + +Default value is 0. + @item -shortest (@emph{output}) Finish encoding when the shortest input stream ends. @item -dts_delta_threshold diff --git a/ffmpeg.c b/ffmpeg.c index e798d92277..76bf008c73 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -3234,6 +3234,30 @@ static void parse_forced_key_frames(char *kf, OutputStream *ost, ost->forced_kf_pts = pts; } +static void init_encoder_time_base(OutputStream *ost, AVRational default_time_base) +{ + InputStream *ist = get_input_stream(ost); + AVCodecContext *enc_ctx = ost->enc_ctx; + AVFormatContext *oc; + + if (ost->enc_timebase.num > 0) { + enc_ctx->time_base = ost->enc_timebase; + return; + } + + if (ost->enc_timebase.num < 0) { + if (ist) { + enc_ctx->time_base = ist->st->time_base; + return; + } + + oc = output_files[ost->file_index]->ctx; + av_log(oc, AV_LOG_WARNING, "Input stream data not available, using default time base\n"); + } + + enc_ctx->time_base = default_time_base; +} + static int init_output_stream_encode(OutputStream *ost) { InputStream *ist = get_input_stream(ost); @@ -3304,10 +3328,13 @@ static int init_output_stream_encode(OutputStream *ost) enc_ctx->sample_rate = av_buffersink_get_sample_rate(ost->filter->filter); enc_ctx->channel_layout = av_buffersink_get_channel_layout(ost->filter->filter); enc_ctx->channels = av_buffersink_get_channels(ost->filter->filter); - enc_ctx->time_base = (AVRational){ 1, enc_ctx->sample_rate }; + + init_encoder_time_base(ost, av_make_q(1, enc_ctx->sample_rate)); break; + case AVMEDIA_TYPE_VIDEO: - enc_ctx->time_base = av_inv_q(ost->frame_rate); + init_encoder_time_base(ost, av_inv_q(ost->frame_rate)); + if (!(enc_ctx->time_base.num && enc_ctx->time_base.den)) enc_ctx->time_base = av_buffersink_get_time_base(ost->filter->filter); if ( av_q2d(enc_ctx->time_base) < 0.001 && video_sync_method != VSYNC_PASSTHROUGH diff --git a/ffmpeg.h b/ffmpeg.h index d34561275a..854ed1924a 100644 --- a/ffmpeg.h +++ b/ffmpeg.h @@ -226,6 +226,8 @@ typedef struct OptionsContext { int nb_program; SpecifierOpt *time_bases; int nb_time_bases; + SpecifierOpt *enc_time_bases; + int nb_enc_time_bases; } OptionsContext; typedef struct InputFilter { @@ -453,6 +455,7 @@ typedef struct OutputStream { int64_t last_mux_dts; // the timebase of the packets sent to the muxer AVRational mux_timebase; + AVRational enc_timebase; int nb_bitstream_filters; uint8_t *bsf_extradata_updated; diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c index ce85f324cf..4720e12269 100644 --- a/ffmpeg_opt.c +++ b/ffmpeg_opt.c @@ -1311,6 +1311,17 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e st->time_base = q; } + MATCH_PER_STREAM_OPT(enc_time_bases, str, time_base, oc, st); + if (time_base) { + AVRational q; + if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 || + q.den <= 0) { + av_log(NULL, AV_LOG_FATAL, "Invalid time base: %s\n", time_base); + exit_program(1); + } + ost->enc_timebase = q; + } + ost->max_frames = INT64_MAX; MATCH_PER_STREAM_OPT(max_frames, i64, ost->max_frames, oc, st); for (i = 0; inb_max_frames; i++) { @@ -3629,6 +3640,11 @@ const OptionDef options[] = { { "time_base", HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(time_bases) }, "set the desired time base hint for output stream (1:24, 1:48000 or 0.04166, 2.0833e-5)", "ratio" }, + { "enc_time_base", HAS_ARG | OPT_STRING | OPT_EXPERT | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(enc_time_bases) }, + "set the desired time base for the encoder (1:24, 1:48000 or 0.04166, 2.0833e-5). " + "two special values are defined - " + "0 = use frame rate (video) or sample rate (audio)," + "-1 = match source time base", "ratio" }, { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(bitstream_filters) }, "A comma-separated list of bitstream filters", "bitstream_filters" }, -- 2.11.0