ffmpeg ラウドノルム 2pass を一行で実行する

ffmpeg ラウドノルム 2pass を一行で実行する

TL;DR ffpmpeg を使用した 1 行のloudnorm 2pass の例 (ffmpeg-normalize は単一のスレッド/プロセスであり、他の ffmpeg オプションを組み合わせることはできません)

ffmpegにとって比較的新しいため、loudnormの例はあまりありません。私はffmpegを10年ほど使用しています。ただし、loudnormは初めてです。

もう読んだ:

翻訳元:

ffmpeg を使用してオーディオを正規化するにはどうすればよいですか?

これらは役に立ちます。しかし、複数のffmpegエントリを1つに統合しようとしています。ffmpeg-normalize(Python)ライブラリを使用すると、スレッド/プロセスも1つに制限されます。これは遅いです。

ffmpeg x264 の 2 パスの場合は、次のようにするだけです。

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

ただし、loudnorm には存在しないようです。シングル パスと 2 パスでそれを実行する方法がまったくわかりません。

現在、ビデオをエンコードし、次にオーディオを正規化し、最後にファイルからメタデータとチャプターデータ(存在する場合)を削除しています(存在するかどうかに関係なく)。

これにより、3 つの使い捨てファイル (元のファイルを含む) が作成されます。

1 行でloudnormを実行できれば、他のものを追加するのに役立ちます。また、x264の2パスとloudnormの2パスを同時に実行することは可能ですか? つまり、2つを処理してから、2番目のパスでそれらを結合するということです。

できれば、リンクではなく、これらの例をお願いします。リンクは自分でグーグルで検索できますし、数週間前から検索しています。ありがとうございます

答え1

ffmpegだけで2パスラウドノルムフィルターを自動的に実行する方法はありませんが、ffmpeg-normalize代わりに実行してくれるプログラムです。すでに言及されていると思いますが、ビデオを同時にエンコードしたい場合、特に 2 パスでエンコードしたい場合は、1 つの中間ファイルで作業する必要があります。

  • 最初の実行:ffmpeg-normalize元のビデオで、元のビデオ ストリームをコピーします。
  • 2 回目の実行: 正規化されたオーディオ ファイルまたは元のファイルのビデオ ストリームの x264 エンコード (マルチスレッド)。

ffmpeg だけでは、達成したいことは単純には実現できません。特に複数のファイルを並行して処理したい場合は、独自のソリューションをプログラムする必要があります。これにより、1 回の ffmpeg 実行で 1 つのスレッドしか使用しない場合でも、プロセスは確実に高速化されます。

出発点として、よりシンプルなRubyスクリプトFFmpeg リポジトリにあります。これは 2 つのラウドノルム パスを実行し、最初の実行の統計を読み取ります。これを変更して、マルチスレッドで 2 パスの x264 エンコードを追加実行することもできます。つまり、最初の実行で最初の x264 パスを実行し、2 番目の実行で 2 番目のパスを実行します。

最初のパス:

ffmpeg -y -i $FILE -c:v libx264 -b:v 4000k -pass 1 -filter:a loudnorm=print_format=json -f mkv /dev/null

出力から JSON 統計を読み取り(たとえば、Python の JSON パーサー、またはなどloudnormの他のツールを使用)、2 番目のパスを実行します。grepawk

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

ここで、、、は$input_i最初$input_lraのパスから読み取られた値です。$input_tp$input_thresh

答え2

別のプログラムは必要ありません。これは実際には ffmpeg だけで実行できます。実際にこれを行う bat ファイルを作成しました。

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

これは、まずオーディオを分析し、その結果をテキスト ファイルに保存します。次に、テキスト ファイルから結果を読み取り、必要な測定フィールドごとに変数として保存します。ファイル内の I= と TP= を好みに合わせて調整するだけです。

答え3

から始まるピーター提案、これは *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

$input と $output を、入力ファイルと出力ファイルに置き換えます。

最初ffmpegコマンドは最終的なJSONオブジェクトを含む詳細な出力を生成し、これはsedパイプ内のコマンドは一時ファイルに保存されます。後続の5つのコマンドはそれぞれ、2番目のコマンドに渡す関連パラメータを変数に読み込みます。ffmpegフィルタリングはパイプの3つのステップで動作します。まず、関連するパラメータを含む行が選択されます(グレップ)、次に値が名前(カット)、そして最後に数値部分だけがソートされます(tr)。このプロセスは、ffmpeg コマンドの出力形式に依存するため、100% 信頼できるわけではありません。

答え4

ffmpeg ラウドノルム フィルター用の bash スクリプト

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

関連情報