Junte-se aos arquivos mp4 no linux


31

Quero juntar dois arquivos mp4 para criar um único. Os fluxos de vídeo são codificados em h264 e o áudio em aac. Não consigo recodificar os vídeos para outro formato devido a razões computacionais. Além disso, não posso usar nenhum programa da GUI, todo o processamento deve ser realizado com os utilitários de linha de comando do Linux. O FFmpeg não pode fazer isso para arquivos mpeg4, então usei o MP4Box:

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

Infelizmente, o áudio fica todo misturado. Eu pensei que o problema era que o áudio estava no aac, então eu o transcodifiquei em mp3 e usei novamente o MP4Box. Nesse caso, o áudio é bom para a primeira metade de newvideo.mp4(correspondente a video1.mp4), mas então não há áudio e não posso navegar no vídeo também.

Meu próximo pensamento foi que os fluxos de áudio e vídeo apresentavam pequenas discrepâncias em seus comprimentos que eu deveria corrigir. Assim, para cada vídeo de entrada, dividi os fluxos de vídeo e áudio e os juntei à opção -shortest no FFmpeg.

Assim, para o primeiro vídeo eu corri:

 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

Da mesma forma, para o segundo vídeo e, em seguida, usou o MP4Box como anteriormente. Infelizmente isso também não funcionou. O único sucesso que tive foi quando ingressei nos fluxos de vídeo separadamente (por exemplo, videostream1.mp4 e videostream2.mp4) e nos fluxos de áudio (como audiostream1.m4a e audiostream2.m4a) e depois ingressei no vídeo e no áudio em um arquivo final. No entanto, a sincronização é perdida na segunda metade do vídeo. Concretamente, há um atraso de 1 segundo de áudio e vídeo. Todas as sugestões são realmente bem-vindas.


"O FFmpeg não pode fazer isso em arquivos mpeg4, então usei o MP4Box", você quer dizer arquivo MP4? fazer o áudio-vídeo córregos usos mesmos parâmetros de codificação (largura, altura, SPS, PPS, framerate, samplingrate, número de canais?

using ffprobe Vejo que os fluxos de áudio têm atributos idênticos. Os fluxos de vídeo têm as mesmas dimensões, mas taxas diferentes. Para o 1º vídeo: h264, 720x592, 277 kb / s, PAR 18944: 12915 DAR 512: 287, 24,97 fps, 45k tbr, 90k tbn, 90k tbc, enquanto para o segundo vídeo: h264, 720x592, 226 kb / s, PAR 481: 330 DAR 39:22, 24,91 fps, 45k tbr, 90k tbn, 90k tbc. Você acredita que esta é a fonte dos meus problemas?

O MP4 suporta a junção de vídeo / áudio com características diferentes usando faixas diferentes para vídeos diferentes, mas o player não é tão inteligente.
Rajneesh


Sua pergunta já foi respondida nas perguntas frequentes do ffmpeg: ffmpeg.org/faq.html#How-can-I-join-video-files_003f
Palec

Respostas:


31

Atualmente, a melhor maneira de fazer isso é com o desmuxador concat . Primeiro, crie um arquivo chamado inputs.txtformatado da seguinte forma:

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

Em seguida, basta executar este comando ffmpeg:

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

Veja também concatenação nas ffmpegperguntas frequentes .


Estou mantendo o seguinte aqui para o benefício de qualquer pessoa que utilize versões mais antigas do ffmpeg.

As versões mais recentes do ffmpeg podem fazer isso: você precisará remuxar os arquivos primeiro nos fluxos de transporte mpeg (bastante leve para o processador, pois está apenas alterando o formato do contêiner):

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

Se isso gerar um erro sobre o h264, talvez você precise usar:

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

Você precisará fazer isso separadamente com cada arquivo de entrada. Para concatenar os arquivos juntos, use:

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

Se isso gerar um erro sobre o aac, talvez você precise usar o

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

Se o seu sistema suportar pipes nomeados, você poderá fazer isso sem criar arquivos intermediários.

mkfifo temp0 temp1

Você precisará fazer o seguinte em três terminais virtuais separados:

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 o output.mp4 já existir, o terceiro ffmpeg perguntará se você deseja substituí-lo, mas fará isso depois de acessar os FIFOs , e isso fará com que o primeiro ffmpegs seja fechado. Portanto, certifique-se de escolher um nome não utilizado para o seu arquivo de saída.

Isso pode não funcionar se os arquivos de entrada forem diferentes - acredito que as diferenças na taxa de bits sejam aceitáveis, mas o tamanho do quadro, a taxa de quadros etc. devem corresponder.


muitos thx companheiro, funcionou como um encanto
José Armando

2
@DaveJarvis Não é assim; essa é uma mensagem deliberada e maliciosa espalhada pela equipe de libav, que é um grupo de desenvolvedores que se separaram do projeto ffmpeg para desenvolver avconv (e mudaram o nome porque não podiam garantir os direitos autorais sobre o nome ffmpeg). Veja quem pode me dizer a diferença e a relação entre ffmpeg, libav e avconv? para um pouco mais de informação.
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.é uma mensagem que vejo agora em execuçãoffmpeg
Lorde Loh.

@LordLoh. Veja o link no meu comentário anterior.
#

1
Essa resposta não responde - como concatenar mp4 comavconv
Lord Loh.

7

Para mp4, a única solução que encontrei foi com o MP4Box do pacote 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

ou comando é

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

com mencoder e avconv eu não poderia fazê-lo funcionar :-(


2

Obrigado pelo script dvo. Foi um ótimo ponto de partida para mim. Como não tive problemas em usar pipes nomeados, adaptei o script para usá-los. Além disso, eu o consertei para trabalhar com nomes de arquivos com espaços neles. A saída para pipes nomeados não "vai" até que você comece a ler deles, daí a necessidade de colocar em segundo plano as tarefas de remux inicial com um & antes da chamada final para avconv. Além disso, não se esqueça de usar -c copy ou você acaba recodificando o lote inteiro.

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

Por alguma razão, isso está me dando um erro "concat: first.m4v.fifo | second.m4v.fifo: não existe esse arquivo ou diretório" .. mesmo entre aspas (-i concat: "$ IN" ou -i "concat: $ IN "). O MP4Box sugerido na outra resposta abaixo, no entanto, funciona muito bem!
precisa saber é o seguinte

2

Em um Mac (macOS 10.13 High Sierra), usei o seguinte com êxito:

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

Reordene como descrito acima da mesma forma, se necessário (observe que o ./ foi removido - o caminho estava causando o ffmpeg lançar o erro de nome de arquivo não seguro).

Então eu tive que remover o codec e a taxa de bits especificados para o padrão MacPorts ffmpeg para gostar:

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

Bem-vindo ao Superusuário !, Por favor, leia a pergunta novamente com atenção. Sua resposta não responde à pergunta original que era sobre linux. Se você acredita que ele funcionará no Linux, por favor, acrescente que os futuros leitores terão um entendimento claro, além disso, bem-vindo novamente ao superusuário e obrigado pela sua contribuição. Reserve alguns minutos e leia: - superuser.com/help .Resposta: superuser.com/help/how-to-answer .
mic84

2

Aqui está uma lista que torna tudo muito mais fácil. Ele faz tudo o que é necessário para finalmente fornecer um arquivo de vídeo resultante. Felicidades!

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

1

Obrigado evilsoup; Aqui está um pequeno script para automatizar o processo, usando o mais recente avconv.
BTW, pipes nomeados não funcionaram para mim (a saída para eles ficou bloqueada).

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

Tiveram grande sucesso com

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

pode ser necessário reorganizar levemente o mylist.txt

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

ffmpeg versão 2.2.3

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.