Eingangsvideo mit ffmpeg wiederholen/schleifen?

Ich möchte nur ein mp4-Video mit ffmpeg loopen und die aktuellen Einstellungen und den aktuellen Codec beibehalten.

Wenn beispielsweise input.mp4 0:10 lang ist und ich es 4 Mal wiederholen möchte, sodass output.mp4 0:40 lang ist, wie könnte ich die folgende Befehlszeile ändern, um dies zu tun?

ffmpeg -i input.mp4 -c copy output.mp4

Ich habe es versucht...

ffmpeg -loop 4 -i input.mp4 -c copy output.mp4

...aber ich erhalte die Fehlermeldung "Option loop not found."

Benutze quicktime 7 pro und mov container. Sie erhalten also keine größere Dateigröße als bei OpenSource.

Antworten (6)

-stream_loopMöglichkeit

ffmpeg -stream_loop 3 -i input.mp4 -c copy output.mp4
  • Dadurch kann eine erneute Codierung vermieden werden, da Stream Copy verwendet werden kann .
  • 0bedeutet keine Schleife, -1bedeutet Endlosschleife.
  • Dies funktioniert möglicherweise nicht mit etwas, das älter als FFmpeg 4.0 ist.

Concat-Demuxer

Mit dem concat-Demuxer können Sie eine Eingabe loopen, ohne sie neu codieren zu müssen, da er stream copy verwenden kann .

  1. Erstellen Sie eine Textdatei. Inhalt einer Beispieltextdatei, die 4 Mal wiederholt werden soll.

     file 'input.mp4'
     file 'input.mp4'
     file 'input.mp4'
     file 'input.mp4'
    
  2. Dann laufen ffmpeg:

     ffmpeg -f concat -i list.txt -c copy output.mp4
    

Wenn Sie zusätzliche Eingaben hinzufügen möchten, stellen Sie sicher, dass alle dieselben Attribute haben.

Automatisch list.txtin Linux/macOS erstellen

Dieses Beispiel ist dasselbe wie oben, aber Sie müssen Folgendes nicht manuell vornehmen list.txt:

for i in {1..4}; do printf "file '%s'\n" input.mp4 >> list.txt; done
ffmpeg -f concat -i list.txt -c copy output.mp4

Mit den am häufigsten verwendeten modernen Shells können Sie die Erstellung der list.txtDatei sogar vollständig vermeiden. Zum Beispiel mit bash:

ffmpeg -f concat -i <(for i in {1..4}; do printf "file '%s'\n" input.mp4; done) -c copy output.mp4

Siehe auch:


Schleifenfilter

Beispiel für die Verwendung des Schleifenfilters zum 4-maligen Schleifen, jede Schleife besteht aus 75 Frames, jede Schleife überspringt die ersten 25 Frames der Eingabe:

ffmpeg -i input.mp4 -filter_complex "loop=loop=3:size=75:start=25" output.mp4
  • Oder verwenden Sie die Kurzform:loop=3:75:25
  • Das Filtern erfordert eine erneute Codierung.
  • Dieser Filter platziert alle Frames im Speicher .
  • Die Verwendung loop=3wird 4 Mal wiederholt.
  • Um eine Endlosschleife zu verwenden, verwenden Sie -1.
  • Sie müssen die Anzahl der zu loopenden Frames auflisten (im obigen Beispiel als 75 dargestellt). Der maximale Wert ist 32767.
  • Siehe auch ffmpeg -h filter=loop.

Filmfilter

Die Film- und Amovie-Filter haben eine Loop-Option:

ffmpeg -f lavfi -i "movie=filename=input.mp4:loop=4,setpts=N/FRAME_RATE/TB" -f lavfi -i "amovie=filename=input.mp4:loop=4,asetpts=N/SR/TB" output.mp4
  • Das Filtern erfordert eine erneute Codierung.
  • 1bedeutet keine Schleife, 0bedeutet Endlosschleife.

-loopMöglichkeit

Die -loopOption ist spezifisch für den Bilddatei-Demuxer und den GIF- Muxer , sodass sie nicht für typische Videodateien verwendet werden kann. Aber es kann verwendet werden, um ein einzelnes Bild oder eine Reihe von Bildern endlos zu wiederholen.

Einzelbild

In diesem Beispiel wird ein einzelnes Bild immer wieder wiederholt, aber -t 30die Ausgabedauer wird auf 30 Sekunden begrenzt:

ffmpeg -loop 1 -i input.png -t 30 -vf format=yuv420p output.mp4

-vf format=yuv420pist aus Kompatibilitätsgründen.

Reihe von Bildern

ffmpeg -loop 1 -i %03d.jpg -t 30 -vf format=yuv420p output.mp4

GIF-Ausgabe

Oder um ein GIF zu loopen:

ffmpeg -i input -loop 3 output.gif

Informationen zur GIF-Ausgabe finden Sie auch unter Wie konvertiere ich ein Video mit ffmpeg in GIF mit angemessener Qualität?

Funktioniert das gut mit mp4-Dateien?
Ich bekomme diesen Fehler> <(for i in {1..4}; do printf "file '%s'\n" input.mp4; done) -bash: /dev/fd/63: Permission denied
@jamesfzhang - Ich denke, das liegt daran, dass Sie einen absoluten Pfad zur Datei benötigen (wie hier erklärt: trac.ffmpeg.org/wiki/Concatenate ). Um das zu erfüllen, könnten Sie schreiben: ffmpeg -safe 0 -f concat -i <(for i in {1..4}; do printf "file '$PWD'/'%s'\n" input.mp4; done ) -c Ausgabe kopieren.mp4
Für mich funktioniert dies, um ein Vollzeitvideo zu wiederholen, ohne Berühmtheiten 4 Mal zu überspringenffmpeg -i video.mp4 -filter_complex "loop=4:32767" output.mp4
Diese Ausgabe ist 4 Jahre alt und niemand hat bemerkt, dass der Link zur zweiten Ausgabe in diesem -stream_loopAbschnitt auf dasselbe Ticket wie das erste verweist ...
Gibt es bei der Arbeit an Bildern einen Unterschied zwischen -i %03d.png -t 30und -t 30 -i %03d.png? Ich weiß, dass Sie bei der Arbeit an Videos normalerweise -t(und -ss) vor der Eingabe möchten, um Dekodierungszeit zu sparen, aber spielt das für Bilder eine Rolle? Ich habe kürzlich einige Befehle mit -tvor der Eingabe ausgeführt und es hat gut funktioniert.
@DigiVisionMedia Sollte keinen Unterschied machen.
Nehmen die geloopten Teile im Ausgabevideo zusätzliche Größe ein? Wenn die ursprüngliche Videogröße beispielsweise 1 MB beträgt, ist loop=loop=3 gleich 3 MB?

Mit ffmpeg 2.8.4 erstellt der folgende Befehl output.mp4, das eine sich wiederholende Kopie von input.mp4 ist, bis der ffmpeg-Prozess gestoppt wird:

ffmpeg -stream_loop -1 -i input.mp4 -c copy output.mp4

Dieser Befehl wird nicht von selbst beendet, und die Ausgabedatei wächst unendlich.

Scheint die schnellste Methode zu sein
Die schnellste Methode ist eine Untertreibung, diese Methode steigert sich in Sekundenschnelle auf mehrstündige Videos.
Dies ist eine sehr praktische Methode, da keine Datei mit sich wiederholenden Zeilen erstellt werden muss.
Die Benutzer müssen den Wert für den Parameter -stream_loop von -1einer positiven Ganzzahl entsprechend ihren Anforderungen ändern. Andernfalls wächst die Datei und das System gibt einen No space left on deviceFehler aus.
Dies sollte die beste Antwort sein, die vom ersten Versuch an funktioniert.
Wenn Sie eine Zeit angeben möchten, fügen Sie -t 30 hinzu, dies erzeugt ein gelooptes Video mit 30 Sekunden

Zumindest auf FFmpeg 2.8.x (aber Oldie sollte auch funktionieren) können Sie lavfials Eingabeformat und komplexes Filterdiagramm verwenden, indem Sie movieund setptsFilter als Argument für die -iOption verwenden.

Nächster Befehl, der diese Arbeit für Sie erledigt:

ffmpeg -re -f lavfi -i "movie=filename=input.mp4:loop=0, setpts=N/(FRAME_RATE*TB)" output.mp4

Nullargumente loop=bedeuten Endlosschleife. Werte größer Null setzen Wiederholungszählungen. setptsFilter, die für die PTS-Anpassung für zweite und spätere Wiederholungen erforderlich sind, da sonst die meisten Ausgangs-Muxer mit nicht monotoner PTS-Erhöhung fehlschlagen: Schleife berechnet PTS nicht neu.

Beachten Sie, dass die Verwendung von Filtern unter der Annahme, dass Frames ohne Dekodierung/Kodierung umgangen werden, unmöglich ist: Filter behandeln nur dekodierte Frames.

Bei FFmpeg 2.8.2 neue Eingabemöglichkeit -stream_loopeingeführt. Ich schaue zuerst, dass es einfacher funktioniert und das Kopieren von Inhalten ohne Transcodierung ermöglicht:

ffmpeg -re -stream_loop -1 -i input.mp4 -c copy -y output.mp4

Aber PTS wird nicht neu berechnet und die Ausgabedatei ist falsch. Wenn Sie einen Filter hinzufügen, um PTS zu reparieren (siehe setpts), müssen Sie ihn auch entfernen -c copy. Nur Bitstream-Filter können mit codierten Paketen umgehen, aber es gibt keine Bitstream-Filter, um PTS zu reparieren (siehe: https://ffmpeg.org/ffmpeg-bitstream-filters.html )

In jedem Fall schlägt ffmpeg beim zweiten Durchgang mit Fehler fehl:

input.mp4: Resource temporarily unavailable

Bekannte Problemumgehung für mich : Container für Eingabedatei ohne PTS-Grenzen verwenden (Streaming-Container). Einer davon, mir bekannt, ist MPEG-TS. So können Sie Ihre MP4-Datei einfach in MPEG-TS konvertieren:

ffmpeg -i input.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts input.ts

Und verwenden Sie den nächsten Befehl, um eine Infinity-Datei zu erstellen:

ffmpeg -re -stream_loop -1 -i input.ts -c copy -strict -2 -bsf:a aac_adtstoasc -y output.mp4

(Bitstream-Filter sollten nur bei Bedarf verwendet werden, bei meinen Samples ist dies erforderlich)

FFmpeg >= 2.8.2 ist in diesem Fall erforderlich.

Wenn ich diesen Befehl ausführe, erhalte ich den Fehler: „[mp4 @ 00000000053fa1a0] Konnte Tag für Codec Rawvideo in Stream #0 nicht finden, Codec derzeit nicht im Container unterstützt“. Wenn ich -vcodec h264 vor der Eingabe hinzufüge, verschwindet dieser Fehler, aber der Encoder wird nicht beendet. Das Bereitstellen einer Schleifenzahl ungleich Null erzeugt viele Fehler, wird jedoch beendet. Die Datei ist keine gültige Ausgabe.
Die Dokumentation für stream_loop sagt: "Loop 0 bedeutet keine Schleife, Loop -1 bedeutet Endlosschleife."
Scheint falsche Eingabedateien. Könntest du es bitte teilen? "Schleife 0 bedeutet keine Schleife, Schleife -1 bedeutet Endlosschleife." - scheint ich alte Dokumente zu sehen :-)
Meine waren gültige MP4s, können aber die von mir verwendeten nicht teilen. Sie können eine mit ffmpeg generieren und diese dann verwenden. Fügen Sie die Konsolenausgabe ein, wenn sie funktioniert.
Ich habe vergessen: Filter unter der Annahme von Transcodierung (decodieren/codieren). Von Entwurf. Sie müssen also entfernen -c copy. Antwort behoben.
Schön zu wissen, aber das ist eine erhebliche Einschränkung, wenn Sie eine große Schleife generieren müssen.
Fügen Sie Informationen über stream_loop und WA hinzu, um das PTS-Problem ohne erneute Codierung zu beheben. FFmpeg >= 2.8.2 ist erforderlich.
@MonahTuk Ich finde, dass der Schleifenfilter viel besser funktioniert als stream_loop (was bei jeder Datei, die ich ausprobiert habe, zu einer kurzen Pause führt), mit einer Ausnahme: In dem Moment, in dem ich den Schleifenfilter hinzufüge, verschwindet das Audio?
@MikeVersteeg, du solltest Dateien überprüfen. Von Zeit zu Zeit haben verschiedene Spuren in der Datei eine etwas andere Länge oder einen unterschiedlichen Versatz, was sich auf das Muxen auswirken kann. Probleme können auch in Nie-Versionen von FFmpeg auftreten. Außerdem verwenden die meisten Arbeitsfälle den MPEG TS-Container als Ein- und Ausgabe.
@echo off

setlocal ENABLEDELAYEDEXPANSION

REM When not there gives file not found message
for /f "tokens=*" %%I in ('dir /b "*.mkv"') do (
    if exist "%%~nI.nl.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    )
    if exist "%%~nI.en.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    ) 
)
for /f "tokens=*" %%I in ('dir /b "*.mp4"') do (
    if exist "%%~nI.nl.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    )
    if exist "%%~nI.en.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    ) 
)
for /f "tokens=*" %%I in ('dir /b "*.webm"') do (
    if exist "%%~nI.nl.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    )
    if exist "%%~nI.en.srt" (
        call :BURN_FILE "%%~nI" "%%I"
    ) 
)

pause

if not exist ORIGINAL mkdir ORIGINAL
move "%%I" ORIGINAL >NUL
move "%%~nI.*" ORIGINAL >NUL

exit /b

:BURN_FILE

    set hoppa=%1
    set input=%2
    echo hoppa=!hoppa!
    echo input=!input!

    ffprobe.exe -v error -select_streams v:0 -show_entries format=bit_rate -of default=nw=1 !input! > bit_rate2.txt
    ffprobe.exe -v error -show_entries format=duration -of default=nw=1 !input! > duration2.txt
    ffprobe.exe -v error -show_entries format=duration -of default=nw=1 intro.wav > duration_intro.txt

    for /F "tokens=*" %%R in (bit_rate2.txt) do (
        for /f "tokens=1,2 delims==" %%a in ("%%R") do set NAME=%%a & set bit_rate=%%b
    )
    for /F "tokens=*" %%R in (duration2.txt) do (
        for /f "tokens=1,2 delims==" %%a in ("%%R") do set NAME=%%a & set duration=%%b
    )
    for /F "tokens=*" %%R in (duration_intro.txt) do (
        for /f "tokens=1,2 delims==" %%a in ("%%R") do set NAME=%%a & set duration_intro=%%b
    )
    for /f "tokens=1 delims=." %%a in ('echo !duration!') do set /a number=%%a
    for /f "tokens=1 delims=." %%a in ('echo !duration_intro!') do set /a number_intro=%%a

    set /A number_offset = !number! - !number_intro! - 1
    set /A number_offset = !number_offset! * 1000

    sof.exe "!hoppa!.nl.srt"

    if not exist DUTCH mkdir DUTCH

    for %%x in ("!hoppa!.nl.srt.fixed") do (
        if not %%~zx == 0 (
            if not  exist "DUTCH/!hoppa!.nl.mp4" (

            ffmpeg -y -hide_banner -i !input! -i intro.wav -i intro.wav -i pacman2.mp4 -loop 20 -filter_complex "[1]adelay=500|500[s1];[1]adelay=!number_offset!|!number_offset![s2];[0][s1][s2]amix=inputs=3;[0:v]scale=1920:1080[j];[3:v]split[m][a];[a]geq='lum(X,Y)',hue=s=0[al];[m][al]alphamerge[ovr];[ovr]scale=150:-1[sml];[j][sml]overlay=main_w-overlay_w-2:main_h-overlay_h-2[l];[l]subtitles='!hoppa!.nl.srt.fixed':force_style='FontName=Mada Black,FontSize=32,BackColour=&HA0000000,BorderStyle=4'[k]" -map "[k]" -map 0:a -strict -2 -c:v h264_nvenc -pix_fmt yuv420p -rc-lookahead 32 -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac -shortest "DUTCH/!hoppa!.nl.PART.mp4"

rem             ffmpeg -y -hide_banner -i !input! -filter_complex "[0:v]scale=1920:1080[j];[j]subtitles='!hoppa!.nl.srt.fixed':force_style='FontName=Mada Black,FontSize=32'[k]" -map "[k]" -map 0:a -strict -2 -c:v h264_nvenc -pix_fmt yuv420p -rc-lookahead 32 -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac "DUTCH/!hoppa!.nl.PART.mp4"
rem             ffmpeg -y -hide_banner -i !input! -filter_complex "[0:v]scale=1920:1080[j];[j]subtitles='!hoppa!.nl.srt.fixed'[k]" -map "[k]" -map 0:a -strict -2 -c:v h264_nvenc -pix_fmt yuv420p -rc-lookahead 32 -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac "DUTCH/!hoppa!.nl.PART.mp4"
rem             ffmpeg -y -hide_banner -i !input! -filter_complex "[0:v]scale=1920:1080[j];[j]subtitles='!hoppa!.nl.srt.fixed'[k]" -map "[k]" -map 0:a -strict -2 -c:v libx264 -preset slow -crf 23 -pix_fmt yuv420p -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac "DUTCH/!hoppa!.nl.PART.mp4"

            ) else (
                echo Already exists: "DUTCH/!hoppa!.nl.mp4" 
            )
        ) else (
            echo Subtitle file empty: !hoppa!.nl.srt.fixed
        )
    )

    if exist "DUTCH/!hoppa!.nl.PART.mp4" rename "DUTCH\!hoppa!.nl.PART.mp4" "!hoppa!.nl.mp4"

rem if not exist SUBTITLES mkdir SUBTITLES
rem if exist "!hoppa!.nl.srt.fixed" move "!hoppa!.nl.srt.fixed" SUBTITLES
rem if exist "!hoppa!.nl.srt" move "!hoppa!.nl.srt" SUBTITLES

rem remark (rem) goto for making second language
goto :ENDING

sof.exe "!hoppa!.en.srt"

if not exist ENGLISH mkdir ENGLISH

for %%x in ("!hoppa!.en.srt.fixed") do (
    if not %%~zx == 0 (
        if not  exist "ENGLISH/!hoppa!.en.mp4" (
            ffmpeg -y -hide_banner -i !input! -filter_complex "[0:v]scale=1920:1080[j];[j]subtitles='!hoppa!.en.srt.fixed'[k]" -map "[k]" -map 0:a -strict -2 -c:v h264_nvenc -pix_fmt yuv420p -rc-lookahead 32 -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac "ENGLISH/!hoppa!.en.PART.mp4"
rem                 ffmpeg -y -hide_banner -i !input! -filter_complex "[0:v]scale=1920:1080[j];[j]subtitles='!hoppa!.en.srt.fixed'[k]" -map "[k]" -map 0:a -strict -2 -c:v libx264 -preset slow -crf 23 -pix_fmt yuv420p -b:v !bit_rate! -ac 2 -ar 44100 -acodec aac "ENGLISH/!hoppa!.en.PART.mp4"
        ) else (
            echo Already exists: "DUTCH/!hoppa!.en.mp4" 
        )
    ) else (
        echo Subtitle file empty: !hoppa!.en.srt.fixed
    )
)

if exist "ENGLISH/!hoppa!.en.PART.mp4" rename "ENGLISH\!hoppa!.en.PART.mp4" "!hoppa!.en.mp4"

rem     if exist "!hoppa!.en.srt.fixed" move "!hoppa!.en.srt.fixed" SUBTITLES >NUL
rem     if exist "!hoppa!.en.srt" move "!hoppa!.en.srt" SUBTITLES >NUL

:ENDING

if not exist ORIGINAL mkdir ORIGINAL
move !input! ORIGINAL >NUL
move "!hoppa!.*" ORIGINAL >NUL

exit /b

Wenn Sie MP4-Dateien haben, können diese verlustfrei verkettet werden, indem Sie sie zuerst in MPEG-2-Transportströme umwandeln. Mit H.264-Video und AAC-Audio kann Folgendes verwendet werden:

ffmpeg -i input.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate.ts
ffmpeg -i "concat:intermediate.ts|intermediate.ts|intermediate.ts|intermediate.ts" -c copy -bsf:a aac_adtstoasc output.mp4

Die einfache Methode, die Probleme vermeidet, welche Befehle mit welcher Version funktionieren, ist die 'triviale Lösung':

ffmpeg -i input.mp4 -i input.mp4 -i input.mp4 -i input.mp4 -c copy output.mp4

Siehe auch: https://trac.ffmpeg.org/wiki/Concatenate für viele Beispiele.

Dies führt keine Verkettung durch. Mindestens eine der concat-Methoden muss verwendet werden: Protokoll, Filter oder Demuxer. In diesem Befehl wählt die automatische Zuordnung von ffmpeg einen Video-, einen Audio- und einen Untertitel-Stream aus den Eingängen aus. Da sie identisch sind, entspricht dies dem ersten Befehl des OP.
Vielen Dank, dass Sie Mulvya getestet haben, da es sich von dem in den Dokumenten beschriebenen Verhalten unterscheidet: ffmpeg.org/ffmpeg.html#Description - Wenn es Ähnlichkeiten in den Dateinamen gibt, verwenden Sie "-i -i /tmp/test%d.mp4" ( et al.) ist ebenfalls möglich.