Wie verkette ich zwei MP4-Dateien mit FFmpeg?

442

Ich versuche zwei mp4-Dateien mit ffmpeg zu verketten. Ich brauche dies, um ein automatischer Prozess zu sein, deshalb habe ich mich für ffmpeg entschieden. Ich konvertiere die beiden Dateien in .ts-Dateien und verkette sie dann und versuche dann, diese verkettete .ts-Datei zu codieren. Die Dateien sind h264 und aac-codiert und ich hoffe, dass die Qualität gleich bleibt oder dem Original so nahe wie möglich kommt.

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

Leider wird beim Codieren die folgende Fehlermeldung von ffmpeg angezeigt:

[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

Dies geschieht ungefähr in der Mitte der Codierung, was mich denken lässt, dass Sie nicht zwei .ts-Dateien zusammenfassen können, damit es funktioniert.

Mark L.
quelle

Antworten:

785

FFmpeg verfügt über drei Verkettungsmethoden:

1. Concat-Videofilter

Verwenden Sie diese Methode, wenn Ihre Eingaben nicht dieselben Parameter (Breite, Höhe usw.) oder dieselben Formate / Codecs haben oder wenn Sie eine Filterung durchführen möchten. (Sie können nur die nicht übereinstimmenden Eingänge neu codieren, sodass sie denselben Codec und andere Parameter verwenden. Verwenden Sie dann den Concat-Demuxer, um eine erneute Codierung der anderen Eingänge zu vermeiden.)

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

Beachten Sie, dass diese Methode eine Neucodierung durchführt.

2. Concat Demuxer

Verwenden Sie diese Methode, wenn Sie eine Neucodierung vermeiden möchten und Ihr Format keine Verkettung auf Dateiebene unterstützt (die meisten von allgemeinen Benutzern verwendeten Dateien unterstützen keine Verkettung auf Dateiebene).

$ 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

Für 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. Concat-Protokoll

Verwenden Sie diese Methode mit Formaten, die die Verkettung auf Dateiebene unterstützen (MPEG-1, MPEG-2 PS, DV). Sie nicht mit MP4 verwenden.

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

Diese Methode funktioniert aufgrund der Art dieser Formate und der vereinfachten Verkettung mit dieser Methode nicht für viele Formate, einschließlich MP4.


Wenn Sie sich nicht sicher sind, welche Methode Sie verwenden sollen, versuchen Sie es mit dem concat-Demuxer.

Siehe auch

Rogerdpack
quelle
3
Das Escapezeichen der Windows-Eingabeaufforderung lautet ^; Ich hatte auch Probleme mit den Anführungszeichen, so dass es wurde: ffmpeg -i concat: input1 ^ | input2 -codec copy output
user423430
1
Hilfreiche Antwort. Und es machte noch mehr Sinn für mich, als ich diese Variation las: superuser.com/a/607384/74576
Ryan
3
Concat Demuxer funktioniert für Video, aber ich verliere Audio
Loïc
23
Für einen Oneliner verwenden Sie: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv akzeptiert mehr Codecs als mp4, aber Sie können es auch mit mp4 versuchen). Das -safe 0ist für die letzten ffmpeg Versionen über beschweren Unsichere Dateinamen und das -type fist nur für Dateien auflistet. Ich habe hinzugefügt | sort, um die Dateien alphabetisch zu sortieren. weil findliest sie in der Reihenfolge wie im Dateisystem gespeichert. Funktioniert auch für Dateien mit Leerzeichen.
Erik
1
Bei mir haben in Windows doppelte Anführungszeichen funktioniert (anstelle der einfachen in Ihrem Beispiel) : ffmpeg -i "concat:input1|input2" -codec copy output. Es ist nicht erforderlich, dem Pipe-Zeichen zu entkommen.
Shovalt
82

FÜR MP4-DATEIEN

Für MP4- Dateien (die ich von DailyMotion.com erhalten habe: eine 50-minütige TV-Episode, die nur in drei Teilen als drei MP4-Videodateien heruntergeladen werden kann) war das Folgende eine effektive Lösung für Windows 7 und beinhaltet KEINE Neucodierung der Dateien.

Ich habe die Dateien (als file1.mp4 , file2.mp4 , file3.mp4 ) so umbenannt, dass die Teile in der richtigen Reihenfolge für die Anzeige der gesamten TV-Episode waren.

Dann habe ich eine einfache Batch-Datei (concat.bat) mit folgendem Inhalt erstellt:

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

Die Batch-Datei und ffmpeg.exe müssen sich beide im selben Ordner wie die zu verbindenden MP4-Dateien befinden. Führen Sie dann die Batchdatei aus. Die Ausführung dauert normalerweise weniger als zehn Sekunden.
.

Nachtrag (21.10.2018) -

Wenn Sie nach einer Methode gesucht haben, mit der Sie alle mp4-Dateien im aktuellen Ordner ohne viel erneutes Eingeben angeben können, versuchen Sie dies stattdessen in Ihrer Windows- Batchdatei ( MUSS die Option -safe 0 enthalten ):

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

Dies funktioniert unter Windows 7 in einer Batchdatei. Versuchen Sie nicht , es in der Befehlszeile zu verwenden, da es nur in einer Batch-Datei funktioniert!

Ed999
quelle
5
Die mit Abstand einfachste Lösung.
1934286
Dies sollte die beste und einfachste Antwort sein. Gute Arbeit, mein Bruder. Du hast meinen Tag gerettet.
DysaniazzZ
Dies ist eine gute Lösung, aber wenn Sie über eine Batch-Datei sprechen, klingt dies primitiv (wie im Batch) und komplexer als es ist (da eine Batch-Datei völlig unnötig ist). Es ist viel klarer, wenn Sie einfach anzeigen (damit C:\blah>type mylist.txt<ENTER>sie den Inhalt dieser Datei sehen). Dann ffmpeg -f concat -i mylist.txt -c copy output.mp4<ENTER> sollten Sie auch eine Referenz trac.ffmpeg.org/wiki/Concatenate einfügen (diese Referenz verwendet sogar denselben Dateinamen, mylist.txt)
barlop
Dies ist eine sehr gute Lösung, da Sie dadurch keine langen Listen von Dateien für -iParameter eingeben müssen . Unter Linux habe ich Folgendes getan: Das ls -1 P1041*.mp4 | sed s/"P"/" file P"/g > mylist.txtist sogar noch cooler als das Codieren eines Batch-Skripts. Wie auch immer, arbeitet -c copysehr schnell (was mir nicht bewusst war) und das ist die wahre Magie dieser Antwort.
Würgspaß
1
Bei meinen mp4-Dateien enthält die Ausgabedatei überhaupt kein Audio, nachdem Sie Ihren Concat-Code auf einem Mac mit ffmpeg v3.2.2 ausgeführt haben.
Kakyo
59

Hier ist eine schnelle (dauert weniger als 1 Minute) und verlustfreie Möglichkeit, dies zu tun, ohne Zwischendateien zu benötigen:

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

Das "ls" enthält die Dateien, die verbunden werden sollen. Das "Perl" erstellt die Verkettungsdatei im laufenden Betrieb in einer Pipe. Der Teil "-i -" weist ffmpeg an, aus der Pipe zu lesen

(Hinweis: Meine Dateien enthielten keine Leerzeichen oder seltsamen Elemente. Wenn Sie diese Idee mit "harten" Dateien ausführen möchten, benötigen Sie eine entsprechende Shell-Escape-Funktion.)

cnd
quelle
2
Habe das unter OSX gemacht und es hat super funktioniert! Tolle, schnelle, verlustfreie Lösung mit geringen Anforderungen.
GM Lucid
1
Mit der richtigen Flucht für Dateien mit Leerzeichen: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
Sie können dies auch tun, ls * | perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4wenn Ihre Dateien gut benannt und in Ordnung sind. Hat unter OS X hervorragend funktioniert, genau das, was ich wollte.
Natebeaty
3
Unter Linux habe ich diesen Oneliner verwendet: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv akzeptiert mehr Codecs als mp4, aber Sie können es auch mit mp4 versuchen). Das -safe 0ist für die letzten ffmpeg Versionen über beschweren Unsichere Dateinamen und das -type fist nur für Dateien auflistet. Ich habe hinzugefügt | sort, um die Dateien alphabetisch zu sortieren. weil findliest sie in der Reihenfolge wie im Dateisystem gespeichert. Funktioniert auch für Dateien mit Leerzeichen.
Erik
12
Ich musste diesen Parameter hinzufügen ffmpeg, damit es funktioniert:-protocol_whitelist file,tcp,http,pipe
Bensge
44

für MP4-Dateien:

Wenn es sich nicht genau um MP4-Dateien handelt (100% gleicher Codec, gleiche Auflösung, gleicher Typ), müssen Sie sie zunächst in Zwischen-Streams umcodieren:

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

HINWEIS! : Die Ausgabe erfolgt wie die erste Datei (und nicht wie eine zweite).

T.Todua
quelle
2
Wie in meiner Antwort unten dargestellt, ist das Umcodieren der Dateien nicht erforderlich. FFmpeg kann mehrere mp4-Dateien zu einer einzigen mp4-Datei verketten - ohne Zwischenschritte und ohne Neucodierung. Der einzige Fall, in dem eine Neucodierung erforderlich wäre, besteht darin, dass die Originaldateien keine MP4-Dateien sind, sondern eine MP4-Datei als Ausgabedatei erstellt werden soll.
Ed999
@T. Todua: Es würde mich interessieren, was genau die Unterschiede zwischen Ihren beiden MP4-Quelldateien sind. Verwenden sie unterschiedliche Abtastraten (z. B. 44.100 Hz und 48.000 Hz)? Oder verwenden sie unterschiedliche Bitraten (z. B. 128 kbps und 64 kbps)? In beiden Fällen verstehe ich nicht ganz, wie der Befehl -c copy (eine Stream-Copy-Anweisung) die Quelldateien ändern würde, um sie kompatibel zu machen.
Ed999
4
@ T.Todua Hallo, der Befehl funktioniert gut, wenn Videos ohne Audiospur sind. Wenn jedoch myfile1.mp4 ohne Audio und myfile2.mp4 mit Audio ist, ist das Ergebnis output.mp4 ohne Audio. Die erwartete Ausgabe.mp4 sollte Audio enthalten. Wie kann ich das lösen?
AnswerZhao
2
@ T.Todua ähm .... Es ist schade. Die Datei1 | Datei2 generiert das unterschiedliche Video mit der Datei2 | Datei1. Die Reihenfolge ist wichtig.
AnswerZhao
1
Ich habe Ihren Befehl für Concat 2 MP4-Dateien ausprobiert. Es klappt. Das Audio der zweiten Datei wird jedoch abgehackt wie Ah-oh-Ee-Stimmen in der erzeugten neuen Verkettung. Hast du eine Lösung dafür?
Superlinux
35

Ich habe versucht, drei .mp3Audiodateien zu einer .m4aDatei zu verketten, und dieser Befehl ffmpeg funktioniert.

Eingabebefehl:

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

Bedeutungen von: "-filter_complex concat = n = 3: v = 0: a = 1" :

concat bedeutet, dass Sie die Funktion zum Verketten (Verbinden) von Medien verwenden.
n bedeutet, die Gesamtzahl der Eingabedateien zu bestätigen.
v bedeutet hat Video ? benutze 0 = kein Video, 1 = enthält Video.
ein Mittel hat Audio ? Verwenden Sie 0 = kein Audio, 1 = Audio enthalten.
-f bedeutet erzwingen, dass das Dateiformat festgelegt wird (um alle unterstützten Formate anzuzeigen , verwenden Sie ffmpeg -formats)
-vn bedeutet, dass Video deaktiviert wird (und auch -anAudio deaktiviert wird, wenn dies nicht gewünscht wird)
-y bedeutet, dass Ausgabedateien überschrieben werden (falls die Ausgabedatei bereits vorhanden ist).

Für weitere Informationen: Verwenden Sie ffmpeg -h full alle Optionen drucken (einschließlich aller format- und codecspezifischen Optionen, sehr lang).

Ellie Tam
quelle
1
-f concat -safe 0 -i "file.txt" -c copy -y "OutPut.mp4"Wenn Sie dies verwenden , wird es konkatieren, aber wenn einige Videos mit Audio und andere ohne Audio sind, funktioniert es nicht. Wie kann ich das klären? Danke -
Ahmad
1
Das funktioniert. Vielen Dank für die ausführliche Erklärung in Ihrer Antwort. Es ist sehr hilfreich.
Joe T. Boka
31

Am Ende habe ich mpg als Zwischenformat verwendet und es hat funktioniert (HINWEIS: Dies ist ein gefährliches Beispiel, -qscale 0 wird das Video neu codieren ...)

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.
quelle
8
Ab diesem Kommentar -sameqwurde entfernt. Verwenden Sie -qscale 0stattdessen.
Xavier Ho
6
-sameqbedeutet nicht "gleiche Qualität" und wurde aus ffmpeg entfernt, wie von @XavierHo erwähnt.
Llogan
3
Es scheint eine Schande zu sein, das Video durch ein Zwischenformat transkodieren zu müssen, um zwei Dateien zu verketten. Sie werden Generationsverlust bekommen. Es ist besser, nicht tiefer als das Containerformat zu gehen und den concatBefehl in ffmpeg zu verwenden, wie es @rogerdpack oben tut.
Randall Cook
8
Wie kommt es, dass dies eine akzeptierte Antwort ist? Das ist eine sehr schlechte Methode.
Anzeigename
4
@ SargeBorsch Weil es funktioniert. Ich habe alles andere auf der Seite ausprobiert. Keiner von ihnen funktioniert.
14

Eine ausführliche Dokumentation zu verschiedenen Arten der Verkettung in ffmpeg finden Sie hier .

Sie können den 'Concat-Filter' für eine schnelle Verkettung verwenden.

Es führt eine Neucodierung durch. Diese Option ist am besten geeignet, wenn die Eingänge unterschiedliche Video- / Audioformate haben.

Zum Verketten von 2 Dateien:

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

Zum Verketten von 3 Dateien:

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

Dies funktioniert sowohl für denselben als auch für mehrere Eingabedateitypen.

SJ00
quelle
Können Sie weitere Details zu den Optionen angeben, die Sie in diesem Beispiel haben?
Entwickler
@ Entwickler: Zur Erklärung der Optionen -> Concat Filter Wiki
SJ00
4
Wenn Sie 3 Dateien verketten, sollten Sie concat = n = 3: v = 1: a = 1, nicht n = 2
Cynapsis
1
Ich bekomme keine verlustfreie Verkettung. Meine ouput.mp4Video-Bitrate ist deutlich niedriger als die Video-Bitrate der Eingangsvideos
Jason
Vielen Dank an Cynapsis für den Hinweis und georgiecasey für die Aktualisierung des Befehls
SJ00
10

Ich habe festgestellt, dass der Pipe-Operator bei mir nicht funktioniert hat, als Option 3 verwendet wurde, um mehrere MP4s auf einem Mac in der akzeptierten Antwort zu speichern.

Der folgende Einzeiler funktioniert auf einem Mac (High Sierra), um MP3s zu verketten, ohne dass eine zwischengeschaltete Dateierstellung erforderlich ist.

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

Ben Siver
quelle
2
Diese einfache Antwort ist die einzige, die tatsächlich für mich funktioniert hat. Seiten über Seiten der Dokumentation hier und anderswo, während dieser einfache Einzeiler alles ist, was benötigt wird - und tatsächlich funktioniert. Vielen Dank.
Blujay
10

Hier 2 reine Bash-Lösungen nur mit ffmpegund nicht mit

  • eine Zwischendatei
  • Perl, Python oder Javascript

Einzeilige Lösung mit 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

Funktion, die 0 oder 2+ Argumente akzeptiert

#######################################
# 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
}

Hinweis: Ich habe einige Lösungen in diesem Thread ausprobiert und keine hat mich zufrieden gestellt

Florent Roques
quelle
9

Basierend auf den Antworten von Rogerdpack und Ed999 habe ich meine .sh-Version erstellt

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

Es verbindet alle *.mp4Dateien im aktuellen Ordner injoined-out.mp4

auf Mac getestet.

Die resultierende Dateigröße ist die genaue Summe meiner 60 getesteten Dateien. Sollte kein Verlust sein. Genau das, was ich brauchte

Alexandr Perfilov
quelle
9

das hat bei mir funktioniert (unter Windows)

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

ein Beispiel...

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

Python

Verwenden Sie Python-Code, um mit so vielen mp4-Dateien in einem Ordner zu arbeiten (installieren Sie Python von python.org, kopieren Sie diesen Code, fügen Sie ihn ein, speichern Sie ihn in einer Datei namens mp4.py und führen Sie ihn aus dem cmd aus, der im Ordner mit Python geöffnet ist mp4.py und alle mp4 im Ordner werden verkettet)

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 mit Python

Aus meinem Beitrag in meinem Blog entnommen , mache ich das in Python so:

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
quelle
1
Das Concat-Protokoll sollte nicht mit MP4 verwendet werden und funktioniert nicht wie in der akzeptierten Antwort angegeben .
Llogan
@LordNeckbeard Ich frage mich, ob Sie die Antwort auf diese ffmpeg-Frage zum Verketten von 2 MP4-Videos kennen, während Sie die Ausgabe-Bitrate angeben. video.stackexchange.com/q/24569/5657 Danke.
Ryan
@ LordNeckbeard Meine Vermutung ist, dass Ihre Antwort immer noch die beste wäre, wenn Sie dazu bereit sind! Ich bin mit meinen nicht besonders zufrieden.
Ryan
Nicht nur (wie Lord Neckbeard betont) ist es notwendig, eine MP4-Datei in das Zwischenformat .TS zu konvertieren, damit die Verkettung erfolgreich ist, sondern, vielleicht noch schlimmer, diese Antwort beginnt nicht einmal, die Notwendigkeit der Eingabe zu befriedigen Videodateien mit übereinstimmender Bitrate, Bildrate, Abtastrate, Zeitbasis und Dauer. Ohne alle fünf gemeinsamen Faktoren können Dateien nicht verkettet werden (dh mithilfe einer Stream-Kopie verbunden werden ), sondern müssen stattdessen neu codiert werden.
Ed999
7

.mp4Ich fand, dass es für Dateien besser und schneller funktioniert, das OpenSource-Befehlszeilentool zu verwenden : mp4box. Dann können Sie es folgendermaßen verwenden:

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

Laden Sie es hier für die meisten Plattformen herunter: https://gpac.wp.imt.fr/mp4box/

Mario
quelle
2
Obwohl dies für jemanden nützlich sein könnte, lautete die Anforderung: " Ich versuche, zwei mp4-Dateien mit ffmpeg zu verketten. Ich brauche dies, um ein automatischer Prozess zu sein. " Bitte lesen Sie die vollständige Frage und versuchen Sie, eine zutreffende Antwort zu geben.
thvs86
5
Diese Antwort ist völlig zutreffend. Es ist ein FOSS-Tool, das den gleichen Job macht. Es kann in einem Skript wie FFmpeg verwendet werden. Es erledigt die Arbeit einfacher als jede der FFmpeg-Antworten. Schau dir an, wie kompliziert sie sind! Einer von ihnen benutzt Node.js, um FFmpeg aufzurufen! Wahnsinn. Bitte hören Sie mit dem Wonkismus auf und versuchen Sie, StackOverflow wieder nützlich zu machen. Diese Seite ist dank Wins wie Ihnen ein Schatten ihres früheren Selbst. Außerdem ist diese Frage ein Beispiel für das "XY-Problem", mit dem ein Wonk wie Sie vertraut sein sollte.
Blujay
Es spielt keine Rolle, dass mp4box ein FOSS-Tool ist. Die Frage wurde mit ffmpeg und nicht mit mp4box beantwortet.
jramos775
@ thvs86 Ich bin ein Beispiel dafür. Ich benutze ffmpeg, da es ein echtes Schweizer Messer für Medien ist. Ich suche auch nach Hilfe bei meinen speziellen Anwendungsfällen, da die Struktur von Argumenten sehr komplex sein kann (was durch die unterschiedlichen Antworten hier gezeigt wird). Dies ist das erste Mal, dass ich von mp4box höre und ich hätte es ohne diese Antwort nicht gefunden. Also +1 von mir und bitte, bitte, denken Sie mehr an Leute, die nach Antworten suchen, als an bedeutungslose Internetpunkte und starre Regeln.
Pavel
4

Hier ist ein Skript, das ich erstellt habe, um mehrere GoPro-MP4s zu einem 720p-MP4 zu verketten. Hoffe es ist hilfreich.

#!/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
quelle
Dies ist NICHT verkettend. Dieser Code verkettet die Eingaben nicht, sondern codiert sie neu. Dadurch werden beliebige Videodateien verwendet und in eine gemeinsame Audio- und Videobitrate geändert (unabhängig von der ursprünglichen Bitrate oder der ursprünglichen Bildgröße der Quelldateien). Das O / P wollte zwei Dateien mithilfe einer Stream-Kopie verbinden und nicht neu codieren, damit die gestellte Frage nicht beantwortet wird.
Ed999
4

Aus der Dokumentation hier: https://trac.ffmpeg.org/wiki/Concatenate

Wenn Sie über MP4-Dateien verfügen, können diese verlustfrei verkettet werden, indem Sie sie zuerst in MPEG-2-Transportströme umcodieren. Mit H.264-Video und AAC-Audio kann Folgendes verwendet werden:

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

Dieser Ansatz funktioniert auf allen Plattformen.

Ich brauchte die Fähigkeit, dies in einem plattformübergreifenden Skript zu kapseln, also habe ich fluent-ffmpegdie folgende Lösung verwendet und gefunden:

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
quelle
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
quelle
1
Sie können nicht nur eine Antwort veröffentlichen, sondern auch kleine Erklärungen hinzufügen, die die Lösung für OP und zukünftige Leser besser verstehen.
Balagurunathan Marimuthu
1
Dadurch wurde ein neues stilles Video erstellt, bei dem beide Eingänge gleichzeitig nebeneinander abgespielt wurden. Ich erwartete, dass die Verkettung ein Video erstellen würde, in dem input_1.mp4 abgespielt und dann input_2.mp4
Alexx Roche
3
Dies war die völlig falsche Antwort. Dies hat die Videos nicht in den Mittelpunkt gerückt, sondern sie werden nur lautlos nebeneinander abgespielt, wie @AlexxRoche erwähnt hatte.
Kalob Taulien
1

Zusammenführen aller mp4-Dateien aus dem aktuellen Verzeichnis

Ich persönlich mag es nicht, externe Dateien zu erstellen, die ich später löschen muss, daher folgte meine Lösung, die eine Auflistung der Dateinummern enthält (wie 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
quelle
Ich habe diesen Code in Notepad kopiert und nichts ist passiert.
7vujy0f0hy
1
@ 7vujy0f0hy dies funktioniert unter einem Linux mit einer Bash-Shell vielleicht könnte es mit Cygwin funktionieren
Pipo
1

Nach verschiedenen Versuchen unten funktionierte das Skript für mich unter 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

Hier erstellen die ersten beiden Zeilen eine Textdatei temp.txt mit folgendem Inhalt

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

Die 3. und 4. Zeile prüfen, ob ffmpeg im Pfad verfügbar ist, und erstellen die Datei "join.mp4".

Die wichtigsten Unterschiede zu anderen Antworten sind nachstehend aufgeführt

usage  of -bsf:v hevc_mp4toannexb -an

Für meine oben funktionierende MP4-Datei müssen Sie möglicherweise andere Alternativen wie die folgenden verwenden, abhängig von Ihrer Videokodierung.

h264_mp4toannexb

Alle möglichen Bitstream-Filter finden Sie unter https://ffmpeg.org/ffmpeg-bitstream-filters.html

rahul maindargi
quelle
Meine waren MP4 von einer CCTV-Kamera. Ohne diesen Befehl kann die Konversation keine Ausgabedatei generieren. Ich verwende das neueste ffmpeg von seiner Website.
Rahul Maindargi
0

Hier ist meine Methode zum Verbinden eines Verzeichnisses voller MP4-Dateien mithilfe der Befehlssubstitution und des Concat-Videofilters (dieser wird neu codiert) 17 Dateien auf einen Schlag verbunden):

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

Hinweis: Dieser Befehl verknüpft Ihre Dateien in der Reihenfolge, in der sie benannt sind (dh in derselben Reihenfolge, in der sie beim Ausführen angezeigt werden ls *.mp4). In meinem Fall hatten sie jeweils eine Titelnummer, sodass es hervorragend funktioniert hat.

Peter
quelle
0

Das hier beschriebene Concat-Protokoll; https://trac.ffmpeg.org/wiki/Concatenate#protocol

Bei Implementierung mit Named Pipes, um Zwischendateien zu vermeiden

Ist sehr schnell (lesen: sofort), hat keine Frames gelöscht und funktioniert gut.

Denken Sie daran, die genannten Pipe-Dateien zu löschen und zu überprüfen, ob es sich bei dem Video um H264 und AAC handelt, was Sie nur tun können ffmpeg -i filename.mp4(überprüfen Sie, ob h264 und aac erwähnt wurden).

Roel Van de Paar
quelle
-1

Die akzeptierte Antwort in Form eines wiederverwendbaren PowerShell-Skripts

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
quelle