diff --git a/ffmpeg.c b/ffmpeg.c index df0ad32b5c..6d1e358a85 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -2905,7 +2905,8 @@ static int init_output_stream_streamcopy(OutputStream *ost) return ret; // copy timebase while removing common factors - ost->st->time_base = av_add_q(av_stream_get_codec_timebase(ost->st), (AVRational){0, 1}); + if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0) + ost->st->time_base = av_add_q(av_stream_get_codec_timebase(ost->st), (AVRational){0, 1}); // copy disposition ost->st->disposition = ist->st->disposition; @@ -3330,7 +3331,8 @@ static int init_output_stream(OutputStream *ost, char *error, int error_len) } // copy timebase while removing common factors - ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1}); + if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0) + ost->st->time_base = av_add_q(ost->enc_ctx->time_base, (AVRational){0, 1}); ost->st->codec->codec= ost->enc_ctx->codec; } else if (ost->stream_copy) { ret = init_output_stream_streamcopy(ost); diff --git a/ffmpeg.h b/ffmpeg.h index 081913bcfc..75bf50ec29 100644 --- a/ffmpeg.h +++ b/ffmpeg.h @@ -224,6 +224,8 @@ typedef struct OptionsContext { int nb_disposition; SpecifierOpt *program; int nb_program; + SpecifierOpt *time_bases; + int nb_time_bases; } OptionsContext; typedef struct InputFilter { diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c index a4b8d24991..a1c02fc29b 100644 --- a/ffmpeg_opt.c +++ b/ffmpeg_opt.c @@ -1231,7 +1231,7 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e OutputStream *ost; AVStream *st = avformat_new_stream(oc, NULL); int idx = oc->nb_streams - 1, ret = 0; - const char *bsfs = NULL; + const char *bsfs = NULL, *time_base = NULL; char *next, *codec_tag = NULL; double qscale = -1; int i; @@ -1308,6 +1308,17 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e ost->encoder_opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL); } + MATCH_PER_STREAM_OPT(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.num <= 0 || q.den <= 0) { + av_log(NULL, AV_LOG_FATAL, "Invalid time base: %s\n", time_base); + exit_program(1); + } + st->time_base = 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++) { @@ -3649,6 +3660,9 @@ const OptionDef options[] = { { "sdp_file", HAS_ARG | OPT_EXPERT | OPT_OUTPUT, { .func_arg = opt_sdp_file }, "specify a file in which to print sdp information", "file" }, + { "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" }, + { "bsf", HAS_ARG | OPT_STRING | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(bitstream_filters) }, "A comma-separated list of bitstream filters", "bitstream_filters" }, { "absf", HAS_ARG | OPT_AUDIO | OPT_EXPERT| OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_old2new },