这个问题困扰了我好几个月。我有 50 多盘 DV 磁带(来自一台老款索尼摄像机)需要转换成更现代、更易用的格式(最有可能是 H264)。我先使用 DVGRAB 将文件拉到我的 PC(通过火线)。我有两个选择:从 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
这个具体值相差 1.448 秒。正如我所说,差异很大。
至于解决方案。我可以拉伸音频并将其与视频合并(我已经测试过了),但我不能确定音频是否会在录制过程中同步。
我认为我已经找到这种现象的根源。每当我打开或关闭相机(开始和停止录制)时,视频的启动速度都会比音频快一点点。因此,磁带上的“碎片”越多,这些差异就越大。
我该如何解决这个问题?有没有办法用时间戳对音频和视频进行解复用,以便在转换后它们能够正确相加?或者有没有办法填补音频中的这些空白,以便两个流一开始的大小相同?
答案1
以下是解决这个问题的三种通配符尝试:
方法 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与虚拟音频合并
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以上内容的组合
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。
答案2
我终于解决了这个问题——虽然有点过度,但确实有效。
我意识到,如果我将 .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 的知识。
答案3
我有一个类似的设置,但存在同样的音频不同步问题。我还设法重现了一个音频不同步的剪辑。如果有人想要样本,请询问。
我可能已经找到了解决这个问题的方法。基诺是一款非常老旧且不再维护的软件,它能够从 dvgrab(原始)加载 .dv 并再次导出为 .dv 或 dv1/avi(或 dv2/avi)文件,并对音频进行“重新采样”。那么,输出是更正文件将在“ffmpeg”转码之前和之后很好地同步。
有一些缺点。Kino 可能会停止工作,甚至完全无法工作,因为它太旧了。我刚刚从“aur”(Arch linux)安装了它,我可以直接使用它。没有命令行界面。我找不到自动化的方法。
编辑:
可能还有其他解决方案。我认为问题在于流的开始和停止位不知何故被破坏了,时间码变得更糟。我有一些剪辑的日期似乎是“2068 年”。无论如何,每次它认为有新的记录流时,您都可以再次使用“dvgrab”来分割剪辑:
dvgrab -I input -size 0 -a -format=raw -showstatus -srt -t output
'-a' 执行自动拆分,'-srt' 和 '-t' 帮助跟踪文件(分别使用日期构建 srt 并将日期附加到文件)。这将为每个新文件创建一个新文件溪流。由于每个流的开头都是同步的,因此您可以单独使用“ffmpeg”处理它们。似乎每个文件都包含原始“会话”的时间码(dvgrab 称之为),因此,如果您直接使用 ffmpeg 连接所有文件,您仍然会得到不同步的结果。
答案4
我修复了 50 个 DV 文件,并可以使用以下 bash 脚本纠正 Linux 中的同步问题:
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)。