diff mbox series

[FFmpeg-devel,v2] ffmpeg: add option fps_mode

Message ID 20220610130938.862-1-ffmpeg@gyani.pro
State Accepted
Commit 09c53a04c5892baee88872fbce3df17a00472faa
Headers show
Series [FFmpeg-devel,v2] ffmpeg: add option fps_mode | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Gyan Doshi June 10, 2022, 1:09 p.m. UTC
fps_mode sets video sync per output stream. Overrides vsync for matching
streams.

vsync is deprecated.
---
 doc/ffmpeg.texi      | 14 ++++++++------
 fftools/ffmpeg.c     |  9 +++++----
 fftools/ffmpeg.h     |  3 +++
 fftools/ffmpeg_mux.c |  2 +-
 fftools/ffmpeg_opt.c | 42 +++++++++++++++++++++++++++++++-----------
 5 files changed, 48 insertions(+), 22 deletions(-)

Comments

Gyan Doshi June 11, 2022, 4:23 a.m. UTC | #1
Pushed as 09c53a04c5892baee88872fbce3df17a00472faa

On 2022-06-10 06:39 pm, Gyan Doshi wrote:
> fps_mode sets video sync per output stream. Overrides vsync for matching
> streams.
>
> vsync is deprecated.
> ---
>   doc/ffmpeg.texi      | 14 ++++++++------
>   fftools/ffmpeg.c     |  9 +++++----
>   fftools/ffmpeg.h     |  3 +++
>   fftools/ffmpeg_mux.c |  2 +-
>   fftools/ffmpeg_opt.c | 42 +++++++++++++++++++++++++++++++-----------
>   5 files changed, 48 insertions(+), 22 deletions(-)
>
> diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
> index 0d7e1a479d..51515c2cb8 100644
> --- a/doc/ffmpeg.texi
> +++ b/doc/ffmpeg.texi
> @@ -1618,12 +1618,14 @@ it may cause packet loss.
>   It is useful for when flow speed of output packets is important, such as live streaming.
>   @item -re (@emph{input})
>   Read input at native frame rate. This is equivalent to setting @code{-readrate 1}.
> -@item -vsync @var{parameter}
> -Video sync method.
> -
> -For compatibility reasons some of the values can be specified as numbers (shown
> -in parentheses in the following table). This is deprecated and will stop working
> -in the future.
> +@item -vsync @var{parameter} (@emph{global})
> +@itemx -fps_mode[:@var{stream_specifier}] @var{parameter} (@emph{output,per-stream})
> +Set video sync method / framerate mode. vsync is applied to all output video streams
> +but can be overridden for a stream by setting fps_mode. vsync is deprecated and will be
> +removed in the future.
> +
> +For compatibility reasons some of the values for vsync can be specified as numbers (shown
> +in parentheses in the following table).
>   
>   @table @option
>   @item passthrough (0)
> diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
> index a5e1bf3993..09caa3e3c4 100644
> --- a/fftools/ffmpeg.c
> +++ b/fftools/ffmpeg.c
> @@ -3017,11 +3017,12 @@ static int init_output_stream_encode(OutputStream *ost, AVFrame *frame)
>   
>           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
> -           && (video_sync_method == VSYNC_CFR || video_sync_method == VSYNC_VSCFR ||
> -               (video_sync_method == VSYNC_AUTO && !(of->format->flags & AVFMT_VARIABLE_FPS)))){
> +        if (   av_q2d(enc_ctx->time_base) < 0.001 && ost->vsync_method != VSYNC_PASSTHROUGH
> +           && (ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR ||
> +               (ost->vsync_method == VSYNC_AUTO && !(of->format->flags & AVFMT_VARIABLE_FPS)))){
>               av_log(oc, AV_LOG_WARNING, "Frame rate very high for a muxer not efficiently supporting it.\n"
> -                                       "Please consider specifying a lower framerate, a different muxer or -vsync 2\n");
> +                                       "Please consider specifying a lower framerate, a different muxer or "
> +                                       "setting vsync/fps_mode to vfr\n");
>           }
>   
>           enc_ctx->width  = av_buffersink_get_w(ost->filter->filter);
> diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
> index 7326193caf..69a368b8d1 100644
> --- a/fftools/ffmpeg.h
> +++ b/fftools/ffmpeg.h
> @@ -176,6 +176,8 @@ typedef struct OptionsContext {
>       int        nb_qscale;
>       SpecifierOpt *forced_key_frames;
>       int        nb_forced_key_frames;
> +    SpecifierOpt *fps_mode;
> +    int        nb_fps_mode;
>       SpecifierOpt *force_fps;
>       int        nb_force_fps;
>       SpecifierOpt *frame_aspect_ratios;
> @@ -489,6 +491,7 @@ typedef struct OutputStream {
>       AVRational max_frame_rate;
>       enum VideoSyncMethod vsync_method;
>       int is_cfr;
> +    const char *fps_mode;
>       int force_fps;
>       int top_field_first;
>       int rotate_overridden;
> diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c
> index 794d580635..a55fd18f8f 100644
> --- a/fftools/ffmpeg_mux.c
> +++ b/fftools/ffmpeg_mux.c
> @@ -96,7 +96,7 @@ void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost,
>           return;
>       }
>   
> -    if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP) ||
> +    if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->vsync_method == VSYNC_DROP) ||
>           (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0))
>           pkt->pts = pkt->dts = AV_NOPTS_VALUE;
>   
> diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
> index 2c1b3bd0dd..398067da96 100644
> --- a/fftools/ffmpeg_opt.c
> +++ b/fftools/ffmpeg_opt.c
> @@ -81,6 +81,7 @@ static const char *const opt_name_codec_tags[]                = {"tag", "atag",
>   static const char *const opt_name_sample_fmts[]               = {"sample_fmt", NULL};
>   static const char *const opt_name_qscale[]                    = {"q", "qscale", NULL};
>   static const char *const opt_name_forced_key_frames[]         = {"forced_key_frames", NULL};
> +static const char *const opt_name_fps_mode[]                  = {"fps_mode", NULL};
>   static const char *const opt_name_force_fps[]                 = {"force_fps", NULL};
>   static const char *const opt_name_frame_aspect_ratios[]       = {"aspect", NULL};
>   static const char *const opt_name_rc_overrides[]              = {"rc_override", NULL};
> @@ -265,6 +266,26 @@ static AVDictionary *strip_specifiers(AVDictionary *dict)
>       return ret;
>   }
>   
> +static int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global)
> +{
> +    if      (!av_strcasecmp(arg, "cfr"))         *vsync_var = VSYNC_CFR;
> +    else if (!av_strcasecmp(arg, "vfr"))         *vsync_var = VSYNC_VFR;
> +    else if (!av_strcasecmp(arg, "passthrough")) *vsync_var = VSYNC_PASSTHROUGH;
> +    else if (!av_strcasecmp(arg, "drop"))        *vsync_var = VSYNC_DROP;
> +    else if (!is_global && !av_strcasecmp(arg, "auto"))  *vsync_var = VSYNC_AUTO;
> +    else if (!is_global) {
> +        av_log(NULL, AV_LOG_FATAL, "Invalid value %s specified for fps_mode of #%d:%d.\n", arg, file_idx, st_idx);
> +        exit_program(1);
> +    }
> +
> +    if (is_global && *vsync_var == VSYNC_AUTO) {
> +        video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
> +        av_log(NULL, AV_LOG_WARNING, "Passing a number to -vsync is deprecated,"
> +               " use a string argument as described in the manual.\n");
> +    }
> +    return 0;
> +}
> +
>   static int opt_filter_threads(void *optctx, const char *opt, const char *arg)
>   {
>       av_free(filter_nbthreads);
> @@ -1905,6 +1926,10 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in
>           MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
>   
>           ost->vsync_method = video_sync_method;
> +        MATCH_PER_STREAM_OPT(fps_mode, str, ost->fps_mode, oc, st);
> +        if (ost->fps_mode)
> +            parse_and_set_vsync(ost->fps_mode, &ost->vsync_method, ost->file_index, ost->index, 0);
> +
>           if (ost->vsync_method == VSYNC_AUTO) {
>               if (!strcmp(oc->oformat->name, "avi")) {
>                   ost->vsync_method = VSYNC_VFR;
> @@ -3248,16 +3273,8 @@ static int opt_audio_filters(void *optctx, const char *opt, const char *arg)
>   
>   static int opt_vsync(void *optctx, const char *opt, const char *arg)
>   {
> -    if      (!av_strcasecmp(arg, "cfr"))         video_sync_method = VSYNC_CFR;
> -    else if (!av_strcasecmp(arg, "vfr"))         video_sync_method = VSYNC_VFR;
> -    else if (!av_strcasecmp(arg, "passthrough")) video_sync_method = VSYNC_PASSTHROUGH;
> -    else if (!av_strcasecmp(arg, "drop"))        video_sync_method = VSYNC_DROP;
> -
> -    if (video_sync_method == VSYNC_AUTO) {
> -        video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
> -        av_log(NULL, AV_LOG_WARNING, "Passing a number to -vsync is deprecated,"
> -               " use a string argument as described in the manual.\n");
> -    }
> +    av_log(NULL, AV_LOG_WARNING, "-vsync is deprecated. Use -fps_mode\n");
> +    parse_and_set_vsync(arg, &video_sync_method, -1, -1, 1);
>       return 0;
>   }
>   
> @@ -3620,7 +3637,7 @@ const OptionDef options[] = {
>           "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\" or \"dv50\" "
>           "with optional prefixes \"pal-\", \"ntsc-\" or \"film-\")", "type" },
>       { "vsync",          HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_vsync },
> -        "video sync method", "" },
> +        "set video sync method globally; deprecated, use -fps_mode", "" },
>       { "frame_drop_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT,      { &frame_drop_threshold },
>           "frame drop threshold", "" },
>       { "async",          HAS_ARG | OPT_INT | OPT_EXPERT,              { &audio_sync_method },
> @@ -3777,6 +3794,9 @@ const OptionDef options[] = {
>           "force video tag/fourcc", "fourcc/tag" },
>       { "qphist",       OPT_VIDEO | OPT_BOOL | OPT_EXPERT ,                        { &qp_hist },
>           "show QP histogram" },
> +    { "fps_mode",     OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT |
> +                      OPT_SPEC | OPT_OUTPUT,                                     { .off = OFFSET(fps_mode) },
> +        "set framerate mode for matching video streams; overrides vsync" },
>       { "force_fps",    OPT_VIDEO | OPT_BOOL | OPT_EXPERT  | OPT_SPEC |
>                         OPT_OUTPUT,                                                { .off = OFFSET(force_fps) },
>           "force the selected framerate, disable the best supported framerate selection" },
Jie Zhang June 11, 2022, 8:45 a.m. UTC | #2
Now the `vsync` function has a better name. On the other hand, I'm curious
whether the `vsync`/`fps_mode` function is still valuable in the ffmpeg
tool source since the `fps` filter does almost the same job, but may have
less coupling?

On Sat, Jun 11, 2022 at 12:24 PM Gyan Doshi <ffmpeg@gyani.pro> wrote:

> Pushed as 09c53a04c5892baee88872fbce3df17a00472faa
>
> On 2022-06-10 06:39 pm, Gyan Doshi wrote:
> > fps_mode sets video sync per output stream. Overrides vsync for matching
> > streams.
> >
> > vsync is deprecated.
> > ---
> >   doc/ffmpeg.texi      | 14 ++++++++------
> >   fftools/ffmpeg.c     |  9 +++++----
> >   fftools/ffmpeg.h     |  3 +++
> >   fftools/ffmpeg_mux.c |  2 +-
> >   fftools/ffmpeg_opt.c | 42 +++++++++++++++++++++++++++++++-----------
> >   5 files changed, 48 insertions(+), 22 deletions(-)
> >
> > diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
> > index 0d7e1a479d..51515c2cb8 100644
> > --- a/doc/ffmpeg.texi
> > +++ b/doc/ffmpeg.texi
> > @@ -1618,12 +1618,14 @@ it may cause packet loss.
> >   It is useful for when flow speed of output packets is important, such
> as live streaming.
> >   @item -re (@emph{input})
> >   Read input at native frame rate. This is equivalent to setting
> @code{-readrate 1}.
> > -@item -vsync @var{parameter}
> > -Video sync method.
> > -
> > -For compatibility reasons some of the values can be specified as
> numbers (shown
> > -in parentheses in the following table). This is deprecated and will
> stop working
> > -in the future.
> > +@item -vsync @var{parameter} (@emph{global})
> > +@itemx -fps_mode[:@var{stream_specifier}] @var{parameter}
> (@emph{output,per-stream})
> > +Set video sync method / framerate mode. vsync is applied to all output
> video streams
> > +but can be overridden for a stream by setting fps_mode. vsync is
> deprecated and will be
> > +removed in the future.
> > +
> > +For compatibility reasons some of the values for vsync can be specified
> as numbers (shown
> > +in parentheses in the following table).
> >
> >   @table @option
> >   @item passthrough (0)
> > diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
> > index a5e1bf3993..09caa3e3c4 100644
> > --- a/fftools/ffmpeg.c
> > +++ b/fftools/ffmpeg.c
> > @@ -3017,11 +3017,12 @@ static int
> init_output_stream_encode(OutputStream *ost, AVFrame *frame)
> >
> >           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
> > -           && (video_sync_method == VSYNC_CFR || video_sync_method ==
> VSYNC_VSCFR ||
> > -               (video_sync_method == VSYNC_AUTO && !(of->format->flags
> & AVFMT_VARIABLE_FPS)))){
> > +        if (   av_q2d(enc_ctx->time_base) < 0.001 && ost->vsync_method
> != VSYNC_PASSTHROUGH
> > +           && (ost->vsync_method == VSYNC_CFR || ost->vsync_method ==
> VSYNC_VSCFR ||
> > +               (ost->vsync_method == VSYNC_AUTO && !(of->format->flags
> & AVFMT_VARIABLE_FPS)))){
> >               av_log(oc, AV_LOG_WARNING, "Frame rate very high for a
> muxer not efficiently supporting it.\n"
> > -                                       "Please consider specifying a
> lower framerate, a different muxer or -vsync 2\n");
> > +                                       "Please consider specifying a
> lower framerate, a different muxer or "
> > +                                       "setting vsync/fps_mode to
> vfr\n");
> >           }
> >
> >           enc_ctx->width  = av_buffersink_get_w(ost->filter->filter);
> > diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
> > index 7326193caf..69a368b8d1 100644
> > --- a/fftools/ffmpeg.h
> > +++ b/fftools/ffmpeg.h
> > @@ -176,6 +176,8 @@ typedef struct OptionsContext {
> >       int        nb_qscale;
> >       SpecifierOpt *forced_key_frames;
> >       int        nb_forced_key_frames;
> > +    SpecifierOpt *fps_mode;
> > +    int        nb_fps_mode;
> >       SpecifierOpt *force_fps;
> >       int        nb_force_fps;
> >       SpecifierOpt *frame_aspect_ratios;
> > @@ -489,6 +491,7 @@ typedef struct OutputStream {
> >       AVRational max_frame_rate;
> >       enum VideoSyncMethod vsync_method;
> >       int is_cfr;
> > +    const char *fps_mode;
> >       int force_fps;
> >       int top_field_first;
> >       int rotate_overridden;
> > diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c
> > index 794d580635..a55fd18f8f 100644
> > --- a/fftools/ffmpeg_mux.c
> > +++ b/fftools/ffmpeg_mux.c
> > @@ -96,7 +96,7 @@ void of_write_packet(OutputFile *of, AVPacket *pkt,
> OutputStream *ost,
> >           return;
> >       }
> >
> > -    if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
> video_sync_method == VSYNC_DROP) ||
> > +    if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
> ost->vsync_method == VSYNC_DROP) ||
> >           (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
> audio_sync_method < 0))
> >           pkt->pts = pkt->dts = AV_NOPTS_VALUE;
> >
> > diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
> > index 2c1b3bd0dd..398067da96 100644
> > --- a/fftools/ffmpeg_opt.c
> > +++ b/fftools/ffmpeg_opt.c
> > @@ -81,6 +81,7 @@ static const char *const opt_name_codec_tags[]
>         = {"tag", "atag",
> >   static const char *const opt_name_sample_fmts[]               =
> {"sample_fmt", NULL};
> >   static const char *const opt_name_qscale[]                    = {"q",
> "qscale", NULL};
> >   static const char *const opt_name_forced_key_frames[]         =
> {"forced_key_frames", NULL};
> > +static const char *const opt_name_fps_mode[]                  =
> {"fps_mode", NULL};
> >   static const char *const opt_name_force_fps[]                 =
> {"force_fps", NULL};
> >   static const char *const opt_name_frame_aspect_ratios[]       =
> {"aspect", NULL};
> >   static const char *const opt_name_rc_overrides[]              =
> {"rc_override", NULL};
> > @@ -265,6 +266,26 @@ static AVDictionary *strip_specifiers(AVDictionary
> *dict)
> >       return ret;
> >   }
> >
> > +static int parse_and_set_vsync(const char *arg, int *vsync_var, int
> file_idx, int st_idx, int is_global)
> > +{
> > +    if      (!av_strcasecmp(arg, "cfr"))         *vsync_var = VSYNC_CFR;
> > +    else if (!av_strcasecmp(arg, "vfr"))         *vsync_var = VSYNC_VFR;
> > +    else if (!av_strcasecmp(arg, "passthrough")) *vsync_var =
> VSYNC_PASSTHROUGH;
> > +    else if (!av_strcasecmp(arg, "drop"))        *vsync_var =
> VSYNC_DROP;
> > +    else if (!is_global && !av_strcasecmp(arg, "auto"))  *vsync_var =
> VSYNC_AUTO;
> > +    else if (!is_global) {
> > +        av_log(NULL, AV_LOG_FATAL, "Invalid value %s specified for
> fps_mode of #%d:%d.\n", arg, file_idx, st_idx);
> > +        exit_program(1);
> > +    }
> > +
> > +    if (is_global && *vsync_var == VSYNC_AUTO) {
> > +        video_sync_method = parse_number_or_die("vsync", arg, OPT_INT,
> VSYNC_AUTO, VSYNC_VFR);
> > +        av_log(NULL, AV_LOG_WARNING, "Passing a number to -vsync is
> deprecated,"
> > +               " use a string argument as described in the manual.\n");
> > +    }
> > +    return 0;
> > +}
> > +
> >   static int opt_filter_threads(void *optctx, const char *opt, const
> char *arg)
> >   {
> >       av_free(filter_nbthreads);
> > @@ -1905,6 +1926,10 @@ static OutputStream
> *new_video_stream(OptionsContext *o, AVFormatContext *oc, in
> >           MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first,
> oc, st);
> >
> >           ost->vsync_method = video_sync_method;
> > +        MATCH_PER_STREAM_OPT(fps_mode, str, ost->fps_mode, oc, st);
> > +        if (ost->fps_mode)
> > +            parse_and_set_vsync(ost->fps_mode, &ost->vsync_method,
> ost->file_index, ost->index, 0);
> > +
> >           if (ost->vsync_method == VSYNC_AUTO) {
> >               if (!strcmp(oc->oformat->name, "avi")) {
> >                   ost->vsync_method = VSYNC_VFR;
> > @@ -3248,16 +3273,8 @@ static int opt_audio_filters(void *optctx, const
> char *opt, const char *arg)
> >
> >   static int opt_vsync(void *optctx, const char *opt, const char *arg)
> >   {
> > -    if      (!av_strcasecmp(arg, "cfr"))         video_sync_method =
> VSYNC_CFR;
> > -    else if (!av_strcasecmp(arg, "vfr"))         video_sync_method =
> VSYNC_VFR;
> > -    else if (!av_strcasecmp(arg, "passthrough")) video_sync_method =
> VSYNC_PASSTHROUGH;
> > -    else if (!av_strcasecmp(arg, "drop"))        video_sync_method =
> VSYNC_DROP;
> > -
> > -    if (video_sync_method == VSYNC_AUTO) {
> > -        video_sync_method = parse_number_or_die("vsync", arg, OPT_INT,
> VSYNC_AUTO, VSYNC_VFR);
> > -        av_log(NULL, AV_LOG_WARNING, "Passing a number to -vsync is
> deprecated,"
> > -               " use a string argument as described in the manual.\n");
> > -    }
> > +    av_log(NULL, AV_LOG_WARNING, "-vsync is deprecated. Use
> -fps_mode\n");
> > +    parse_and_set_vsync(arg, &video_sync_method, -1, -1, 1);
> >       return 0;
> >   }
> >
> > @@ -3620,7 +3637,7 @@ const OptionDef options[] = {
> >           "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\"
> or \"dv50\" "
> >           "with optional prefixes \"pal-\", \"ntsc-\" or \"film-\")",
> "type" },
> >       { "vsync",          HAS_ARG | OPT_EXPERT,                        {
> .func_arg = opt_vsync },
> > -        "video sync method", "" },
> > +        "set video sync method globally; deprecated, use -fps_mode", ""
> },
> >       { "frame_drop_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT,      {
> &frame_drop_threshold },
> >           "frame drop threshold", "" },
> >       { "async",          HAS_ARG | OPT_INT | OPT_EXPERT,              {
> &audio_sync_method },
> > @@ -3777,6 +3794,9 @@ const OptionDef options[] = {
> >           "force video tag/fourcc", "fourcc/tag" },
> >       { "qphist",       OPT_VIDEO | OPT_BOOL | OPT_EXPERT ,
>           { &qp_hist },
> >           "show QP histogram" },
> > +    { "fps_mode",     OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT |
> > +                      OPT_SPEC | OPT_OUTPUT,
>          { .off = OFFSET(fps_mode) },
> > +        "set framerate mode for matching video streams; overrides
> vsync" },
> >       { "force_fps",    OPT_VIDEO | OPT_BOOL | OPT_EXPERT  | OPT_SPEC |
> >                         OPT_OUTPUT,
>           { .off = OFFSET(force_fps) },
> >           "force the selected framerate, disable the best supported
> framerate selection" },
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>
diff mbox series

Patch

diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index 0d7e1a479d..51515c2cb8 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1618,12 +1618,14 @@  it may cause packet loss.
 It is useful for when flow speed of output packets is important, such as live streaming.
 @item -re (@emph{input})
 Read input at native frame rate. This is equivalent to setting @code{-readrate 1}.
-@item -vsync @var{parameter}
-Video sync method.
-
-For compatibility reasons some of the values can be specified as numbers (shown
-in parentheses in the following table). This is deprecated and will stop working
-in the future.
+@item -vsync @var{parameter} (@emph{global})
+@itemx -fps_mode[:@var{stream_specifier}] @var{parameter} (@emph{output,per-stream})
+Set video sync method / framerate mode. vsync is applied to all output video streams
+but can be overridden for a stream by setting fps_mode. vsync is deprecated and will be
+removed in the future.
+
+For compatibility reasons some of the values for vsync can be specified as numbers (shown
+in parentheses in the following table).
 
 @table @option
 @item passthrough (0)
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index a5e1bf3993..09caa3e3c4 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -3017,11 +3017,12 @@  static int init_output_stream_encode(OutputStream *ost, AVFrame *frame)
 
         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
-           && (video_sync_method == VSYNC_CFR || video_sync_method == VSYNC_VSCFR ||
-               (video_sync_method == VSYNC_AUTO && !(of->format->flags & AVFMT_VARIABLE_FPS)))){
+        if (   av_q2d(enc_ctx->time_base) < 0.001 && ost->vsync_method != VSYNC_PASSTHROUGH
+           && (ost->vsync_method == VSYNC_CFR || ost->vsync_method == VSYNC_VSCFR ||
+               (ost->vsync_method == VSYNC_AUTO && !(of->format->flags & AVFMT_VARIABLE_FPS)))){
             av_log(oc, AV_LOG_WARNING, "Frame rate very high for a muxer not efficiently supporting it.\n"
-                                       "Please consider specifying a lower framerate, a different muxer or -vsync 2\n");
+                                       "Please consider specifying a lower framerate, a different muxer or "
+                                       "setting vsync/fps_mode to vfr\n");
         }
 
         enc_ctx->width  = av_buffersink_get_w(ost->filter->filter);
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 7326193caf..69a368b8d1 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -176,6 +176,8 @@  typedef struct OptionsContext {
     int        nb_qscale;
     SpecifierOpt *forced_key_frames;
     int        nb_forced_key_frames;
+    SpecifierOpt *fps_mode;
+    int        nb_fps_mode;
     SpecifierOpt *force_fps;
     int        nb_force_fps;
     SpecifierOpt *frame_aspect_ratios;
@@ -489,6 +491,7 @@  typedef struct OutputStream {
     AVRational max_frame_rate;
     enum VideoSyncMethod vsync_method;
     int is_cfr;
+    const char *fps_mode;
     int force_fps;
     int top_field_first;
     int rotate_overridden;
diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c
index 794d580635..a55fd18f8f 100644
--- a/fftools/ffmpeg_mux.c
+++ b/fftools/ffmpeg_mux.c
@@ -96,7 +96,7 @@  void of_write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost,
         return;
     }
 
-    if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && video_sync_method == VSYNC_DROP) ||
+    if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ost->vsync_method == VSYNC_DROP) ||
         (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && audio_sync_method < 0))
         pkt->pts = pkt->dts = AV_NOPTS_VALUE;
 
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 2c1b3bd0dd..398067da96 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -81,6 +81,7 @@  static const char *const opt_name_codec_tags[]                = {"tag", "atag",
 static const char *const opt_name_sample_fmts[]               = {"sample_fmt", NULL};
 static const char *const opt_name_qscale[]                    = {"q", "qscale", NULL};
 static const char *const opt_name_forced_key_frames[]         = {"forced_key_frames", NULL};
+static const char *const opt_name_fps_mode[]                  = {"fps_mode", NULL};
 static const char *const opt_name_force_fps[]                 = {"force_fps", NULL};
 static const char *const opt_name_frame_aspect_ratios[]       = {"aspect", NULL};
 static const char *const opt_name_rc_overrides[]              = {"rc_override", NULL};
@@ -265,6 +266,26 @@  static AVDictionary *strip_specifiers(AVDictionary *dict)
     return ret;
 }
 
+static int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global)
+{
+    if      (!av_strcasecmp(arg, "cfr"))         *vsync_var = VSYNC_CFR;
+    else if (!av_strcasecmp(arg, "vfr"))         *vsync_var = VSYNC_VFR;
+    else if (!av_strcasecmp(arg, "passthrough")) *vsync_var = VSYNC_PASSTHROUGH;
+    else if (!av_strcasecmp(arg, "drop"))        *vsync_var = VSYNC_DROP;
+    else if (!is_global && !av_strcasecmp(arg, "auto"))  *vsync_var = VSYNC_AUTO;
+    else if (!is_global) {
+        av_log(NULL, AV_LOG_FATAL, "Invalid value %s specified for fps_mode of #%d:%d.\n", arg, file_idx, st_idx);
+        exit_program(1);
+    }
+
+    if (is_global && *vsync_var == VSYNC_AUTO) {
+        video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
+        av_log(NULL, AV_LOG_WARNING, "Passing a number to -vsync is deprecated,"
+               " use a string argument as described in the manual.\n");
+    }
+    return 0;
+}
+
 static int opt_filter_threads(void *optctx, const char *opt, const char *arg)
 {
     av_free(filter_nbthreads);
@@ -1905,6 +1926,10 @@  static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in
         MATCH_PER_STREAM_OPT(top_field_first, i, ost->top_field_first, oc, st);
 
         ost->vsync_method = video_sync_method;
+        MATCH_PER_STREAM_OPT(fps_mode, str, ost->fps_mode, oc, st);
+        if (ost->fps_mode)
+            parse_and_set_vsync(ost->fps_mode, &ost->vsync_method, ost->file_index, ost->index, 0);
+
         if (ost->vsync_method == VSYNC_AUTO) {
             if (!strcmp(oc->oformat->name, "avi")) {
                 ost->vsync_method = VSYNC_VFR;
@@ -3248,16 +3273,8 @@  static int opt_audio_filters(void *optctx, const char *opt, const char *arg)
 
 static int opt_vsync(void *optctx, const char *opt, const char *arg)
 {
-    if      (!av_strcasecmp(arg, "cfr"))         video_sync_method = VSYNC_CFR;
-    else if (!av_strcasecmp(arg, "vfr"))         video_sync_method = VSYNC_VFR;
-    else if (!av_strcasecmp(arg, "passthrough")) video_sync_method = VSYNC_PASSTHROUGH;
-    else if (!av_strcasecmp(arg, "drop"))        video_sync_method = VSYNC_DROP;
-
-    if (video_sync_method == VSYNC_AUTO) {
-        video_sync_method = parse_number_or_die("vsync", arg, OPT_INT, VSYNC_AUTO, VSYNC_VFR);
-        av_log(NULL, AV_LOG_WARNING, "Passing a number to -vsync is deprecated,"
-               " use a string argument as described in the manual.\n");
-    }
+    av_log(NULL, AV_LOG_WARNING, "-vsync is deprecated. Use -fps_mode\n");
+    parse_and_set_vsync(arg, &video_sync_method, -1, -1, 1);
     return 0;
 }
 
@@ -3620,7 +3637,7 @@  const OptionDef options[] = {
         "specify target file type (\"vcd\", \"svcd\", \"dvd\", \"dv\" or \"dv50\" "
         "with optional prefixes \"pal-\", \"ntsc-\" or \"film-\")", "type" },
     { "vsync",          HAS_ARG | OPT_EXPERT,                        { .func_arg = opt_vsync },
-        "video sync method", "" },
+        "set video sync method globally; deprecated, use -fps_mode", "" },
     { "frame_drop_threshold", HAS_ARG | OPT_FLOAT | OPT_EXPERT,      { &frame_drop_threshold },
         "frame drop threshold", "" },
     { "async",          HAS_ARG | OPT_INT | OPT_EXPERT,              { &audio_sync_method },
@@ -3777,6 +3794,9 @@  const OptionDef options[] = {
         "force video tag/fourcc", "fourcc/tag" },
     { "qphist",       OPT_VIDEO | OPT_BOOL | OPT_EXPERT ,                        { &qp_hist },
         "show QP histogram" },
+    { "fps_mode",     OPT_VIDEO | HAS_ARG | OPT_STRING | OPT_EXPERT |
+                      OPT_SPEC | OPT_OUTPUT,                                     { .off = OFFSET(fps_mode) },
+        "set framerate mode for matching video streams; overrides vsync" },
     { "force_fps",    OPT_VIDEO | OPT_BOOL | OPT_EXPERT  | OPT_SPEC |
                       OPT_OUTPUT,                                                { .off = OFFSET(force_fps) },
         "force the selected framerate, disable the best supported framerate selection" },