Unisci file mp4 in linux


31

Voglio unire due file mp4 per crearne uno singolo. I flussi video sono codificati in h264 e l'audio in aac. Non riesco a ricodificare i video in un altro formato a causa di motivi computazionali. Inoltre, non posso usare alcun programma GUI, tutta l'elaborazione deve essere eseguita con le utility della riga di comando di Linux. FFmpeg non può farlo per i file mpeg4, quindi ho usato MP4Box:

MP4Box -add video1.mp4 -cat video2.mp4 newvideo.mp4

Sfortunatamente l'audio si confonde. Ho pensato che il problema fosse che l'audio era in aac, quindi l'ho transcodificato in mp3 e ho usato di nuovo MP4Box. In questo caso l'audio va bene per la prima metà di newvideo.mp4(corrispondente a video1.mp4) ma poi il loro non è audio e non posso navigare anche nel video.

Il mio pensiero successivo è stato che i flussi audio e video presentavano alcune piccole discrepanze nelle loro lunghezze che avrei dovuto correggere. Quindi per ogni video di input ho diviso i flussi video e audio e poi li ho uniti con l'opzione -shortest in FFmpeg.

Quindi per il primo video ho eseguito:

 avconv -y -i video1.mp4 -c copy -map 0:0 videostream1.mp4
 avconv -y -i video1.mp4 -c copy -map 0:1 audiostream1.m4a
 avconv -y -i videostream1.mp4 -i audiostream1.m4a  -c copy -shortest  video1_aligned.mp4

Allo stesso modo per il secondo video e quindi utilizzato MP4Box come in precedenza. Sfortunatamente neanche questo ha funzionato. L'unico successo che ho avuto è stato quando ho unito i flussi video separatamente (ovvero videostream1.mp4 e videostream2.mp4) e i flussi audio (ovvero audiostream1.m4a e audiostream2.m4a) e poi ho unito il video e l'audio in un file finale. Tuttavia, la sincronizzazione viene persa per la seconda metà del video. Concretamente, c'è un ritardo di 1 secondo di audio e video. Qualsiasi suggerimento è davvero gradito.


"FFmpeg non può farlo per i file mpeg4, quindi invece ho usato MP4Box" intendi il file MP4? entrambi i flussi audio-video utilizzano gli stessi parametri di codifica (larghezza, altezza, SPS, PPS, framerate, frequenza di campionamento, numero di canali?

usando ffprobe vedo che i flussi audio hanno attributi identici. I flussi video hanno le stesse dimensioni ma velocità diverse. Per il primo video Video: h264, 720x592, 277 kb / s, PAR 18944: 12915 DAR 512: 287, 24.97 fps, 45k tbr, 90k tbn, 90k tbc mentre per il secondo video: h264, 720x592, 226 kb / s, PAR 481: 330 DAR 39:22, 24.91 fps, 45k tbr, 90k tbn, 90k tbc. Credi che questa sia la fonte dei miei problemi?

MP4 supporta l'unione di video / audio con caratteristiche diverse utilizzando tracce diverse per video diversi, ma il lettore non è così intelligente.
Rajjesh,


La tua domanda ha già una risposta nelle FAQ di ffmpeg: ffmpeg.org/faq.html#How-can-I-join-video-files_003f
Palec

Risposte:


31

Il modo migliore per farlo attualmente è con il demuxer concat . Innanzitutto, crea un file chiamato inputs.txtformattato in questo modo:

file '/path/to/input1.mp4'
file '/path/to/input2.mp4'
file '/path/to/input3.mp4'

Quindi, esegui semplicemente questo comando ffmpeg:

ffmpeg -f concat -i inputs.txt -c copy output.mp4

Vedi anche concatenazione nelle ffmpegFAQ .


Conservo quanto segue qui a beneficio di chiunque usi versioni precedenti di ffmpeg.

Le ultime versioni di ffmpeg possono fare questo: dovrai prima rimodellare i file in flussi di trasporto mpeg (abbastanza leggero dal processore, poiché sta solo cambiando il formato del contenitore):

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts

Se ciò genera un errore su h264, potrebbe essere necessario utilizzare:

ffmpeg -i input.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb middle.ts

Dovrai farlo separatamente con ogni file di input. Per concatenare i file insieme, utilizzare:

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy output.mp4

Se ciò genera un errore su aac, potrebbe essere necessario utilizzare

ffmpeg -i "concat:middle1.ts|middle2.ts|middle3.ts" -c copy -absf aac_adtstoasc output.mp4

Se il tuo sistema supporta pipe denominate, puoi farlo senza creare file intermedi.

mkfifo temp0 temp1

Dovrai fare quanto segue in tre terminali virtuali separati:

ffmpeg -i input0.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp0
ffmpeg -i input1.mp4 -map 0 -c copy -f mpegts -bsf h264_mp4toannexb -y temp1
ffmpeg -f mpegts -i "concat:temp0|temp1" -c copy -absf aac_adtstoasc output.mp4

Se output.mp4 esiste già, il terzo ffmpeg ti chiederà se vuoi sovrascriverlo, ma lo farà dopo che avrà avuto accesso agli FIFO , e questo farà chiudere i primi a ffmpeg. Quindi assicurati di scegliere un nome inutilizzato per il tuo file di output.

Questo potrebbe non funzionare se i tuoi file di input sono diversi: credo che le differenze nella velocità in bit siano OK, ma le dimensioni del frame, il frame rate ecc. Devono corrispondere.


molti grazie, ha lavorato come un incantesimo
Jose Armando il

2
@DaveJarvis Non è così; questo è un messaggio deliberatamente e maliziosamente diffuso dal team libav, che è un gruppo di sviluppatori che si sono separati dal progetto ffmpeg per sviluppare avconv (e hanno cambiato il nome perché non potevano proteggere il copyright sul nome ffmpeg). Vedi Chi può dirmi la differenza e la relazione tra ffmpeg, libav e avconv? per qualche informazione in più.
evilsoup,

2
*** THIS PROGRAM IS DEPRECATED *** This program is only provided for compatibility and will be removed in a future release. Please use avconv instead.è un messaggio che vedo ora in esecuzioneffmpeg
Lord Loh.

@LordLoh. Vedi il link nel mio commento precedente.
evilsoup,

1
Quella risposta non risponde - come concatenare mp4 conavconv
Lord Loh.

7

Per mp4 l'unica soluzione funzionante che ho trovato era con MP4Box dal pacchetto gpac

#!/bin/bash
filesList=""
for file in $(ls *.mp4|sort -n);do
    filesList="$filesList -cat $file"
done
MP4Box $filesList -new merged_files_$(date +%Y%m%d_%H%M%S).mp4

o comando è

MP4Box -cat file1.mp4 -cat file2.mp4 -new mergedFile.mp4

con mencoder e avconv non sono riuscito a farlo funzionare :-(


2

Grazie per lo script dvo. È stato un ottimo punto di partenza per me. Non ho avuto problemi con l'utilizzo di named pipe, quindi ho adattato lo script per usarli. Inoltre l'ho risolto per funzionare con nomi di file con spazi all'interno. L'output su named pipe non "va" fino a quando non si inizia a leggere da loro, quindi la necessità di mettere in background le attività di remux iniziale con un & prima della chiamata finale ad avconv. Inoltre, non dimenticare di usare -c copy, o finirai per ricodificare l'intero lotto.

#!/bin/bash
for FILE in "$@"; do
   TAG=$(echo "$FILE" | sed -e s/[^A-Za-z0-9.]/_/g)
   mkfifo $TAG.mp4concatpipe
   avconv -loglevel "quiet" -i "$FILE"  -f mpegts -c copy -bsf h264_mp4toannexb -y $TAG.mp4concatpipe &
   IN=$IN\|$TAG.fifo
done

IN=${IN#\|}
avconv -i concat:$IN -c copy out.mp4
rm *.mp4concatpipe

Per qualche motivo questo mi sta dando un errore "concat: first.m4v.fifo | second.m4v.fifo: nessun file o directory simile" .. anche con virgolette (-i concat: "$ IN" o -i "concat: $ IN "). MP4Box suggerito nell'altra risposta qui sotto funziona comunque alla grande!
vorburger,

2

Su un Mac (macOS 10.13 High Sierra) ho usato con successo quanto segue:

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

Riordinare come sopra allo stesso modo, se necessario (notare che ./ è stato rimosso: il percorso causava a ffmpeg il lancio dell'errore di nome file non sicuro).

Quindi ho dovuto rimuovere il codec e il bitrate specificati per il ffmpeg predefinito di MacPorts:

ffmpeg -f concat -i mylist.txt  output.m4a

Benvenuto in Super User !, Leggi di nuovo attentamente la domanda. La tua risposta non risponde alla domanda originale che riguardava Linux. Se ritieni che funzionerà su Linux, ti preghiamo di aggiungere che così i futuri lettori avranno una chiara comprensione, a parte questo benvenuto a superutente e grazie per il tuo contributo. Ti preghiamo di dedicare un paio di minuti e leggere: - superuser.com/help. Risposta: superuser.com/help/how-to-answer .
Mic84,

2

Ecco un one-liner che rende tutto molto più semplice. Fa tutto ciò che è necessario per fornire finalmente un file video risultante. Saluti!

find *.mp4 | sed 's:\ :\\\ :g'| sed 's/^/file /' > list.txt; ffmpeg -f concat -i list.txt -c copy output.mp4; rm list.txts

1

Grazie malvagio; ecco un piccolo script per automatizzare il processo, usando il più recente avconv.
A proposito, le pipe con nome non hanno funzionato per me (l'output è stato bloccato).

   #!/bin/bash

    for FILE in $@; do
      avconv -i $FILE -map 0 -f mpegts -bsf h264_mp4toannexb -c:v copy -y $FILE.tmp
      IN=$IN\|$FILE.tmp
    done

    IN=${IN#\|}
    avconv -i concat:"$IN" out.mp4

    for FILE in $@; do
      rm $FILE.tmp
    done

0

Ho avuto un grande successo con

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

potrebbe essere necessario riordinare leggermente mylist.txt

ffmpeg -f concat -i mylist.txt -c:a libfdk_aac -b:a 128k output.m4a

ffmpeg versione 2.2.3

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.