如何使用 ffmpeg 规范音频?

如何使用 ffmpeg 规范音频?

我希望电影剪辑中最响亮的峰值声音与编解码器允许的音量一样大,然后相应地放大其他所有声音。

使用 ffmpeg 实现此目的的实用示例是什么?

答案1

选项 1:内置规范化过滤器

当前 ffmpeg 有三个滤波器可直接用于标准化 - 尽管它们已经相当先进,因此它们不会简单地应用增益来达到峰值水平。如果您想要“简单”的基于 RMS 或峰值标准化到 0 dBFS(或任何其他目标),请转到此答案的最后一部分。

过滤器的基本用法是:

ffmpeg -i input -filter:a filter output

以下是三个更高级的过滤器:

  • loudnorm:根据 EBU R128 进行响度标准化。您可以设置综合响度目标、响度范围目标或最大真实峰值。建议将此用于发布音频和视频,世界各地的广播公司都在使用它。您应该在双通道模式下使用此过滤器,因此我推荐我的包装器脚本ffmpeg-normalize对于它(更多信息请参见下文)。

  • dynaudnorm:无削波的“智能”响度标准化,可动态地对文件的窗口部分应用标准化。这可能会改变声音的特性,因此应谨慎使用。中等压缩示例:

    ffmpeg -i input.wav -filter:a "dynaudnorm=p=0.9:s=5" output.wav
    
  • speechnorm:专为语音标准化而设计。请参阅这里的例子

此外,该volume过滤器还可用于执行简单的音量调节。请参阅音量控制更多内容请参阅 wiki 条目。


选项 2:使用ffmpeg-normalize工具

由于您应该使用两次传递的 Loudnorm 过滤器,并且这可能在脚本中包装起来有点复杂,因此我创建了一个用于规范化媒体文件的 Python 程序也可以在 PyPi 上使用.您只需:

  • 下载 ffmpeg(选择一个静态构建(3.1 版或更高版本)
  • 将可执行文件放入ffmpeg你的$PATH文件中,例如/usr/local/bin将其目录添加到$PATH
  • 跑步pip install ffmpeg-normalize
  • 使用ffmpeg-normalize

例如:

ffmpeg-normalize input.mp4 -o output.mp4 -c:a aac -b:a 192k

或者,简单地批量标准化一些音频文件并将它们作为未压缩的 WAV 写入输出文件夹:

ffmpeg-normalize *.m4a -of /path/to/outputFolder -ext wav

该工具支持 EBU R128(默认)、RMS 和峰值。查看ffmpeg-normalize -h更多选项并检查自述举一些例子。

此外,它还支持使用其他编码器(例如 AAC 或 MP3)重新编码,或将音频自动合并回视频。


选项 3:使用以下方式手动标准化音频ffmpeg

在 ffmpeg 中,您可以使用volume过滤器来更改音轨的音量。请确保下载最新版本该计划。

本指南适用于顶峰标准化,这意味着它会让文件中最响亮的部分位于 0 dB 而不是更低的水平。还有基于 RMS 的标准化,它试图让平均的多个文件之间的音量相同。要做到这一点,不要尝试将最大音量推到 0 dB,而是将平均音量推到所选的 dB 级别(例如 -26 dB)。

找出要应用的增益

首先,您需要分析最大音量的音频流,看看标准化是否有用:

ffmpeg -i video.avi -af "volumedetect" -vn -sn -dn -f null /dev/null

在Windows上替换/dev/nullNUL
-vn-sn, 和-dn参数指示 ffmpeg 在分析过程中忽略非音频流。这大大加快了分析速度。

这将输出类似以下内容:

[Parsed_volumedetect_0 @ 0x7f8ba1c121a0] mean_volume: -16.0 dB
[Parsed_volumedetect_0 @ 0x7f8ba1c121a0] max_volume: -5.0 dB
[Parsed_volumedetect_0 @ 0x7f8ba1c121a0] histogram_0db: 87861

如您所见,我们的最大音量为 -5.0 dB,因此我们可以应用 5 dB 增益。如果您得到的值为 0 dB,则无需对音频进行标准化。

应用音量过滤器:

现在我们应用volume筛选到音频文件。请注意,应用过滤器意味着我们必须重新编码音频流。当然,您想要的音频编解码器取决于原始格式。以下是一些示例:

  • 纯音频文件:只需使用您需要的编码器对文件进行编码:

     ffmpeg -i input.wav -af "volume=5dB" output.mp3
    

    当然,您的选择非常广泛。

  • AVI 格式:通常情况下,AVI 容器中含有 MP3 音频和视频:

     ffmpeg -i video.avi -af "volume=5dB" -c:v copy -c:a libmp3lame -q:a 2 output.avi
    

    这里我们选择质量等级 2。值的范围是 0-9,值越低表示越好。检查MP3 VBR 指南有关设置质量的更多信息。-b:a 192k例如,您还可以使用 设置固定比特率。

  • MP4 格式:对于 MP4 容器,您通常会找到 AAC 音频。我们可以使用 ffmpeg 的内置 AAC 编码器。

     ffmpeg -i video.mp4 -af "volume=5dB" -c:v copy -c:a aac -b:a 192k output.mp4
    

    您还可以在这里使用其他 AAC 编码器。其中一些也支持 VBR。请参阅这个答案AAC 编码指南获得一些提示。

在上面的例子中,视频流将使用 进行复制-c:v copy。如果输入文件中有字幕或多个视频流,请-map 0在输出文件名前使用该选项。

答案2

这是用于规范 .m4a 文件声音级别的脚本。请注意声音级别是否太低。在这种情况下,如果您使用 Audacity 之类的工具,最终的声音可能会更好。

#!/bin/bash

# Purpose: Use ffmpeg to normalize .m4a audio files to bring them up to max volume, if they at first have negative db volume. Doesn't process them if not. Keeps bitrate same as source files.
# Parameters: $1 should be the name of the directory containing input .m4a files.
#   $2 should be the output directory.

INPUTDIR=$1
OUTPUTDIR=$2

<<"COMMENT"

# For ffmpeg arguments http://superuser.com/questions/323119/how-can-i-normalize-audio-using-ffmpeg
# and
# https://kdecherf.com/blog/2012/01/14/ffmpeg-converting-m4a-files-to-mp3-with-the-same-bitrate/
ffmpeg -i test.m4a -af "volumedetect" -f null /dev/null

ffmpeg -i test.m4a -af "volumedetect" -f null /dev/null 2>&1 | grep max_volume
# output: max_volume: -10.3 dB

ffmpeg -i test.m4a -af "volumedetect" -f null /dev/null 2>&1 | grep 'max_volume\|Duration'
# Output:
#  Duration: 00:00:02.14, start: 0.000000, bitrate: 176 kb/s
# [Parsed_volumedetect_0 @ 0x7f8531e011a0] max_volume: -10.3 dB

ffmpeg -i test.m4a -af "volumedetect" -f null /dev/null 2>&1 | grep max_volume | awk -F': ' '{print $2}' | cut -d' ' -f1
# Output: -10.3

ffmpeg -i test.m4a 2>&1 | grep Audio
# output: Stream #0:0(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 170 kb/s (default)

ffmpeg -i test.m4a 2>&1 | grep Audio | awk -F', ' '{print $5}' | cut -d' ' -f1
# output: 170

# This works, but I get a much smaller output file. The sound levels do appear normalized.
ffmpeg -i test.m4a -af "volume=10.3dB" -c:v copy -c:a aac -strict experimental output.m4a

# Operates quietly.
ffmpeg -i test.m4a -af "volume=10.3dB" -c:v copy -c:a aac -strict experimental -b:a 192k output.m4a -loglevel quiet

COMMENT

# $1 (first param) should be the name of a .m4a input file, with .m4a extension
# $2 should be name of output file, with extension
function normalizeAudioFile {
    INPUTFILE=$1
    OUTPUTFILE=$2

    DBLEVEL=`ffmpeg -i ${INPUTFILE} -af "volumedetect" -f null /dev/null 2>&1 | grep max_volume | awk -F': ' '{print $2}' | cut -d' ' -f1`

    # We're only going to increase db level if max volume has negative db level.
    # Bash doesn't do floating comparison directly
    COMPRESULT=`echo ${DBLEVEL}'<'0 | bc -l`
    if [ ${COMPRESULT} -eq 1 ]; then
        DBLEVEL=`echo "-(${DBLEVEL})" | bc -l`
        BITRATE=`ffmpeg -i ${INPUTFILE} 2>&1 | grep Audio | awk -F', ' '{print $5}' | cut -d' ' -f1`

        # echo $DBLEVEL
        # echo $BITRATE

        ffmpeg -i ${INPUTFILE} -af "volume=${DBLEVEL}dB" -c:v copy -c:a aac -strict experimental -b:a ${BITRATE}k ${OUTPUTFILE} -loglevel quiet

    else
        echo "Already at max db level:" $DBLEVEL "just copying exact file"
        cp ${INPUTFILE} ${OUTPUTFILE}
    fi
}

for inputFilePath in ${INPUTDIR}/*; do
    inputFile=$(basename $inputFilePath)
    echo "Processing input file: " $inputFile
    outputFilePath=${OUTPUTDIR}/$inputFile
    normalizeAudioFile ${inputFilePath} ${outputFilePath}
done

答案3

我无法对最佳消息进行评论,因此这是我基于此进行的丑陋抨击

ffmpeg -i sound.mp3 -af volumedetect -f null -y nul &> original.txt
grep "max_volume" original.txt > original1.tmp
sed -i 's|: -|=|' original1.tmp
if [ $? = 0 ]
 then
 sed -i 's| |\r\n|' original.tmp
 sed -i 's| |\r\n|' original.tmp
 sed -i 's| |\r\n|' original.tmp
 sed -i 's| |\r\n|' original.tmp
 grep "max_volume" original1.tmp > original2.tmp
 sed -i 's|max_volume=||' original2.tmp
 yourscriptvar=$(cat "./original2.tmp")dB
 rm result.mp3
 ffmpeg -i sound.mp3 -af "volume=$yourscriptvar" result.mp3
 ffmpeg -i result.mp3 -af volumedetect -f null -y nul &> result.txt
fi

答案4

我使用命令行(根据您的需求进行调整)

mkdir NORMALIZED; for mkv in *.mkv ; do wav=`basename "$mkv" .mkv`.wav; echo "${wav}"; ffmpeg -i "${mkv}" -acodec copy "${wav}" ; normalize-audio "${wav}"; ffmpeg -i "${mkv}"  -i "${wav}" -codec copy NORMALIZED/"${mkv}"; done;

或批量

[ ! -d work ] && echo "work directory does not ezists" && exit 1

for fn in *.mkv
do
  map=$(ffmpeg -i "$fn" |& grep Stream | grep pcm_s16le) # pcm_dvd ac3 mp3

  if [ "$map" != "" ]
  then
    echo "$fn"
    fb=${fn%.mkv} #; shopt -s extglob; fb=${fb%%+([[:space:]])}
    amap=${map:12:3}
    ffmpeg -y -i "$fn" -map $amap -acodec pcm_s16le work/"$fb".wav 2>/dev/null
    wavegain -y work/"$fb".wav
    ffmpeg -y -i "$fn" -i work/"$fb".wav -c:v copy -c:a copy -map 0:v:0 -map 1:a:0 work/"$fb".mkv 2>/dev/null
    rm -f work/"$fb".wav
    echo
  fi
done

read -p "BAIGTA"

相关内容