Como concatenar dois arquivos MP4 usando o FFmpeg?

442

Estou tentando concatenar dois arquivos mp4 usando ffmpeg. Eu preciso que este seja um processo automático, por isso escolhi o ffmpeg. Estou convertendo os dois arquivos em arquivos .ts, concatenando-os e tentando codificá-lo. Os arquivos são codificados h264 e aac e espero manter a qualidade igual ou o mais próximo possível do original.

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

Infelizmente, estou recebendo a seguinte mensagem de erro retornando do ffmpeg durante a codificação:

[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

Isso acontece na metade da codificação, o que me faz pensar que você não pode concaturar dois arquivos .ts e fazê-lo funcionar.

Mark L
fonte

Respostas:

785

O FFmpeg possui três métodos de concatenação:

1. filtro de vídeo concat

Use este método se suas entradas não tiverem os mesmos parâmetros (largura, altura, etc), ou não forem os mesmos formatos / codecs, ou se você desejar executar alguma filtragem. (Você pode recodificar apenas as entradas que não correspondem, para que compartilhem o mesmo codec e outros parâmetros e, em seguida, use o desmuxador concat para evitar a recodificação das outras entradas).

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

Observe que esse método executa uma recodificação.

2. concat desmuxer

Use esse método quando desejar evitar uma recodificação e seu formato não oferece suporte à concatenação no nível do arquivo (a maioria dos arquivos usados ​​por usuários em geral não oferece suporte à concatenação no nível do arquivo).

$ 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

Para 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. protocolo de concat

Use este método com formatos compatíveis com concatenação no nível do arquivo (MPEG-1, MPEG-2 PS, DV). Você não usar com MP4.

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

Este método não funciona para muitos formatos, incluindo MP4, devido à natureza desses formatos e à concatenação simplista realizada por esse método.


Em caso de dúvida sobre qual método usar, tente o concat desmuxer.

Veja também

rogerdpack
fonte
3
O caractere de escape do prompt de comando do Windows é ^; Eu também tive problemas com as aspas por isso tornou-se: ffmpeg -i concat: input1 ^ | input2 -codec saída de cópia
user423430
1
Resposta útil. E fez ainda mais sentido para mim quando eu li esta variação: superuser.com/a/607384/74576
Ryan
3
concat demuxer funciona para vídeo, mas eu estou perdendo áudio
Loïc
23
Para um uso oneliner: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(o mkv aceita mais codecs que o mp4, mas você também pode experimentá-lo com o mp4). O -safe 0é para versões recentes do ffmpeg queixam-se do nome de arquivo inseguro e o -type fé apenas para listar arquivos. Eu adicionei| sort para classificar os arquivos em ordem alfabética; porque os findlê em ordem como salvos no sistema de arquivos. Funciona também para arquivos com espaços em branco.
Erik
1
Para mim, no Windows, as aspas duplas funcionaram (em vez da única no seu exemplo): ffmpeg -i "concat:input1|input2" -codec copy output . Não há necessidade de escapar do caractere de pipe.
Shovalt
82

PARA ARQUIVOS MP4

Para arquivos .mp4 (que obtive do DailyMotion.com: um episódio de 50 minutos da TV, que pode ser baixado apenas em três partes, como três arquivos de vídeo .mp4), a seguir foi uma solução eficaz para o Windows 7 e NÃO envolve recodificar o arquivo arquivos.

Renomeei os arquivos (como arquivo1.mp4 , arquivo2.mp4 , arquivo3.mp4 ), de modo que as peças estivessem na ordem correta para a exibição do episódio de TV completo.

Depois, criei um arquivo em lotes simples (concat.bat), com o seguinte conteúdo:

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

o arquivo em lotes e o ffmpeg.exe devem ser colocados na mesma pasta que os arquivos .mp4 a serem ingressados. Em seguida, execute o arquivo em lotes. Normalmente, leva menos de dez segundos para ser executado.
.

Adenda (21/10/2018) -

Se o que você estava procurando é um método para especificar todos os arquivos mp4 na pasta atual sem muita redigitação, tente isso no arquivo em lotes do Windows em ( DEVE incluir a opção -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

Isso funciona no Windows 7, em um arquivo em lotes. Não tente usá-lo na linha de comando, porque ele funciona apenas em um arquivo em lotes!

Ed999
fonte
5
A solução mais fácil de longe.
1934286 20/0317
Essa deve ser a melhor e mais fácil resposta. Bom trabalho, meu irmão. Você salvou o meu dia.
DysaniazzZ
Essa é uma boa solução, mas falar sobre um arquivo em lotes faz com que esse som seja primitivo (como se fosse feito em lotes) e mais complexo do que é (porque um arquivo em lotes é completamente desnecessário). É muito mais claro se você simplesmente mostra C:\blah>type mylist.txt<ENTER>(para que eles vejam o conteúdo desse arquivo). ffmpeg -f concat -i mylist.txt -c copy output.mp4<ENTER> Além disso, você deve incluir uma referência trac.ffmpeg.org/wiki/Concatenate (essa referência ainda usa o mesmo nome de arquivo, mylist.txt)
barlop
Esta é uma solução muito boa, pois evita que você digite longas listas de arquivos como -iparâmetro. No Linux, eu fiz isso: o ls -1 P1041*.mp4 | sed s/"P"/" file P"/g > mylist.txtque é ainda mais interessante do que codificar um script em lote. Enfim, -c copyexecuta muito rapidamente (o que eu não sabia) e essa é a verdadeira mágica desta resposta.
Würgspaß
1
Nos meus arquivos mp4, não há áudio no arquivo de saída depois de executar o código concat em um Mac, usando o ffmpeg v3.2.2.
kakyo
59

Aqui está uma maneira rápida (leva menos de 1 minuto) e sem perdas de fazer isso sem a necessidade de arquivos intermediários:

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

O "ls" contém os arquivos para ingressar O "perl" cria o arquivo de concatenação rapidamente em um pipe A parte "-i -" diz ao ffmpeg para ler no pipe

(note - meus arquivos não tinham espaços ou coisas estranhas - você precisará de escape de shell apropriado se quiser fazer essa idéia com arquivos "físicos").

cnd
fonte
2
Fiz isso no OSX e funcionou muito bem! Solução impressionante, rápida e sem perdas, com poucos requisitos.
GM Lucid
1
Com escape adequado para arquivos que contêm espaço em branco: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 28/01
4
Você também pode fazer isso ls * | perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4se seus arquivos estiverem bem nomeados e em ordem. Funcionou muito bem para mim no OS X, exatamente o que eu queria.
Netebeaty
3
No Linux, usei este oneliner: ffmpeg -safe 0 -f concat -i <(find . -type f -name '*' -printf "file '$PWD/%p'\n" | sort) -c copy output.mkv(o mkv aceita mais codecs que o mp4, mas você também pode tentar com o mp4). O -safe 0é para versões recentes do ffmpeg queixam-se do nome de arquivo inseguro e o -type fé apenas para listar arquivos. Eu adicionei | sortpara classificar os arquivos em ordem alfabética; porque os findlê em ordem como salvos no sistema de arquivos. Funciona também para arquivos com espaços em branco.
Erik
12
Eu tive que adicionar este parâmetro para ffmpegfazê-lo funcionar:-protocol_whitelist file,tcp,http,pipe
Bensge 05/10
44

para arquivos MP4:

Se eles não forem exatamente os mesmos arquivos MP4 (100% mesmo codec, mesma resolução, mesmo tipo), será necessário transcodificá-los em fluxos intermediários primeiro:

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! : A saída será como o primeiro arquivo (e não o segundo)

T.Todua
fonte
2
Como ilustrado na minha resposta, abaixo, a transcodificação dos arquivos não é necessária. O FFmpeg pode concatenar vários arquivos mp4 em um único arquivo mp4 - sem nenhuma etapa intermediária e sem recodificação. O único caso em que qualquer recodificação seria necessária é se os arquivos originais não forem arquivos mp4, mas a intenção é criar um arquivo mp4 como arquivo de saída.
Ed999
@T. Todua: Gostaria de saber quais são as diferenças entre os dois arquivos de origem mp4. Eles estão usando taxas de amostragem diferentes (por exemplo, 44.100 Hz e 48.000 Hz)? Ou eles estão usando taxas de bits diferentes (por exemplo, 128 kbps e 64 kbps)? Em ambos os casos, não entendo como o comando -c copy (uma instrução de cópia de fluxo) modificaria os arquivos de origem para torná-los compatíveis.
Ed999
4
@ T.Todua Olá, o comando funciona bem quando os vídeos estão sem faixa de áudio. No entanto, quando o myfile1.mp4 estiver sem áudio e o myfile2.mp4 estiver com áudio, o resultado output.mp4 ficará sem áudio. O output.mp4 esperado deve conter áudio. Como posso resolver isso?
AnswerZhao
2
@ T.Todua er .... É muito ruim. O arquivo1 | arquivo2 gera o vídeo diferente com o arquivo2 | arquivo1. a ordem é importante.
AnswerZhao
1
Eu tentei o seu comando em concat 2 arquivos mp4. Funciona. No entanto, o áudio do segundo arquivo fica instável como as vozes Ah-oh-Ee na nova concatenação produzida. você tem uma correção para isso?
Superlinux
35

Eu estava tentando concatenar três .mp3arquivos de áudio em um .m4aarquivo e esse comando ffmpeg funciona.

Comando de entrada:

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

Significados de: "-filter_complex concat = n = 3: v = 0: a = 1" :

concat significa usar a função concatenar mídia (ingressar).
n significa confirmar a contagem total de arquivos de entrada.
v significa que tem vídeo ? use 0 = sem vídeo, 1 = contém vídeo.
um meio tem áudio ? use 0 = sem áudio, 1 = contém áudio.
-f significa forçar o formato do arquivo definido (para ver todos os formatos suportados, use ffmpeg -formats)
-vn significa desativar o vídeo (e também -andesativaria o áudio se não for desejado)
-y significa substituir os arquivos de saída (se o arquivo de saída já existir).

Para obter mais informações: use ffmpeg -h full todas as opções de impressão (incluindo todas as opções específicas de formato e codec, muito longas)

Ellie Tam
fonte
1
fi usar isso, -f concat -safe 0 -i "file.txt" -c copy -y "OutPut.mp4"ele irá concat, mas quando alguns vídeos estão com áudio e outros sem áudio, não está funcionando, como posso resolver isso. Obrigado -
Ahmad
1
Isso funciona. Obrigado pela explicação detalhada em sua resposta. É muito útil.
9788 Joe J Boka
31

Acabei usando mpg como formato intermediário e funcionou (NOTA: este é um exemplo perigoso, -qscale 0 irá recodificar o vídeo ...)

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
Mark L
fonte
8
A partir deste comentário, -sameqfoi removido. Use em -qscale 0vez disso.
Xavier Ho
6
-sameqnão significa "mesma qualidade" e foi removido do ffmpeg conforme mencionado por @XavierHo.
Llogan
3
Parece uma pena ter que transcodificar o vídeo em um formato intermediário apenas para concatenar dois arquivos. Você terá perda de geração. É melhor não ir mais fundo do que o formato do contêiner e usar o concatcomando ffmpeg, como o @rogerdpack faz acima.
Randall Cozinhe
8
Como é que esta é uma resposta aceita? Este é um método muito ruim.
Exibir nome
4
@SargeBorsch Porque funciona. Já tentei de tudo na página ... Nenhum deles funciona.
14

Documentação detalhada sobre várias formas de concatenação no ffmpeg pode ser encontrada aqui .

Você pode usar o 'filtro Concat' para concatenação rápida.

Ele executa uma recodificação. Esta opção é melhor quando as entradas têm diferentes formatos de vídeo / áudio.

Para concatenar 2 arquivos:

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

Para concatenar 3 arquivos:

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

Isso funciona para o mesmo e para vários tipos de arquivos de entrada.

SJ00
fonte
você pode especificar mais detalhes sobre as opções que você tem neste exemplo?
desenvolvedor
@ Developer: Para explicação das opções -> Wiki do filtro Concat
SJ00 04/04
4
Ao concatenar 3 arquivos, você deve usar concat = n = 3: v = 1: a = 1 not n = 2
Cynapsis
1
Eu não estou recebendo lossless concatenação minha ouput.mp4bitrate de vídeo é significativamente menor do que a vídeos de entrada de vídeo taxa de bits
Jasan
Obrigado Cynapsis por apontar e georgiecasey por atualizar o comando
SJ00 15/17
10

Descobri que o operador do tubo não funcionou para mim ao usar a opção 3 para concaturar vários MP4s em um Mac na resposta aceita.

O one-liner a seguir funciona em um Mac (High Sierra) para concatenar mp4s, sem a necessidade de criação de arquivo intermediário.

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

Ben Siver
fonte
2
Essa resposta simples é a única que realmente funcionou para mim. Páginas e páginas de documentação aqui e em outros lugares, enquanto essa linha simples é tudo o que é necessário - e realmente funciona. Obrigado.
blujay
10

Aqui, 2 soluções de bash puras usando apenas ffmpege não usando

  • um arquivo intermediário
  • perl, python nem javascript

Solução de uma linha usando 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

Função que recebe 0 ou 2 ou mais argumentos

#######################################
# 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: havia tentado algumas soluções neste segmento e nenhuma me satisfez

Florent Roques
fonte
9

com base nas respostas de rogerdpack e Ed999, criei minha versão .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

junta todos os *.mp4arquivos da pasta atual emjoined-out.mp4

testado no mac.

O tamanho do arquivo resultante é a soma exata dos meus 60 arquivos testados. Não deve haver nenhuma perda. Exatamente o que eu precisava

Alexandr Perfilov
fonte
9

isso funcionou para mim (no windows)

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

um exemplo...

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

Pitão

Usando algum código python para fazê-lo com o maior número possível de mp4 em uma pasta (instale python em python.org, copie e cole e salve esse código em um arquivo chamado mp4.py e execute-o a partir do cmd aberto na pasta com python mp4.py e todos os mp4 da pasta serão concatenados)

import glob
import os

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

Versão 2 com Python

Retirado do meu post no meu blog , é assim que eu faço em 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()
Giovanni G. PY
fonte
1
O protocolo concat não deve ser usado com o MP4 e não funcionará como mencionado na resposta aceita .
Llogan
@ LordNeckbeard Gostaria de saber se você sabe a resposta para esta pergunta ffmpeg sobre concatenar 2 vídeos MP4 enquanto especifica a taxa de bits de saída? video.stackexchange.com/q/24569/5657 Obrigado.
21718 Ryan
@LordNeckbeard Meu palpite é que sua resposta seria a melhor, ainda, se você quiser! Não estou particularmente satisfeito com o meu.
21718 Ryan
Não apenas (como destaca Lord Neckbeard) é necessário converter um arquivo .mp4 para o formato .TS intermediário para que a concatenação seja bem-sucedida, mas, talvez ainda pior, essa resposta nem sequer começa a abordar a necessidade da entrada arquivos de vídeo com taxa de bits, taxa de quadros, taxa de amostragem, base de tempo e duração correspondentes. Sem todos esses 5 fatores em comum, os arquivos não podem ser concatenados (ou seja, juntados usando a cópia de fluxo ), mas devem ser recodificados.
Ed999 #
7

Para .mp4arquivos, eu achei que funciona melhor e mais rápido para usar a ferramenta de linha de comando opensource: mp4box. Então você pode usá-lo desta maneira:

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

Faça o download aqui para a maioria das plataformas: https://gpac.wp.imt.fr/mp4box/

Mario
fonte
2
Embora isso possa ser útil para alguém, o requisito era: " Estou tentando concatenar dois arquivos mp4 usando ffmpeg. Preciso que este seja um processo automático ". Leia a pergunta completa e tente fornecer uma resposta que esteja correta.
thvs86
5
Esta resposta está totalmente correta. É uma ferramenta FOSS que faz o mesmo trabalho. Pode ser usado em um script como o FFmpeg. Ele faz o trabalho de maneira mais simples do que qualquer das respostas do FFmpeg. Veja como eles são complicados! Um deles usa o Node.js para chamar FFmpeg! Insanidade. Por favor, pare com o wonkism e tente tornar o StackOverflow útil novamente. Este site é uma sombra de seu antigo eu, graças a pessoas como você. Além disso, esta pergunta é um exemplo do "Problema XY", com o qual você deve estar familiarizado.
blujay
Não importa que o mp4box seja uma ferramenta de software livre. A pergunta pediu respostas usando ffmpeg, não mp4box.
jramos775 29/01
@ thvs86 Eu sou um exemplo disso. Eu uso o ffmpeg, pois é uma verdadeira faca suíça para mídia. Também busco ajuda com meus casos de uso específicos, pois a estrutura de argumentos pode ser bastante complexa (o que é demonstrado pelas respostas variadas aqui). É a primeira vez que ouço sobre o mp4box e não o teria encontrado se não fosse essa resposta. Então, +1 de mim e, por favor, pense mais em pessoas que procuram respostas do que em pontos sem sentido na Internet e regras rígidas.
Pavel
4

Aqui está um script que eu fiz para concatenar vários mp4 da GoPro em um mp4 de 720p. Espero que seja de ajuda.

#!/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}
Reid Ellis
fonte
Isso NÃO está concatenando. Este código não concatena as entradas, recodifica-as. Isso pega todos os arquivos de vídeo arbitrários e os altera para uma taxa de bits comum de áudio e vídeo (independentemente da taxa de bits ou do tamanho de quadro original dos arquivos de origem). O o / p queria unir dois arquivos usando a cópia de fluxo, não os recodifique, para que isso não resolva a questão.
Ed999 #
4

Na documentação aqui: https://trac.ffmpeg.org/wiki/Concatenate

Se você tiver arquivos MP4, eles poderão ser concatenados sem perdas , primeiro transcodificando-os para fluxos de transporte MPEG-2. Com vídeo H.264 e áudio AAC, é possível usar o seguinte:

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

Essa abordagem funciona em todas as plataformas.

Eu precisava da capacidade de encapsular isso em um script de plataforma cruzada, então usei fluent-ffmpege vi a seguinte solução:

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!')
)
itslittlejohn
fonte
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
Deepak Kumar
fonte
1
Não apenas postando uma resposta, você pode adicionar pouca explicação para entender melhor a solução para OP e futuros leitores.
Balagurunathan Marimuthu
1
Isso criou um novo vídeo silencioso com as duas entradas sendo reproduzidas ao mesmo tempo, próximas uma da outra. Eu esperava concatenação criaria um vídeo onde input_1.mp4 jogado e depois input_2.mp4
Alexx Roche
3
Esta foi a resposta errada inteiramente. Isso não concatenou os vídeos, apenas os reproduz silenciosamente lado a lado, como o @AlexxRoche havia mencionado.
Kalob Taulien
1

Mesclando todos os arquivos mp4 do diretório atual

Pessoalmente, eu não gosto de criar arquivos externos que tenho que excluir posteriormente, então minha solução foi a seguir, que inclui a listagem de numeração dos arquivos (como 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
Pipo
fonte
Copiei esse código para o bloco de notas e nada aconteceu.
7vujy0f0hy
1
@ 7vujy0f0hy Isso funciona em um linux com um shell bash talvez ele poderia trabalhar com cygwin
Pipo
1

Após várias tentativas abaixo, o script funcionou para mim no 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

Aqui, as duas primeiras linhas criam um arquivo de texto temp.txt que possui o seguinte conteúdo

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

3ª e 4ª linhas verificam se o ffmpeg está disponível no caminho e cria o "join.mp4"

As principais diferenças de outras respostas são as seguintes

usage  of -bsf:v hevc_mp4toannexb -an

para o meu arquivo mp4 acima funcionou, pode ser necessário usar outras alternativas, como abaixo, dependendo da codificação do vídeo.

h264_mp4toannexb

Todos esses filtros Bitstream possíveis podem ser encontrados em https://ffmpeg.org/ffmpeg-bitstream-filters.html

rahul maindargi
fonte
Os meus eram MP4 provenientes de uma câmera de CFTV. Sem esse comando, a conversa falha ao gerar o arquivo de saída. Estou usando o ffmpeg mais recente em seu site.
rahul maindargi 16/03/19
0

Aqui está o meu método para ingressar em um diretório cheio de arquivos MP4 usando a substituição de comandos e o filtro de vídeo concat (isso será recodificado) - imaginamos que alguém obterá algum uso dessa linha única, especialmente se você tiver muitos arquivos (eu apenas juntou 17 arquivos de uma só vez):

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

Nota: este comando une seus arquivos na ordem em que são nomeados (ou seja, na mesma ordem em que são apresentados se você executar ls *.mp4) - no meu caso, cada um deles tinha um número de faixa, por isso funcionou muito bem.

Pedro
fonte
0

O protocolo concat descrito aqui; https://trac.ffmpeg.org/wiki/Concatenate#protocol

Quando implementado usando pipes nomeados para evitar arquivos intermediários

É muito rápido (leia-se: instantâneo), não possui quadros perdidos e funciona bem.

Lembre-se de excluir os arquivos de pipe nomeados e verifique se o vídeo é H264 e AAC com o qual você pode fazer apenas ffmpeg -i filename.mp4(verifique as menções h264 e aac)

Roel Van de Paar
fonte
-1

A resposta aceita na forma de script reutilizável do PowerShell

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
}
fjch1997
fonte