[FFmpeg-devel] [PATCH] Complete rewrite of the "fps" video filter section. More accurate.

Jim DeLaHunt list+ffmpeg-dev at jdlh.com
Fri May 1 00:09:13 EEST 2020


On 2020-04-28 08:50, Carl Eugen Hoyos wrote:

> Am Mo., 27. Apr. 2020 um 08:18 Uhr schrieb <list+ffmpeg-dev at jdlh.com>:
>
> The suggested patch is currently not ok.
Thank you for your review, Carl Eugen. The patch will be the better for 
your comments.

My responses interleaved.

…[snip]…

>> -Convert the video to specified constant frame rate by duplicating or dropping
>> -frames as necessary.
>> +Generate a video, having the specified constant frame rate, from the frames of
> I am not saying that "convert" is ideal but "Generate a video" is simply wrong.

I will look at all the word choices for verbs and see if I can make this 
clearer.

The word "generate" was a response to the the original text using the 
word "convert". "Convert" gave me the impression that the filter might 
just change time base and frame rate metadata parameters, but leave the 
rest unchanged. The *fps* filter does more than that. It alters the PTS 
values. It can add frames. It can drop frames. To my reading the output 
video is a new thing, not the original thing with some tweaks.

>> +the input video, by copying or duplicating or dropping input frames based on
> What is the difference between "copying" and "duplicating"?

Good point. I will look harder at these word choices.

What I am trying to convey is that the filter can do one of three things 
to the input frames: pass them through, or drop some of them, or repeat 
some of them. I will look for words which communicate this three-way path.

>> +their input presentation time stamps (PTSs). The output video has new PTSs. You
>> +can choose the method for rounding from input PTS to output PTS.
>>
>>   It accepts the following parameters:
>>   @table @option
>>
>>   @item fps
>> -The desired output frame rate. The default is @code{25}.
>> +The output frame rate, as a number of frames per second. This value can be an
>> +integer, real, or rational number, or an abbreviation. The default is @code{25}.
>>
>>   @item start_time
>> -Assume the first PTS should be the given value, in seconds. This allows for
>> -padding/trimming at the start of stream. By default, no assumption is made
>> -about the first frame's expected PTS, so no padding or trimming is done.
>> -For example, this could be set to 0 to pad the beginning with duplicates of
>> -the first frame if a video stream starts after the audio stream or to trim any
>> -frames with a negative PTS.
>> +The time, in seconds from the start of the input stream, which is converted to
>> +an input starting PTS value and an output starting PTS value.
>> +If set, @var{fps} drops input frames
>> +which have PTS values less than the input starting PTS. If not set, the input
>> +and output starting PTS values are zero, but @var{fps} drops no input frames based
>> +on PTS.
> This is different than the explanation above and (hopefully) wrong.

I based my new text on reading the code. Take a look for yourself: 
ffmpeg/libavfilter/vf_fps.c:159-174 
<https://github.com/FFmpeg/FFmpeg/blob/1128aa875367f66ac11adc30364d5652919a2591/libavfilter/vf_fps.c#L159-L174>, 
within config_props(), and ffmpeg/libavfilter/vf_fps.c:195-204 
<https://github.com/FFmpeg/FFmpeg/blob/1128aa875367f66ac11adc30364d5652919a2591/libavfilter/vf_fps.c#L195-L204>, 
within read_frame().

I think the first sentence of the old text, "Assume the first PTS should 
be the given value", doesn't match what the code does. The code does not 
include a clear high-level statement of what the parameter does. I think 
that means we have to take the implementation as correct, and document 
what it actually does.

The rest of the old text is actually a guide on how to use the 
`start_time` parameter. I kept that, but moved it down to after the 
parameter definition table.

>> +(See details below.)
>>
>>   @item round
>> -Timestamp (PTS) rounding method.
>> +Rounding method to use when calculating output Presentation Timestamp
>> +(PTS) integer values from input PTS values. If the calculated output PTS value
>> +is not exactly an integer, then the method determines which of the two
>> +neighbouring integer values to choose.
> I do not see any improvement with this change.

The old text fails to answer these questions: what is being rounded? 
What is the calculation which leads to the result being rounded? What is 
the frame of reference for "towards 0", "towards infinity"? What 
possible values does the rounding choose among? The new text tries to 
answer those questions.

There may be a better way to answer these questions. I will try to think 
of better wording. But I think the documentation should provide answers.

>> -Possible values are:
>> +Possible method names are:
> Not being a native speaker, the change makes this harder to read.
> ("Verschlimmbesserung")
As I replied to Josh, I think this is a wording style point.  This 
section uses the word "value" to indicate numerical quantities, and the 
strings passed to the `round` parameter are not numerical. It seems 
clearer to use a different word, and to tie it to "method". But if this 
is all that stands in the way of getting the patch accepted, I will concede.
>>   @table @option
>>   @item zero
>>   round towards 0
>> @@ -11170,43 +11177,167 @@ round towards -infinity
>>   @item up
>>   round towards +infinity
>>   @item near
>> -round to nearest
>> +round to nearest (and if exactly at midpoint, away from 0)
> I wonder if this implementation detail should be documented.
> Are you sure that the current behaviour is intended and must
> not change?

Again, the code does not provide a high-level statement of what it 
intends. It does not separate essence of interface from accident of 
implementation. However, one clue is that the `near` value for `round` 
corresponds to AV_ROUND_NEAR_INF, which is defined in 
ffmpeg/libavutil/mathematics.c:84 
<https://github.com/FFmpeg/FFmpeg/blob/a0ac49e38ee1d1011c394d7be67d0f08b2281526/libavutil/mathematics.h#L84>, 
where it says:

AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero.

So, is that comment in *mathematics.c* an interface specification?  Is 
the use of that value in *vf_fps.c* an interface specification? It sure 
would be nice if the code had a high-level statement of intent. But it 
seems not to.

I don't feel strongly about this point. If you all tell me to leave this 
halfway case behaviour out of the documentation, I can live with that.

>>   @end table
>>   The default is @code{near}.
>>
>>   @item eof_action
>> -Action performed when reading the last frame.
>> +Action which @var{fps} takes with the final input frame.
> "Verschlimmbesserung", see above.

The new text makes two changes to the old:

1. The new text is clear that the last /input/ frame, not output frame, 
is what the parameter controls. The old text is ambiguous.

2. The new text uses the active voice ("@var{fps} takes"). The old text 
uses "when" plus a present progressive clause. The style guides I 
remember say that active voice is more lively than indirect 
constructions. In any case, it looks like the old text should have used 
"while" instead of "when" 
<https://english.stackexchange.com/a/17318/33109>.  (Thank you for 
leading me to a discussion of subject complements, by the way.)

I care about #1, because I want the documentation to say what the filter 
does. I am flexible on #2.

>
>> The input video passes
>> +in an ending input PTS, which @var{fps} converts to an ending output PTS.
>> + at var{fps} drops any input frames with a PTS at or after this ending PTS.
> What is this supposed to mean / isn't this wrong?

I guess the wording is unclear. The code is even more unclear.

Take a look: ffmpeg/libavfilter/vf_fps.c:234-245 
<https://github.com/FFmpeg/FFmpeg/blob/1128aa875367f66ac11adc30364d5652919a2591/libavfilter/vf_fps.c#L234-L245>, 
within write_frame(). There is a comment, "If we have status (EOF) set, 
drop frames when we hit the status timestamp." I have a hard time 
relating it to what the code does.

If you can clarify what the code a) actually does, and b) is supposed to 
do, I am glad to try to describe that more clearly.

>>   Possible values are:
>>   @table @option
>>   @item round
>> -Use same timestamp rounding method as used for other frames.
>> +Use same rounding method as for other frames, to convert the ending input PTS
>> +to output PTS.
> Useless change.

"Useless"? No, it restates for clarity what the rounding operates on.

However, "not very useful, and not worth the cost in extra words"?  
Maybe so. I will take another look at these words when I edit to reduce 
word count.

>> +
>>   @item pass
>> -Pass through last frame if input duration has not been reached yet.
>> +Round the ending input PTS using @code{up}. This can have the effect of passing
>> +through one last input frame.
>>   @end table
>> +
>>   The default is @code{round}.
>>
>>   @end table
>>
>> -Alternatively, the options can be specified as a flat string:
>> +Alternatively, the options may be specified as a flat string:
>>   @var{fps}[:@var{start_time}[:@var{round}]].
> The remaining part is far too long and not acceptable.

By "the remaining part" I understand you to mean the remaining three 
paragraphs in the main section, and the entire subsection "Details". I 
presume you still want to keep the "Examples" subsection.

I think what I put in those paragraphs is all true. It all accurately 
describes the code. It all explains points which I found to be necessary 
to understand as I was trying, as a user, to figure out if the *fps* 
filter would accomplish a purpose I wanted to do.

> Allow me to repeat: The patch is currently not ok.

Your earlier comments are about specific points. Some I agree with, some 
I disagree with. But I can imagine working with you to resolve them.

Your final comment, "The remaining part is far too long and not 
acceptable", comes across as a rejection of the very idea of improving 
*FFmpeg* documentation.

*FFmpeg* is a complex tool. Even apparently simple filters are complex. 
The present documentation is inadequate to explain to a user how the 
code behaves. This presents a big obstacle for *FFmpeg* users. Traffic 
on the ffmpeg-users list proves this constantly.

What do you have against removing this obstacle? What do you have 
against documentation which describes what the code actually does?

I will go through all these comments and make a revised patch. Let's see 
how that looks.

> Carl Eugen
Best regards,

      —Jim DeLaHunt, software engineer, Vancouver, Canada




More information about the ffmpeg-devel mailing list