从 DV 转码(解复用)时,FFMPEG 音频不同步

Woj*_*ech 3 audio video sync ffmpeg dv

几个月来我一直被这个问题困扰。我有 50 多盘 DV 磁带(来自和旧的 Sony 摄像机)要转换为更现代、更可用的格式(很可能是 H264)。我已经开始使用 DVGRAB 将文件拉到我的电脑(通过火线)。在那里我有两个选择:从 dv 磁带中提取 RAW 数据,生成一个多路复用文件,或者将其解复用并保存到 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
Run Code Online (Sandbox Code Playgroud)

这个特殊的相差 1.448 秒。正如我所说,差异很大。

至于解决办法。我可以拉伸音频并将其与视频结合(我已经测试过),但我不能确定音频是否会在录音中间的某个地方同步。

我想我已经确定了这种行为的根源。每当我打开或关闭相机(至开始和停止录制)时,视频的启动速度都会比音频快一点。因此,磁带上的“片段”越多,这些差异加起来就越大。

我怎样才能解决这个问题?有没有办法用时间戳解复用音频和视频,以便转换后它们能正确加起来?或者无论如何要填补音频中的这些空白,以便两个流开始时的大小相同?

Gya*_*yan 11

以下是解决此问题的三种通配符尝试:

方法 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
Run Code Online (Sandbox Code Playgroud)

方法 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
Run Code Online (Sandbox Code Playgroud)

方法 2与虚拟音频合并

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
Run Code Online (Sandbox Code Playgroud)

方法三结合以上

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
Run Code Online (Sandbox Code Playgroud)

您可以通过插入-t N例如-t 2020 秒的测试,在短时间内测试它们中的每一个。

如果它们中的任何一个工作,我们就可以继续将输出包装为 MP4。


Woj*_*ech 1

我终于解决了这个问题——虽然有点矫枉过正,但确实有效。

我意识到,如果我将 .dv 复制到任何其他容器,音频和视频显然不同步。然后我想将该文件从第 51 分钟开始剪切为 1 分钟片段(-ss 51:00 -t 60),它显然仍然不同步。

然而,当我在原始 .dv 上使用相同的剪辑(-ss 51:00 -t 60)时,它是同步的!所以我最终做的是编写一个脚本,每秒将 .dv 文件切成 1 秒的片段,并将其保存到单独的文件中(是​​的,每个 .dv 超过 3600 个文件)。无需编码,只需将副本流式传输到新容器 (avi)。然后我使用 -f concat 将这些小文件放入一个 avi 文件中,现在就同步了!任何间隙都听不见!剩下的就是将 H264 和 AAC 编码为 MP4。

我在我的家庭服务器上运行了这个脚本,花了几天时间处理 50 个 .dv 文件,但现在它已经完成了!

谢谢大家的帮助!我总体上了解了很多有关 ffmpeg 和 a/v 的知识。