Come concatenare due file MP4 usando FFmpeg?

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 poi concatenandoli e poi provando a codificare il file .ts concatenato. I file sono codificati in h264 e aac e spero di mantenere la qualità il più ansible simile 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 accade a metà strada attraverso la codifica che mi fa pensare che non è ansible conciliare due file .ts insieme e farlo funzionare.

FFmpeg ha tre metodi di concatenazione.

1. filtro video concat

 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

 $ cat mylist.txt file '/path/to/file1' file '/path/to/file2' file '/path/to/file3' $ ffmpeg -f concat -i mylist.txt -c copy output 

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

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

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

Quale usare

  • filtro concat : usa se i tuoi input non hanno gli stessi parametri (larghezza, altezza, ecc.), o non hanno gli stessi formati / codec, o se vuoi eseguire qualsiasi filtraggio. (Potresti ricodificare solo gli input che non corrispondono, in modo che condividano lo stesso codec e altri parametri, quindi usare il concat demuxer per evitare di ricodificare gli altri input).

  • concat demuxer : utilizzare 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).

  • protocollo concat : utilizzare con formati che supportano la concatenazione a livello di file (MPEG-1, MPEG-2 PS, DV). Non usare con MP4.

In caso di dubbio, prova il demulatore concat.

Vedi anche

  • Domande frequenti su FFmpeg: Come posso unire i file video?
  • FFmpeg Wiki: come concatenare (unire, unire) i file multimediali

Ecco un modo veloce (richiede meno di 1 minuto) e senza perdita per farlo senza bisogno 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 

La “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 elementi bizzarri in essi – avrete bisogno di un’apposita shell-escape se volete fare questa idea con file “hard”).

Ho finito per usare mpg come formato intermedio e ha funzionato (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 

Stavo cercando di concatenare tre file audio .mp3 in un file .m4a 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 di concatenazione dei media (join).
n significa confermare il conteggio totale dei file di input.
v significa ha un video ? usa 0 = nessun video, 1 = contiene video.
un mezzo ha audio ? usa 0 = nessun audio, 1 = contiene audio.
-f significa force set file format (per vedere tutti i formati supportati, usa ffmpeg -formats )
-vn significa disabilitare il video (e anche -an disabilitare l’audio se non lo si desidera)
-y significa sovrascrivere i file di output (se il file di output esiste già).

Per maggiori informazioni: usa ffmpeg -h full stampa a ffmpeg -h full tutte le opzioni (incluso tutto il formato e le opzioni specifiche del codec, molto lunghe)

per file MP4:

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

 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 

Risultato : l’output si comporterà come il primo file (e non un secondo)

PER I 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) quanto segue è stata 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 che le parti fossero nell’ordine corretto per la visualizzazione dell’intero episodio televisivo.

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 occorrono meno di dieci secondi per l’esecuzione.

La documentazione dettagliata sui vari modi di concatenazione in ffmpeg può essere trovata qui .

Puoi usare “Filtro Concat” per una concatenazione rapida.

Esegue una ricodifica. Questa opzione è la migliore quando gli input 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 

Funziona sia per lo stesso che per più tipi di file di input.

Ecco una sceneggiatura che ho fatto per concatenare diversi GoPro mp4 in un 720p mp4. 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} 

sulla base delle risposte di rogerdpack e di 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 file *.mp4 nella cartella corrente in joined-out.mp4

testato su mac.

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

 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 

Unione di tutti i file mp4 dalla directory corrente

Personalmente mi piace non creare file esterni che devo eliminare in seguito, quindi seguiva la mia soluzione che include la lista dei file che elenca (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 

questo ha funzionato per me (su Windows)

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

in particolare

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

Pitone

Usando un po ‘di codice Python per farlo con tanti mp4 ci sono in una cartella import import di glob

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

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

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

 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 piattaforms.

Avevo bisogno della capacità di incapsulare questo in uno script multipiattaforma, quindi ho usato fluent-ffmpeg e ho 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!') )