Opened 23 months ago

Last modified 4 months ago

#10150 open defect

Variable framerate with a maximum value

Reported by: Zoont Owned by:
Priority: important Component: undetermined
Version: git-master Keywords: fps framerate vfr cfr vsync
Cc: Fsc Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

Summary of the bug:
I have been using the -fps_mode option together with -fps_max to to allow my videos to have variable framerate while at the same time limiting it to 30 fps, similar to how handbrake have a peak framerate setting. But now when I do that it gives this error message "One of -r/-fpsmax was specified together a non-CFR -vsync/-fps_mode. This is contradictory.". I found out that this was a recent change, specifically This commit on git master. The description of this commit talks about how -r should always give constant framerate but it doesn't talk about -fpsmax. If this is intentional I would like to know how to achieve something like handbrake's peak framerate option with ffmpeg with this new restriction. Thanks in advance!

How to reproduce:

% ffmpeg -i input -fps_mode vfr -fpsmax 30 -c:v libx264 -crf 20 -c:a copy output
ffmpeg version git-master
built on 22/1/2023

Change History (6)

comment:1 by Balling, 23 months ago

Status: newopen

I propose to introduce -allowrvfr to bypass

            av_log(NULL, AV_LOG_FATAL, "One of -r/-fpsmax was specified "
                   "together a non-CFR -vsync/-fps_mode. This is contradictory.\n");

comment:2 by elenril, 21 months ago

Are you entirely sure this worked as you wanted? I see no indication that -fpsmax was ever intended to work with VFR. As per the manpage:

-fpsmax[:stream_specifier] fps (output,per-stream)

Set maximum frame rate (Hz value, fraction or abbreviation).

Clamps output frame rate when output framerate is auto-set and is higher than this value. Useful in batch processing or when input framerate is wrongly detected as very high. It cannot be set together with "-r". It is ignored during streamcopy.

In other words, it affects the way the output framerate is selected, but there still is a fixed output framerate.

in reply to:  2 comment:3 by Tynach, 14 months ago

Replying to elenril:

Are you entirely sure this worked as you wanted? I see no indication that -fpsmax was ever intended to work with VFR. As per the manpage:

-fpsmax[:stream_specifier] fps (output,per-stream)

Set maximum frame rate (Hz value, fraction or abbreviation).

Clamps output frame rate when output framerate is auto-set and is higher than this value. Useful in batch processing or when input framerate is wrongly detected as very high. It cannot be set together with "-r". It is ignored during streamcopy.

In other words, it affects the way the output framerate is selected, but there still is a fixed output framerate.

I used to do the same thing, using -r and -vsync vfr together. I thought it was a nifty undocumented feature. Also, elenril, while I'm not the same person as the one who opened this bug, I have extensively tested it, and it did used to do what is described (allow a variable framerate with a maximum output framerate).

Personally, I think that commit should be completely reverted, and instead the documentation changed to reflect the actual behavior. The commit in question only provides one reason for their change, and that is that the behavior didn't match the documentation.. But this is clearly a regression in functionality.

Either revert the commit and make a different commit that updates the documentation, or add another flag that provides the old behavior. Seeing as -fpsmax already exists and sounds like it ought to do what used to be possible, and according to Zoont used to also provide this desired behavior, then if it's decided not to fully revert the offending commit then I propose that -fpsmax is modified to allow the previous behavior.

Also, for what it's worth, I documented this working back in 2016 by writing this Super User answer. Given it has 35 upvotes, it's almost certain that there are other people who depend on this functionality, or at least have used it at some point in the past.

In regards to the original reason why the change was made.. There are PLENTY of undocumented behaviors in FFmpeg, including undocumented command line parameters. Looking at the commit in question, it seems like the tests had to be changed in order to pass.. That should have been a red flag that the changes shouldn't have been made to begin with. if tests didn't need to be changed for this commit to pass them, then the test changes should have been a separate commit.

comment:4 by Fsc, 13 months ago

Cc: Fsc added

comment:5 by Gyan, 13 months ago

There's another side-effect of disallowing -r in VFR mode. Some encoders (most notably x264) modulate their ratecontrol based on the set framerate. Higher the rate, lower the quality. This could earlier be used to encode sparse slideshow streams while controlling output stream size. Now ffmpeg is limited to using the input probed frame rate if VFR is to be maintained. And the wrapper sets the rate based on the avctx framerate.

in reply to:  5 comment:6 by Tynach, 4 months ago

Replying to Gyan:

There's another side-effect of disallowing -r in VFR mode. Some encoders (most notably x264) modulate their ratecontrol based on the set framerate. Higher the rate, lower the quality. This could earlier be used to encode sparse slideshow streams while controlling output stream size. Now ffmpeg is limited to using the input probed frame rate if VFR is to be maintained. And the wrapper sets the rate based on the avctx framerate.

I did some more digging, and found that 'GyanD' wrote the original code. Am I correct in assuming that's you? The commit message explicitly mentions that -fpsmax is meant for clamping the framerate, but that wasn't clearly stated in the documentation (commit d99cc1782563672bcdb46fb5ec51135847db8c99). If it had been, perhaps Elenril wouldn't have thought it was contradictory. As it is, -fpsmax is now basically identical to -r, which defeats the entire purpose.

I'm getting kinda tired of having to use an old build of ffmpeg to make sure this works, and am tempted to just put in the work to get this re-added myself.. But I don't know much about how this code is organized, and I don't even understand the tests.

If everyone else is stretched too thin, I understand, but would appreciate at least some guidance on this. If it'd be more effort to get someone new caught up with everything than to just make the changes (after all, the code was there, even if it has been rearranged a bit since it was originally written), then it's probably best to do that instead.

Note: See TracTickets for help on using tickets.