FFMPEG аудио не синхронизирован при транскодировании (демультиплексировании) с DV
Я застрял с этой проблемой в течение нескольких месяцев. У меня есть более 50 DV-кассет (от старой видеокамеры Sony), которые необходимо преобразовать в более современный и удобный формат (скорее всего, H264). Я начал с вытягивания файлов на свой компьютер (через FireWire), используя DVGRAB. Там у меня было два варианта: извлечение RAW-данных с DVD-ленты, в результате чего был получен мультиплексированный файл ИЛИ демультиплексировать его и сохранить в DVI-файл.
Вот где начались проблемы. Сохранение его в файл DVI привело к нарушению синхронизации звука. Я подумал, что это проблема с DVGRAB, поэтому я сохранил файлы RAW (которые синхронизируются правильно) и хотел обработать их с помощью ffmpeg.
Оказывается, что независимо от того, как я это делюкс, звук всегда не синхронизирован. ДО того, как вы скажете что-нибудь о частоте дискретизации - аудио различия имеют абсолютно случайную длину. Часовая лента может иметь задержку звука от 0,1 до 4 секунд в конце.
Вот пример файла, который я разделил на отдельные аудио и видео файлы, чтобы проверить различия.
# ffprobe -i ./video_conversion/13.dv
ffprobe version 2.8.4 Copyright (c) 2007-2015 the FFmpeg developers
built with gcc 5.3.0 (GCC)
configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-avisynth --enable-avresample --enable-fontconfig --enable-gnutls --enable-gpl --enable-ladspa --enable-libass --enable-libbluray --enable-libdcadec --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-shared --enable-version3 --enable-x11grab
libavutil 54. 31.100 / 54. 31.100
libavcodec 56. 60.100 / 56. 60.100
libavformat 56. 40.101 / 56. 40.101
libavdevice 56. 4.100 / 56. 4.100
libavfilter 5. 40.101 / 5. 40.101
libavresample 2. 1. 0 / 2. 1. 0
libswscale 3. 1.101 / 3. 1.101
libswresample 1. 2.101 / 1. 2.101
libpostproc 53. 3.100 / 53. 3.100
[dv @ 0x864f2a0] Detected timecode is invalid
[dv @ 0x864f2a0] Estimating duration from bitrate, this may be inaccurate
Input #0, dv, from './video_conversion/13.dv':
Duration: 01:00:45.80, start: 0.000000, bitrate: 28800 kb/s
Stream #0:0: Video: dvvideo, yuv420p, 720x576 [SAR 16:15 DAR 4:3], 28800 kb/s, 25 fps, 25 tbr, 25 tbn, 25 tbc
Stream #0:1: Audio: pcm_s16le, 48000 Hz, stereo, s16, 1536 kb/s
# ffprobe -i ./video_conversion/tmp/13.mp4
ffprobe version 2.8.4 Copyright (c) 2007-2015 the FFmpeg developers
built with gcc 5.3.0 (GCC)
configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-avisynth --enable-avresample --enable-fontconfig --enable-gnutls --enable-gpl --enable-ladspa --enable-libass --enable-libbluray --enable-libdcadec --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-shared --enable-version3 --enable-x11grab
libavutil 54. 31.100 / 54. 31.100
libavcodec 56. 60.100 / 56. 60.100
libavformat 56. 40.101 / 56. 40.101
libavdevice 56. 4.100 / 56. 4.100
libavfilter 5. 40.101 / 5. 40.101
libavresample 2. 1. 0 / 2. 1. 0
libswscale 3. 1.101 / 3. 1.101
libswresample 1. 2.101 / 1. 2.101
libpostproc 53. 3.100 / 53. 3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from './video_conversion/tmp/13.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf56.40.101
Duration: 01:00:45.80, start: 0.000000, bitrate: 5685 kb/s
Stream #0:0(und): Video: h264 (Main) (avc1 / 0x31637661), yuv420p, 720x576 [SAR 16:15 DAR 4:3], 5683 kb/s, 25 fps, 25 tbr, 12800 tbn, 50 tbc (default)
Metadata:
handler_name : VideoHandler
# ffprobe -i ./video_conversion/tmp/13.mp3
ffprobe version 2.8.4 Copyright (c) 2007-2015 the FFmpeg developers
built with gcc 5.3.0 (GCC)
configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-avisynth --enable-avresample --enable-fontconfig --enable-gnutls --enable-gpl --enable-ladspa --enable-libass --enable-libbluray --enable-libdcadec --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-libschroedinger --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-shared --enable-version3 --enable-x11grab
libavutil 54. 31.100 / 54. 31.100
libavcodec 56. 60.100 / 56. 60.100
libavformat 56. 40.101 / 56. 40.101
libavdevice 56. 4.100 / 56. 4.100
libavfilter 5. 40.101 / 5. 40.101
libavresample 2. 1. 0 / 2. 1. 0
libswscale 3. 1.101 / 3. 1.101
libswresample 1. 2.101 / 1. 2.101
libpostproc 53. 3.100 / 53. 3.100
[mp3 @ 0x954c2a0] Skipping 0 bytes of junk at 237.
Input #0, mp3, from './video_conversion/tmp/13.mp3':
Metadata:
encoder : Lavf56.40.101
Duration: 01:00:44.35, start: 0.023021, bitrate: 128 kb/s
Stream #0:0: Audio: mp3, 48000 Hz, stereo, s16p, 128 kb/s
Metadata:
encoder : Lavc56.60
Этот конкретный отличается на 1,448 секунды. Как я уже сказал, различия сильно различаются.
Что касается решения. Я мог бы просто растянуть звук и объединить его с видео (я это проверял), но я не уверен, будет ли звук синхронизирован где-то в середине записи.
Я думаю, что я точно определил источник этого поведения. Всякий раз, когда я включаю или выключаю камеру (например, чтобы начать и остановить запись), видео начинается чуть-чуть быстрее, чем звук. Таким образом, чем больше "фрагментов" на ленте, тем больше эти различия складываются.
Как я могу это исправить? Есть ли способ демультиплексировать аудио и видео с метками времени, чтобы после конвертации они правильно сложились? Или в любом случае заполнить эти пробелы в аудио, чтобы оба потока были одинакового размера для начала?
4 ответа
Я наконец решил проблему - это излишество, но оно работает.
Я понял, что если я скопирую.dv в любой другой контейнер, аудио и видео явно не синхронизированы. Затем я хотел сократить этот файл до 1-минутного сегмента, начиная с 51-й минуты (-ss 51:00 -t 60), он, очевидно, все еще не синхронизирован.
Однако, когда я использовал тот же вырез (-ss 51:00 -t 60) на оригинальном.dv, он был синхронизирован! В итоге я написал скрипт, который каждую секунду разрезал файл.dv на 1-секундный сегмент и сохранял его в отдельных файлах (да, более 3600 файлов на.dv). Нет кодировки, просто потоковое копирование в новый контейнер (avi). Затем я использовал -f concat, чтобы поместить крошечные файлы в один avi-файл, который теперь был синхронизирован! Любые пробелы не слышны! Осталось только кодировать H264 и AAC в MP4.
Я запустил скрипт на своем домашнем сервере, который пару дней перемалывал 50 файлов.dv, но теперь все готово!
СПАСИБО ВСЕМ ЗА ПОМОЩЬ! Я многое узнал о ffmpeg и a/v в целом.
Вот три подстановочных знака решения этой проблемы:
Метод 1a Используйте системное время в качестве меток времени
ffmpeg -use_wallclock_as_timestamps 1 -i input.dv \
-c:v libx264 -b:v 4000k -c:a aac -b:a 128k -fflags +genpts method1.ts
Метод 1b Используйте ресэмплер с установленным флагом, чтобы ввести молчание, когда временные метки входного аудио имеют пробелы
ffmpeg -i input.dv -c:v libx264 -b:v 4000k \
-af "aresample=async=1:first_pts=0" -c:a aac -b:a 128k -fflags +genpts method1.ts
Метод 2 из 3: Слияние с фиктивным звуком
ffmpeg -i input.dv -f lavfi -i "aevalsrc=0:c=2:s=48000" \
-filter_complex "[0:a][1:a]amerge[a]" -map 0:v -map "[a]" -c:v libx264 -b:v 4000k -c:a aac -b:a 128k -ac 2 -shortest method2.ts
Метод 3 из 3: Сочетание вышеперечисленного
ffmpeg -use_wallclock_as_timestamps 1 -i input.dv -f lavfi -use_wallclock_as_timestamps 1 -i "aevalsrc=0:c=2:s=48000" \
-filter_complex "[0:a][1:a]amerge[a]" -map 0:v -map "[a]" -c:v libx264 -b:v 4000k -c:a aac -b:a 128k -ac 2 -shortest method3.ts
Вы можете проверить каждый из них на короткое время, вставив -t N
например -t 20
для 20-секундного теста.
Если какой-либо из них сработает, мы можем перейти к переносу вывода как MP4.
У меня есть аналогичная установка с той же проблемой аудио из синхронизации. Мне также удалось воспроизвести клип с несинхронизированным звуком. Если кто-то хочет образцы, пожалуйста, спросите.
Возможно, я нашел решение этой проблемы. Kino - очень старое и более не обслуживаемое программное обеспечение, которое может загружать.dv из dvgrab (raw) и снова экспортировать как файл.dv или dv1/avi (или dv2/avi) с "повторной выборкой" аудио, Что ж, на выходе получается исправленный файл, который будет хорошо синхронизирован до и после транскодирования ffmpeg.
Есть некоторые недостатки. Кино может прекратить работу или даже вообще не работать, так как она старая. Я только что установил его из 'aur' (Arch linux), и я смог использовать его прямо. Нет интерфейса командной строки. Я не мог найти способ автоматизировать это.
РЕДАКТИРОВАТЬ:
Там может быть другое решение. Я думаю, что проблема в том, что начальные и конечные биты потока каким-то образом нарушаются, а временной код ухудшается. У меня есть несколько клипов с датой 2068 года. В любом случае, вы можете снова использовать dvgrab для разделения клипов каждый раз, когда он думает, что есть новый поток записей:
dvgrab -I input -size 0 -a -format=raw -showstatus -srt -t output
'-a' выполняет автоматическое разделение, '-srt' и '-t' помогают отслеживать файлы (создает srt с датами и добавляет дату к файлам соответственно). Это создаст новый файл для каждого нового потока. Поскольку начало каждого потока синхронизировано, вы можете "ffmpeg" их по отдельности. Похоже, что каждый файл содержит временный код исходного "сеанса" (как его называет dvgrab), поэтому, если вы объедините все файлы напрямую с помощью ffmpeg, вы все равно не получите синхронизацию.
Я исправил 50 DV-файлов и смог исправить проблему синхронизации в Linux с помощью следующего bash-скрипта:
SRC="/home/brian/Desktop/audio_shift"
set -f
for FILE in $(find "$SRC" -name *.dv); do
echo "Konvertiere $FILE "
dvgrab -input $FILE -f dv2 -s 0 -t
done
При этом для каждого файла DV в текущей папке создается файл AVI (формат DV2), который можно в дальнейшем конвертировать без каких-либо проблем с синхронизацией звука (например, в MP4).