FFmpeg concat видео и аудио не синхронизированы
Объединение нескольких файлов с помощью ffmpeg concat, похоже, приводит к несоответствию временных меток или смещений для аудио. Я пробовал несколько видеороликов и заметил ту же проблему для h.264/MP4.
Использование concat
и кодирование видео, кажется, работают нормально. Звук остается в синхронизации, так как ffmpeg выполняет вычисления полного преобразования и, кажется, все правильно.
Однако просто конкатенация видео без каких-либо преобразований или кодирования приводит к медленно растущей проблеме синхронизации. Очевидно, что кодирование видео, а не просто присоединение к ним приведет к потере информации/качества, поэтому я бы скорее нашел способ решить эту проблему.
Я пробовал несколько флагов, чтобы решить эту проблему, которая, как представляется, основана на отметках времени. Однако ничто из этого не позволяет устранить проблему.
ffmpeg -f concat -fflags +genpts -async 1 -i segments.txt test.mov
ffmpeg -auto_convert 1 -f concat -fflags +genpts -async 1 -i segments.txt -c copy test2.mov
ffmpeg -f concat -i segments.txt -c copy -fflags +genpts test3.mp4
ffmpeg -f concat -fflags +genpts -async 1 -i segments.txt -copyts test4.mov
ffmpeg -f concat -i segments.txt -copyts test5.mov
ffmpeg -f concat -i segments.txt -copyts -c copy test6.mov
ffmpeg -f concat -fflags +genpts -i segments.txt -copyts -c copy test7.mov
Примечание. Все остальные вопросы, которые я мог бы найти на SO, похоже, "исправить" проблему, просто заново закодировав видео. Нехорошее решение.
Update
Я понял, что конкат не был проблемой. Исходный набор клипов имел неверные временные метки. Каким-то образом concat + encoding исправил проблему, но я не хочу, чтобы каждый раз повторно кодировал видео и терял качество.
ffmpeg -y -ss 00:00:02.750 -i input.MOV -c copy -t 00:00:05.880 output.MOV
Это привело к следующим данным
ffprobe -v quiet -show_entries stream=start_time,duration output.MOV
start_time=-0.247500
duration=6.131125
start_time=-0.257333
duration=6.155333
С тех пор я попытался использовать -to
m и -t
в разных местах вместе с -af apad -c:v copy
, и мне все еще не удалось сохранить продолжительность.
Подробные файлы примеров
Я записал образец видео, добавил команды, чтобы расколоть его, а затем конкатентно. http://davidpennington.me/share/audio_sync_test_video.zip
Ответы
Ответ 1
Этот двухэтапный процесс должен работать
Шаг 1 Разложите звук в каждом сегменте
ffmpeg -i segment1.mov -af apad -c:v copy <audio encoding params> -shortest -avoid_negative_ts make_zero -fflags +genpts padded1.mov
или
Создание сегментов с синхронизированными потоками
ffmpeg -y -ss 00:00:02.750 -i input.MOV -c copy -t 00:00:05.880 -avoid_negative_ts make_zero -fflags +genpts segment.MOV
Шаг 2 Конкат
ffmpeg -f concat -i segments.txt -c copy test.mov
где segments.txt
состоит из имен дополненных файлов.
Ответ 2
Я тоже долгое время боролся с этим. Особенно при работе с файлами MTS от Panasonic, созданных AVCHD. Мое текущее решение - объединить их на уровне ОС, а не ffmpeg. Я делаю это на окнах, и это выглядит примерно так:
COPY /b input_1.mts + input_2.mts + input_3.mts output.mts
В linux должно быть что-то вроде:
$ cat input_1.mts input_2.mts input_3.mts > output.mts
Вы можете найти документацию для windows и linux двоичная конкатенация.
Этот метод конкатенации, который используется для транскодирования, - это способ пойти, если исходный формат будет работать для вас. Этот метод практически не использует процессорную обработку и сохраняет исходное качество. Беспроигрышный при работе с крупными СМИ высокого качества.
Ответ 3
вы можете использовать filter_complex
для согласования разных параметров за один раз
fmpeg -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]" <encoding options> output.mkv
Ответ 4
Если входные видео были закодированы с одинаковыми настройками, вы можете использовать mkvmerge
вместо mkvtoolnix:
mkvmerge -o output.mkv file1.mkv + file2.mkv + file3.mkv
Мне нужно было конкатенировать видео из разных источников, которые были закодированы с разными настройками, поэтому я использовал такую команду, чтобы сначала изменить размер и перекодировать входные видео:
for f in *.mp4;do width=1280;height=720;ffmpeg -i $f -filter:v "scale=iw*min($width/iw\,$height/ih):ih*min($width/iw\,$height/ih), pad=$width:$height:($width-iw*min($width/iw\,$height/ih))/2:($height-ih*min($width/iw\,$height/ih))/2" -c:v libx264 -crf 22 -preset slow -pix_fmt yuv420p -c:a libfdk_aac -vbr 3 -ac 2 -ar 44100 ${f%mp4}mkv;done
В некоторых видео не было аудиоканала, поэтому мне пришлось использовать такую команду, чтобы добавить к ним тихий аудиоканал:
for f in *.mkv;do ffprobe $f|&grep -q '1: Audio'||{ ffmpeg -i $f -f lavfi -i anullsrc -c:a libfdk_aac -shortest -c:v copy temp-$f;mv temp-$f $f; };done
Затем я конкатенировал видео, используя следующую команду:
mkvmerge -o output.mkv $(printf %s\\n *.mkv|sed '1!s/^/+/')