ffmpeg junte dois arquivos mp4 com o ffmpeg na linha de comando

29

Posso ingressar com êxito em vários arquivos usando o seguinte comando:

ffmpeg -f concat -i input.txt -codec copy output.mp4

O único problema com este comando é que você precisa ler os caminhos do arquivo de texto chamado input.txt com o seguinte conteúdo:

file 'C:\Users\fabio\Downloads\Super\Sharks\01.mp4'
file 'C:\Users\fabio\Downloads\Super\Sharks\02.mp4'
file 'C:\Users\fabio\Downloads\Super\Sharks\03.mp4'

Existe uma maneira de atingir o mesmo objetivo sem precisar ler os caminhos de arquivo de um arquivo? Eu tentei o seguinte sem sorte:

ffmpeg -f concat -i file "C:\a\b\01.mp4" file "C:\a\b\02.mp4" -codec copy output.mp4
ffmpeg -f concat -i "C:\a\b\01.mp4" "C:\a\b\02.mp4" -codec copy output.mp4

Eu tenho que usar um comando diferente?

Fabio Delarias
fonte
11
related: stackoverflow.com/questions/7333232/…
Ciro Santilli escreveu:

Respostas:

37

Atualização de 2019:

Conforme mencionado nos comentários, o Stack Overflow possui uma ótima descrição das opções disponíveis para concatenação, além de uma discussão sobre qual método usar, dependendo dos tipos de arquivos que você está usando:

Como concatenar dois arquivos MP4 usando o FFmpeg?

Resposta original de 2016:

Você deve poder usar o método de protocolo concat para combinar os arquivos:

ffmpeg -i "concat:input1.mp4|input2.mp4|input3.mp4" -c copy output.mp4

Além disso, o manual FFmpeg discute um método especificamente para arquivos MP4, para concatená-los sem perdas, mas requer que você crie arquivos temporários (ou pipes nomeados):

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
Carson Darling
fonte
11
O primeiro comando funcionou para mim como uma manteiga .. demorou 2 a 3 segundos para concatinar meus 6 arquivos mp4 no arquivo de saída (aproximadamente 239 MB).
Sachin
22
O primeiro comando não funcionou para mim. Apenas copiou o primeiro arquivo.
Luis A. Florit
3
Isso não funciona, apenas copiou o primeiro arquivo para output.mp4.
Crmpicco
2
A concatenação no nível do arquivo não funciona para MP4, portanto, o protocolo concat não é recomendado para este formato e geralmente não funciona.
llogan 21/02
11
@brasofilo Obrigado pelo link. Isso está muito atrasado, mas eu atualizei a resposta para apontar as pessoas nessa direção.
Carson Darling
5

Você pode substituir o arquivo pela lista, enviando uma lista para stdoute lendo a lista stdinpor ffmpeg:

(echo file 'a.mp4' & echo file 'b.mp4') | ffmpeg -protocol_whitelist file,pipe -f concat -safe 0 -i pipe: -vcodec copy -acodec copy "result.mp4"
Qwertiy
fonte
Usando o ffmpeg versão 2.4.3-tessus no Mac OS 10.12.6, isso gera um erro: "Opção não reconhecida 'protocol_whitelist'". Sem a opção protocol_whitelist, parece apenas fazer uma cópia do segundo arquivo MP4.
James
2

Não, parece não haver maneira de usar o ffmpeg concat desmuxer em uma única linha de comando sem algum hack. Você precisa criar o arquivo de texto de entrada com a lista de arquivos. Eu mesmo pensei isso, talvez alguém adicione isso ao FFMpeg posteriormente.

A resposta aceita para essa pergunta usa o protocolo concat, não o desmuxer concat, que é o que o OP pediu.

georgiecasey
fonte
11
Na verdade existe. stdin.
Qwertiy 21/02
O protocolo concat não deve ser usado com MP4 ou qualquer outro formato, pois requer um cabeçalho global.
llogan 18/09
1

Você ainda pode fazer isso em um script sem alterar o comando. Algo como:

echo "file fname1" >$$.tmp    #single redirect creates or truncates file
echo "file fname2" >>$$.tmp   # double redirect appends
echo "file fname3" >>$$.tmp   # do as many as you want.

ffmpeg -f concat -i $$.tmp -codec copy output.mp4

rm $$.tmp  # just to clean up the temp file. 
           # For debugging, I usually leave this out.

O $$ se expande para o pid do shell executando o comando, portanto o nome do arquivo será diferente toda vez que você o executar. então você pode usar $$ .txt, se preferir. Ou outra coisa...

Além disso, você pode usar os arquivos aqui para adicionar um monte de dados ao arquivo:

cat <<EOF >$$.tmp
file fname1
file fname2
file fname3
EOF

bash A substituição de variáveis ​​funciona, para que você possa determinar programaticamente o conteúdo do arquivo, ele não precisa ser corrigido. Eu incorporo esse tipo de coisa em loops o tempo todo. Por fim, o redirecionamento funciona da mesma maneira que acima, portanto,> $$. Tmp trunca e, em seguida, escreve >> >> .tmp anexado.

Richard Betel
fonte
2
A pergunta é: "existe uma maneira de alcançar o mesmo objetivo sem ter que ler os caminhos de arquivos de um arquivo?" Tudo o que você fez é fornecer uma maneira de gravar os caminhos de arquivo em um arquivo (antes de ler os caminhos de arquivo). Isso não responde à pergunta.
Scott