Add -fpsmin analogously to -fpsmax for setting a lower bound to the auto-set frame rate.
Signed-off-by: Matthias Neugebauer <mtn...@mailbox.org> --- doc/ffmpeg.texi | 7 +++++++ fftools/ffmpeg.c | 7 ++++++- fftools/ffmpeg.h | 3 +++ fftools/ffmpeg_opt.c | 26 +++++++++++++++++++++++--- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index 9feabe6517..5576508347 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -862,6 +862,13 @@ Clamps output frame rate when output framerate is auto-set and is higher than th Useful in batch processing or when input framerate is wrongly detected as very high. It cannot be set together with @code{-r}. It is ignored during streamcopy. +@item -fpsmin[:@var{stream_specifier}] @var{fps} (@emph{output,per-stream}) +Set minimum frame rate (Hz value, fraction or abbreviation). + +Clamps output frame rate when output framerate is auto-set and is lower than this value. +Useful in batch processing or when input framerate is wrongly detected as very low. +It cannot be set together with @code{-r}. It is ignored during streamcopy. + @item -s[:@var{stream_specifier}] @var{size} (@emph{input/output,per-stream}) Set frame size. diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index b3658d8f65..fd9747a8ac 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -3390,7 +3390,7 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) ost->frame_rate = ist->framerate; if (ist && !ost->frame_rate.num) ost->frame_rate = ist->st->r_frame_rate; - if (ist && !ost->frame_rate.num && !ost->max_frame_rate.num) { + if (ist && !ost->frame_rate.num && !ost->max_frame_rate.num && !ost->min_frame_rate.num) { ost->frame_rate = (AVRational){25, 1}; av_log(NULL, AV_LOG_WARNING, "No information " @@ -3400,6 +3400,11 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame) ost->file_index, ost->index); } + if (ost->min_frame_rate.num && + (av_q2d(ost->frame_rate) < av_q2d(ost->min_frame_rate) || + !ost->frame_rate.den)) + ost->frame_rate = ost->min_frame_rate; + if (ost->max_frame_rate.num && (av_q2d(ost->frame_rate) > av_q2d(ost->max_frame_rate) || !ost->frame_rate.den)) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 606f2afe0c..515d0c7a46 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -110,6 +110,8 @@ typedef struct OptionsContext { int nb_frame_rates; SpecifierOpt *max_frame_rates; int nb_max_frame_rates; + SpecifierOpt *min_frame_rates; + int nb_min_frame_rates; SpecifierOpt *frame_sizes; int nb_frame_sizes; SpecifierOpt *frame_pix_fmts; @@ -486,6 +488,7 @@ typedef struct OutputStream { /* video only */ AVRational frame_rate; AVRational max_frame_rate; + AVRational min_frame_rate; int is_cfr; int force_fps; int top_field_first; diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 849d24b16d..b0d7550ce6 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -56,6 +56,7 @@ static const char *const opt_name_audio_channels[] = {"ac", NULL}; static const char *const opt_name_audio_sample_rate[] = {"ar", NULL}; static const char *const opt_name_frame_rates[] = {"r", NULL}; static const char *const opt_name_max_frame_rates[] = {"fpsmax", NULL}; +static const char *const opt_name_min_frame_rates[] = {"fpsmin", NULL}; static const char *const opt_name_frame_sizes[] = {"s", NULL}; static const char *const opt_name_frame_pix_fmts[] = {"pix_fmt", NULL}; static const char *const opt_name_ts_scale[] = {"itsscale", NULL}; @@ -1694,7 +1695,7 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in AVStream *st; OutputStream *ost; AVCodecContext *video_enc; - char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL; + char *frame_rate = NULL, *max_frame_rate = NULL, *min_frame_rate = NULL, *frame_aspect_ratio = NULL; ost = new_output_stream(o, oc, AVMEDIA_TYPE_VIDEO, source_index); st = ost->st; @@ -1712,14 +1713,30 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in exit_program(1); } + MATCH_PER_STREAM_OPT(min_frame_rates, str, min_frame_rate, oc, st); + if (min_frame_rate && av_parse_video_rate(&ost->min_frame_rate, min_frame_rate) < 0) { + av_log(NULL, AV_LOG_FATAL, "Invalid minimum framerate value: %s\n", min_frame_rate); + exit_program(1); + } + if (frame_rate && max_frame_rate) { av_log(NULL, AV_LOG_ERROR, "Only one of -fpsmax and -r can be set for a stream.\n"); exit_program(1); } - if ((frame_rate || max_frame_rate) && + if (frame_rate && min_frame_rate) { + av_log(NULL, AV_LOG_ERROR, "Only one of -fpsmin and -r can be set for a stream.\n"); + exit_program(1); + } + + if (min_frame_rate && max_frame_rate && av_q2d(ost->min_frame_rate) > av_q2d(ost->max_frame_rate)) { + av_log(NULL, AV_LOG_ERROR, "-fpsmin cannot be larger then -fpsmax.\n"); + exit_program(1); + } + + if ((frame_rate || max_frame_rate || min_frame_rate) && video_sync_method == VSYNC_PASSTHROUGH) - av_log(NULL, AV_LOG_ERROR, "Using -vsync 0 and -r/-fpsmax can produce invalid output files\n"); + av_log(NULL, AV_LOG_ERROR, "Using -vsync 0 and -r/-fpsmax/-fpsmin can produce invalid output files\n"); MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st); if (frame_aspect_ratio) { @@ -3609,6 +3626,9 @@ const OptionDef options[] = { { "fpsmax", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(max_frame_rates) }, "set max frame rate (Hz value, fraction or abbreviation)", "rate" }, + { "fpsmin", OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_SPEC | + OPT_OUTPUT, { .off = OFFSET(min_frame_rates) }, + "set min frame rate (Hz value, fraction or abbreviation)", "rate" }, { "s", OPT_VIDEO | HAS_ARG | OPT_SUBTITLE | OPT_STRING | OPT_SPEC | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(frame_sizes) }, "set frame size (WxH or abbreviation)", "size" }, -- 2.31.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".