Questão Como posso normalizar o áudio usando o ffmpeg?


Eu quero que o som de pico mais alto em um clipe de filme seja tão alto quanto o codec permitir, e então ter todos os outros sons amplificados de acordo.

O que é um exemplo prático para conseguir isso usando o ffmpeg?


87


origem


Você está procurando ter o áudio 'normalizado'. eu encontrei esta discussão e há muita informação boa lá. Espero que ajude! - bobsbarricades


Respostas:


Opção 1: filtros de normalização incorporados

O ffmpeg atual tem dois filtros que podem ser usados ​​diretamente para a normalização - embora eles já sejam bastante avançados, então eles não aplicam simplesmente o ganho para alcançar um nível de pico. Aqui estão eles:

  • loudnorm: normalização do volume de acordo com a EBU R128. Você pode definir um alvo de intensidade integrada, um alvo de variação de intensidade ou um pico máximo real. Isso é recomendado para publicar áudio e vídeo e é usado por emissoras de todo o mundo.
  • dynaudnorm: Normalização de loudness “inteligente” sem clipping, que aplica a normalização dinamicamente em partes de janela do arquivo. Isso pode alterar as características do som, por isso deve ser aplicado com cuidado.

Também o volume filtro pode ser usado para realizar ajustes simples de volume. Veja o Manipulação de Volume de Áudio entrada wiki para mais.

o loudnorm O filtro pode ser usado com uma passagem, mas é recomendável executar duas passagens, o que permite uma normalização linear mais precisa. Isso é um pouco difícil de automatizar. Além disso, se você quiser uma normalização de pico simples ou baseada em RMS para 0 dBFS (ou qualquer outro destino), continue lendo.


Opção 2: use o ffmpeg-normalize ferramenta

eu criei um programa em Python para normalizar arquivos de mídia, disponível no PyPi também. Você simplesmente:

  • baixar ffmpeg (escolha um construção estática, versão 3.1 ou superior)
  • coloque o ffmpeg executável em seu $PATH adicionando-o, por exemplo, /usr/local/binou adicionando seu diretório para $PATH
  • Corre pip install ffmpeg-normalize
  • Usar ffmpeg-normalize

Por exemplo:

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

Ou, simplesmente para normalizar em lotes um número de arquivos de áudio e gravá-los como WAV descompactado em uma pasta de saída:

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

A ferramenta suporta EBU R128 (padrão), RMS e pico. Dê uma olhada em ffmpeg-normalize -h para mais opções e verifique o README para alguns exemplos.

Além disso, suporta a recodificação com outros codificadores (por exemplo, AAC ou MP3) ou a fusão automática do áudio de volta ao vídeo.


Opção 3: normalizando manualmente o áudio com ffmpeg

No ffmpeg você pode usar o volume filtrar para alterar o volume de uma faixa. Assegure-se de que você baixe uma versão recente do programa.

Este guia é para pico normalização, o que significa que fará com que a maior parte do arquivo fique em 0 dB em vez de algo menor. Há também a normalização baseada em RMS que tenta fazer com que média loudness o mesmo em vários arquivos. Para fazer isso, não tente empurrar o volume máximo para 0 dB, mas o volume médio para o nível de dB de escolha (por exemplo, -26 dB).

Descubra o ganho para aplicar

Primeiro, você precisa analisar o fluxo de áudio para o volume máximo para ver se a normalização seria compensada:

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

Substituir /dev/null com NUL no Windows.
o -vn, -sne -dn argumentos instruem o ffmpeg a ignorar fluxos não-auditivos durante esta análise. Isso acelera drasticamente a análise.

Isso produzirá algo como o seguinte:

[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

Como você pode ver, nosso volume máximo é de -5,0 dB, então podemos aplicar um ganho de 5 dB. Se você obtiver um valor de 0 dB, não será necessário normalizar o áudio.

Aplique o filtro de volume:

Agora nós aplicamos o volume filtro para um arquivo de áudio. Observe que, ao aplicar o filtro, teremos que recodificar o fluxo de áudio. O codec que você deseja para áudio depende do formato original, é claro. aqui estão alguns exemplos:

  • Arquivo de áudio simples: Apenas codifique o arquivo com qualquer codificador que você precisar:

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

    Suas opções são muito amplas, é claro.

  • Formato AVI: Geralmente há áudio MP3 com vídeo que vem em um contêiner AVI:

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

    Aqui escolhemos o nível de qualidade 2. Os valores variam de 0 a 9 e inferiores significam melhor. Verifica a Guia de MP3 VBR para mais informações sobre como definir a qualidade. Você também pode definir uma taxa de bits fixa -b:a 192k, por exemplo.

  • Formato MP4: Com um contêiner MP4, você normalmente encontrará o áudio AAC. Podemos usar o codificador AAC embutido do ffmpeg.

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

    Aqui você também pode usar outros codificadores AAC. Alguns deles suportam VBR também. Vejo esta resposta e a Guia de codificação AAC para algumas dicas.

Nos exemplos acima, o fluxo de vídeo será copiado usando -c:v copy. Se houver legendas em seu arquivo de entrada ou em vários fluxos de vídeo, use a opção -map 0 antes do nome do arquivo de saída.


131



Comentários não são para discussão extensa; esta conversa foi mudou-se para conversar. - Journeyman Geek♦
Este é o presente que continua dando. 6 anos depois, e ainda está sendo atualizado e mantido. Bem feito! - Jon Skarpeteig
@Jon Obrigado, muito apreciado! - slhck
A opção 3 evita o recorte se eu definir o novo volume para que max_volume seja zero? isto é, usando o valor oposto inicial dado por max_volume - rraallvv
@rraallvv Sim, deveria. Isso também é o que o ffmpeg-normalize ferramenta faz, quando você especifica um nível de 0 dB e pico de normalização. - slhck


Eu não posso comentar sobre a melhor mensagem de modo que é o meu feio bash baseado nele para fazer isso

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

6





Aqui está um script para normalizar os níveis de som dos arquivos .m4a. Observe se os níveis de som estão muito baixos para começar. O som final pode ser melhor se você usar algo como o Audacity nesse caso.

#!/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