題 如何使用ffmpeg規範化音頻?


我希望電影剪輯中最響亮的峰值聲音與編解碼器允許的一樣響亮,然後相應地放大所有其他聲音。

為了使用ffmpeg實現這個目的,有什麼實際的例子?


89
2017-08-14 19:56


起源


你希望音頻'正常化'。我發現 這個帖子 那裡有很多很好的信息。希望能幫助到你! - bobsbarricades


答案:


選項1:內置標準化過濾器

當前的ffmpeg有兩個可以直接用於標準化的濾波器 - 雖然它們已經非常先進,但它們並不是簡單地應用增益來達到峰值水平。他們來了:

  • loudnorm:根據EBU R128的響度標準化。您可以設置集成響度目標,響度範圍目標或最大真實峰值。建議用於發布音頻和視頻,並由世界各地的廣播公司使用。
  • dynaudnorm:沒有剪切的“智能”響度標準化,它在文件的窗口部分動態地應用標準化。這可能會改變聲音的特性,因此應謹慎使用。

而且, volume 過濾器可用於執行簡單的音量調整。見 音量操作 維基進入更多。

loudnorm 濾波器可以一次使用,但建議執行兩次通過,這樣可以實現更精確的線性歸一化。這有點難以自動化。此外,如果您希望“簡單”基於RMS或峰值歸一化為0 dBFS(或任何其他目標),請繼續閱讀。


選項2:使用 ffmpeg-normalize 工具

我建立 用於規範化媒體文件的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

更換 /dev/null 同 NUL 在Windows上。
-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 在輸出文件名之前。


139
2017-08-14 20:11



評論不適用於擴展討論;這次談話已經開始了 轉移到聊天。 - Journeyman Geek♦
這是繼續奉獻的禮物。 6年後,它仍在更新和維護。做得好! - Jon Skarpeteig
@Jon謝謝,非常感謝! - slhck
如果設置新卷,那麼選項3是否會避免削波,因此max_volume為零?即使用max_volume給出的相反值初始值 - rraallvv
@rraallvv是的,它應該。這也是什麼 ffmpeg-normalize 當你指定0 dB的水平和峰值歸一化時,工具會這樣做。 - slhck


我不能評論最好的消息,所以這是我的醜陋bash基於它來做到這一點

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

7
2018-05-19 14:51





這是一個規範化.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

5
2017-09-12 04:57