Как объединить два файла MP4 с помощью FFmpeg?
Я пытаюсь объединить два файла mp4 с помощью ffmpeg. Мне нужно, чтобы это был автоматический процесс, поэтому я выбрал ffmpeg. Я конвертирую эти два файла .файлы 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 файлы вместе и заставить его работать.
13 ответов:
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
для 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
этот метод не работает для многих форматов, в том числе MP4, из-за природы этих форматов и упрощенного конкатенация выполняется этим методом.
какой из них использовать
concat filter: используйте, если ваши входные данные не имеют одинаковых параметров (ширина, высота и т. д.), Или не являются одинаковыми форматами/кодеками, или если вы хотите выполнить какую-либо фильтрацию. (Вы можете перекодировать только те входы, которые не совпадают, поэтому они используют один и тот же кодек и другие параметры, а затем использовать демуксер concat, чтобы избежать перекодирования другого входной.)
concat demuxer: используйте, когда вы хотите избежать повторного кодирования и формата не поддерживает конкатенацию на уровне файлов (большинство файлов, используемых обычными пользователями, не поддерживают конкатенацию на уровне файлов).
протоколом функция concat: используйте с форматами, которые поддерживают конкатенацию на уровне файлов (MPEG-1, MPEG-2 PS, DV). Не используйте с MP4.
если вы сомневаетесь, попробуйте конкат демультиплексора.
см. Также
вот быстрый (занимает менее 1 минуты) и без потерь способ сделать это без необходимости промежуточных файлов: -
ls Movie_Part_1.mp4 Movie_Part_2.mp4 | perl -ne 'print "file $_"' | ffmpeg -f concat -i - -c copy Movie_Joined.mp4
"ls" содержит файлы для присоединения Этот "перл" создает файл конкатенации на лету в трубу Часть "- i - " говорит ffmpeg читать из трубы
(Примечание-мои файлы не имели пробелов или странных вещей в них - вам понадобится соответствующая оболочка-экранирование, если вы хотите сделать эту идею с "жесткими" файлами).
в итоге я использовал 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
для файлов 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
результат: выход будет вести себя как первый файл ( а не второй)
Я пытался объединить три
.mp3
аудиофайлы в один.m4a
file и эта команда 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 означает использование функции Media concatenate (присоединение).
n означает подтверждение общего количества входных файлов.
v означает есть видео? используйте 0 = Нет видео, 1 = содержит видео.
a означает аудио? используйте 0 = Нет звука, 1 = содержит звук.
- f означает принудительно установить формат файла (чтобы увидеть все поддерживаемые форматы, используйтеffmpeg -formats
)
- vn означает отключить видео (а также-an
отключил бы звук, если бы не хотел)
- y означает перезапись выходных файлов (если выходной файл уже существует).для получения дополнительной информации: используйте
ffmpeg -h full
печать всех параметров (включая все параметры формата и кодека, очень длинные)
ДЛЯ ФАЙЛОВ 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 файлы для присоединения. Затем запустите пакетный файл. Это, как правило, занимает менее десяти секунд, чтобы запустить.
подробная документация по различным способам конкатенации в 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
это работает для одной а также нескольких типов входных файлов.
вот сценарий, который я сделал, чтобы объединить несколько GoPro mp4 в 720p mp4. Надеюсь, это поможет.
#!/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}
основываясь на ответах 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 проверенных файлов. Не должно быть никаких потерь. Только то, что мне нужно
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
объединение всех файлов mp4 из текущего каталога
мне лично нравится не создавать внешний файл, который я должен удалить впоследствии, поэтому мое решение было следующим, которое включает в себя список нумерации файлов (например,
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
это сработало для меня (на windows)
ffmpeg -i "concat:input1|input2" -codec copy output
в частности
ffmpeg -i "concat:01.mp4|02.mp4" -codec copy output.mp4
Python
используя некоторый код python, чтобы сделать это с таким количеством mp4 есть в папке импорт Глоб импорт ОС
stringa = "" for f in glob.glob("*.mp4"): stringa += f + "|" os.system("ffmpeg -i \"concat:" + stringa + "\" -codec copy output.mp4")
из документации здесь: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!') )