ffmpeg Loudnorm 2pass 單行

ffmpeg Loudnorm 2pass 單行

TL;DR 使用 ffpmpeg 在單行中使用 Loudnorm 2pass 的範例(ffmpeg-normalize 是單執行緒/進程,我無法將其他 ffmpeg 選項組合到其中)

關於 Loudnorm 的例子並不多,因為它對 ffmpeg 來說相對較新,我已經使用 ffmpeg 10 年左右了。然而我是 Loudnorm 的新手

我讀了:

http://k.ylo.ph/2016/04/04/loudnorm.html

如何使用 ffmpeg 標準化音訊?

這很有幫助。然而,我試圖將多個 ffmpeg 條目合併到 1. 使用 ffmpeg-normalize (python)庫也將您限制為單一執行緒/進程。這很慢

對於 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 來說似乎不存在。我根本看不出有什麼辦法可以透過一次和兩次通過來做到這一點?

目前我正在編碼視頻,然後規範化音頻,最後從文件中剝離元數據和章節數據(如果存在)(無論它是否存在)

這會建立 3 個廢棄文件(包括原始文件)

能夠在一行中執行 Loudnorm 將幫助我在其中添加其他內容,是否可以同時執行 x264 的 2pass 和 Loudnorm 的 2pass?就像它處理兩者然後在第二遍中將它們組合起來一樣。

如果可能的話,我想要這些例子,而不是連結。我可以自己用谷歌搜索鏈接,並且已經持續了幾個星期。謝謝

答案1

僅使用 ffmpeg 無法自動執行兩通調響濾波器,但您可以使用ffmpeg-normalize程序為您做這件事。我知道您已經提到過這一點,但如果您想同時對視訊進行編碼(尤其是兩次傳遞),那麼您將必須使用一個中間文件,即:

  • 第一次運行:ffmpeg-normalize在原始影片上,複製原始視訊串流。
  • 第二次運行:標準化音訊檔案或原始檔案視訊串流的 x264 編碼(多執行緒)。

你想要實現的目標根本無法只靠 ffmpeg 來完成。您需要編寫自己的解決方案,特別是如果您想並行處理多個文件。即使單一 ffmpeg 運行僅使用一個線程,這肯定會加快該過程。

作為起點,還有一個更簡單的 Ruby 腳本在 FFmpeg 儲存庫中。它執行兩次 Loudnorm 傳遞,讀取第一次運行的統計資料。您可以修改它以使用多執行緒額外運行雙通道 x264 編碼,即在第一次運行中運行第一個 x264 通道,在第二次運行中運行第二個通道:

第一遍:

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

從輸出讀取 JSON 統計資料loudnorm(例如,使用 Python 的 JSON 解析器或任何其他工具,如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命令在管道中並儲存在臨時檔案中。接下來的五個命令中的每一個都會在變數中載入要傳遞給第二個命令的相關參數ffmpeg經過。過濾按管道的三個步驟進行:首先選擇包含相關參數的行(grep),接下來該值由名稱 (),最後只整理出數字部分(t)。該過程不是 100% 可靠,因為它取決於 ffmpeg 命令的輸出格式。

答案4

更多 ffmpeg Loudnorm 過濾器的 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

相關內容