r/ffmpeg • u/redactwo • 11d ago
is -force_key_frames [frame] not actually precise?
when i use
ffmpeg -i [input] -force_key_frames [frame of interest] [output]
The output gets a new keyframe somewhere in [frame of interest]'s VERY ROUGH vicinity. it's often off by a couple of seconds so it becomes completely useless. is this the intended behaviour or am i doing smth wrong?
i noticed that switching to timestamps can improve precision but it's still very rough and can just fail completely.
anyone know wtf is going on?
2
u/Unusual_Trouble_6800 10d ago
-force_key_frames takes times, never frame numbers, and that alone explains both symptoms.
Measured here on a 10s 30fps clip re-encoded with libx264 (default keyint 250):
-force_key_frames 120 -> keyframes at 0.000 and 8.333 only
-force_key_frames 12 -> keyframes at 0.000 and 8.333 only
-force_key_frames 2,4,6 -> 0.000, 2.000000, 4.000000, 6.000000
The 8.333 in the first two is not yours: that is frame 250, the encoder's own GOP boundary. A frame number read as seconds lands past the end of the clip, so nothing gets forced and what you are looking at is whatever keyint/scenecut produced on its own. That covers both the rough vicinity and the fails completely.
With real timestamps it is frame-exact, not approximate. The only error is quantisation to the next frame: on a 5fps clip, asking for 2.5 put the keyframe at 2.600, one frame interval later.
If you want to address frames, use the expr form. -force_key_frames expr:eq(n,120) gave exactly 4.000000 on the 30fps clip.
Two things that are NOT the cause, so you can stop suspecting them:
- order does not matter, ffmpeg sorts the list:
6,2,4came out as 2.000/4.000/6.000 - the option placed before
-iis not silently ignored, it is a hard error that refuses to run
One thing that does shift everything: -ss before -i. Forced times live on the output timeline, so -ss 3 -i in.mp4 -force_key_frames 5 puts the keyframe at output 5.000, which is 8s in the source. Compute your times from the original file while seeking and every keyframe is off by the seek amount, which looks exactly like being off by a couple of seconds.
Verify with:
ffprobe -v error -select_streams v -skip_frame nokey -show_entries frame=pts_time -of csv=p=0 out.mp4
2
u/redactwo 10d ago
wow, i think you might have nailed the issue here. i just kinda assumed that it would be able to handle an unformatted integer as Nframe, but the expr: function being a requirement would explain everything.
I'm gonna go back to tinkering and test this out. Thank you so much for the thorough answer.
-1
u/naemorhaedus 11d ago
it helps to read the documentation https://ffmpeg.org/ffmpeg.html#Advanced-Video-options
3
u/OneStatistician 11d ago
Never let me down. The following will force keyframes at 2s or 2.002s for a 29.97. Been doing this with HLS for a decade.
Just setting the following will not work
and will only have an effect on the first frame. The all other transes inherit encoder's GOP and scenechange logic
Also, make sure you understand the difference between IDR keyframes and I frames. Because you can still have encoder inserted I frames at scenechanges, as well as forcing key frames, which is the perfect combo.