ffmpeg is nice but often we need to figure some hackish way around to do what you want...
I recorded a 30 min long video from webcame which is controlled by opencv (cv2 python binding). The video was created fine but the problem started when I wanted to change the fps of the video.
usually -r option is the way to go. This seems to work when input is either buffer through stdin or image sequence (001.png etc). But when the input is a video file (in my case avi container), r option alone does not seem to work as intended.
First try with vsync (playback is not fixed)
Here are the two tricks I had to do to change the fps.
(1) set vsync option to 3 (drop) to discard the timestamp information in the original file
(2) set vframes option to specify the frame number to decode/encode.
With these, the muxer will create a fresh timestamp for the output video. The command looks like this:
ffmpeg -vframes 540000 -y -i input.avi -vsync 3 -r 30 out.avi
30 (min) x 60 (s) x 30 (fps) = 54000
so -vframes option is redundant but was needed for vsynch to work.
-y option will just overwrite the output file if it already exists.
The webcame was capturing at 30 fps but the output video was set to 10 fps with -r option to slow it down for easy inspection of fast movements.
I still have a problem with this though. After converting this original video to 30 fps with the above command, I did get a 30 min length video but both VLC and the windows media player will still playback at 10 fps.
This can be actually handy for me, because I can seek the video with the correct time (the video length is not x3 longer than the actual time) but it still plays x3 slower which I wanted. But if I want to recover both the playback speed and timestamp then this is not enough.
Second try with video filter
Hence, the 2nd try here. I found a wiki "How to speed up slow down a video" in the official site, which recommend -filter option.
With -filter_complex, you can re-compute and update the timestamp information. Great! But my ffmpeg executable is old (from 2011) and did not like -filter_complex or -filter option, so I used -vf option (alias to -filter) which somehow worked ok.
ffmpeg -y -i -an input.avi -vf setpts=PTS/3.0 -r 30 out.avi
This sped up the original video x3. For sure, I will forget all these in 2 weeks, hence this blog article.
Could I just copy the video stream and only change the frame rate?
There is this -vcodec copy option to avoid decoding and re-encoding process. It would be nice if I can use this when changing just the frame rate.
To me, frame rate looks like just a metadata, no???? If so, why wouldn't we be able to just modify the metadata without compromising the video quality at all?
Sadly, the answer seems no. According to this post to the mailing list, [FFmpeg-user] Deinterlace and change framerate with -vcodec copy.
| I would really like to do it
| with -vcodec copy. Is is possible? If it is, which codecs
| allow for framerate changes like this? Does h264 support it?
No. To change frame rate you have to decode, throw away 'baseband' 'I'
frames, and re-encode.
After all, the frame rate is part of video frame data that cannot be modified without decoding and re-encoding.