FFmpeg 9.1 AAC 编码器重写

FFmpeg 9.1 AAC 编码器重写

FFmpeg 9.1 引入了一个完全重写的原生 AAC 编码器,旨在取代之前表现欠佳的原生实现。新编码器在各种比特率下都能实现卓越的音频质量,在 Google 的 Zimtohrli 和 ViSQOL 等指标上优于 fdk-aac 和 Apple 的 qaac

技术架构与优化

新编码器是对码率控制、率失真优化 (RDO) 以及所有核心编码工具的彻底重写。关键技术改进包括:

  • 全 RDO 集成:所有编码工具——包括感知噪声替换 (PNS)、时间噪声整形 (TNS)、强度立体声 (I/S) 和中/侧 (M/S) 编码——都已集成到 RDO 循环中。编码器避免了任意的比特率截断或启发式算法,而是利用工具在给定的比特预算内提供最佳质量。
  • 感知优化:与一些依赖简单频带能量曲线的竞争对手不同,新编码器使用掩蔽频带能量进行 RDO,以便更好地将比特分配给可听频率。
  • 严格的 CBR 实现:编码器针对恒定比特率 (CBR) 进行了优化,因为固定的比特预算目标可以显著提高编码效率。开发者建议不要使用 -q:a (实际的 VBR 模式)。
  • 战略性频带置零:编码器通过将掩蔽频带置零或使用 PNS 进行处理,特意在频谱图中留下“空隙”。这种设计选择优先考虑可听频带的高质量编码,而不是试图对所有频带进行低质量编码。

性能基准测试

根据开发者所言,在 Zimtohrli 和 ViSQOL 指标下(其中 Zim 值越低、ViS 值越高越好),新编码器(特别是 nmr 编码器)在大多数比特率下都优于 fdk-aac 和 Apple 的编码器。

Bitrate (kbps) 8.1 fast 8.1 twoloop nmr fdk-aac apple libopus
64 0.01315 / 2.65 0.00696 / 3.24 0.00309 / 3.83 0.00322 / 3.69 0.00612 / 3.29 0.00100 / 4.59
96 0.00338 / 3.77 0.00268 / 3.99 0.00134 / 4.04 0.00153 / 3.98 0.00175 / 3.87 0.00039 / 4.62
128 0.00229 / 4.10 0.00170 / 4.28 0.00072 / 4.47 0.00143 / 4.27 0.00081 / 4.44 0.00020 / 4.68
160 0.00129 / 4.30 0.00108 / 4.44 0.00051 / 4.56 0.00065 / 4.31 0.00117 / 4.51 0.00084 / 4.68
256 0.00105 / 4.41 0.00121 / 4.55 0.00031 / 4.61 0.00103 / 4.45 0.00067 / 4.63 0.00002 / 4.73

注:列出了 Zim/ViS 值。Opus 仍然是整体表现最好的编码器。

使用指南与限制

为了在使用新编码器时获得最佳效果,用户应遵循以下特定配置:

  • 采样率:编码器主要针对 48kHz 音频进行了优化。虽然支持 44.1kHz 和 96kHz,但建议使用 48kHz 以获得最高质量。
  • 混音 (Downmixing):如果预期输出将进行混音,用户应使用 -aac_is 0 -aac_pns 0 以保留原始信号的相位。
  • 带宽截断:开发者建议使用 -cutoff 标志将 128kbps 下的带宽降低至 16kHz,并将 160kbps+ 下的带宽降低至 18kHz。

社区反馈与已知问题

HydrogenAudio 上的早期用户测试突出了以下几个值得关注的点:

  • 总体质量:用户报告在 134kbps 和 200kbps 下有“极佳的听感”,并指出这比旧的原生编码器产生的“啁啾”伪影明显改善。
  • TNS 滴答声:一名用户报告在高比特率 (192kbps) 下出现了“滴答声”,当禁用 TNS 时 (-aac_tns 0),该声音消失了。开发者建议这可能是由于 libavcodec/aacenc_tns.c 中过于激进的 TNS 设置导致的。
  • 低比特率下的立体声像:在 64kbps 立体声模式下,一些用户发现新编码器比旧编码器更显“模糊”或“金属感”,尽管开发者指出 64kbps 通常对于高质量的立体声 AAC 来说比特率过低。

命令行示例

对于正在转向使用新编码器用户,建议使用以下命令:

# Standard high-quality encode
ffmpeg -i input.flac -map 0:0 -c:a aac -b:a 128000 output.m4a

# Encode while disabling Intensity Stereo to maintain phase
ffmpeg -i input.flac -map 0:0 -c:a aac -aac_is 0 -b:a 128000 output.m4a

# Encode while disabling PNS to maintain phase
ffmpeg -i input.flac -map 0:0 -c:a aac -aac_pns 0 -b:a 128000 output.m4a

Sources