Ändern Sie die Bildrate in ffmpeg ohne erneute Kodierung

Ändern Sie die Bildrate in ffmpeg ohne erneute Kodierung

Ich habe ein MKV-Video (h264) mit 23,976 fps (24000/1001), aber ich möchte es in 25 fps umwandeln, ohne es neu zu kodieren und an Qualität zu verlieren. Ich weiß, dass mkvmerge das kann (mit der Option --default-duration '0:25fps'), aber ich würde es, wenn möglich, gerne direkt von ffmpeg aus machen. Laut der Dokumentation sollte das funktionieren:

ffmpeg -i input.mkv -r 25 -vcodec copy output.mkv

aber wenn ich es ausführe, erhalte ich nur die gleichen Video-FPS. Was ist die richtige Methode dafür (falls vorhanden) in ffmpeg?

Antwort1

Hier ist die Methode mit aktuellen Versionen von FFmpeg. Sie basiert darauf, dass der Concat-Demuxer die PTS der Eingaben nach der ersten Datei nicht neu skaliert, sondern einfach einen festen Offset anwendet. Nehmen wir an, Sie haben einen 30-fps-Stream mit einer Zeitskala von 15360(typisch für FFmpeg-Ausgabe). Das bedeutet, dass Frame 0PTS 0und Frame 30PTS hat 15360. Dies würde zu einem 45-fps-Stream werden, wenn wir die Zeitskala auf ändern könnten, 23040ohne die PTS-Werte zu beeinflussen.

Im Wesentlichen ist es das, was die folgende Methode macht.

1. Identifizieren Sie die Quelleigenschaften.

Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1171 kb/s,
       30 fps, 30 tbr, 15360 tbn (default)

Sie möchten die Quelleigenschaften notieren, insbesondere Auflösung und tbn.


2a(Optional) Ändern Sie die Zeitskala auf einen geeigneten Wert, um die Berechnungen zu vereinfachen.

ffmpeg -i in.mp4 -c copy -an -video_track_timescale 30 in-v30.mp4

Das bringt uns

Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1171 kb/s, \
       30 fps, 30 tbr, 30 tbn (default

Wenn Sie diesen Schritt ausführen, sollte die neue Zeitskala gleich oder ein ganzzahliges Vielfaches der ursprünglichen Bildrate sein.

2b. Berechnen Sie die erforderliche Zeitskala, sodass für die Ziel-Framerate xPTS von Frame # xin der Quelle den gleichen Wert wie der neue hat . Wenn Sie Schritt 2a ausgeführt haben, ist dies sehr einfach und es ist einfach die neue Framerate. Für die Ziel-FPS sollte der neue Wert tbnalso sein .45tbn45


3. Dummy-Video generieren.

ffmpeg -f lavfi -i color=s=1280x720:r=45:d=1 -profile:v main -video_track_timescale 45 0.mp4

Für optimale Ergebnisse sollten alle Eigenschaften wie Auflösung, H.264-Profil, Pixelformat, Referenzanzahl usw. gleich sein.


4Verketten Sie die Videos.

Erstellen Sie zunächst eine Textdatei

file '0.mp4'
file 'in-v30.mp4'

Dann wird die Konkat

ffmpeg -f concat -i list.txt -c copy -video_track_timescale 45 45fps.mp4

In der Ausgabedatei wird das zweite Video mit 45 fps abgespielt.

5. Nun spalten Sie den Dummy-Preroll ab

ffmpeg -ss 1.1 -i 45fps.mp4 -c copy -avoid_negative_ts make_zero in45.mp4

und du hast

Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 1757 kb/s, \
       45 fps, 45 tbr, 11520 tbn (default)

Ich habe ja gesagt, dass das kompliziert ist!

Antwort2

ffmpeg -itsscale 1.0427083 -i input.mp4 -codec copy output.mp4

Dies verlangsamt eine von Handbrake erstellte MP4 mit 25 fps aus einer PAL-DVD-Quelle korrekt auf 23,974 fps. Die Originalsendung ist NTSC. Der Ton bleibt während der gesamten Laufzeit von nun 47 Minuten synchron. Es ist sehr schnell, da keine Dekodierung/Kodierung durchgeführt wird. Es gibt jedoch durchgehend Audiostörungen (Aussetzer) in Abständen von etwa 3 Sekunden. Dasselbe Ergebnis mit einem vcodecErsatzcodec, außer dass das Video zwar nicht neu kodiert wird, der Ton jedoch mit der halben ursprünglichen Bitrate neu kodiert wird und immer noch die Aussetzer aufweist.

ffmpeg -itsscale 1.0427083 -i input.mp4 -vcodec copy -filter:a "atempo=0.959041" output.mp4

Dadurch werden die Audioaussetzer eliminiert, Audio wird jedoch neu kodiert. Das ist viel schneller als die Neukodierung von Videos. Der verbleibende Nachteil ist, dass standardmäßig die Hälfte der ursprünglichen Audiobitrate verwendet wird. Sie müssen herausfinden, wie Sie die Audiobitrate für die Neukodierung einstellen.

Antwort3

Verwenden-itsscaleauf dem Eingangsvideo, um eine effektive Framerate-Änderung zu erreichen. Funktioniert gut mit -vcodec copy.

Antwort4

Sie können dies mit dem Bitstream-Filter tun setts. Dadurch entfällt auch der Aufwand, einen Rohdatenstrom in eine Datei zu schreiben und ihn dann erneut zu remuxen. Dies funktioniert, weil Sie mit Codec Copy ( -c:v copy) zwar keine normalen Filter verwenden können, da diese auf dem dekodierten Videostrom funktionieren, Sie aber Bitstream-Filter verwenden können, die auf dem kodierten Strom funktionieren.

Um beispielsweise die Bildrate auf 60 fps zu ändern, fügen Sie ein

-bsf:v setts=ts=STARTPTS+N/TB_OUT/60

Dies sollte sowohl als auch ohne Dekodierung des Streams einstellen pts. dtsWenn Sie ein Video mit variabler Bildrate haben, benötigen Sie möglicherweise stattdessen so etwas

-bsf:v setts=ts='if(PREV_OUTPTS+9223372036854775808\,PREV_OUTPTS\,STARTPTS)+PREV_OUTDURATION*2'

Dies ändert die Dauer des Frames, anstatt anzunehmen, dass jeder Frame eine konstante Dauer hat. Der seltsam aussehende ifAusdruck soll sicherstellen, dass der erste Frame richtig versetzt ist, da während des ersten Frames PREV_OUTPTSauf (Mindestwert einer 64-Bit-Ganzzahl) eingestellt ist -9223372036854775808und wir es durch Null ersetzen müssen.

Wenn Sie B-Frames haben, kann dies die Dekodierung durcheinander bringen, da dtskleiner als sein muss pts, aber bei mir scheint es trotzdem gut zu funktionieren. Sie können versuchen, setts=tsdurch zu ersetzen setts=pts, wenn Sie auf Probleme stoßen. Siehehttps://ffmpeg.org/ffmpeg-bitstream-filters.html#settsfür Details

verwandte Informationen