ffmpeg - safe - ubuntu unir dos videos
¿Cómo concatenar dos archivos MP4 usando FFmpeg? (15)
Estoy tratando de concatenar dos archivos mp4 usando ffmpeg. Necesito que esto sea un proceso automático, por lo tanto, elegí ffmpeg. Estoy convirtiendo los dos archivos en archivos .ts y luego concatenándolos y luego tratando de codificar ese archivo .ts concatenado. Los archivos están codificados en h264 y aac y espero mantener la calidad lo más original posible.
ffmpeg -i part1.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy part1.ts
ffmpeg -i part2.mp4 -vcodec copy -vbsf h264_mp4toannexb -acodec copy part2.ts
cat part1.ts part2.ts > parts.ts
ffmpeg -y -i parts.ts -acodec copy -ar 44100 -ab 96k -coder ac -vbsf h264_mp4toannexb parts.mp4
Desafortunadamente, recibo el siguiente mensaje de error de ffmpeg durante la codificación:
[h264 @ 0x1012600]sps_id out of range
[h264 @ 0x1012600]non-existing SPS 0 referenced in buffering period
[h264 @ 0x1012600]sps_id out of range
[h264 @ 0x1012600]non-existing SPS 0 referenced in buffering period
[NULL @ 0x101d600]error, non monotone timestamps 13779431 >= 13779431kbits/s
av_interleaved_write_frame(): Error while opening file
Esto sucede aproximadamente a mitad de la codificación, lo que me hace pensar que no se pueden agrupar dos archivos .ts juntos y hacer que funcionen.
para archivos MP4:
Si no son exactamente los mismos archivos MP4 (el 100% del mismo códec, la misma resolución, el mismo tipo), al principio debe codificarlos en secuencias intermedias:
ffmpeg -i myfile1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp1.ts
ffmpeg -i myfile2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts temp2.ts
// now join
ffmpeg -i "concat:temp1.ts|temp2.ts" -c copy -bsf:a aac_adtstoasc output.mp4
¡NOTA! : La salida será como el primer archivo (y no un segundo)
Fusionando todos los archivos mp4 del directorio actual
Personalmente me gusta no crear un archivo externo que tengo que eliminar después, por lo que mi solución fue la siguiente, que incluye la lista de archivos de numeración (como file_1_name, file_2_name, file_10_name, file_20_name, file_100_name
, ...)
#!/bin/bash
filesList=""
for file in $(ls -1v *.mp4);do #lists even numbered file
filesList="${filesList}${file}|"
done
filesList=${filesList%?} # removes trailing pipe
ffmpeg -i "concat:$filesList" -c copy $(date +%Y%m%d_%H%M%S)_merged.mp4
Aquí hay un script que hice para concatenar varios mp4 de GoPro en un mp4 de 720p. Espero que sea de ayuda.
#!/bin/sh
cmd="( "
for i; do
cmd="${cmd}ffmpeg -i $i -ab 256000 -vb 10000000 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -f mpeg -; "
done
cmd="${cmd} ) | ffmpeg -i - -vb 10000000 -ab 256000 -s 1280x720 -y out-`date +%F-%H%M.%S`.mp4"
echo "${cmd}"
eval ${cmd}
Aquí hay una manera rápida (de menos de 1 minuto) y sin pérdida de hacerlo sin necesidad de archivos intermedios:
ls Movie_Part_1.mp4 Movie_Part_2.mp4 | perl -ne ''print "file $_"'' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4
La "ls" contiene los archivos para unirse. La "perl" crea el archivo de concatenación sobre la marcha en una tubería La parte "-i -" le dice a ffmpeg que lea desde la tubería
(nota: mis archivos no tenían espacios o cosas extrañas en ellos; necesitarás un escape de shell adecuado si quieres hacer esta idea con archivos "duros").
De la documentación aquí: https://trac.ffmpeg.org/wiki/Concatenate
Si tiene archivos MP4, estos podrían ser concatenados sin pérdidas al primero, transcodificándolos a flujos de transporte MPEG-2. Con el video H.264 y el audio AAC, se puede usar lo siguiente:
ffmpeg -i input1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts
ffmpeg -i input2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts
ffmpeg -i "concat:intermediate1.ts|intermediate2.ts" -c copy -bsf:a aac_adtstoasc output.mp4
Este enfoque funciona en todas las plataformas.
Necesitaba la capacidad de encapsular esto en un script multiplataforma, así que usé fluent-ffmpeg
y encontré la siguiente solución:
const unlink = path =>
new Promise((resolve, reject) =>
fs.unlink(path, err => (err ? reject(err) : resolve()))
)
const createIntermediate = file =>
new Promise((resolve, reject) => {
const out = `${Math.random()
.toString(13)
.slice(2)}.ts`
ffmpeg(file)
.outputOptions(''-c'', ''copy'', ''-bsf:v'', ''h264_mp4toannexb'', ''-f'', ''mpegts'')
.output(out)
.on(''end'', () => resolve(out))
.on(''error'', reject)
.run()
})
const concat = async (files, output) => {
const names = await Promise.all(files.map(createIntermediate))
const namesString = names.join(''|'')
await new Promise((resolve, reject) =>
ffmpeg(`concat:${namesString}`)
.outputOptions(''-c'', ''copy'', ''-bsf:a'', ''aac_adtstoasc'')
.output(output)
.on(''end'', resolve)
.on(''error'', reject)
.run()
)
names.map(unlink)
}
concat([''file1.mp4'', ''file2.mp4'', ''file3.mp4''], ''output.mp4'').then(() =>
console.log(''done!'')
)
Descubrí que el operador de tuberías no me funcionó cuando usé la opción 3 para calcular varios MP4 en una Mac en la respuesta aceptada.
El siguiente one-liner funciona en una Mac (High Sierra) para concatenar mp4s, sin necesidad de creación de archivos intermediarios.
ffmpeg -f concat -safe 0 -i <(for f in ./*.mp4; do echo "file ''$PWD/$f''"; done) -c copy output.mp4
Estaba tratando de concatenar tres archivos de audio .mp3
en un archivo .m4a
y este comando ffmpeg funciona.
Comando de entrada:
ffmpeg -i input1.mp3 -i input2.mp3 -i input3.mp3 -filter_complex concat=n=3:v=0:a=1 -f MOV -vn -y input.m4a
Significados de: "-filter_complex concat = n = 3: v = 0: a = 1" :
concat significa usar la función concatenar (unirse) de medios.
n significa confirmar el recuento total de archivos de entrada.
v significa tiene video ? use 0 = no video, 1 = contiene video.
¿Un medio tiene audio ? use 0 = sin audio, 1 = contiene audio.
-f significa forzar el conjunto de formatos de archivo (para ver todos los formatos compatibles, useffmpeg -formats
)
-vn significa deshabilitar video (y también-an
deshabilitaría el audio si no se desea)
-y significa sobrescribir archivos de salida (si el archivo de salida ya existe).
Para obtener más información: use ffmpeg -h full
print todas las opciones (incluyendo todas las opciones específicas de formato y códec, muy largas)
FFmpeg tiene tres métodos de concatenación.
1. filtro de video concat
ffmpeg -i opening.mkv -i episode.mkv -i ending.mkv /
-filter_complex "[0:v] [0:a] [1:v] [1:a] [2:v] [2:a] concat=n=3:v=1:a=1 [v] [a]" /
-map "[v]" -map "[a]" output.mkv
Tenga en cuenta que este método realiza una recodificación.
2. concat demuxer
$ cat mylist.txt
file ''/path/to/file1''
file ''/path/to/file2''
file ''/path/to/file3''
$ ffmpeg -f concat -i mylist.txt -c copy output
para Windows :
(echo file ''first file.mp4'' & echo file ''second file.mp4'' )>list.txt
ffmpeg -safe 0 -f concat -i list.txt -c copy output.mp4
3. protocolo concat
ffmpeg -i "concat:input1|input2" -codec copy output
Este método no funciona para muchos formatos, incluyendo MP4, debido a la naturaleza de estos formatos y la concatenación simplista realizada por este método.
Cual usar
filtro concat : utilícelo si sus entradas no tienen los mismos parámetros (ancho, altura, etc.), no son los mismos formatos / códecs, o si desea realizar algún tipo de filtrado. (Puede volver a codificar solo las entradas que no coincidan para que compartan el mismo códec y otros parámetros, y luego usar el demonio de concat para evitar volver a codificar las otras entradas).
concat demuxer : se usa cuando se quiere evitar una recodificación y su formato no admite la concatenación de nivel de archivo (la mayoría de los archivos utilizados por los usuarios generales no admiten la concatenación de nivel de archivo).
protocolo concat : se utiliza con formatos que admiten concatenación de nivel de archivo (MPEG-1, MPEG-2 PS, DV). No utilizar con MP4.
En caso de duda probar el demoledor concat.
Ver también
La documentación detallada sobre varias formas de concatenación en ffmpeg se puede encontrar aquí .
Puede usar el ''filtro de concat'' para una concatenación rápida.
Realiza una recodificación. Esta opción es mejor cuando las entradas tienen diferentes formatos de video / audio.
Para concatenar 2 archivos:
ffmpeg -i input1.mp4 -i input2.webm /
-filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] concat=n=2:v=1:a=1 [v] [a]" /
-map "[v]" -map "[a]" output.mp4
Para concatenar 3 archivos:
ffmpeg -i input1.mp4 -i input2.webm -i input3.mp4 /
-filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0] [2:v:0] [2:a:0] concat=n=3:v=1:a=1 [v] [a]" /
-map "[v]" -map "[a]" output.mp4
Esto funciona tanto para el mismo como para múltiples tipos de archivos de entrada.
Para los archivos mp4, encontré que funciona mejor y más rápido para usar la herramienta de línea de comandos opensource "mp4box". Entonces puedes usarlo de esta manera:
mp4box.exe -add video1.mp4 -cat video2.mp4 destvideo.mp4
Descárguelo aquí para la mayoría de las plataformas: https://gpac.wp.imt.fr/mp4box/
Terminé usando mpg como formato intermedio y funcionó (NOTA: este es un ejemplo peligroso, -qscale 0 volverá a codificar el video ...)
ffmpeg -i 1.mp4 -qscale 0 1.mpg
ffmpeg -i 2.mp4 -qscale 0 2.mpg
cat 1.mpg 2.mpg | ffmpeg -f mpeg -i - -qscale 0 -vcodec mpeg4 output.mp4
basado en las respuestas de rogerdpack y Ed999, he creado mi versión .sh
#!/bin/bash
[ -e list.txt ] && rm list.txt
for f in *.mp4
do
echo "file $f" >> list.txt
done
ffmpeg -f concat -i list.txt -c copy joined-out.mp4 && rm list.txt
une todos los archivos *.mp4
en la carpeta actual en joined-out.mp4
probado en mac.
el tamaño del archivo resultante es la suma exacta de mis 60 archivos probados. No debería haber ninguna pérdida. Justo lo que necesitaba
esto funcionó para mí (en windows)
ffmpeg -i "concat:input1|input2" -codec copy output
en particular
ffmpeg -i "concat:01.mp4|02.mp4" -codec copy output.mp4
Pitón
Usando algo de código python para hacerlo con tantos mp4 hay en una carpeta.
stringa = ""
for f in glob.glob("*.mp4"):
stringa += f + "|"
os.system("ffmpeg -i /"concat:" + stringa + "/" -codec copy output.mp4")
PARA ARCHIVOS MP4
Para los archivos .mp4 (que obtuve de DailyMotion.com: un episodio de televisión de 50 minutos, descargable solo en tres partes, como tres archivos de video .mp4) la siguiente fue una solución efectiva para Windows 7 , y NO implica volver a codificar el archivos.
Cambié el nombre de los archivos (como file1.mp4 , file2.mp4 , file3.mp4 ) de modo que las partes estuvieran en el orden correcto para ver el episodio completo de televisión.
Luego creé un archivo por lotes simple (concat.bat), con los siguientes contenidos:
:: Create File List
echo file file1.mp4 > mylist.txt
echo file file2.mp4 >> mylist.txt
echo file file3.mp4 >> mylist.txt
:: Concatenate Files
ffmpeg -f concat -i mylist.txt -c copy output.mp4
El archivo por lotes , y ffmpeg.exe , deben colocarse en la misma carpeta que los archivos .mp4 para unirse. A continuación, ejecute el archivo por lotes. Por lo general, tardará menos de diez segundos en ejecutarse.
.
Anexo (2018/10/21) -
Si lo que buscaba es un método para especificar todos los archivos mp4 en la carpeta actual sin tener que volver a escribirlos, intente esto en su archivo por lotes de Windows:
:: Create File List
for %%i in (*.mp4) do echo file "%%i">> mylist.txt
ffmpeg /
-i input_1.mp4 /
-i input_2.mp4 /
-filter_complex ''[0:v]pad=iw*2:ih[int];[int][1:v]overlay=W/2:0[vid]'' /
-map [vid] /
-c:v libx264 /
-crf 23 /
-preset veryfast /
output.mp4