web-dev-qa-db-ja.com

ffmpegを使って音声を正規化するにはどうすればよいですか?

私は、ムービークリップの最も大きなピークサウンドを、コーデックが許す範囲でできるだけ大きくし、それから他のすべてのサウンドをそれに応じて増幅させることを望みます。

Ffmpegを使用してこれを達成するための実用的な例は何ですか?

109
Jon Skarpeteig

オプション1:内蔵正規化フィルタ

現在のffmpegには、正規化に直接使用できる2つのフィルタがあります - これらはすでにかなり高度なものですが、ピークレベルに達するためにゲインを適用するだけではありません。どうぞ:

  • loudnorm :EBU R 128によるラウドネス正規化。統合音量ターゲット、音量範囲ターゲット、または最大真ピークを設定できます。これはオーディオやビデオのパブリッシュに推奨されており、世界中の放送局で使用されています。
  • dynaudnorm :クリッピングなしの「インテリジェント」ラウドネス正規化。ファイルのウィンドウ部分に正規化を動的に適用します。これは音の特性を変えるかもしれないので、それは慎重に適用されるべきです。

また、volumeフィルタを使って簡単な音量調整を行うこともできます。詳しくは Audio Volume Manipulation wikiの項目を見てください。

loudnormフィルタは1回のパスでも使用できますが、2回のパスを実行することをお勧めします。これにより、より正確な線形正規化が可能になります。これを自動化するのは少し難しいです。また、0 dBFS(または他のターゲット)への「単純な」RMSベースまたはピーク正規化が必要な場合は、次に進んでください。


オプション2:ffmpeg-normalizeツールを使用する

メディアファイルを正規化するための Pythonプログラムを作成しましたPyPiでも利用できます 。あなたは簡単です:

  • download ffmpeg静的ビルド、バージョン3.1以上を選択してください)
  • たとえば$PATHに追加するか、 にそのディレクトリを/usr/local/bin に追加することによって、ffmpeg実行可能ファイルを$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、およびpeakをサポートします。他のオプションについてはffmpeg-normalize -hを見て、いくつかの例については README をチェックしてください。

また、他のエンコーダ(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 filter をオーディオファイルに適用します。フィルタを適用すると、オーディオストリームを再エンコードする必要があることになります。オーディオにどのコーデックが必要かは、もちろん元のフォーマットによって異なります。ここではいくつかの例を示します。

  • 普通のオーディオファイル:必要なエンコーダでファイルをエンコードするだけです。

    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を使用してください。

171
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

これは、.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
Chris Prince