¿Repetir/repetir video de entrada en bucle con ffmpeg?

Solo quiero reproducir un video mp4 con ffmpeg y mantener la configuración y el códec actuales.

Por ejemplo, si input.mp4 tiene una duración de 0:10 y me gustaría repetirlo 4 veces para que output.mp4 tenga una duración de 0:40, ¿cómo podría cambiar la siguiente línea de comando para hacer eso?

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

Lo intenté...

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

... pero aparece el error "No se encontró el bucle de opción".

Utilice quicktime 7 pro y mov container. Por lo tanto, no obtendrá un tamaño de archivo más grande que con uno de código abierto.

Respuestas (6)

-stream_loopopción

ffmpeg -stream_loop 3 -i input.mp4 -c copy output.mp4
  • Esto puede evitar la recodificación porque puede usar stream copy .
  • 0significa sin bucle, -1significa bucle infinito.
  • Es posible que esto no funcione con nada anterior a FFmpeg 4.0.

demultiplexor de concatenación

El demuxer concat le permite hacer un bucle de una entrada sin necesidad de volver a codificar porque puede usar la copia de flujo .

  1. Haz un archivo de texto. Contenido de un archivo de texto de ejemplo para repetir 4 veces.

     file 'input.mp4'
     file 'input.mp4'
     file 'input.mp4'
     file 'input.mp4'
    
  2. Luego ejecuta ffmpeg:

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

Si desea agregar entradas adicionales, asegúrese de que todas tengan los mismos atributos.

Hacer automáticamente list.txten Linux/macOS

Este ejemplo es el mismo que el anterior, pero no tiene que hacer manualmente 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

Con los shells modernos más utilizados, incluso puede evitar la creación del list.txtarchivo por completo. Por ejemplo, con bash:

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

Ver también:


filtro de bucle

Ejemplo usando el filtro de bucle para hacer un bucle 4 veces, cada bucle tiene 75 fotogramas, cada bucle salta los primeros 25 fotogramas de la entrada:

ffmpeg -i input.mp4 -filter_complex "loop=loop=3:size=75:start=25" output.mp4
  • O usa la abreviatura:loop=3:75:25
  • El filtrado requiere volver a codificar.
  • Este filtro coloca todos los marcos en la memoria .
  • Usando loop=3se repetirá 4 veces.
  • Para hacer un bucle infinito, use -1.
  • Debe enumerar el número de fotogramas para reproducir en bucle (se muestra como 75 en el ejemplo anterior). El valor máximo es 32767.
  • ffmpeg -h filter=loopTambién vea

filtro de pelicula

Los filtros de película y amovie tienen una opción de bucle:

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
  • El filtrado requiere volver a codificar.
  • 1significa sin bucle, 0significa bucle infinito.

-loopopción

La -loopopción es específica para el demuxer de archivos de imagen y gif muxer , por lo que no se puede usar para archivos de video típicos. Pero se puede usar para repetir infinitamente una sola imagen o una serie de imágenes.

sola imagen

Este ejemplo repetirá una sola imagen una y otra vez, pero -t 30limitará la duración de la salida a 30 segundos:

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

-vf format=yuv420pes por razones de compatibilidad.

serie de imágenes

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

salida GIF

O para reproducir un GIF:

ffmpeg -i input -loop 3 output.gif

Para la salida de GIF también vea ¿Cómo convierto un video a GIF usando ffmpeg, con una calidad razonable?

¿Funciona bien con archivos mp4?
me sale este error> <(for i in {1..4}; do printf "file '%s'\n" input.mp4; done) -bash: /dev/fd/63: Permission denied
@jamesfzhang: creo que es porque necesita una ruta absoluta al archivo (como se explica aquí: trac.ffmpeg.org/wiki/Concatenate ). Para cumplir con eso, podrías escribir: ffmpeg -safe 0 -f concat -i <(for i in {1..4}; do printf "file '$PWD'/'%s'\n" input.mp4; done ) -c copiar salida.mp4
En cuanto a mí, esto funciona para repetir el video a tiempo completo sin saltarse las famas 4 veces.ffmpeg -i video.mp4 -filter_complex "loop=4:32767" output.mp4
Este número tiene 4 años y nadie se dio cuenta de que el enlace al segundo número de la -stream_loopsección apunta al mismo ticket que el primero...
Al trabajar con imágenes, ¿hay alguna diferencia entre -i %03d.png -t 30y -t 30 -i %03d.png? Sé que cuando trabajas en video, por lo general deseas -t(y -ss) antes de la entrada para ahorrar tiempo de decodificación, pero ¿importa esto para las imágenes? Recientemente ejecuté algunos comandos -tantes de la entrada y funcionó bien.
@DigiVisionMedia No debería marcar la diferencia.
¿Las partes en bucle ocupan un tamaño adicional en el video de salida? Por ejemplo, si el tamaño del video original es de 1 MB loop=loop=3 es igual a 3 MB.

Con ffmpeg 2.8.4, el siguiente comando crea output.mp4 que es una copia repetida de input.mp4 hasta que se detiene el proceso de ffmpeg:

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

Este comando no terminará por sí solo y el archivo de salida crecerá infinitamente.

Parece ser el método más rápido.
El método más rápido es un eufemismo, este método aumenta a videos de varias horas en cuestión de segundos.
Este es un método muy conveniente, porque no hay necesidad de crear un archivo con líneas repetidas.
Las personas deben cambiar el valor del parámetro -stream_loop de -1algún número entero positivo de acuerdo con sus requisitos. De lo contrario, el archivo crece y el sistema arroja No space left on deviceun error.
Esta debería ser la mejor respuesta que funcione desde el primer intento.
Si desea especificar un tiempo, agregue -t 30 esto generará un video en bucle con 30 segundos

Al menos en FFmpeg 2.8.x (pero el antiguo también debería funcionar) puede usar lavficomo formato de entrada y un gráfico de filtro complejo usando moviey setptsfiltros como argumento para la -iopción.

Siguiente comando haciendo este trabajo por usted:

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

Cero loop=argumentos significa bucle infinito. Los valores superiores a cero establecen recuentos repetidos. setptsSe requieren filtros para el ajuste de PTS para la segunda y posteriores repeticiones; de lo contrario, la mayoría de los muxers de salida fallarán con el aumento de PTS no monótono: el bucle no vuelve a calcular PTS.

Tenga en cuenta que el uso de filtros asumiendo que eluden los marcos sin decodificar/codificar es imposible: por diseño, los filtros se ocupan solo de los marcos decodificados.

En FFmpeg 2.8.2 se introdujo una nueva opción de entrada -stream_loop. Primero veo que funciona de manera más simple y permite copiar contenido sin transcodificar:

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

Pero no vuelve a calcular PTS y el archivo de salida es incorrecto. Si agrega un filtro para corregir PTS (consulte setpts), también debe eliminarlo -c copy. Solo los filtros de flujo de bits pueden manejar paquetes codificados, pero no hay filtros de flujo de bits para corregir PTS (ver: https://ffmpeg.org/ffmpeg-bitstream-filters.html )

En cualquier caso, ffmpeg en el segundo paso falla con un error:

input.mp4: Resource temporarily unavailable

Solución conocida para mí : use el contenedor para el archivo de entrada sin límites PTS (contenedor de transmisión). Uno de ellos, conocido por mí, es MPEG-TS. Entonces, puede simplemente convertir su archivo MP4 a MPEG-TS:

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

Y use el siguiente comando para componer el archivo infinito:

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

(Los filtros de flujo de bits deben usarse solo si es necesario, en mis muestras es obligatorio)

En este caso, se requiere FFmpeg >= 2.8.2.

Ejecutar ese comando me da el error: "[mp4 @ 00000000053fa1a0] No se pudo encontrar la etiqueta para el códec rawvideo en la transmisión #0, el códec no es compatible actualmente con el contenedor". Si agrego -vcodec h264 antes de la entrada, ese error desaparece, pero el codificador no sale. Proporcionar un recuento de bucle distinto de cero produce muchos errores, pero sale. El archivo no es una salida válida.
La documentación de stream_loop dice "Loop 0 significa que no hay loop, loop -1 significa loop infinito".
Parece archivos de entrada incorrectos. ¿Podrías compartirlo? "El bucle 0 significa que no hay bucle, el bucle -1 significa bucle infinito". - parece que veo documentos antiguos :-)
Los míos eran MP4 válidos pero no puedo compartir los que usé. Puedes generar uno usando ffmpeg y luego usarlo. Pegue la salida de la consola si funciona.
Lo olvidé: filtros asumiendo transcodificación (decodificación/codificación). Por diseño. Por lo que debes eliminar -c copy. Respuesta arreglada.
Es bueno saberlo, pero esa es una limitación importante si tiene que generar un bucle grande.
Agregue información sobre stream_loop y WA para solucionar el problema de PTS sin volver a codificar. Se requiere FFmpeg >= 2.8.2.
@MonahTuk Encuentro que el filtro de bucle funciona mucho mejor que stream_loop (lo que provoca una breve pausa para cualquier archivo que probé), con una excepción: en el momento en que agrego el filtro de bucle, ¿desaparece el audio?
@MikeVersteeg, debe verificar los archivos. De vez en cuando, diferentes pistas en el archivo tienen una longitud o un desplazamiento un poco diferentes, lo que puede afectar la muxización. También pueden ocurrir problemas en versiones nunca de FFmpeg. Además, la mayoría de los casos de trabajo: use el contenedor MPEG TS como entrada y salida.
@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

Si tiene archivos MP4, estos pueden concatenarse sin pérdidas volviéndolos a empaquetar primero en flujos de transporte MPEG-2. Con video H.264 y audio AAC, se puede usar lo siguiente:

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

El método simple que evita problemas de qué comandos funcionan con qué versión es la 'solución trivial':

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

Consulte también: https://trac.ffmpeg.org/wiki/Concatenate para ver muchos ejemplos.

Esto no hace ninguna concatenación. Se debe utilizar al menos uno de los métodos de concatenación: protocolo, filtro o demuxer. En este comando, el mapeo automático de ffmpeg seleccionará un flujo de video, audio y subtítulos de entre las entradas. Como son idénticos, es equivalente al primer comando del OP.
Gracias por probar ese Mulvya, ya que difiere del comportamiento descrito en los documentos: ffmpeg.org/ffmpeg.html#Description - Si hay similitud en los nombres de los archivos usando "-i -i /tmp/test%d.mp4" ( et al) también es posible.