Joignez des fichiers MP4 sous Linux

31

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 GUI, tout le traitement doit être effectué avec les utilitaires de ligne de commande Linux. FFmpeg ne peut pas faire cela pour les fichiers mpeg4, j'ai donc utilisé MP4Box à la place:

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, je l'ai donc transcodé en mp3 et utilisé à nouveau MP4Box. Dans ce cas, l'audio est correct pour la première moitié de newvideo.mp4(correspondant à video1.mp4), mais il n'y a pas d'audio et je ne peux pas naviguer dans la vidéo également.

Ma prochaine pensée était que les flux audio et vidéo présentaient de petites différences de longueur que je devais corriger. Donc, pour chaque vidéo d'entrée, j'ai divisé les flux vidéo et audio, puis les ai joints avec l'option -shortest dans FFmpeg.

Ainsi pour la première vidéo j'ai couru:

 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. Le seul succès que j'ai eu a été lorsque j'ai joint les flux vidéo séparément (c.-à-d. Videostream1.mp4 et videostream2.mp4) et les flux audio (c.-à-d. 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 retard de 1 sec de l'audio et de la vidéo. Toutes les suggestions sont vraiment les bienvenues.

Jose Armando
la source
"FFmpeg ne peut pas faire cela pour les fichiers mpeg4 donc j'ai plutôt utilisé MP4Box" voulez-vous dire fichier MP4? les deux flux audio-vidéo utilisent-ils les mêmes paramètres d'encodage (largeur, hauteur, SPS, PPS, fréquence d'images, taux d'échantillonnage, nombre de canaux?
en utilisant ffprobe, je vois que les flux audio ont des attributs identiques. Les flux vidéo ont les mêmes dimensions mais des taux différents. Pour la 1ère vidéo Vidéo: h264, 720x592, 277 kb / s, PAR 18944: 12915 DAR 512: 287, 24,97 ips, 45k tbr, 90k tbn, 90k tbc tandis que pour la deuxième vidéo: h264, 720x592, 226 kb / s, PAR 481: 330 DAR 39:22, 24,91 ips, 45k tbr, 90k tbn, 90k tbc. Croyez-vous que c'est la source de mes problèmes?
MP4 prend en charge la jonction vidéo / audio avec des caractéristiques différentes en utilisant une piste différente pour une vidéo différente, mais le lecteur n'est pas si intelligent.
rajneesh
Votre question est déjà répondue dans ffmpeg FAQ: ffmpeg.org/faq.html#How-can-I-join-video-files_003f
Palec

Réponses:

31

La meilleure façon de le faire actuellement est d' utiliser le démultiplexeur concat . Tout d'abord, créez un fichier appelé inputs.txtformaté 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 aussi concaténation dans la ffmpegFAQ .


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 d'abord remuxer les fichiers dans des flux de transport mpeg (assez légers, car cela ne fait que 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 concernant 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 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 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 souhaitez l'écraser, mais il le fera après avoir accédé aux FIFO , ce qui entraînera la fermeture du premier ffmpegs. Assurez-vous donc que vous choisissez un nom inutilisé 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 d'image, la fréquence d'image, etc. doivent correspondre.

evilsoup
la source
beaucoup de compagnon de thx, a travaillé comme un charme
Jose Armando
2
@DaveJarvis Pas du tout; c'est un message délibérément et malicieusement répandu par l'équipe libav, qui est un groupe de développeurs qui se sont séparés du projet ffmpeg pour développer avconv (et ont changé le nom car ils ne pouvaient pas sécuriser le copyright sur le nom ffmpeg). Voir Qui peut me dire la différence et la relation entre ffmpeg, libav et avconv? pour un peu plus d'informations.
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.est un message que je vois maintenant en cours d'exécutionffmpeg
Lord Loh.
@LordLoh. Voir le lien dans mon commentaire précédent.
evilsoup
1
Cette réponse ne répond pas - comment concaténer mp4 avecavconv
Lord Loh.
7

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 :-(

Philippe Gachoud
la source
2

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 de canaux nommés, 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 tant que vous ne commencez pas à les lire, d'où la nécessité d'arrière-plan des tâches de remux initiales avec un & avant l'appel final à avconv. De plus, n'oubliez pas d'utiliser -c copie, ou vous finissez 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
marque
la source
Pour une raison quelconque, cela me donne une erreur "concat: first.m4v.fifo | second.m4v.fifo: Aucun fichier ou répertoire". Même avec des guillemets (-i concat: "$ IN" ou -i "concat: $ EN "). MP4Box suggéré dans l'autre réponse ci-dessous fonctionne cependant très bien!
vorburger
2

Sur un Mac (macOS 10.13 High Sierra), j'ai utilisé avec succès les éléments suivants:

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

Réorganisez comme ci-dessus de la même façon si nécessaire (notez que le ./ a été supprimé - le chemin provoquait ffmpeg pour lancer l'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 MacPorts par défaut pour l'aimer:

ffmpeg -f concat -i mylist.txt  output.m4a
Robert Cole
la source
Bienvenue dans Super User !, Veuillez relire attentivement la question. Votre réponse ne répond pas à la question d'origine qui portait sur Linux. Si vous pensez que cela fonctionnera sur Linux, veuillez ajouter que les futurs lecteurs auront une compréhension claire, à part cela, bienvenue à nouveau au superutilisateur et merci pour votre contribution. Veuillez prendre quelques minutes et lire: - superuser.com/help .Réponse: superuser.com/help/how-to-answer .
mic84
2

Voici une doublure qui rend tout cela beaucoup plus facile. Il fait tout ce qui était nécessaire pour vous fournir enfin un fichier vidéo résultant. À 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
Anonyme
la source
1

Merci evilsoup; voici un petit script pour automatiser le processus, en utilisant le plus récent avconv.
BTW, les tubes nommés ne fonctionnaient pas pour moi (la sortie sur eux é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
dvo
la source
0

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

Benjoin
la source