ffmpeg - How can I cut starting precisely from a keyframe while codec copying?

3

Using -ss as input option together with -c:v copy might not be accurate since ffmpeg is forced to only use/split on i-frames. Though it will—if possible—adjust the start time of the stream to a negative value to compensate for that. Basically, if you specify "second 157" and there is no key frame until second 159, it will include two seconds of audio (with no video) at the start, then will start from the first key frame. So be careful when splitting and doing codec copy.

To avoid this, I’ve tried first finding the timestamps of the frames needed for -ss and -to by building a tile of all nearby frames. I’ve generated the tiles using

ffmpeg -i "INPUT.mkv" -ss 09:55 -t 3 -vf "drawtext=fontfile=I\\:\Misc\\\\~Software\\\\~OS\\\\I386\\\\arial.ttf: fontsize=60: text='F%{n}\(%{pict_type}\)\@%{pts\:hms}': x=(w-tw)/2: y=h-(2*lh): fontcolor=white: box=1: boxcolor=0x00000000@1,scale=320:-1,tile=layout=12x10" tiles%03d.png

and according to them the needed keyframe should be starting from 00:09:56.012, and the last needed frame should be at 00:10:00.224. However, the fragment created when cutting with these timestamps

ffmpeg -i "INPUT.mkv" -map 0:0 -map 0:4 -map 0:5 -map 0:6 -ss 09:56.012 -to 00:10:00.224 -vcodec copy -acodec copy J01.mkv

starts at a non-key frame (sound only) and ends at a wrong place as well. In contrast, cutting the same fragment in Avidemux works fine even with Video- and Audio-output settings set to Copy (IIUC, no re-encoding and start from a no-key frame). Displayed timestamps in Avidemux are also different (-ss 09:56.346 -to 10:00.558 v.s. -ss 09:56.012 -to 10:00.224).

I’ve also tried cutting by pkt_dts_time (https://stackoverflow.com/questions/14005110/), but that didn’t work either.

p.s. Another similar procedure to what I am trying to do (to abovementioned Avidemux) is when in Sony Vegas you zoom in into the timeline until you can step from one frame to another, then set the first frame after scene change (which is also a keyframe) as the starting point and the last frame of the same scene (after which comes the next keyframe that is not needed) as the endpoint and then render. Something like this can also be done in Avidemux while also copying the video and audio streams.

edit1: Here’s the log for -copyts version: pastebin . com /Cxzrc8Er. Should I do others as well?


edit2: Here are results for "PATHTO\ffprobe.exe" -select_streams v -show_entries packet=pts_time,flags -of compact -read_intervals 580%600 "INPUT.mkv" | findstr K.

packet|pts_time=578.160000|flags=K
packet|pts_time=581.205000|flags=K
packet|pts_time=583.499000|flags=K
packet|pts_time=585.042000|flags=K
packet|pts_time=588.671000|flags=K
packet|pts_time=594.885000|flags=K
packet|pts_time=596.012000|flags=K

I’ve also tried the whole combo of commands (tiles, listing frames this way, cutting fragment two different ways) on another 2 videos, and the results are similar. Keyframe times listed in terminal using your suggested command match the ones in tiles made by mine; and generally cutting by my method leaves a small frozen section (~1s) in the beginning and sometimes several unwanted frames at the end and cutting by your method leaves a longer empty video-stream at the beginning.

I’ve also found a better video fragment for experimenting because it’s visually easier to determine how much of the wanted frames are missing and of the unwanted have been added (imgur.com /a /DTzmt, relevant part can be downloaded at bit.ly /Kmnz112f1). Your solution worked better on it as well.

Also, just to make sure: Did you mean -ss 09:56.013 and not -ss 09:56.012 in your original solution? And, am I right to guess that it generally works on videos you’re cutting and that it doesn’t on mine is out of usual?


ffmpeg
video-editing
asked on Super User May 12, 2016 by Imfego • edited May 23, 2017 by Community

2 Answers

0

Try

ffmpeg -ss 09:56.013 -i "INPUT.mkv" -map 0:0 -map 0:4 -map 0:5 -map 0:6 -to 00:10:00.224 -vcodec copy -acodec copy -avoid_negative_ts make_zero J01.mkv
answered on Super User May 13, 2016 by Gyan
0

One solution could be to:

  1. Cut the first, say, 5 seconds of the clip (i.e. where you want to cut)
  2. Encode it using the same codec as the input has
  3. Use it as layer 1
  4. Copy the clip with codec copy as layer 2
  5. Overlay the layer 1 over layer 2.

This might be slower than just copying.

Another solution could be to find the first keyframe, and concat two clips:

  • One from the clip start to the keyframe, encoded with the same codec
  • Other from the keyframe to the clip end, using codec copy.

I did not try either (yet).

answered on Super User Apr 11, 2020 by Ondra Žižka

User contributions licensed under CC BY-SA 3.0