Как объединить два файла MP4 с помощью FFmpeg? - PullRequest
288 голосов
/ 07 сентября 2011

Я пытаюсь объединить два файла mp4 с помощью ffmpeg. Мне нужно, чтобы это был автоматический процесс, поэтому я выбрал ffmpeg. Я конвертирую эти два файла в файлы .ts, затем объединяю их, а затем пытаюсь кодировать этот объединенный файл .ts. Файлы имеют кодировку h264 и aac, и я надеюсь сохранить качество на том же уровне или максимально приблизиться к оригиналу.

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

К сожалению, я получаю следующее сообщение об ошибке, возвращаемое ffmpeg во время кодирования:

[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

Это происходит примерно в середине кодирования, что заставляет меня думать, что вы не можете объединить два файла .ts вместе и заставить его работать.

Ответы [ 16 ]

562 голосов
/ 24 июня 2012

FFmpeg имеет три метода конкатенации.

1. concat video filter

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

Обратите внимание, что этот метод выполняет перекодирование.

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

Для 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. протокол concat

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

Этот метод не работает для многих форматов, включая MP4, из-за природы этих форматов и упрощенной конкатенации, выполняемой этим методом.

Какой использовать

  • concat filter : используйте, если ваши входные данные не имеют одинаковые параметры (ширина, высота и т. Д.) Или не имеют одинаковые форматы / кодеки, или если вы хотите выполнить какую-либо фильтрацию , (Вы можете перекодировать только те входные данные, которые не совпадают, чтобы они использовали один и тот же кодек и другие параметры, а затем использовать демультиплексор concat, чтобы избежать перекодирования других входных данных).

  • concat demuxer : Используйте, если вы хотите избежать перекодирования и вашего формата не поддерживает конкатенацию на уровне файлов (большинство файлов, используемых обычными пользователями, не поддерживают конкатенацию на уровне файлов).

  • протокол concat : Используйте с форматами, которые поддерживают конкатенацию на уровне файлов (MPEG-1, MPEG-2 PS, DV). Не использовать с MP4.

Если есть сомнения, попробуйте демультиплексор concat.

Также см.

51 голосов
/ 30 декабря 2016

ДЛЯ MP4 ФАЙЛОВ

Для .mp4 файлов (которые я получил от DailyMotion.com: 50-минутный телевизионный эпизод, загружаемый только из трех частей, как три видеофайла .mp4), следующее было эффективным решением для Windows 7 , и НЕ включает повторное кодирование файлов.

Я переименовал файлы (как file1.mp4 , file2.mp4 , file3.mp4 ), чтобы детали были в правильном порядке для просмотра полный телевизионный эпизод.

Затем я создал простой командный файл (concat.bat) со следующим содержанием:

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

Пакетный файл и ffmpeg.exe должны быть помещены в одну папку с файлами .mp4 , которые необходимо объединить. Затем запустите пакетный файл. Обычно для запуска требуется менее десяти секунд.
,

Приложение (2018/10/21) -

Если вы искали метод указания всех файлов mp4 в текущей папке без повторной перепечатки, попробуйте это в своем пакетном файле Windows вместо этого ( MUST включите опцию -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

Это работает в Windows 7, в командном файле. Не попробуйте использовать его в командной строке, потому что он работает только в командном файле!

48 голосов
/ 27 марта 2014

Вот быстрый (занимает менее 1 минуты) и способ без потерь сделать это без необходимости в промежуточных файлах:

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

«ls» содержит файлы для присоединения «perl» создает файл конкатенациина лету в канал Часть "-i -" сообщает ffmpeg читать из канала

(обратите внимание - в моих файлах нет пробелов или странных вещей - вам нужно соответствующее экранирование оболочкиесли вы хотите сделать эту идею с «жесткими» файлами).

35 голосов
/ 13 мая 2016

для файлов MP4:

Если они не совсем одинаковые (100% одинаковый кодек, одинаковое разрешение, тот же тип) MP4-файлы, то сначала вам нужно транскодировать их в промежуточные потоки:

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

Примечание : Вывод будет похож на первый файл (а не второй)

32 голосов
/ 09 апреля 2014

Я пытался объединить три .mp3 аудиофайла в один .m4a файл, и эта команда ffmpeg работает.

Команда ввода:

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

Значения: "-filter_complex concat = n = 3: v = 0: a = 1" :

concat означает использование функции объединения медиаданных (присоединения).
n означает подтверждение общего количества входных файлов.
v означает имеет видео ?используйте 0 = нет видео, 1 = содержит видео.
a означает, что имеет звук ?использовать 0 = нет звука, 1 = содержать звук.
-f означает принудительно установить формат файла (для просмотра всех поддерживаемых форматов используйте ffmpeg -formats)
-vn означает отключить видео (а также -an отключит звук, если не хочет)
-y означает перезаписать выходные файлы (если выходной файл уже существует).

Длябольше информации: используйте ffmpeg -h full печать всех параметров (включая все параметры формата и кодека, очень длинные)

29 голосов
/ 07 сентября 2011

В итоге я использовал mpg в качестве промежуточного формата, и это сработало (ПРИМЕЧАНИЕ: это опасный пример, -qscale 0 перекодирует видео ...)

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
11 голосов
/ 14 октября 2014

Подробную документацию по различным способам объединения в ffmpeg можно найти здесь .

Вы можете использовать 'Concat filter' для быстрой конкатенации.

Выполняет перекодирование.Этот вариант лучше всего подходит, когда входы имеют разные видео / аудио форматы.

Для объединения 2 файлов:

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

Для объединения 3 файлов:

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

Это работает для одинаковых, а также для нескольких типов входных файлов.

6 голосов
/ 08 февраля 2017

Основываясь на ответах rogerdpack и Ed999, я создал .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

объединяет все *.mp4 файлы в текущей папке в joined-out.mp4

проверено на Mac.

Полученный размер файла - это точная сумма моих 60 проверенных файлов. Не должно быть никаких потерь. Как раз то, что мне нужно

4 голосов
/ 22 августа 2018

Из документации, приведенной здесь: https://trac.ffmpeg.org/wiki/Concatenate

Если у вас есть файлы MP4, они могут быть без потерь объединены путем первого их перекодирования в транспортные потоки MPEG-2.С видео H.264 и аудио AAC может использоваться следующее:

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

Этот подход работает на всех платформах.

Мне нужна была возможность инкапсулировать это в кросссценарий платформы, поэтому я использовал fluent-ffmpeg и предложил следующее решение:

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!')
)
3 голосов
/ 12 ноября 2018

Я обнаружил, что оператор pipe не работает для меня, когда я использовал вариант 3 для объединения нескольких MP4 на Mac в принятом ответе.

Следующая однострочная программа работает на Mac (High Sierra) для объединения mp4s без создания промежуточного файла.

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

...