Unir archivos mp4 en linux

27

Quiero unir dos archivos mp4 para crear uno solo. Las secuencias de video están codificadas en h264 y el audio en aac. No puedo volver a codificar los videos a otro formato debido a razones computacionales. Además, no puedo usar ningún programa GUI, todo el procesamiento debe realizarse con las utilidades de línea de comandos de Linux. FFmpeg no puede hacer esto para archivos mpeg4, así que en su lugar usé MP4Box:

MP4Box -add video1.mp4 -cat video2.mp4 newvideo.mp4

Desafortunadamente, el audio se mezcla todo. Pensé que el problema era que el audio estaba en aac, así que lo transcodifiqué en mp3 y usé nuevamente MP4Box. En este caso, el audio está bien para la primera mitad de newvideo.mp4 (correspondiente a video1.mp4 ) pero entonces no hay audio y tampoco puedo navegar en el video.

Mi siguiente pensamiento fue que las secuencias de audio y video tenían algunas pequeñas discrepancias en sus longitudes que debería solucionar. Así que para cada video de entrada, dividí los flujos de video y audio y luego los uní con la opción -shortest en FFmpeg.

Así, para el primer video corrí:

 avconv -y -i video1.mp4 -c copy -map 0:0 videostream1.mp4
 avconv -y -i video1.mp4 -c copy -map 0:1 audiostream1.m4a
 avconv -y -i videostream1.mp4 -i audiostream1.m4a  -c copy -shortest  video1_aligned.mp4

Similarmente para el segundo video y luego usé MP4Box como anteriormente. Desafortunadamente esto tampoco funcionó. El único éxito que tuve fue cuando me uní a las secuencias de video por separado (es decir, videostream1.mp4 y videostream2.mp4) y las secuencias de audio (es decir, audiostream1.m4a y audiostream2.m4a) y luego uní el video y el audio en un archivo final. Sin embargo, la sincronización se pierde para la segunda mitad del video. Concretamente, hay un retraso de 1 segundo de audio y video. Cualquier sugerencia es realmente bienvenida.

Jose Armando
fuente
"FFmpeg no puede hacer esto para archivos mpeg4, así que en lugar de eso usé MP4Box" ¿quieres decir archivo MP4? ¿Las secuencias de audio y video utilizan los mismos parámetros de codificación (ancho, alto, SPS, PPS, tasa de cuadros, tasa de muestreo, número de canales?
usando ffprobe veo que las secuencias de audio tienen atributos idénticos. Las secuencias de video tienen las mismas dimensiones pero diferentes tasas. Para el primer video Video: h264, 720x592, 277 kb / s, PAR 18944: 12915 DAR 512: 287, 24.97 fps, 45k tbr, 90k tbn, 90k tbc mientras que para el segundo video: h264, 720x592, 226 kb / s PAR 481: 330 DAR 39:22, 24.91 fps, 45k tbr, 90k tbn, 90k tbc. ¿Crees que esta es la fuente de mis problemas?
MP4 admite la unión de video / audio con diferentes características utilizando diferentes pistas para diferentes videos, pero el reproductor no es tan inteligente.
rajneesh
Tu pregunta ya está respondida en las preguntas frecuentes de ffmpeg: ffmpeg.org/faq.html#How-can-I-join-video-files_003f
Palec

Respuestas:

26

La mejor manera de hacer esto actualmente es con el concat demuxer . Primero, crea un archivo llamado inputs.txt formateado como tal:

file '/path/to/input1.mp4'
file '/path/to/input2.mp4'
file '/path/to/input3.mp4'

Luego, simplemente ejecute este comando ffmpeg:

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

Ver también concatenación en ffmpeg Preguntas más frecuentes .


Mantengo lo siguiente aquí para el beneficio de cualquiera que use versiones anteriores de ffmpeg.

Las últimas versiones de ffmpeg pueden hacer esto: primero tendrá que transformar los archivos en flujos de transporte mpeg (bastante luz de procesador, ya que solo está cambiando el formato del contenedor):

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts

Si eso produce un error sobre h264, es posible que deba usar:

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts

Tendrás que hacer esto por separado con cada archivo de entrada. Para concatenar los archivos juntos, use:

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy output.mp4

Si eso produce un error sobre aac, es posible que deba usar

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy -absf aac_adtstoasc output.mp4

Si su sistema admite canalizaciones con nombre, puede hacerlo sin crear archivos intermedios.

mkfifo temp0 temp1

Tendrás que hacer lo siguiente en tres terminales virtuales separadas:

ffmpeg -i input0.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp0
ffmpeg -i input1.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp1
ffmpeg -f mpegts -i "concat:temp0|temp1" -c copy -absf aac_adtstoasc output.mp4

Si ya existe output.mp4, el tercer ffmpeg le preguntará si desea sobrescribirlo, pero lo hará. Después de haber accedido a los FIFOs. , y esto hará que los primeros en ffmpegs se cierren. Así que asegúrese de elegir un nombre no utilizado para su archivo de salida.

Es posible que esto no funcione si sus archivos de entrada son diferentes. Creo que las diferencias en la velocidad de bits están bien, pero el tamaño del cuadro, la velocidad del cuadro, etc., deben coincidir.

evilsoup
fuente
Muchas gracias compañero, trabajaron como un amuleto.
Jose Armando
2
@DaveJarvis No es así; ese es un mensaje difundido deliberadamente y maliciosamente por el equipo de libav, que son un grupo de desarrolladores que se separaron del proyecto ffmpeg para desarrollar avconv (y cambiaron el nombre porque no pudieron asegurar el copyright del nombre ffmpeg). Ver ¿Quién puede decirme la diferencia y la relación entre ffmpeg, libav y avconv? Para un poco más de información.
evilsoup
2
*** THIS PROGRAM IS DEPRECATED *** This program is only provided for compatibility and will be removed in a future release. Please use avconv instead. Es un mensaje que veo ahora en funcionamiento. ffmpeg
Lord Loh.
@LordLoh. Vea el enlace en mi comentario anterior.
evilsoup
1
Esa respuesta no responde - cómo concatenar mp4 con avconv
Lord Loh.
7

Para mp4, la única solución de trabajo que encontré fue con MP4Box del paquete gpac

#!/bin/bash
filesList=""
for file in $(ls *.mp4|sort -n);do
    filesList="$filesList -cat $file"
done
MP4Box $filesList -new merged_files_$(date +%Y%m%d_%H%M%S).mp4

o comando es

MP4Box -cat file1.mp4 -cat file2.mp4 -new mergedFile.mp4

con mencoder y avconv no pude hacerlo funcionar :-(

Philippe Gachoud
fuente
2

Gracias por el script dvo. Fue un gran punto de partida para mí. No tuve ningún problema con el uso de canalizaciones con nombre, así que adapté la secuencia de comandos para usarlas en su lugar. Además lo arreglé para trabajar con nombres de archivos con espacios en ellos. La salida a las canalizaciones con nombre no "va" hasta que comience a leerlas, por lo tanto, es necesario hacer un fondo de las tareas de remux iniciales con un & amp; Antes de la llamada final a avconv. Además, no olvides usar la copia -c, o terminarás recodificando todo el lote.

#!/bin/bash
for FILE in "$@"; do
   TAG=$(echo "$FILE" | sed -e s/[^A-Za-z0-9.]/_/g)
   mkfifo $TAG.mp4concatpipe
   avconv -loglevel "quiet" -i "$FILE"  -f mpegts -c copy -bsf h264_mp4toannexb -y $TAG.mp4concatpipe &
   IN=$IN\|$TAG.fifo
done

IN=${IN#\|}
avconv -i concat:$IN -c copy out.mp4
rm *.mp4concatpipe
Mark
fuente
Por alguna razón, esto me está dando un "concat: first.m4v.fifo | second.m4v.fifo: no existe tal archivo o directorio" error ... incluso con comillas (-i concat: "$ IN" o -i "concat: $ EN "). MP4Box sugirió en la otra respuesta a continuación, sin embargo, funciona muy bien!
vorburger
2

En una Mac (macOS 10.13 High Sierra) usé lo siguiente con éxito:

for f in *.m4a; do echo "file '$f'" >> mylist.txt; done

Reordene lo anterior de manera similar si es necesario (tenga en cuenta que se eliminó el ./ - la ruta estaba causando que ffmpeg arrojara el error de nombre de archivo no seguro).

Luego tuve que eliminar el códec y la tasa de bits especificada para que el MacPorts ffmpeg predeterminado me gustara:

ffmpeg -f concat -i mylist.txt  output.m4a
Robert Cole
fuente
¡Bienvenido a Superusuario! Por favor, lea la pregunta nuevamente con cuidado. Su respuesta no responde a la pregunta original sobre Linux. Si cree que funcionará en Linux, agregue que para que los futuros lectores tengan una comprensión clara, aparte de eso, nuevamente, bienvenido a superusuario y gracias por su aporte. Por favor tómese un par de minutos y lea: - superuser.com/help .Respuesta: superuser.com/help/how-to-answer .
mic84
1

Gracias evilsoup; Aquí hay un pequeño script para automatizar el proceso, usando el más reciente avconv.
Por cierto, las tuberías con nombre no funcionaron para mí (la salida se atascó).

   #!/bin/bash

    for FILE in $@; do
      avconv -i $FILE -map 0 -f mpegts -bsf h264_mp4toannexb -c:v copy -y $FILE.tmp
      IN=$IN\|$FILE.tmp
    done

    IN=${IN#\|}
    avconv -i concat:"$IN" out.mp4

    for FILE in $@; do
      rm $FILE.tmp
    done
dvo
fuente
0

Han disfrutado de gran éxito con

for f in ./*.m4a; do echo "file '$f'" >> mylist.txt; done

Es posible que deba reordenar mylist.txt ligeramente

ffmpeg -f concat -i mylist.txt -c:a libfdk_aac -b:a 128k output.m4a

ffmpeg versión 2.2.3

Benjamin
fuente