Come concatenare due file MP4 usando FFmpeg?


444

Sto cercando di concatenare due file mp4 usando ffmpeg. Ho bisogno che questo sia un processo automatico, quindi perché ho scelto ffmpeg. Sto convertendo i due file in file .ts e quindi concatenandoli e quindi provando a codificare quel file .ts concesso. I file sono codificati in h264 e aac e spero di mantenere la qualità uguale o il più vicino possibile all'originale.

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

Sfortunatamente sto ricevendo il seguente messaggio di errore che ritorna da ffmpeg durante la codifica:

[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

Questo succede a metà della codifica, il che mi fa pensare che non puoi concatenare due file .ts insieme e farlo funzionare.

Risposte:


788

FFmpeg ha tre metodi di concatenazione:

1. concat filtro video

Utilizzare questo metodo se gli input non hanno gli stessi parametri (larghezza, altezza, ecc.) O se non sono gli stessi formati / codec o se si desidera eseguire qualsiasi filtro. (È possibile ricodificare solo gli input che non corrispondono in modo che condividano lo stesso codec e altri parametri, quindi utilizzare il demuxer concat per evitare la ricodifica degli altri input).

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

Si noti che questo metodo esegue una ricodifica.

2. concat demuxer

Utilizzare questo metodo quando si desidera evitare una ricodifica e il formato non supporta la concatenazione a livello di file (la maggior parte dei file utilizzati dagli utenti generici non supporta la concatenazione a livello di file).

$ 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

Per 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. protocollo concat

Utilizzare questo metodo con formati che supportano la concatenazione a livello di file (MPEG-1, MPEG-2 PS, DV). Da non utilizzare con MP4.

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

Questo metodo non funziona per molti formati, incluso MP4, a causa della natura di questi formati e della concatenazione semplicistica eseguita da questo metodo.


In caso di dubbi sul metodo da utilizzare, provare il demuxer concat.

Vedi anche


3
Il carattere di escape del prompt dei comandi di Windows è ^; Ho anche riscontrato problemi con le virgolette, quindi è diventato: ffmpeg -i concat: input1 ^ | input2 -codec copia output
user423430

1
Risposta utile. E per me era ancora più sensato leggere questa variante: superuser.com/a/607384/74576
Ryan,

3
il demuxer concat funziona per i video, ma sto perdendo l'audio
Loïc

24
Per un uso oneliner: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv accetta più codec di mp4, ma puoi anche provarlo con mp4). Il -safe 0è per le versioni più recenti ffmpeg lamentano Unsafe nome del file , e l' -type fè messa in vendita solo i file. Ho aggiunto | sortper ordinare i file in ordine alfabetico; perché findli legge in ordine come salvati sul filesystem. Funziona anche con file con spazi bianchi.
erik,

1
Per me, in Windows, doppie virgolette lavorato (al posto del singolo nel tuo esempio): ffmpeg -i "concat:input1|input2" -codec copy output. Non è necessario sfuggire al personaggio della pipa.
Shovalt,

85

PER FILE MP4

Per i file .mp4 (che ho ottenuto da DailyMotion.com: un episodio televisivo di 50 minuti, scaricabile solo in tre parti, come tre file video .mp4), la seguente era una soluzione efficace per Windows 7 e NON comporta la ricodifica del File.

Ho rinominato i file (come file1.mp4 , file2.mp4 , file3.mp4 ) in modo tale che le parti fossero nell'ordine corretto per visualizzare l'episodio TV completo.

Quindi ho creato un semplice file batch (concat.bat), con i seguenti contenuti:

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

Il file batch e ffmpeg.exe devono essere entrambi inseriti nella stessa cartella dei file .mp4 da unire. Quindi eseguire il file batch. In genere sono necessari meno di dieci secondi per l'esecuzione.
.

Addendum (2018/10/21) -

Se quello che stavi cercando è un metodo per specificare tutti i file mp4 nella cartella corrente senza molta riscrittura, prova invece questo nel tuo file batch di Windows ( DEVE includere l'opzione -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

Funziona su Windows 7, in un file batch. Non provare a usarlo dalla riga di comando, perché funziona solo in un file batch!


5
Di gran lunga la soluzione più semplice.
1934286,

Questa dovrebbe essere la risposta migliore e più semplice. Bel lavoro, mio ​​fratello. Mi hai salvato la giornata.
DysaniazzZ,

Questa è una buona soluzione, ma parlare di un file batch rende questo suono primitivo (come è stato fatto in batch) e più complesso di quello che è (perché un file batch è completamente inutile). È molto più chiaro se mostri semplicemente C:\blah>type mylist.txt<ENTER>(così vedono il contenuto di quel file) Quindi ffmpeg -f concat -i mylist.txt -c copy output.mp4<ENTER> dovresti anche includere un riferimento trac.ffmpeg.org/wiki/Concatenate (quel riferimento usa anche lo stesso nome file, mylist.txt)
barlop

Questa è un'ottima soluzione perché ti salva dalla digitazione di lunghi elenchi di file per -iparametro. Su Linux ho fatto questo: ls -1 P1041*.mp4 | sed s/"P"/" file P"/g > mylist.txtche è ancora più bello della codifica di uno script batch. Ad ogni modo, si -c copyesibisce molto rapidamente (di cui non ero a conoscenza) e questa è la vera magia di questa risposta.
Würgspaß,

1
Con i miei file mp4, non c'è alcun audio nel file di output dopo aver eseguito il tuo codice concat su un Mac, usando ffmpeg v3.2.2.
Kakyo,

60

Ecco un modo veloce (richiede meno di 1 minuto) e senza perdite per farlo senza la necessità di file intermedi:

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

"Ls" contiene i file da unire Il "perl" crea il file di concatenazione al volo in una pipe La parte "-i -" dice a ffmpeg di leggere dalla pipe

(nota - i miei file non avevano spazi o cose strane in essi - avrai bisogno di una fuga di shell appropriata se vuoi fare questa idea con file "difficili").


2
Fatto su OSX e ha funzionato alla grande! Straordinaria soluzione rapida e senza perdite con piccoli requisiti.
GM Lucid,

1
Con una corretta escape per i file contenenti spazi bianchi: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
Puoi anche fare solo ls * | perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4se i tuoi file sono ben nominati e in ordine. Ha funzionato alla grande con me su OS X, esattamente quello che volevo.
natebeaty,

3
Su Linux ho usato questo oneliner: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(mkv accetta più codec di mp4, ma potresti anche provarlo con mp4). Il -safe 0è per le versioni più recenti ffmpeg lamentano Unsafe nome del file , e l' -type fè messa in vendita solo i file. Ho aggiunto | sortper ordinare i file in ordine alfabetico; perché findli legge in ordine come salvati sul filesystem. Funziona anche con file con spazi bianchi.
erik,

13
Ho dovuto aggiungere questo parametro per ffmpegfarlo funzionare:-protocol_whitelist file,tcp,http,pipe
Bensge,

45

per file MP4:

Se non sono esattamente gli stessi file MP4 (100% stesso codec, stessa risoluzione, stesso tipo), all'inizio devi transcodificarli in flussi intermedi:

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

NOTA! : L'output sarà come il primo file (e non un secondo)


2
Come illustrato nella mia risposta, di seguito, la transcodifica dei file non è necessaria. FFmpeg può concatenare più file mp4 in un singolo file mp4, senza passaggi intermedi e senza ricodifica. L'unico caso in cui sarebbe necessaria una nuova codifica è se i file originali non sono file mp4 ma l'intenzione è quella di creare un file mp4 come file di output.
Ed999,

@T. Todua: Sarei interessato a sapere quali sono esattamente le differenze tra i tuoi due file sorgente mp4. Stanno usando frequenze di campionamento diverse (es. 44.100 Hz e 48.000 Hz)? Oppure usano bit rate diversi (ad es. 128 kbps e 64 kbps)? In entrambi i casi, non capisco bene come il comando -c copy (un'istruzione stream-copy) modificherebbe i file sorgente per renderli compatibili.
Ed999,

4
@ T.Todua Ciao, il comando funziona bene quando i video sono senza traccia audio. Tuttavia, quando myfile1.mp4 è senza audio e myfile2.mp4 è con audio, il risultato output.mp4 è senza audio. L'output.mp4 previsto dovrebbe contenere audio. Come posso risolverlo?
Rispondi Zhao,

2
@ T.Todua er .... È troppo male. Il file1 | file2 genera il diverso video con il file2 | file1. l'ordine è importante.
RispondiZhao,

1
Ho provato il tuo comando su file concat 2 mp4. Funziona. Tuttavia, l'audio del secondo file diventa instabile come le voci Ah-oh-Ee nella nuova concatenazione prodotta. hai una soluzione a questo?
Superlinux,

35

Stavo cercando di concatenare tre .mp3file audio in un unico .m4afile e questo comando ffmpeg funziona.

Comando di input:

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

Significati di: -filter_complex "concat = n = 3: v = 0: a = 1" :

concat significa utilizzare la funzione concatenata (unione) dei media.
n significa confermare il conteggio totale dei file di input.
v significa che ha un video ? usa 0 = nessun video, 1 = contiene video.
un mezzo ha l'audio ? usa 0 = nessun audio, 1 = contiene audio.
-f significa forzare il formato del file impostato (per visualizzare tutti i formati supportati, utilizzare ffmpeg -formats)
-vn significa disabilitare il video (e -andisabiliterebbe anche l'audio se non desiderato)
-y significa sovrascrivere i file di output (se il file di output esiste già).

Per maggiori informazioni: usa ffmpeg -h full stampa tutte le opzioni (incluse tutte le opzioni specifiche per formato e codec, molto lunghe)


1
fi userà questo -f concat -safe 0 -i "file.txt" -c copy -y "OutPut.mp4"concatenerà ma quando alcuni video sono con audio e alcuni sono senza audio non funziona come posso risolvere questo. Grazie -
Ahmad

1
Questo funziona Grazie per la spiegazione dettagliata nella tua risposta. È molto utile.
Joe T. Boka,

31

Ho finito per usare mpg come formato intermedio e ha funzionato (NOTA questo è un esempio pericoloso, -qscale 0 ricodificherà il video ...)

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

8
A partire da questo commento, è -sameqstato rimosso. Usa -qscale 0invece.
Xavier Ho,

6
-sameqnon significa "stessa qualità" ed è stato rimosso da ffmpeg come indicato da @XavierHo.
Llogan,

3
Sembra un peccato dover transcodificare il video attraverso un formato intermedio solo per concatenare due file. Avrai la perdita di generazione. Meglio non andare più in profondità del formato contenitore e usare il concatcomando in ffmpeg, come fa @rogerdpack sopra.
Randall Cook,

8
Come mai questa è una risposta accettata? Questo è un metodo pessimo.
Visualizza nome

4
@SargeBorsch Perché funziona. Ho provato tutto il resto sulla pagina ... Nessuno di loro funziona.

14

La documentazione dettagliata sui vari modi di concatenazione in ffmpeg è disponibile qui .

Puoi usare 'Filtro Concat' per una concatenazione rapida.

Esegue una ricodifica. Questa opzione è ottimale quando gli ingressi hanno formati video / audio diversi.

Per concatenare 2 file:

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

Per concatenare 3 file:

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

Questo funziona per tipi di file di input uguali e multipli.


puoi specificare maggiori dettagli sulle opzioni che hai in questo esempio?
Sviluppatore

@Developer: per la spiegazione delle opzioni -> Concat wiki del filtro
SJ00

4
Quando si concatenano 3 file, è necessario utilizzare concat = n = 3: v = 1: a = 1 non n = 2
Cynapsis

1
non ottengo concatenazione senza perdita di dati il ​​mio ouput.mp4bitrate video è significativamente inferiore al bitrate del video di input video
jasan

Grazie Cynapsis per averlo segnalato e georgiecasey per l'aggiornamento del comando
SJ00

10

Ho scoperto che l'operatore di pipe non ha funzionato per me quando ho usato l'opzione 3 per concatenare diversi MP4 su un Mac nella risposta accettata.

Il seguente one-liner funziona su un Mac (High Sierra) per concatenare mp4, senza la necessità di creare file intermedi.

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


2
Questa semplice risposta è l'unica che ha funzionato davvero per me. Pagine su pagine di documentazione qui e altrove, mentre questo semplice one-liner è tutto ciò che serve - e funziona davvero. Grazie.
Blujay,

10

Qui 2 soluzioni pure bash che usano solo ffmpege non usando

  • un file intermedio
  • perl, python né javascript

Utilizzo di una soluzione di rivestimento 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

Funzione che accetta 0 o 2+ argomenti

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

Nota: ho provato alcune soluzioni in questo thread e nessuno mi ha soddisfatto


9

sulla base delle risposte di rogerdpack e Ed999, ho creato la mia versione .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

unisce tutti i *.mp4file nella cartella corrente injoined-out.mp4

testato su mac.

la dimensione del file risultante è la somma esatta dei miei 60 file testati. Non dovrebbe esserci alcuna perdita. Proprio quello di cui avevo bisogno


9

questo ha funzionato per me (su windows)

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

un esempio...

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

Pitone

Usando un po 'di codice Python per farlo con altrettanti mp4 presenti in una cartella (installa python da python.org, copia e incolla e salva questo codice in un file chiamato mp4.py ed eseguilo dal cmd aperto nella cartella con python mp4.py e tutti gli mp4 nella cartella verranno concatenati)

import glob
import os

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

Versione 2 con Python

Tratto dal mio post sul mio blog , ecco come lo faccio in 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()

1
Il protocollo concat non deve essere utilizzato con MP4 e non funzionerà come indicato nella risposta accettata .
Llogan,

@LordNeckbeard Mi chiedo se conosci la risposta a questa domanda ffmpeg sulla concatenazione di 2 video MP4 specificando il bitrate in uscita? video.stackexchange.com/q/24569/5657 Grazie.
Ryan,

@LordNeckbeard La mia ipotesi è che la tua risposta sarebbe la migliore, comunque, se sei all'altezza! Non sono particolarmente soddisfatto del mio.
Ryan,

Non solo (come sottolinea Lord Neckbeard) è necessario convertire un file .mp4 nel formato .TS intermedio affinché la concatenazione abbia successo, ma, forse anche peggio, questa risposta non inizia nemmeno a rispondere all'esigenza dell'input file video con bitrate, frequenza dei fotogrammi, frequenza di campionamento, base dei tempi e durata corrispondenti. Senza tutti e 5 questi fattori in comune, i file non possono essere concatenati (ovvero uniti usando la copia stream ), ma devono essere ricodificati.
Ed999,

7

Per .mp4i file, ho trovato che funziona meglio e più velocemente di utilizzare lo strumento da riga di comando opensource: mp4box. Quindi puoi usarlo in questo modo:

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

Scaricalo qui per la maggior parte delle piattaforme: https://gpac.wp.imt.fr/mp4box/


2
Anche se questo potrebbe essere utile per qualcuno, il requisito era: " Sto cercando di concatenare due file mp4 usando ffmpeg. Ho bisogno che questo sia un processo automatico ". Si prega di leggere la domanda completa e provare a fornire una risposta puntuale.
thvs86,

5
Questa risposta è del tutto esatta. È uno strumento FOSS che fa lo stesso lavoro. Può essere usato in uno script proprio come FFmpeg. Fa il lavoro più semplicemente di qualsiasi delle risposte di FFmpeg. Guarda quanto sono complicati! Uno di questi usa Node.js per chiamare FFmpeg! Follia. Per favore, smetti di vincere e prova a rendere StackOverflow di nuovo utile. Questo sito è l'ombra del suo antico sé grazie a delinquenti come te. Inoltre, questa domanda è un esempio del "Problema XY", a cui un soldato come te dovrebbe conoscere.
Blujay,

Non importa che mp4box sia uno strumento FOSS. La domanda ha chiesto risposte usando ffmpeg, non mp4box.
jramos775,

@ thvs86 Ne sono un esempio. Uso ffmpeg in quanto è un vero coltello svizzero per i media. Cerco anche aiuto con i miei particolari casi d'uso, poiché la struttura delle argomentazioni può essere piuttosto complessa (come dimostrato dalle varie risposte qui). Questa è la prima volta che sento parlare di mp4box e non lo avrei trovato se non fosse stato per questa risposta. Quindi +1 da me e per favore, per favore, pensa più alle persone che cercano risposte che a punti Internet insignificanti e regole rigide.
Pavel

4

Ecco uno script che ho creato per concatenare diversi mp4 di GoPro in un mp4 a 720p. Spero sia di aiuto.

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

Questo NON è concatenato. Questo codice non concatena gli input, li ricodifica. Questo prende qualsiasi file video arbitrario e li cambia in un comune bitrate audio e video (indipendentemente dal bitrate originale o dalla dimensione del frame originale dei file sorgente). L'o / p voleva unire due file usando lo stream copy, non ricodificarli, quindi questo non risponde alla domanda posta.
Ed999,

4

Dalla documentazione qui: https://trac.ffmpeg.org/wiki/Concatenate

Se si dispone di file MP4, questi potrebbero essere concatenati senza perdita di dati, prima di transcodificarli in flussi di trasporto MPEG-2. Con video H.264 e audio AAC, è possibile utilizzare:

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

Questo approccio funziona su tutte le piattaforme.

Avevo bisogno della capacità di incapsulare questo in uno script multipiattaforma, quindi ho usato fluent-ffmpege trovato la seguente soluzione:

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!')
)

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

1
Non solo pubblicando una risposta, potresti aggiungere una piccola spiegazione che comprenda meglio la soluzione per OP e anche per i lettori futuri.
Balagurunathan Marimuthu,

1
Ciò ha creato un nuovo video muto con entrambi gli ingressi riprodotti contemporaneamente l'uno accanto all'altro. Mi aspettavo che la concatenazione avrebbe creato un video in cui veniva riprodotto input_1.mp4 e quindi input_2.mp4
Alexx Roche,

3
Questa è stata la risposta completamente sbagliata. Questo non ha permesso di concatenare i video, ma li ha riprodotti silenziosamente fianco a fianco, come aveva menzionato @AlexxRoche.
Kalob Taulien,

1

Unendo tutti i file mp4 dalla directory corrente

Personalmente mi piace non creare file esterni che devo eliminare in seguito, quindi la mia soluzione stava seguendo che include l'elenco di numerazione dei file (come 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

Ho copiato questo codice su Blocco note e non è successo nulla.
7vujy0f0hy

1
@ 7vujy0f0hy funziona su un Linux con una shell bash, forse potrebbe funzionare con Cygwin
Pipo

1

Dopo vari tentativi di seguito, lo script ha funzionato per me su 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

Qui le prime due righe creano un file di testo temp.txt che ha il seguente contenuto

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

3a, 4a riga controlla se ffmpeg è disponibile nel percorso e crea il "join.mp4"

Le principali differenze rispetto alle altre risposte sono le seguenti

usage  of -bsf:v hevc_mp4toannexb -an

per il mio file mp4 sopra funzionato, potrebbe essere necessario utilizzare altre alternative come di seguito a seconda della codifica video.

h264_mp4toannexb

Tutti questi possibili filtri Bitstream sono disponibili all'indirizzo https://ffmpeg.org/ffmpeg-bitstream-filters.html


I miei erano MP4 provenienti da una telecamera TVCC. Senza quel comando la conversazione non riesce a generare il file di output. Sto usando ffmpeg più recente dal suo sito web.
Rahul Maindargi,

0

Ecco il mio metodo per unire una directory piena di file MP4 usando la sostituzione dei comandi e il filtro video concat (questo ricodificherà) - ho pensato che qualcun altro avrebbe avuto un po 'di utile da questo one-liner, specialmente se hai molti file (ho solo ha unito 17 file in un colpo solo):

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 questo comando unisce i tuoi file nell'ordine in cui sono stati nominati (cioè nello stesso ordine in cui sono presentati se corri ls *.mp4) - nel mio caso, avevano ciascuno un numero di traccia, quindi ha funzionato alla grande.


0

Il protocollo concat qui descritto; https://trac.ffmpeg.org/wiki/Concatenate#protocol

Se implementato utilizzando pipe denominate per evitare file intermedi

È molto veloce (leggi: istantaneo), non ha rilasciato frame e funziona bene.

Ricorda di eliminare i file di pipe con nome e ricorda di verificare se il video è H264 e AAC che puoi fare solo con ffmpeg -i filename.mp4(controlla le menzioni h264 e aac)


-1

La risposta accettata sotto forma di script PowerShell riutilizzabili

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
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.