DR um exemplo de loudnorm 2pass em linha única usando ffmpeg (ffmpeg-normalize é thread/processo único e não consigo combinar outras opções de ffmpeg a ele)
Não há muitos exemplos no Loudnorm, já que é relativamente novo no ffmpeg. Tenho usado o ffmpeg há cerca de 10 anos. Eu sou novo no Loudnorm, no entanto
Eu li:
http://k.ylo.ph/2016/04/04/loudnorm.html
Como posso normalizar o áudio usando o ffmpeg?
que são úteis. no entanto, estou tentando consolidar várias entradas do ffmpeg em 1. usar a biblioteca ffmpeg-normalize (o python) também limita você a um único thread/processo. que é lento
para 2 passagens do ffmpeg x264 você pode simplesmente fazer:
ffmpeg -y -i $FILE -c:v libx264 -b:v 4000k -pass 1 -c:a aac -b:a 256k -f mkv /dev/null && \
ffmpeg -i $FILE -c:v libx264 -b:v 4000k -pass 2 -c:a aac -b:a 256k $FILE.mkv
não parece existir para o alto padrão. Não vejo uma maneira de fazer isso com uma passagem única e duas?
atualmente estou codificando vídeo, normalizando o áudio e, finalmente, removendo metadados e dados de capítulos de arquivos, se existirem (independentemente de existirem ou não)
isso cria 3 arquivos descartáveis (incluindo o original)
ser capaz de fazer alto-norm em uma única linha me ajudaria a adicionar outras coisas. Também é possível fazer 2 passagens de x264 e 2 passagens de alto-norm simultaneamente? como fazer com que ele processe os dois e depois combine-os na segunda passagem.
Se possível, gostaria de exemplos disso e não de links para coisas. Posso pesquisar links no Google por conta própria e por várias semanas. Obrigado
Responder1
Não há como executar um filtro Loudnorm de duas passagens automaticamente apenas com o ffmpeg, mas você pode usar offmpeg-normalize
programa para fazer isso por você. Eu sei que você mencionou isso, mas se quiser codificar vídeo ao mesmo tempo - principalmente com duas passagens - você terá que trabalhar com um arquivo intermediário, ou seja:
- Primeira execução:
ffmpeg-normalize
no vídeo original, copiando o fluxo de vídeo original. - Segunda execução: codificação x264 (multithread) do arquivo de áudio normalizado ou dos fluxos de vídeo do arquivo original.
O que você deseja alcançar simplesmente não pode ser feito apenas pelo ffmpeg. Você precisa programar sua própria solução, principalmente se quiser lidar com vários arquivos em paralelo. Isso certamente aceleraria o processo, mesmo se uma única execução do ffmpeg usasse apenas um thread.
Como ponto de partida, há também umscript Ruby mais simplesno repositório FFmpeg. Ele executa duas passagens de alto padrão, lendo as estatísticas da primeira execução. Você pode modificá-lo para executar adicionalmente a codificação x264 de duas passagens com multithreading, ou seja, executar a primeira passagem x264 na primeira execução e a segunda na segunda execução:
Primeira passagem:
ffmpeg -y -i $FILE -c:v libx264 -b:v 4000k -pass 1 -filter:a loudnorm=print_format=json -f mkv /dev/null
Leia as estatísticas JSON da loudnorm
saída (por exemplo, usando o analisador JSON do Python ou qualquer outra ferramenta como grep
ou awk
) e execute a segunda passagem:
ffmpeg -i $FILE -c:v libx264 -b:v 4000k -pass 2 -filter:a loudnorm=linear=true:measured_I=$input_i:measured_LRA=$input_lra:measured_tp=$input_tp:measured_thresh=$input_thresh -c:a aac -b:a 256k $FILE.mkv
Onde $input_i
, $input_lra
, $input_tp
, $input_thresh
são os valores lidos na primeira passagem.
Responder2
Não há necessidade de outro programa. Na verdade, isso PODE ser feito apenas com o ffmpeg. Na verdade, criei um arquivo bat que fará isso.
cls
echo off
ffmpeg -i %1 -filter_complex "[0:a]loudnorm=I=-16:TP=-1.5:LRA=11:print_format=summary" -f null x 2>%1.txt
@for /f "tokens=3" %%a in ('findstr /C:"Input Integrated" %1.txt') do (set II=%%a)
echo %II% is the Input Integrated
@for /f "tokens=4" %%a in ('findstr /C:"Input True Peak" %1.txt') do (set ITP=%%a)
echo %ITP% is the Input True Peak
@for /f "tokens=3" %%a in ('findstr /C:"Input LRA" %1.txt') do (set ILRA=%%a)
echo %ILRA% is the Input LRA
@for /f "tokens=3" %%a in ('findstr /C:"Input Threshold" %1.txt') do (set IT=%%a)
echo %IT% is the Input Threshold
@for /f "tokens=3" %%a in ('findstr /C:"Output Integrated" %1.txt') do (set OI=%%a)
echo %OI% is the Output Integrated
@for /f "tokens=4" %%a in ('findstr /C:"Output True Peak" %1.txt') do (set OTP=%%a)
echo %OTP% is the Output True Peak
@for /f "tokens=3" %%a in ('findstr /C:"Output LRA" %1.txt') do (set OLRA=%%a)
echo %OLRA% is the Output LRA
@for /f "tokens=3" %%a in ('findstr /C:"Output Threshold" %1.txt') do (set OT=%%a)
echo %OT% is the Output Threshold
@for /f "tokens=3" %%a in ('findstr /C:"Target Offset" %1.txt') do (set TO=%%a)
echo %TO% is the Target Offset
ffmpeg -i %1 -af loudnorm=linear=true:I=-16:LRA=11:tp=-1.5:measured_I=%II%:measured_LRA=%ILRA%:measured_tp=%ITP%:measured_thresh=%IT%:offset=%TO%:print_format=summary loudnorm.wav
O que isto faz é primeiro analisar o áudio e salvar os resultados em um arquivo de texto. Em seguida, ele lê os resultados do arquivo de texto e os armazena como variáveis para cada campo de medição necessário. Basta ajustar I= e TP= ao seu gosto no arquivo.
Responder3
Começando depetermgsugestão, este é o equivalente para usuários *nix:
ffmpeg -i $input -filter:a loudnorm=print_format=json -f null /dev/null 2>&1 >/dev/null | sed -n '/{/,/}/p' > /tmp/info
ii=`grep \"input_i\" /tmp/info | cut -d: -f2 | tr -cd [:digit:].-`
itp=`grep \"input_tp\" /tmp/info | cut -d: -f2 | tr -cd [:digit:].-`
ilra=`grep \"input_lra\" /tmp/info | cut -d: -f2 | tr -cd [:digit:].-`
it=`grep \"input_thresh\" /tmp/info | cut -d: -f2 | tr -cd [:digit:].-`
to=`grep \"target_offset\" /tmp/info | cut -d: -f2 | tr -cd [:digit:].-`
ffmpeg -i $input -af loudnorm=linear=true:I=-16:LRA=11:tp=-1.5:measured_I=$ii:measured_LRA=$ilra:measured_tp=$itp:measured_thresh=$it:offset=$to:print_format=summary $output
Substitua $input e $output pelos seus arquivos de entrada e saída.
O primeiroffmpegO comando produz uma saída detalhada com um objeto JSON final, que é filtrado pelosedcomando no pipe e armazenado em um arquivo temporário. Cada um dos cinco comandos que se seguem carrega em uma variável um parâmetro relevante para ser alimentado ao segundoffmpegpassar. A filtragem opera em três etapas de um pipe: primeiro é selecionada a linha que contém o parâmetro relevante (grep), em seguida o valor é separado pelo nome (corte) e, finalmente, apenas a parte numérica é classificada (tr). O processo não é 100% confiável, pois depende do formato de saída do comando ffmpeg.
Responder4
mais scripts bash para o filtro ffmpeg loudnorm
#! /usr/bin/env bash
# ffmpeg-loudnorm-analyze.sh
# analyze loudness of audio streams
# write result to stdout in json format
# example output: see end of script
# TODO verify ffmpeg output format: Parsed_loudnorm_([0-9]+)
set -e
set -u
input_file="$1"
shift
# extra args. example: -map 0:a:0 # process only the first audio stream
extra_args=("$@")
# https://ffmpeg.org/ffmpeg-filters.html#loudnorm
ffmpeg -i "$input_file" -pass 1 "${extra_args[@]}" \
-filter:a loudnorm=print_format=json -f null -y /dev/null |
grep -E '^\[Parsed_loudnorm_([0-9]+) @ 0x[0-9a-f]+\]' -A12 |
perl -0777 -pe 's/}\s+\[Parsed_loudnorm_([0-9]+) @ 0x[0-9a-f]+\]\s+/ },\n "$1": /g' |
perl -0777 -pe 's/\[Parsed_loudnorm_([0-9]+) @ 0x[0-9a-f]+\]\s+/ "$1": /g' |
sed 's/^}/ }/' |
sed '1 i\{'
printf '}\n';
exit
example output:
{
"0": {
"input_i": "-30.05",
"input_tp": "-0.01",
...
},
"1": {
"input_i": "-30.05",
"input_tp": "-0.01",
...
}
}
#! /usr/bin/env bash
# ffmpeg-loudnorm-format-filters.sh
# take a json file generated by ffmpeg-loudnorm-analyze.sh
# and format audio filters for ffmpeg
# example output:
# loudnorm=linear=true:I=-14:LRA=7:tp=-1:measured_I=-30.05:measured_LRA=16.60:measured_tp=-0.01:measured_thresh=-41.55:offset=0.46:print_format=summary
# to use the audio filter in ffmpeg:
# ffmpeg -af "loudnorm=..."
# https://ffmpeg.org/ffmpeg-filters.html#loudnorm
# https://superuser.com/questions/1604545/ffmpeg-loudnorm-results-in-not-very-loud
# https://youlean.co/loudness-standards-full-comparison-table/
max_integrated=-14
max_true_peak=-1
# LRA: loudness range target. Range is 1.0 - 50.0. Default value is 7.0
#loudnorm_LRA=11
loudnorm_LRA=7
loudnorm_linear=true
loudnorm_print_format=summary
loudnorm_extra_args=
set -e
set -u
json_file="$1"
stream_ids=$(jq -r 'keys[]' "$json_file" | sort -n)
s='"'
s+='loudnorm='
s+='linear='$loudnorm_linear':'
s+='I='$max_integrated':'
s+='LRA='$loudnorm_LRA':'
s+='tp='$max_true_peak':'
s+='measured_I=\(.input_i):'
s+='measured_LRA=\(.input_lra):'
s+='measured_tp=\(.input_tp):'
s+='measured_thresh=\(.input_thresh):'
s+='offset=\(.target_offset):'
s+='print_format='$loudnorm_print_format
s+="$loudnorm_extra_args"
s+='"'
jq_script="$s"
# print one filter per line, sorted by loudnorm result index
for stream_id in $stream_ids; do
stream_json="$(jq -r ".\"$stream_id\"" "$json_file")"
ffmpeg_loudnorm_filter="$(echo "$stream_json" | jq -r "$jq_script")"
echo "$ffmpeg_loudnorm_filter"
done