ffmpeg调整音频音量踩坑

前一阵用Flutter结合ffmpeg做了一个音视频合并功能,记录一下遇到的问题。

合并方法

首先是音视频合并命令:

ffmpeg -i input.mp4 -i input.mp3 -filter_complex "[1:a]adelay=0s:all=1[a1];[a1]amix=inputs=1[amixout]" -map 0:v:0 -map "[amixout]" -c:v copy -c:a aac output.mp4

说明:

  • -i input.mp4:指定输入视频文件。
  • -i input.mp3:指定输入音频文件。
  • -filter_complex "[1:a]adelay=0s:all=1[a1];[a1]amix=inputs=1[amixout]":使用filter_complex选项进行音频处理。首先,将输入音频文件的音频流([1:a])延迟0秒(adelay=0s),并将所有通道(all=1)保存为一个新的音频流([a1])。然后,使用amix滤镜将该新的音频流与输入视频文件的音频流混合为一个新的音频流([amixout])。
  • -map 0:v:0:指定将输入视频文件的第一个视频流映射到输出文件。
  • -map "[amixout]":指定将音频处理后的音频流映射到输出文件。
  • -c:v copy:指定视频流使用原始编码方式进行复制,即不进行重新编码。
  • -c:a aac:指定音频流使用AAC编码进行重新编码。
  • output.mp4:指定输出文件。

音量问题

因为音频文件音量大小不固定,所以同时提供了音量修改的功能。先修改音量,后合并。这块也是遇到问题的地方。一开始使用的命令是:

ffmpeg -i input.mp3 -af loudnorm=i=-16 output.mp3
  • -af loudnorm=:使用af选项应用loudnorm音频滤镜。loudnorm滤镜用于对音频进行自动增益调整,以使其达到指定的目标音量。
  • i=-16:表示目标音量为-16 LUFS。-16是音乐类的推荐值。

LUFS是一种绝对单位,用于表示音频的整体响度或音量感知。它是根据人耳对不同频率范围内的声音感知的平均响度进行计算的。LUFS的值表示音频相对于标准参考音量的增益或衰减。

查看响度的命令参考:

ffmpeg -nostats -i test.mp3 -af "ebur128=peak=true:framelog=verbose" -f null -

结果如下:

[Parsed_ebur128_0 @ 0000021ebcf9a880] Summary:

  Integrated loudness:
    I:         -33.1 LUFS
    Threshold: -43.5 LUFS

  Loudness range:
    LRA:         5.4 LU
    Threshold: -55.1 LUFS
    LRA low:   -38.1 LUFS
    LRA high:  -32.7 LUFS

  True peak:
    Peak:      -14.2 dBFS
  • I :整体响度。
  • LRA :响度范围。
  • True peak:真峰值,简称TP。

但是调整后,发现有些音频处理会出现杂音,或是有些地方声音小了,整体被平均的感觉。其实是这个调节响度的方式比较复杂,只是简单指定响度不能达到良好效果。

响度标准化

首先获取音频数值:

 ffmpeg -i test.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11:print_format=json -f null -

输出结果:

{
        "input_i" : "-33.13",
        "input_tp" : "-14.19",
        "input_lra" : "5.20",
        "input_thresh" : "-43.60",
        "output_i" : "-16.42",
        "output_tp" : "-2.00",
        "output_lra" : "4.90",
        "output_thresh" : "-28.41",
        "normalization_type" : "dynamic",
        "target_offset" : "0.42"
}

然后把上面的参数重新填入loudnorm中:

ffmpeg -i input.mp3 -af "loudnorm=I=-16:measured_I=-33.13:measured_TP=-14.19:measured_LRA=5.20:measured_thresh=-43.6:offset=0.42:print_format=summary" output.mp3

输出结果:

Input Integrated:    -33.1 LUFS
Input True Peak:     -14.2 dBTP
Input LRA:             5.2 LU
Input Threshold:     -43.6 LUFS

Output Integrated:   -15.6 LUFS
Output True Peak:     -2.0 dBTP
Output LRA:            5.5 LU
Output Threshold:    -27.9 LUFS

Normalization Type:   Dynamic
Target Offset:        -0.4 LU

查看音量:

[Parsed_volumedetect_0 @ 00000198003cfe00] n_samples: 2734011
[Parsed_volumedetect_0 @ 00000198003cfe00] mean_volume: -17.9 dB
[Parsed_volumedetect_0 @ 00000198003cfe00] max_volume: -1.5 dB
[Parsed_volumedetect_0 @ 00000198003cfe00] histogram_1db: 6
[Parsed_volumedetect_0 @ 00000198003cfe00] histogram_2db: 512
[Parsed_volumedetect_0 @ 00000198003cfe00] histogram_3db: 1871
[Parsed_volumedetect_0 @ 00000198003cfe00] histogram_4db: 4690

这样处理后,问题音频正常。因为上面用到的是Loudness normalization(响度标准化),就是将各个音频的音量统一调整均衡,如下图右侧。
ffmpeg调整音频音量踩坑_第1张图片

峰值标准化

下面说一下Peak (level) normalization(峰值标准化)方法(上图左侧)。它就是将音频最大(Peak)的地方,调整到特定大小,然后其他音频做相对应的增/减调整。

首先是获取音频的最大音量:

ffmpeg -i input.mp3 -filter_complex volumedetect -c:v copy -f null /dev/null

结果如下:

[Parsed_volumedetect_0 @ 000002422f31d580] n_samples: 2511872
[Parsed_volumedetect_0 @ 000002422f31d580] mean_volume: -35.2 dB
[Parsed_volumedetect_0 @ 000002422f31d580] max_volume: -14.2 dB
[Parsed_volumedetect_0 @ 000002422f31d580] histogram_14db: 3
[Parsed_volumedetect_0 @ 000002422f31d580] histogram_15db: 10
[Parsed_volumedetect_0 @ 000002422f31d580] histogram_16db: 15
[Parsed_volumedetect_0 @ 000002422f31d580] histogram_17db: 67
[Parsed_volumedetect_0 @ 000002422f31d580] histogram_18db: 161
[Parsed_volumedetect_0 @ 000002422f31d580] histogram_19db: 421
[Parsed_volumedetect_0 @ 000002422f31d580] histogram_20db: 1147
[Parsed_volumedetect_0 @ 000002422f31d580] histogram_21db: 3595

最大音量-14.2dB,然后调整dB:

ffmpeg -i input.mp3 -af volume=14dB output.mp3
  • -af volume=14dB:volume滤镜用于对音频进行增益调整,以增加或减少音频的音量。这里表示增加14dB的音量。

dB是一种相对单位,用于表示音频信号的相对强度或功率。在音频领域中,通常使用dB来表示音量的增益或衰减

调整后音量:

[Parsed_volumedetect_0 @ 0000027108d9f240] n_samples: 2511872
[Parsed_volumedetect_0 @ 0000027108d9f240] mean_volume: -21.6 dB
[Parsed_volumedetect_0 @ 0000027108d9f240] max_volume: -1.0 dB
[Parsed_volumedetect_0 @ 0000027108d9f240] histogram_1db: 9
[Parsed_volumedetect_0 @ 0000027108d9f240] histogram_2db: 14
[Parsed_volumedetect_0 @ 0000027108d9f240] histogram_3db: 35
[Parsed_volumedetect_0 @ 0000027108d9f240] histogram_4db: 122
[Parsed_volumedetect_0 @ 0000027108d9f240] histogram_5db: 253
[Parsed_volumedetect_0 @ 0000027108d9f240] histogram_6db: 693
[Parsed_volumedetect_0 @ 0000027108d9f240] histogram_7db: 2260

这种方法比较简单,根据最大音量数值调整音量。但是音频音量相对小的地方还是小,大的还是大。相当于手机音量调大了。

这种方法比较适合单纯调整音量大小。也比较适合我们的素材文件调整。所以最后选用了这种方式。

优化

如果调整音量过大,音频会失真。所以第一步获取最大音量很重要。或者使用动态范围的方式调整音量。

ffmpeg -i input.mp3 -af "compand=0|0:1|1:-90/-90|-80/-80|-70/-70|-60/-60|-50/-50|-40/-30|-30/-20|-20/-10|-10/-1:6:0:-90:0.2" output.mp3
  • compand:音频过滤器,用于动态范围压缩和扩展。
  • 其他参数我也不好解释。。。重点说一下-90/-90|-80/-80|-70/-70|-60/-60|-50/-50|-40/-30|-30/-20|-20/-10|-10/-1部分。

每对值表示一个映射点(竖线分隔),第一个值是输入音量,第二个值是输出电量。在这个例子中,有9个映射点,分别是(-90dB,-90dB),(-80dB,-80dB),(-70dB,-70dB),(-60dB,-60dB),(-50dB,-50dB),(-40dB,-30dB),(-30dB,-20dB),(-20dB,-10dB),(-10dB,-1dB)。

例如,如果你想让所有-40dB以上的音频信号都被压缩到-30dB,你就可以设置-40/-30。这样,所有-40dB以上的音频信号在经过compand过滤器处理后,都会被压缩到-30dB。同时-50dB以上这种细小的声音不做处理,所以没有增加音量。这样操作下来,实际上加了大约10dB。


最后放一张最终工具运行截图:

ffmpeg调整音频音量踩坑_第2张图片

参考

  • 对视频声音,音频进行音量标准化和响度均化,归一化的标准,原理以及具体操作

你可能感兴趣的:(ffmpeg,音视频,flutter)