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, и мне все еще не удалось сохранить продолжительность.

Вот полный вывод ffprobe

Вот оригинальный (красный) и сегмент (зеленый)

Подробные файлы примеров

Я записал образец видео, добавил команды, чтобы расколоть его, а затем конкатентно. 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/^/+/')