Comment concaténer deux fichiers MP4 en utilisant FFmpeg?

445

J'essaie de concaténer deux fichiers mp4 en utilisant ffmpeg. J'ai besoin que ce soit un processus automatique, c'est pourquoi j'ai choisi ffmpeg. Je suis en train de convertir les deux fichiers en fichiers .ts, puis de les concaténer, puis d'essayer d'encoder ce fichier .ts concédé. Les fichiers sont encodés en h264 et aac et j'espère garder la qualité la même ou aussi proche que possible de l'original.

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

Malheureusement, je reçois le message d'erreur suivant en revenant de ffmpeg lors de l'encodage:

[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

Cela se produit à mi-chemin de l'encodage, ce qui me fait penser que vous ne pouvez pas concaténer deux fichiers .ts ensemble et le faire fonctionner.

Mark L
la source

Réponses:

790

FFmpeg a trois méthodes de concaténation:

1. filtre vidéo concat

Utilisez cette méthode si vos entrées n'ont pas les mêmes paramètres (largeur, hauteur, etc.), ou ne sont pas les mêmes formats / codecs, ou si vous souhaitez effectuer un filtrage. (Vous pouvez réencoder uniquement les entrées qui ne correspondent pas afin qu'elles partagent le même codec et d'autres paramètres, puis utiliser le démultiplexeur concat pour éviter de réencoder les autres entrées).

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

Notez que cette méthode effectue un recodage.

2. concat demuxer

Utilisez cette méthode lorsque vous souhaitez éviter un recodage et que votre format ne prend pas en charge la concaténation au niveau des fichiers (la plupart des fichiers utilisés par les utilisateurs généraux ne prennent pas en charge la concaténation au niveau des fichiers).

$ cat mylist.txt
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'

$ ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

Pour 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. protocole de concaténation

Utilisez cette méthode avec des formats qui prennent en charge la concaténation au niveau du fichier (MPEG-1, MPEG-2 PS, DV). Ne pas utiliser avec MP4.

ffmpeg -i "concat:input1|input2" -codec copy output.mkv

Cette méthode ne fonctionne pas pour de nombreux formats, y compris MP4, en raison de la nature de ces formats et de la concaténation simpliste effectuée par cette méthode.


En cas de doute sur la méthode à utiliser, essayez le démultiplexeur concat.

Regarde aussi

rogerdpack
la source
3
Le caractère d'échappement de l'invite de commande Windows est ^; J'ai également rencontré des problèmes avec les guillemets, c'est donc devenu: ffmpeg -i concat: input1 ^ | input2 -codec copy output
user423430
1
Réponse utile. Et cela avait encore plus de sens pour moi quand j'ai lu cette variation: superuser.com/a/607384/74576
Ryan
3
concat demuxer fonctionne pour la vidéo, mais je perds l'audio
Loïc
24
Pour une utilisation unique: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv accepte plus de codecs que mp4, mais vous pouvez également l'essayer avec mp4). Il -safe 0s'agit des versions récentes de ffmpeg qui se plaignent du nom de fichier non sécurisé et il -type fs'agit uniquement de la liste des fichiers. J'ai ajouté | sortpour trier les fichiers par ordre alphabétique; car les findlit dans l'ordre comme enregistré sur le système de fichiers. Fonctionne également pour les fichiers avec des espaces.
erik
1
Pour moi, dans Windows, les doubles guillemets ont travaillé ( au lieu du seul dans votre exemple): ffmpeg -i "concat:input1|input2" -codec copy output. Il n'est pas nécessaire d'échapper au caractère pipe.
Shovalt
85

POUR LES FICHIERS MP4

Pour les fichiers .mp4 (que j'ai obtenus auprès de DailyMotion.com: un épisode télévisé de 50 minutes, téléchargeable uniquement en trois parties, sous forme de trois fichiers vidéo .mp4), ce qui suit était une solution efficace pour Windows 7 , et n'implique PAS de recodage du des dossiers.

J'ai renommé les fichiers (comme file1.mp4 , file2.mp4 , file3.mp4 ) de telle sorte que les parties étaient dans le bon ordre pour visualiser l'épisode complet de la télévision.

J'ai ensuite créé un simple fichier batch (concat.bat), avec le contenu suivant:

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

Le fichier de commandes et ffmpeg.exe doivent tous deux être placés dans le même dossier que les fichiers .mp4 à joindre. Exécutez ensuite le fichier de commandes. L'exécution prend généralement moins de dix secondes.
.

Addendum (21/10/2018) -

Si ce que vous cherchiez est une méthode pour spécifier tous les fichiers mp4 dans le dossier en cours sans beaucoup de retaper, essayez plutôt cela dans votre fichier batch Windows ( DOIT inclure l'option -safe 0 ):

:: Create File List
for %%i in (*.mp4) do echo file '%%i'>> mylist.txt

:: Concatenate Files
ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

Cela fonctionne sur Windows 7, dans un fichier batch. N'essayez pas de l' utiliser sur la ligne de commande, car cela ne fonctionne que dans un fichier batch!

Ed999
la source
5
La solution la plus simple de loin.
1934286
Cela devrait être la meilleure et la plus simple réponse. Bon travail, mon frère. Tu m'as sauvé la journée.
DysaniazzZ
C'est une bonne solution mais parler d'un fichier batch rend ce son primitif (comme cela a été fait en batch), et plus complexe qu'il ne l'est (car un fichier batch n'est absolument pas nécessaire). Il est beaucoup plus clair si vous affichez simplement C:\blah>type mylist.txt<ENTER>(afin qu'ils voient le contenu de ce fichier) Ensuite, ffmpeg -f concat -i mylist.txt -c copy output.mp4<ENTER> vous devez également inclure une référence trac.ffmpeg.org/wiki/Concatenate (cette référence utilise même le même nom de fichier, mylist.txt)
barlop
C'est une très bonne solution car elle vous évite de taper de longues listes de fichiers pour les -iparamètres. Sur Linux, je l'ai fait: ce ls -1 P1041*.mp4 | sed s/"P"/" file P"/g > mylist.txtqui est encore plus cool que de coder un script batch. Quoi qu'il en soit, se -c copyproduit très rapidement (dont je n'étais pas au courant) et c'est la vraie magie de cette réponse.
Würgspaß
1
Avec mes fichiers mp4, il n'y a aucun son du tout dans le fichier de sortie après avoir exécuté votre code concat sur un Mac, en utilisant ffmpeg v3.2.2.
kakyo
60

Voici un moyen rapide (prend moins d'une minute) et sans perte de le faire sans avoir besoin de fichiers intermédiaires:

ls Movie_Part_1.mp4 Movie_Part_2.mp4 | \
perl -ne 'print "file $_"' | \
ffmpeg -f concat -i - -c copy Movie_Joined.mp4

Le "ls" contient les fichiers à joindre Le "perl" crée le fichier de concaténation à la volée dans un tube La partie "-i -" indique à ffmpeg de lire à partir du tube

(note - mes fichiers n'avaient pas d'espaces ou de trucs bizarres en eux - vous aurez besoin d'un échappement approprié si vous voulez faire cette idée avec des fichiers "durs").

cnd
la source
2
J'ai fait ça sur OSX et ça a bien marché! Solution impressionnante et rapide sans perte avec peu d'exigences.
GM Lucid
1
Avec un échappement correct pour les fichiers contenant des espaces:ls Movie_Part_1.mp4 Movie_Part_2.mp4 | perl -ne '$_ =~ s/\n$//; print "file '"'"'$_'"'"'\n"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4
Thomas Bachem
4
Vous pouvez également le faire ls * | perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4si vos fichiers sont bien nommés et en ordre. Fonctionné très bien pour moi sur OS X, exactement ce que je voulais.
natebeaty
3
Sous Linux, j'ai utilisé cet oneliner: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv accepte plus de codecs que mp4, mais vous pouvez également l'essayer avec mp4). Il -safe 0s'agit des versions récentes de ffmpeg qui se plaignent du nom de fichier non sécurisé et il -type fs'agit uniquement de la liste des fichiers. J'ai ajouté | sortpour trier les fichiers par ordre alphabétique; car les findlit dans l'ordre comme enregistré sur le système de fichiers. Fonctionne également pour les fichiers avec des espaces.
erik
13
J'ai dû ajouter ce paramètre pour ffmpegle faire fonctionner:-protocol_whitelist file,tcp,http,pipe
Bensge
45

pour les fichiers MP4:

S'ils ne sont pas exactement les mêmes (100% même codec, même résolution, même type) fichiers MP4, vous devez d'abord les transcoder en flux intermédiaires:

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

REMARQUE! : La sortie sera comme le premier fichier (et non un second)

T.Todua
la source
2
Comme illustré dans ma réponse, ci-dessous, le transcodage des fichiers n'est pas nécessaire. FFmpeg peut concaténer plusieurs fichiers mp4 en un seul fichier mp4 - sans étapes intermédiaires et sans réencodage. Le seul cas dans lequel un ré-encodage serait nécessaire est si les fichiers d'origine ne sont pas des fichiers mp4 mais l'intention est de créer un fichier mp4 comme fichier de sortie.
Ed999
@T. Todua: J'aimerais savoir quelles sont précisément les différences entre vos deux fichiers source mp4. Utilisent-ils des fréquences d'échantillonnage différentes (par exemple 44 100 Hz et 48 000 Hz)? Ou utilisent-ils des débits binaires différents (par exemple 128 kbps et 64 kbps)? Dans les deux cas, je ne comprends pas très bien comment la commande -c copy (une instruction de copie de flux) modifierait les fichiers source pour les rendre compatibles.
Ed999
4
@ T.Todua Salut, la commande fonctionne bien lorsque les vidéos sont sans piste audio. Toutefois, lorsque le myfile1.mp4 est sans audio et le myfile2.mp4 est avec audio, le résultat output.mp4 est sans audio. Le fichier output.mp4 attendu doit contenir de l'audio. Comment puis-je le résoudre?
AnswerZhao
2
@ T.Todua er .... C'est dommage. Le fichier1 | fichier2 génère les différentes vidéos avec le fichier2 | fichier1. l'ordre est important.
AnswerZhao
1
J'ai essayé votre commande sur concat 2 fichiers mp4. Ça marche. Cependant, l'audio du deuxième fichier devient saccadé comme les voix Ah-oh-Ee dans la nouvelle concaténation produite. avez-vous une solution à cela?
superlinux
35

J'essayais de concaténer trois .mp3fichiers audio en un seul .m4afichier et cette commande ffmpeg fonctionne.

Commande d'entrée:

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

Signification de: -filter_complex "concat = n = 3: v = 0: a = 1" :

concat signifie utiliser la fonction de concaténation (jointure) des médias.
n signifie confirmer le nombre total de fichiers d'entrée.
v signifie a la vidéo ? utilisez 0 = pas de vidéo, 1 = contient de la vidéo.
un moyen a l'audio ? utilisez 0 = pas d'audio, 1 = contient de l'audio.
-f signifie forcer le format de fichier défini (pour voir tous les formats pris en charge, utilisez ffmpeg -formats)
-vn signifie désactiver la vidéo (et -andésactiverait également l'audio si vous ne le souhaitez pas)
-y signifie écraser les fichiers de sortie (si le fichier de sortie existe déjà).

Pour plus d'informations: utilisez ffmpeg -h full toutes les options d'impression (y compris toutes les options spécifiques au format et au codec, très longues)

Ellie Tam
la source
1
fi utilisez cela, -f concat -safe 0 -i "file.txt" -c copy -y "OutPut.mp4"il concatera mais lorsque certaines vidéos sont avec audio et d'autres sans audio, cela ne fonctionne pas, comment puis-je trier cela. Merci -
Ahmad
1
Cela marche. Merci pour l'explication détaillée dans votre réponse. C'est très utile.
Joe T.Boka
31

J'ai fini par utiliser mpg comme format intermédiaire et cela a fonctionné (NOTE ceci est un exemple dangereux, -qscale 0 ré-encodera la vidéo ...)

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
Mark L
la source
8
À partir de ce commentaire, a -sameqété supprimé. Utilisez -qscale 0plutôt.
Xavier Ho
6
-sameqne signifie pas "même qualité" et a été supprimé de ffmpeg comme mentionné par @XavierHo.
llogan
3
Il semble dommage d'avoir à transcoder la vidéo dans un format intermédiaire juste pour concaténer deux fichiers. Vous obtiendrez une perte de génération. Mieux vaut ne pas aller plus loin que le format du conteneur et utiliser la concatcommande dans ffmpeg, comme le fait @rogerdpack ci-dessus.
Randall Cook du
8
Comment se fait-il que cette réponse soit acceptée? C'est une très mauvaise méthode.
Nom d'affichage du
4
@SargeBorsch Parce que ça marche. J'ai essayé tout le reste sur la page - Aucun d'entre eux ne fonctionne.
15

Une documentation détaillée sur les différentes méthodes de concaténation dans ffmpeg peut être trouvée ici .

Vous pouvez utiliser le «filtre Concat» pour une concaténation rapide.

Il effectue un ré-encodage. Cette option est préférable lorsque les entrées ont des formats vidéo / audio différents.

Pour concaténer 2 fichiers:

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

Pour concaténer 3 fichiers:

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

Cela fonctionne aussi bien pour plusieurs types de fichiers d'entrée.

SJ00
la source
pouvez-vous spécifier plus de détails sur les options que vous avez dans cet exemple?
Développeur
@Developer: Pour l'explication des options -> Wiki du filtre
Concat
4
Lors de la concaténation de 3 fichiers, vous devez utiliser concat = n = 3: v = 1: a = 1 not n = 2
Cynapsis
1
je ne reçois pas de concaténation sans perte mon ouput.mp4débit vidéo est nettement inférieur au débit vidéo des vidéos d'entrée
jasan
Merci à Cynapsis de l'avoir signalé et à georgiecasey d'avoir mis à jour la commande
SJ00
10

J'ai trouvé que l'opérateur de tuyau ne fonctionnait pas pour moi lors de l'utilisation de l'option 3 pour concaténer plusieurs MP4 sur un Mac dans la réponse acceptée.

Le one-liner suivant fonctionne sur un Mac (High Sierra) pour concaténer des mp4, sans création de fichier intermédiaire requise.

ffmpeg -f concat -safe 0 -i <(for f in ./*.mp4; do echo "file '$PWD/$f'"; done) -c copy output.mp4

Ben Siver
la source
2
Cette réponse simple est la seule qui a réellement fonctionné pour moi. Pages sur pages de documentation ici et ailleurs, alors que cette simple ligne est tout ce qui est nécessaire - et fonctionne réellement. Je vous remercie.
blujay
10

Voici 2 solutions bash pures utilisant uniquement ffmpeget n'utilisant pas

  • un fichier intermédiaire
  • perl, python ni javascript

Solution monocouche utilisant ls

ls video1.mp4 video2.mp4 | while read line; do echo file \'$line\'; done | ffmpeg -protocol_whitelist file,pipe -f concat -i - -c copy output.mp4

Fonction qui prend 0 ou 2+ arguments

#######################################
# Merge mp4 files into one output mp4 file
# usage:
#   mergemp4 #merges all mp4 in current directory
#   mergemp4 video1.mp4 video2.mp4
#   mergemp4 video1.mp4 video2.mp4 [ video3.mp4 ...] output.mp4 
#######################################
function mergemp4() {
  if [ $# = 1 ]; then return; fi

  outputfile="output.mp4"

  #if no arguments we take all mp4 in current directory as array
  if [ $# = 0 ]; then inputfiles=($(ls -1v *.mp4)); fi
  if [ $# = 2 ]; then inputfiles=($1 $2); fi  
  if [ $# -ge 3 ]; then
    outputfile=${@: -1} # Get the last argument
    inputfiles=(${@:1:$# - 1}) # Get all arguments besides last one as array
  fi

  # -y: automatically overwrite output file if exists
  # -loglevel quiet: disable ffmpeg logs
  ffmpeg -y \
  -loglevel quiet \
  -f concat \
  -safe 0 \
  -i <(for f in $inputfiles; do echo "file '$PWD/$f'"; done) \
  -c copy $outputfile

  if test -f "$outputfile"; then echo "$outputfile created"; fi
}

Remarque: avait essayé quelques solutions dans ce fil et aucun ne m'a satisfait

Florent Roques
la source
9

basé sur les réponses de rogerdpack et d'Ed999, j'ai créé ma version .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

il joint tous les *.mp4fichiers du dossier actuel dansjoined-out.mp4

testé sur mac.

la taille de fichier résultante est la somme exacte de mes 60 fichiers testés. Cela ne devrait pas être une perte. Juste ce dont j'avais besoin

Alexandr Perfilov
la source
9

cela a fonctionné pour moi (sur windows)

ffmpeg -i "concat:input1|input2" -codec copy output

un exemple...

ffmpeg -i "concat:01.mp4|02.mp4" -codec copy output.mp4

Python

Utiliser du code python pour le faire avec autant de mp4 qu'il y a dans un dossier (installez python depuis python.org, copiez et collez et enregistrez ce code dans un fichier appelé mp4.py et exécutez-le à partir de la cmd ouverte dans le dossier avec python mp4.py et tous les mp4 du dossier seront concaténés)

import glob
import os

stringa = ""
for f in glob.glob("*.mp4"):
    stringa += f + "|"
os.system("ffmpeg -i \"concat:" + stringa + "\" -codec copy output.mp4")

Version 2 avec Python

Tiré de mon post sur mon blog , voici comment je le fais en python:

import os
import glob

def concatenate():
    stringa = "ffmpeg -i \"concat:"
    elenco_video = glob.glob("*.mp4")
    elenco_file_temp = []
    for f in elenco_video:
        file = "temp" + str(elenco_video.index(f) + 1) + ".ts"
        os.system("ffmpeg -i " + f + " -c copy -bsf:v h264_mp4toannexb -f mpegts " + file)
        elenco_file_temp.append(file)
    print(elenco_file_temp)
    for f in elenco_file_temp:
        stringa += f
        if elenco_file_temp.index(f) != len(elenco_file_temp)-1:
            stringa += "|"
        else:
            stringa += "\" -c copy  -bsf:a aac_adtstoasc output.mp4"
    print(stringa)
    os.system(stringa)

concatenate()
Giovanni G. PY
la source
1
Le protocole concat ne doit pas être utilisé avec MP4 et ne fonctionnera pas comme mentionné dans la réponse acceptée .
llogan
@LordNeckbeard Je me demande si vous connaissez la réponse à cette question ffmpeg sur la concaténation de 2 vidéos MP4 tout en spécifiant le débit de sortie? video.stackexchange.com/q/24569/5657 Merci.
Ryan
@LordNeckbeard Je pense que votre réponse serait la meilleure, si vous le souhaitez! Je ne suis pas particulièrement satisfait du mien.
Ryan
Non seulement (comme le souligne Lord Neckbeard), il est nécessaire de convertir un fichier .mp4 au format .TS intermédiaire pour que la concaténation réussisse, mais, pire encore, cette réponse ne commence même pas à répondre au besoin d'entrée les fichiers vidéo doivent avoir un débit binaire, une fréquence d'images, une fréquence d'échantillonnage, une base de temps et une durée correspondants. Sans ces 5 facteurs communs, les fichiers ne peuvent pas être concaténés (c'est-à-dire joints à l'aide de la copie de flux ), mais doivent être ré-encodés à la place.
Ed999
7

Pour les .mp4fichiers, je l' ai trouvé fonctionne mieux et plus rapide d'utiliser l'outil de ligne de commande opensource: mp4box. Ensuite, vous pouvez l'utiliser de cette façon:

mp4box.exe -add video1.mp4 -cat video2.mp4 destvideo.mp4

Téléchargez-le ici pour la plupart des plateformes: https://gpac.wp.imt.fr/mp4box/

Mario
la source
2
Bien que cela puisse être utile pour quelqu'un, l'exigence était: " J'essaie de concaténer deux fichiers mp4 en utilisant ffmpeg. J'ai besoin que ce soit un processus automatique ". Veuillez lire l'intégralité de la question et essayer de fournir une réponse pertinente.
thvs86
5
Cette réponse est tout à fait pertinente. C'est un outil FOSS qui fait le même travail. Il peut être utilisé dans un script comme FFmpeg. Il fait le travail plus simplement que n'importe quelle réponse FFmpeg. Regardez comme ils sont compliqués! L'un d'eux utilise Node.js pour appeler FFmpeg! Folie. Veuillez arrêter avec le wonkisme et essayer de rendre StackOverflow utile à nouveau. Ce site est l'ombre de son ancien moi grâce à des winks comme vous. En outre, cette question est un exemple du "problème XY", qu'un connaisseur comme vous devrait connaître.
blujay
Peu importe que mp4box soit un outil FOSS. La question demandait des réponses en utilisant ffmpeg, pas mp4box.
jramos775
@ thvs86 J'en suis un exemple. J'utilise ffmpeg car c'est un vrai couteau suisse pour les médias. Je recherche également de l'aide pour mes cas d'utilisation particuliers, car la structure des arguments peut être assez complexe (ce qui est démontré par les réponses variées ici). C'est la première fois que j'entends parler de mp4box et je ne l'aurais pas trouvé sans cette réponse. Alors +1 de ma part et s'il vous plaît, s'il vous plaît, pensez plus aux personnes qui cherchent des réponses qu'aux points Internet dénués de sens et aux règles rigides.
Pavel
4

Voici un script que j'ai fait pour concaténer plusieurs mp4 GoPro en mp4 720p. J'espère que c'est utile.

#!/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}
Reid Ellis
la source
Ce n'est PAS concaténer. Ce code ne concatène pas les entrées, il les réencode. Cela prend tous les fichiers vidéo arbitraires et les change en un débit binaire audio et vidéo commun (quel que soit le débit binaire d'origine ou la taille d'image d'origine). L'opérateur souhaitait joindre deux fichiers à l'aide de la copie de flux, pas les réencoder, donc cela ne répond pas à la question posée.
Ed999
4

De la documentation ici: https://trac.ffmpeg.org/wiki/Concatenate

Si vous avez des fichiers MP4, ceux-ci pourraient être concaténés sans perte en les transcodant d'abord en flux de transport MPEG-2. Avec la vidéo H.264 et l'audio AAC, les éléments suivants peuvent être utilisés:

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

Cette approche fonctionne sur toutes les plateformes.

J'avais besoin de pouvoir l'encapsuler dans un script multiplateforme, j'ai donc utilisé fluent-ffmpeget trouvé la solution suivante:

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!')
)
itslittlejohn
la source
1
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
Deepak Kumar
la source
1
En plus de publier une réponse, vous pouvez ajouter de petites explications qui permettent de mieux comprendre la solution pour OP et les futurs lecteurs.
Balagurunathan Marimuthu
1
Cela a créé une nouvelle vidéo silencieuse avec les deux entrées jouant en même temps côte à côte. Je m'attendais à ce que la concaténation crée une vidéo dans laquelle input_1.mp4 a été joué, puis input_2.mp4
Alexx Roche
3
Ce n'était pas la bonne réponse. Cela n'a pas concaténé les vidéos, il les a juste jouées silencieusement côte à côte, comme @AlexxRoche l'avait mentionné.
Kalob Taulien
1

Fusion de tous les fichiers mp4 du répertoire actuel

Personnellement, je n'aime pas créer de fichier externe que je dois supprimer par la suite, donc ma solution était la suivante qui inclut la liste de numérotation des fichiers (comme 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
Pipo
la source
J'ai copié ce code dans le Bloc-notes et rien ne s'est produit.
7vujy0f0hy
1
@ 7vujy0f0hy cela fonctionne sur un linux avec un shell bash peut-être que cela pourrait fonctionner avec cygwin
Pipo
1

Après plusieurs essais ci-dessous, le script a fonctionné pour moi sur Windows 10 PowerShell.

    $files=Get-ChildItem -path e:\ -Filter *.mp4


    $files| ForEach-Object  {"file '$($_.FullName)'"}| Out-File -FilePath e:\temp.txt -Encoding ASCII


    if (-not (test-path "e:\ffmpeg\bin\ffmpeg.exe")) {throw "e:\ffmpeg\bin\ffmpeg.exe needed"}

    E:\ffmpeg\bin\ffmpeg.exe -safe 0 -f concat -i "e:\temp.txt" -c copy -bsf:v hevc_mp4toannexb -an e:\joined.mp4

    # Conversion Cleanup
    Remove-Item e:\temp.txt

Ici, les deux premières lignes créent un fichier texte temp.txt qui a le contenu suivant

file 'e:\first.mp4'
file 'e:\second.mp4'

Les 3ème, 4ème lignes vérifient si ffmpeg est disponible sur le chemin et créent le "join.mp4"

Les principales différences par rapport aux autres réponses sont les suivantes

usage  of -bsf:v hevc_mp4toannexb -an

pour que mon fichier mp4 ci-dessus fonctionne, vous devrez peut-être utiliser d'autres alternatives comme ci-dessous en fonction de votre encodage vidéo.

h264_mp4toannexb

Tous ces filtres Bitstream possibles peuvent être trouvés sur https://ffmpeg.org/ffmpeg-bitstream-filters.html

rahul maindargi
la source
Les miens étaient des MP4 provenant d'une caméra CCTV. Sans cette commande, la conversation ne parvient pas à générer le fichier de sortie. J'utilise la dernière ffmpeg de son site Web.
rahul maindargi
0

Voici ma méthode pour rejoindre un répertoire plein de fichiers MP4 à l'aide de la substitution de commandes et du filtre vidéo concat (cela va ré-encoder) - je pensais que quelqu'un d'autre tirerait parti de ce one-liner, surtout si vous avez beaucoup de fichiers (je viens joint 17 fichiers en un seul coup):

ffmpeg $(for f in *.mp4 ; do echo -n "-i $f "; done) -filter_complex \
"$(i=0 ; for f in *.mp4 ; do echo -n "[$i:v] [$i:a] " ; i=$((i+1)) ; done \
&& echo "concat=n=$i:v=1:a=1 [v] [a]")" -map "[v]" -map "[a]" output.mp4

NB cette commande joint vos fichiers dans l'ordre dans lequel ils sont nommés (c'est-à-dire dans le même ordre que celui présenté si vous exécutez ls *.mp4) - dans mon cas, ils avaient chacun un numéro de piste, donc cela fonctionnait très bien.

Peter
la source
0

Le protocole de concaténation décrit ici; https://trac.ffmpeg.org/wiki/Concatenate#protocol

Lorsqu'il est implémenté à l'aide de canaux nommés pour éviter les fichiers intermédiaires

Est très rapide (lire: instantané), aucune image n'a été supprimée et fonctionne bien.

N'oubliez pas de supprimer les fichiers de canaux nommés et n'oubliez pas de vérifier si la vidéo est H264 et AAC, ce que vous pouvez faire avec juste ffmpeg -i filename.mp4(vérifiez les mentions h264 et aac)

Roel Van de Paar
la source
-1

La réponse acceptée sous la forme d'un script PowerShell réutilisable

Param(
[string]$WildcardFilePath,
[string]$OutFilePath
)
try
{
    $tempFile = [System.IO.Path]::GetTempFileName()
    Get-ChildItem -path $wildcardFilePath | foreach  { "file '$_'" } | Out-File -FilePath $tempFile -Encoding ascii
    ffmpeg.exe -safe 0 -f concat -i $tempFile -c copy $outFilePath
}
finally
{
    Remove-Item $tempFile
}
fjch1997
la source