ffmpeg: cut videos to the exact frame
When cutting videos using ffmpeg
using the following command:
ffmpeg -i input.mp4 -ss 00:00:24.183 -to 00:03:22.183 -c copy output.mp4
You may notice that ffmpeg
may sometimes not cut the video to the correct frame. It may start a bit later than the time specified, 00:00:24.183
, by a couple of frames or a couple of seconds. Worse yet, the video may appear frozen until it reaches the arbitrary frame ffmpeg
started on, upon which it will start playing normally. What gives?
Well, it all comes down to keyframe types (again, if you’ve seen my previous posts about ffmpeg
), but the short gist of it is that certain keyframes (P-frames and B-frames) rely on I-frames in order to render. So if your supplied timecode does not start on a I-frame, ffmpeg
skips over until it finds the first I-frame, then repeats that to the start of the video, like this:
Original file:
IPPPBIPPPBIPPPBIPPPB
^ Your supplied start timecode
Where ffmpeg will start:
----------IPPPBIPPPB
^
What ffmpeg will do for the missing frames:
-------IIIIPPPBIPPPB
Finally cut down to size:
IIIIPPPBIPPPB
So how do we tell ffmpeg
to just re-encode based on the previous I-frame, before your start timecode? Well, do you see the -c copy
parameter in the original command? That’s what’s causing the issue. The parameter tells ffmpeg
to copy the file without re-encoding anything, which is fast, but it won’t let ffmpeg
re-encode by rendering the frames on top of each other. The solution is to just replace that parameter with a instruction to re-encode with an encoder:
ffmpeg -i input.mp4 -ss 00:00:24.183 -to 00:03:22.183 -c:v libx264 -crf 18 output.mp4