使用视频的 ffmpeg 重新编码并将音频从 eac3 更改为 aac 后,音频不同步

oct*_*cto 7 audio sync delay ffmpeg aac

最近我使用 ffmpeg 进行了重新编码,在此过程中遇到了听不见但波形可见的音频不同步。

MKV文件和音频流的来源信息:

Mediainfo 显示相对于视频有6 毫秒的音频延迟:

Audio
ID                             : 2
Format                         : E-AC-3
Format/Info                    : Enhanced Audio Coding 3
Format settings, Endianness    : Big
Codec ID                       : A_EAC3
Duration                       : 1 h 0 min
Bit rate mode                  : Constant
Bit rate                       : 640 kb/s
Channel(s)                     : 6 channels
Channel positions              : Front: L C R, Side: L R, LFE
Sampling rate                  : 48.0 kHz
Frame rate                     : 187.500 FPS (256 SPF)
Compression mode               : Lossy
Delay relative to video        : 6 ms
Stream size                    : 276 MiB (7%)
Language                       : English
Service kind                   : Complete Main
Default                        : Yes
Forced                         : No
Run Code Online (Sandbox Code Playgroud)

这也可以通过查看 pts 和流开始时间来看出:

ffprobe -of compact -select_streams a:0 -show_frames -show_entries frame=pkt_pts,pkt_pts_time,pkt_dts,pkt_dts_time,best_effort_timestamp_time,pkt_duration,nb_samples %sourcemkv%

frame|pkt_pts=6|pkt_pts_time=0.006000|pkt_dts=6|pkt_dts_time=0.006000|best_effort_timestamp_time=0.006000|pkt_duration=32|nb_samples=1536

frame|pkt_pts=38|pkt_pts_time=0.038000|pkt_dts=38|pkt_dts_time=0.038000|best_effort_timestamp_time=0.038000|pkt_duration=32|nb_samples=1536

frame|pkt_pts=70|pkt_pts_time=0.070000|pkt_dts=70|pkt_dts_time=0.070000|best_effort_timestamp_time=0.070000|pkt_duration=32|nb_samples=1536
Run Code Online (Sandbox Code Playgroud)

此外,延迟是通过流start_time检查来检测的:

ffprobe -show_entries stream=codec_type,duration,start_time -of compact %sourcemkv%

stream|codec_type=video|start_time=0.000000|duration=N/A
stream|codec_type=audio|start_time=0.006000|duration=N/A
stream|codec_type=subtitle|start_time=0.000000|duration=3617.638000
Run Code Online (Sandbox Code Playgroud)

重新编码过程

我选择仅使用这些标志(无时间戳操作)将 EAC3 转码为 AAC 并缩混为立体声:-acodec aac -b:a 160k -ac 2

我获得延迟结果的一种方法是使用以下命令重新编码:ffmpeg -i %sourcemkv% -vcodec libx264 -profile:v high -crf 23 -tune film -level 4.1 -acodec aac -b:a 160k -ac 2 re-encoded-with-aac.mkv

检测延迟

我通过检查与视频帧相对应的波形来检测延迟。延迟本身不太明显,因为我发现编码版本比原始版本晚了 15.333 毫秒,但根据通过 AvsPmod 中的以下 AviSynth+ 脚本进行的检查,它是存在的:

FFmpegSource2("re-encoded-with-aac.mkv", vtrack=-1, atrack=-1, cache=True, cachefile="", fpsnum=-1, fpsden=1, threads=-1, timecodes="", seekmode=1, overwrite=False, width=-1, height=-1, resizer="BICUBIC", colorspace="", rffmode=0, adjustdelay=-1, utf8=False, varprefix="")
ConvertToMono()
# Test if DelayAudio will sync it!
#AmplifydB(50.0)
#DelayAudio(-0.015333)
waveform( window=1, height=0.6)
Run Code Online (Sandbox Code Playgroud)

我将相同的脚本应用于原始脚本,并比较了某些视频帧的结果波形图:第139 帧的源 mkv 图第 139 帧的 AAC 重新编码视频波形视图 可以看出,除非将 aDelayAudio(-0.015333)应用于重新编码AAC 音频流 - 它们不同步。值得庆幸的是,这种延迟在整个视频中始终存在!

重新编码的其他信息

重新混合的音频流具有start_time=0.000000第一个音频帧的 pts 0.000000。有点奇怪的是,尽管据报道原始音频相对于视频的已知延迟为 6 毫秒,但原始视频和使用 aac 流重新编码的视频之间的最终延迟为 0.5 毫秒15.333ms。我不知道这可能从何而来;也许它与输出音频帧的长度有关,每个音频帧的持续时间为21.333ms?!

问题

  • 从 EAC3 转码到 AAC 时,这是 ffmpeg 的错误吗?
  • 我是否误用了 ffmpeg 或者对它期望过高以正确地重新编码?
  • 是否需要指定一些额外的 ffmpeg 参数才能同步?
  • 除了目视检查帧波形以确定可能发生的任意延迟之外,处理此类情况的最佳解决方案是什么?
  • 原始音频流的 6 毫秒延迟是否会导致重新编码时出现所有这些问题?

其他努力

我还尝试了以下实验:

实验1

  • 在 gMKVExtractGUI 中打开%sourcemkv%。检测到 EAC3 音频流中的 6ms 延迟。提取此音频流。
  • 将 mkvtoolnix-gui 中重新编码的视频流与原始 EAC3 音频重新混合,并在 Delay 字段中明确指定 6ms 延迟。

结果:通过上述检查方法判断,音频与原始音频同步。

实验2

  • 通过FFmpeg将原始音频转换为2通道AAC
  • 在 mkvtoolnix-gui 中将生成的 AAC 音频流与视频重新混合,并为其指定 6 毫秒的延迟 - 就像原始版本一样。

结果:原始和结果之间的音频不同步

oct*_*cto 0

根据 Eugen 的回答,我在这个 VideoHelp 论坛线程上搜索并找到了有关编解码器相关静音(即编码开始时生成的延迟)的更多信息。然后我偶然发现了 Apple 的 QAAC 编码器及其允许修剪编码器特定延迟的选项之一,也在有关延迟的 VideoHelp 线程上建议:

--no-delay             Compensate encoder delay by prepending 960 samples
                       of scilence, then trimming 3 AAC frames from
                       the beginning (and also tweak iTunSMPB).
                       This option is mainly intended for resolving
                       A/V sync issue of video.
Run Code Online (Sandbox Code Playgroud)

通过使用上述选项,我成功实现了使音频与原始音频保持同步的目标,我将在下面进行描述。我决定将此作为一个问题发布,因为主要问题是是否有一种方法可以缩混为 AAC,同时保持音频与源完美同步,我已经找到了一种方法来做到这一点。

脚步:

AAC 缩混提取:

ffmpeg -i %sourcemkv% -vn -ac 2 -acodec pcm_f32le -f wav - | qaac -v 160 --delay 0.006 --no-delay - -o outw6ms.m4a
Run Code Online (Sandbox Code Playgroud)

该命令执行以下操作:

  • 读取原始 mkv 的 EAC3 音频流并使用以下方法将其缩混为立体声-ac 2
  • 它将其解码为浮点 PCM ( pcm_f32le) - 这是必要的,以便缩混保留原始流的响度
  • 将输出传送到 qaac 编码器
  • qaac 编码器具有--no-delay可以减少编码器特定延迟的标志
  • 我还添加了-delay 0.006烘焙 6 毫秒静音的选项,因为原始版本相对于视频有一定的延迟(我可以忽略这一点,而是在 mkvmerge 中重新混合结果,并在那里明确指定音频流需要 6 毫秒延迟 - 我测试过这也可以工作)

然后,我直接在 ffmpeg 中将生成的音频与转码后的视频重新混合:

ffmpeg -i encvideo.mkv -i outw6ms.m4a -codec copy -map 0:v -map 1:a result.mkv
Run Code Online (Sandbox Code Playgroud)

我在 AvsPMod 中尝试了结果waveform(),音频从开始到结束都与源完美同步。

所以最后我找到了一种保持原始音频相对于视频同步的方法。我会再等一段时间,直到接受这个答案,因为我想知道 ffmpeg 中可用的音频编码器是否允许这种具有此选项的行为。这似乎非常有用,并且是专门为此类事情而设计的。qaac--no-delay