Wie kann man die Dauer des ersten Frames eines mp4-Films effizient einstellen?

610
LWChris

Ich habe eine selbstcodierte App, die das auf GitHub veröffentlichte Camera2Video-Beispiel von Google verwendet . Leider scheint es ab Android 6 ein Problem zu geben, das dazu führt, dass aufgezeichnete Videos beschädigt werden. Laut einem Ausgabenbericht auf GitHub ist die Dekodierungszeit des ersten Frames im Vergleich zu einem Arbeitsvideo ginorm.

Für meine Beispieldatei mit einer Länge von 11 Sekunden lauten die Symptome:

  • Auf dem Android-Handy selbst friert der Videoplayer beim ersten Bild ein. Der Ton wird abgespielt, die Wiedergabe stoppt nach 11s. Nachdem Sie den Schieberegler an den Anfang zurückgezogen haben, werden Video und Audio synchron wiedergegeben.
  • Unter Windows mit verschiedenen Playern (Groove, WMP, VLC) gibt es entweder überhaupt kein Video oder friert beim ersten Frame ein. Audio ist immer gut. Die Videolänge wird als 11s angezeigt. Einige Spieler halten am Ende an, andere erhöhen die Wiedergabezeit nach dem Wiedergabeschieberegler auf 100%.
  • In Google Chrome unter Windows wird die Videolänge mit 3,5 Stunden angezeigt. Die Audiowiedergabe erfolgt während der ersten 11s. Das Video zeigt fast immer den ersten Frame, dann 11 Sekunden ab Ende des Videos.

Das Verhalten von Google Chrome zeigt am besten, was los ist: Die Datei enthält 11 Sekunden Audio und 11 Sekunden * 30 Bilder pro Sekunde = 330 Bilder. Das erste Bild ist jedoch nicht 1 / 30s, sondern etwa 3,5 Stunden lang.

Zuerst hatte ich verschiedene Videoreparaturwerkzeuge ausprobiert, um die mp4-Datei zu reparieren, aber die meisten änderten nichts oder fanden kein Problem, das repariert werden sollte, und liefen gar nicht erst.

Nachdem ich einen Fehler probiert hatte, fand ich eine erste funktionierende Lösung . Früher habe ich ffmpeg mit der setptsFilteroption: .\ffmpeg.exe -i "broken.mp4" -vf setpts=N/FRAME_RATE/TB "fixed.mp4". Danach läuft die feste Datei einwandfrei (und ist auch viel kleiner).

Das Problem bei diesem Ansatz ist, dass es ungefähr so ​​lange dauert, bis die Länge des Videos, das ich reparieren möchte, abgeschlossen ist. Aber das Video, das ich mit der App machen möchte, kann in der Zukunft etwa eine Stunde lang sein.

Ich frage mich also, gibt es eine Möglichkeit, die Dauer einzustellen, für die das erste Bild angezeigt wird? Theoretisch sollte dies bedeuten, dass ffmpeg nur eine ganze Zahl ersetzen muss und sich nicht mit de oder encoding beschäftigen muss. Kann es gemacht werden und wie?

0
Ich habe bereits die ffmpeg-Lösung im Thread des Problems veröffentlicht. LWChris vor 5 Jahren 0

1 Antwort auf die Frage

0
Gyan

Da es auf der Grundlage Ihrer Arbeitslösung so aussieht, als wären Sie mit der Anpassung der Ausgabe an eine konstante Framerate in Ordnung, empfehle ich diese schnellere zweistufige Methode. Keine Neucodierung erforderlich.

Rohstrom extrahieren:

ffmpeg.exe -i "broken.mp4" -c copy broken.h264 

Remux:

ffmpeg.exe -i broken.h264 -i broken.mp4 -map 0 -map 1:a -c copy new.mp4 
Es ist richtig, dass es mir nichts ausmacht, das Video auf feste FPS einzustellen, solange es relativ zum Audio synchron bleibt (<100ms). Ihre Methode funktioniert, aber die Ausgabe von ffmpeg sagt: "Zeitstempel werden in einem Paket für Stream 0 nicht gesetzt. Dies ist veraltet und wird zukünftig nicht mehr funktionieren. Korrigieren Sie Ihren Code, um die Zeitstempel richtig festzulegen." LWChris vor 5 Jahren 0
Ja, meine Methode beruht darauf, dass Zeitstempel nicht gesetzt werden. Diese Botschaft gibt es schon seit Jahren, und niemand arbeitet an einem Patch, um das zu ändern. Wenn ja, werde ich die Antwort aktualisieren. Gyan vor 5 Jahren 0
Hm, die Ausgabe ist noch nicht ganz richtig. Zuerst wird es gedreht. Ich habe das mit `-metadata behoben: s: v rotate =" - 90 "`. Zweitens beträgt die Bildrate nur 25 Bilder pro Sekunde, während das Original 30 Bilder pro Sekunde hat. Das bedeutet, dass der Video-Steam zu viele Frames enthält, sodass das Video im Laufe der Zeit hinter dem Audio zurückliegt. Ich habe "-r 30" in beiden Schritten an verschiedenen Orten ausprobiert, aber es scheint nicht zu funktionieren. LWChris vor 5 Jahren 0
Klingt nach einer älteren Version von ffmpeg; neuere Versionen sollten die Framerate broken.h264 lesen. Auf jeden Fall können Sie im zweiten Befehl vor der Option -i broken.h264 `-r 30` hinzufügen. Gyan vor 5 Jahren 0