Wie erzwingt man, dass das erste Bild ein Schlüsselbild ist?

Wie erzwingt man, dass das erste Bild ein Schlüsselbild ist?

Ich möchte nach dem Ansteuern einer bestimmten Position kodieren und das erste Bild zu einem Schlüsselbild machen. Hier der Befehl, den ich verwendet habe:

ffmpeg -ss 300  -i howimet.mp4 -acodec libfaac -ar 48000 -ab 128k -ac 2  -vcodec libx264 -vf "scale=480:270" -f mpegts -force_key_frames 300 -t 120 howimet2.ts

die -force_key_frames ist so eingestellt, dass sie die Position sucht, um dort ein Keyframe zu erstellen. Ich verwende das folgende Skript (vonHier), um zu prüfen, ob das erste Bild ein Schlüsselbild ist

ffprobe -show_frames -v quiet howimet2.ts | awk -F= '   /pict_type=/ { if (index($2, "I")) { i=1; } else { i=0; } } 
  /pkt_pts_time/ { if (i && ($2 >= 0)) print $2; }  
' | head -n 1

Das Ergebnis zeigt, dass sich das erste Keyframe nicht bei Sekunde 0 befindet.

Ich vermute, mein Befehl ist nicht korrekt. Was übersehe ich?

Antwort1

Beim Kodieren von Videos wird das erste Bildhatals Schlüsselbild. Es ist das erste vollständig codierte Bild und nachfolgende Bilder können es zur Inter-Frame-Vorhersage verwenden. Außerdem haben Sie am Anfang der codierten Videosequenz eine H.264-Zugriffseinheit, die dem Decoder mitteilt, dass er aktualisieren soll.

Unabhängig davon, was Sie tun: Sofern Sie nicht einfach den Bitstrom kopieren, kodieren Sie das Video neu und Ihr erstes Frame muss ein Keyframe sein.

Aus irgendeinem Grund hat Ihr Stream nun einen Offset in seiner Startzeit. Das bedeutet, dass alle Präsentationszeitstempel ebenfalls entsprechend diesem Offset verschoben werden. Wenn Sie den Kopf der ffprobe -show_framesAusgabe untersuchen, werden Sie sehen, dass Frame 0 tatsächlich ein Keyframe ist, aber mit einem anderen PTS.

Um dies auszugleichen, können Sie die Startzeit von allen PTS abziehen.

Antwort2

Wie erwähnt muss das erste Bild Ihres Videos ein I-Frame sein. Ihr Problem liegt nicht an der Kodierung (oder Kopie, wenn Ihnen das lieber ist), sondern an der Dekodierung. -ss vor der Eingabe ist ungenau, also tut ffmpeg sein Bestes, um Sie ungefähr dorthin zu bringen, wo Sie hinwollten. Ffmpeg hat diese Position weitergegeben und teilt Ihnen daher einen ersten Zeitstempel ungleich Null mit.

Ich würde empfehlen, nach Ihrem -i ein zweites -ss zu versuchen. Etwa in der Art -ss 299 -i input -ss 1.

Dies bedeutet, dass Sie ungefähr zu dem gewünschten Ort gehen und dann 1 Sekunde lang dekodieren sollen, bevor Sie die Verarbeitung durchführen. Ich bin nicht sicher, ob dies Ihr PTS-Problem beheben wird, aber hoffentlich bringt es Sie in die richtige Richtung.

Um es klarzustellen: Ich glaube nicht, dass der Befehl force_key_frames das tut, was Sie denken. Wenn er etwas tut, sagt er ihm wahrscheinlich nur, dass alle 300 Sekunden ein Keyframe in die Ausgabe eingefügt werden soll, aber das ist nur eine Vermutung. Das bedeutet, dass nur der erste Frame Ihrer Ausgabe ein Keyframe wäre (t=120).

https://ffmpeg.org/ffmpeg.html

Antwort3

Stellen Sie die GOP-Größe mit "-g" ein

Um die Genauigkeit zu demonstrieren, hier sind 1-Sekunden-Segmente

ffmpeg -i  in.mkv -g 30  -hls_time 1 -hls_list_size 0 index.m3u8

So sieht m3u8 aus:

    #EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:1.001000,
index0.ts
#EXTINF:1.001000,
index1.ts
#EXTINF:1.001000,
index2.ts
#EXTINF:1.001000,
index3.ts
#EXTINF:1.001000,
index4.ts
#EXTINF:1.001000,
index5.ts
#EXTINF:1.001000,
index6.ts
#EXTINF:1.001000,
index7.ts
#EXTINF:1.001000,
index8.ts
#EXTINF:1.001000,
index9.ts
#EXTINF:1.001000,
index10.ts
#EXTINF:1.001000,
index11.ts
#EXTINF:1.001000,
index12.ts
#EXTINF:1.001000,
index13.ts
#EXTINF:1.001000,
....

verwandte Informationen