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 | 8 +++++++-
fftools/ffmpeg.h | 3 +++
fftools/ffmpeg_opt.c | 26 +++++++++++++++++++++++---
4 files changed, 40 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 3ad11452da..696ba7d730 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -3390,7 +3390,8 @@ 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 +3401,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" },