41 votes

Rejoindre des fichiers mp4 sous linux

Je veux joindre deux fichiers mp4 pour en créer un seul. Les flux vidéo sont encodés en h264 et l'audio en aac. Je ne peux pas ré-encoder les vidéos dans un autre format pour des raisons de calcul. De plus, je ne peux pas utiliser de programmes GUI, tout le traitement doit être effectué avec les utilitaires en ligne de commande Linux. FFmpeg ne peut pas le faire pour les fichiers mpeg4 donc j'ai utilisé MP4Box à la place :

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

Malheureusement, l'audio est tout mélangé. J'ai pensé que le problème venait de l'audio étant en aac donc je l'ai transcodé en mp3 et j'ai de nouveau utilisé MP4Box. Dans ce cas, l'audio est bon pour la première moitié de newvideo.mp4 (correspondant à video1.mp4) mais ensuite il n'y a pas d'audio et je ne peux pas naviguer dans la vidéo non plus.

Ma prochaine idée était que les flux audio et vidéo avaient de petites différences dans leurs longueurs que je devais corriger. Donc pour chaque vidéo d'entrée j'ai séparé les flux vidéo et audio puis je les ai rejoints avec l'option -shortest dans FFmpeg.

Ainsi, pour la première vidéo j'ai exécuté :

 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

De même pour la deuxième vidéo et puis j'ai utilisé MP4Box comme précédemment. Malheureusement cela n'a pas fonctionné non plus. Le seul succès que j'ai eu était lorsque j'ai joint les flux vidéo séparément (c'est-à-dire videostream1.mp4 et videostream2.mp4) et les flux audio (c'est-à-dire audiostream1.m4a et audiostream2.m4a) puis j'ai joint la vidéo et l'audio dans un fichier final. Cependant, la synchronisation est perdue pour la seconde moitié de la vidéo. Concrètement, il y a un délai d'1 seconde entre l'audio et la vidéo. Toute suggestion est la bienvenue.

49voto

evilsoup Points 12077

La meilleure façon de faire cela actuellement est avec le concat demuxer. Tout d'abord, créez un fichier appelé inputs.txt formaté comme ceci :

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

Ensuite, exécutez simplement cette commande ffmpeg :

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

Voir aussi concaténation dans la FAQ de ffmpeg.


Je garde ce qui suit ici pour le bénéfice de toute personne utilisant des versions plus anciennes de ffmpeg.

Les dernières versions de ffmpeg peuvent le faire : vous devrez remuxer les fichiers en flux de transport mpeg d'abord (assez léger en processeur, car il ne change que le format du conteneur) :

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

Si cela provoque une erreur [1] concernant h264, vous devrez peut-être utiliser :

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

Vous devrez le faire séparément avec chaque fichier d'entrée. Pour concaténer les fichiers, utilisez :

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

Si cela provoque une erreur concernant aac, vous devrez peut-être utiliser

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

Si votre système prend en charge les pipes nommés, vous pouvez le faire sans créer de fichiers intermédiaires.

mkfifo temp0 temp1

Vous devrez faire ce qui suit dans trois terminaux virtuels séparés :

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 output.mp4 existe déjà, le troisième ffmpeg vous demandera si vous souhaitez le remplacer, mais il le fera après avoir accédé aux FIFOs, ce qui fera fermer les premiers ffmpegs. Assurez-vous donc de choisir un nom non utilisé pour votre fichier de sortie.

Cela peut ne pas fonctionner si vos fichiers d'entrée sont différents - je crois que les différences de débit binaire sont OK, mais la taille des trames, le taux de trame, etc. doivent correspondre.

8voto

Weckar E. Points 997

Pour mp4, la seule solution fonctionnelle que j'ai trouvée était avec MP4Box du paquet 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

ou la commande est

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

avec mencoder et avconv je n'ai pas réussi à le faire fonctionner :-(

5voto

Anonymous Points 159

Voici une phrase qui rend tout cela beaucoup plus simple. Elle fait tout ce qui doit être fait pour enfin vous fournir un fichier vidéo résultant. Santé !

find *.mp4 | sed 's:\ :\\\ :g'| sed 's/^/file /' > list.txt; ffmpeg -f concat -i list.txt -c copy output.mp4; rm list.txts

2voto

Mark Points 21

Merci pour le script dvo. C'était un excellent point de départ pour moi. Je n'ai eu aucun problème avec l'utilisation des tubes nommés, donc j'ai adapté le script pour les utiliser à la place. De plus, je l'ai corrigé pour qu'il fonctionne avec des noms de fichiers contenant des espaces. La sortie vers les tubes nommés ne se "déclenche" que lorsque vous commencez à lire à partir d'eux, d'où la nécessité de mettre en arrière-plan les tâches initiales de remux avec un & avant l'appel final à avconv. De plus, n'oubliez pas d'utiliser -c copy, sinon vous risquez de réencoder le tout.

#!/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

2voto

Robert Cole Points 21

Sur un Mac (macOS 10.13 High Sierra), j'ai utilisé ce qui suit avec succès :

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

Réorganisez comme indiqué ci-dessus si nécessaire (notez que le ./ a été enlevé - le chemin causait une erreur de nom de fichier non sécurisé à ffmpeg).

Ensuite, j'ai dû supprimer le codec et le débit binaire spécifiés pour que le ffmpeg par défaut de MacPorts l'apprécie :

ffmpeg -f concat -i mylist.txt output.m4a

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X