2

I noticed that ffmpeg doesn't always scale the duration of a clip to the desired value ( even accounting for milliseconds of precision loss.) For example, whenever I attempt to scale the duration of this tiny 67ms clip to 7 seconds:

ffmpeg -i input.avi -filter:v "setpts=(7/0.067)*PTS" -an output.avi    

the resulting video is only 3.5 seconds in duration.

Not really sure why this is off by multiple seconds, but I suspect it has something to do with the input clip itself ( which is only 2 frames @ 29.97 fps ) So far, I've discovered that if I scale the duration to a much larger value first, then scale back from that to 7 seconds, it works fine:

ffmpeg -i input.avi -filter:v "setpts=(1000)*PTS" -an input_scaled_high.avi
ffmpeg -i input_scaled_high.avi -filter:v "setpts=(7/33.400033)*PTS" -an output.avi

But I'm hoping I don't need to resort to an intermediate file. Is it possible to solve this with a single ffmpeg call?

If it helps, here is the video file I'm working with: https://drive.google.com/drive/folders/1hI5Xo6kfAfMd8ZylM6XrPX5fuO88gncE?usp=sharing

Note: I should mention that I don't need sound at all in this experiment ( hence the -an )

4

1 回答 1

3

What setpts does is alter Presentation TimeStamps. PTS is the time at which a frame is shown/drawn. The duration of a video stream is equal to the PTS of the last frame + duration of the last frame. Your file is 29.97 fps, so each frame has a duration of 0.033s.

In your first command, the 2nd frame gets a new PTS of 3.47s but its duration is still 0.033s, hence the stream has a total duration of 3.5s

In your two step process, the 2nd frame gets a PTS of 6.97s. So even though the duration is 7s, I assume this is not what you want.

The way to do this is

ffmpeg -i input.avi -filter:v "setpts=(7/2)*N/TB" -r 2/7 -an output.avi

where (7/2) indicates target duration (7 seconds) and total frames (2). That fraction is reversed in the -r value. FFmpeg sets frame duration based on the -r value.

于 2018-04-18T06:20:12.183 回答