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 utiliser aucun programme graphique, tous les traitements doivent être effectués avec des utilitaires de ligne de commande Linux. FFmpeg ne peut pas faire cela pour les fichiers mpeg4 alors j'ai plutôt utilisé MP4Box:
MP4Box -add video1.mp4 -cat video2.mp4 newvideo.mp4
Malheureusement, l'audio est tout mélangé. Je pensais que le problème était que l'audio était en aac alors je l'ai transcodé en mp3 et utilisé à nouveau MP4Box. Dans ce cas, le son est correct pour la première moitié de newvideo.mp4
(correspondant à video1.mp4
), mais il n’ya pas d’audio et je ne peux pas naviguer dans la vidéo également.
Ma pensée suivante a été que les flux audio et vidéo présentaient quelques différences minimes que je devrais corriger. Ainsi, pour chaque vidéo d'entrée, j'ai scindé les flux vidéo et audio, puis les ai associés à l'option -shortest dans FFmpeg.
Ainsi pour la première vidéo que j'ai courue:
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 ensuite utilisé MP4Box comme précédemment. Malheureusement, cela n'a pas fonctionné non plus. Mon seul succès a été lorsque j'ai rejoint les flux vidéo séparément (vidéostream1.mp4 et videostream2.mp4) et les flux audio (audiostream1.m4a et audiostream2.m4a), puis jeté 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'une seconde pour l'audio et la vidéo. Toutes les suggestions sont vraiment les bienvenues.
Le meilleur moyen de le faire est actuellement avec le démultiplexeur concat . Commencez par créer un fichier appelé inputs.txt
formaté comme suit:
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 également la concaténation dans ffmpeg
FAQ .
Je garde ce qui suit ici pour le bénéfice de toute personne utilisant les anciennes versions de ffmpeg.
Les dernières versions de ffmpeg peuvent le faire: vous devrez d’abord remuxter les fichiers dans les flux de transport mpeg (assez léger, car il ne s'agit que de changer le format du conteneur):
ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts
Si cela génère une erreur à propos de h264, vous devrez peut-être utiliser:
ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts
Vous devrez le faire séparément avec chaque fichier d'entrée. Pour concaténer les fichiers ensemble, utilisez:
ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy output.mp4
Si cela génère une erreur à propos de 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 canaux nommés, vous pouvez le faire sans créer de fichiers intermédiaires.
mkfifo temp0 temp1
Vous devrez effectuer les opérations suivantes dans trois terminaux virtuels distincts:
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 voulez l’écraser, mais il le fera après avoir accédé aux FIFO , ce qui fera le premier à ffmpegs fermer. Veillez donc à choisir un nom non utilisé pour votre fichier de sortie.
Cela risque de ne pas fonctionner si vos fichiers d’entrée sont différents. Je pense que les différences de débit binaire sont acceptables, mais que la taille, le débit, etc. doivent correspondre.
Pour mp4, la seule solution de travail 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 ne pouvais pas le faire fonctionner :-(
Voici un one-liner qui facilite grandement les choses. Il fait tout ce qui était nécessaire pour vous fournir un fichier vidéo. À votre santé!
find *.mp4 | sed 's:\ :\\\ :g'| sed 's/^/file /' > list.txt; ffmpeg -f concat -i list.txt -c copy output.mp4; rm list.txts
Sur un Mac (macOS 10.13 High Sierra), j’ai utilisé les éléments suivants avec succès:
for f in *.m4a; do echo "file '$f'" >> mylist.txt; done
Réorganisez comme ci-dessus de la même manière si nécessaire (notez que le fichier ./ a été supprimé - le chemin entraînait l'erreur ffmpeg de générer une erreur de nom de fichier non sécurisé).
Ensuite, j'ai dû supprimer le codec et le débit spécifiés pour le ffmpeg par défaut de MacPorts:
ffmpeg -f concat -i mylist.txt output.m4a
Merci pour le script dvo. C'était un excellent point de départ pour moi. Je n'ai eu aucun problème à utiliser des pipes nommées, j'ai donc adapté le script pour les utiliser à la place. De plus, je l'ai corrigé pour qu'il fonctionne avec les noms de fichiers contenant des espaces. La sortie vers les canaux nommés ne "va" pas jusqu'à ce que vous commenciez à les lire, d'où la nécessité d'arrière-plan des tâches de remux initiales avec un & avant le dernier appel à avconv. De plus, n'oubliez pas d'utiliser -c copy, sinon vous finirez par 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
Merci evilsoup; Voici un petit script pour automatiser le processus, en utilisant la plus récente avconv
.
BTW, les pipes nommées ne fonctionnaient pas pour moi (la sortie leur était bloquée).
#!/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
Ont connu un grand succès avec
for f in ./*.m4a; do echo "file '$f'" >> mylist.txt; done
vous devrez peut-être réorganiser légèrement mylist.txt
ffmpeg -f concat -i mylist.txt -c:a libfdk_aac -b:a 128k output.m4a
ffmpeg version 2.2.3