Add loudness normalization settings: introduce NormalizeLoudness and LoudnessTargetLufs options in configuration files, update FfmpegMediaProcessor to apply loudness normalization during media processing, and document changes in media storage guide.
This commit is contained in:
@@ -48,6 +48,10 @@ Media__MaxUploadBytes=21474836480
|
||||
Media__TranscodeThreads=3
|
||||
# Период опроса каталога inbox/ сканером, секунды.
|
||||
Media__InboxScanSeconds=15
|
||||
# Нормализация громкости при обработке (EBU R128 loudnorm) — все ролики одинаковой громкости.
|
||||
Media__NormalizeLoudness=true
|
||||
# Целевая громкость, LUFS (−16 типично для стриминга; тише — уменьшить).
|
||||
Media__LoudnessTargetLufs=-16
|
||||
|
||||
# ── ASP.NET Core ──────────────────────────────────────────────────────────
|
||||
ASPNETCORE_ENVIRONMENT=Production
|
||||
|
||||
@@ -30,7 +30,9 @@
|
||||
"FfprobePath": "ffprobe",
|
||||
"MaxUploadBytes": 21474836480,
|
||||
"TranscodeThreads": 3,
|
||||
"InboxScanSeconds": 15
|
||||
"InboxScanSeconds": 15,
|
||||
"NormalizeLoudness": true,
|
||||
"LoudnessTargetLufs": -16
|
||||
},
|
||||
"Serilog": {
|
||||
"Using": [ "Serilog.Sinks.Console" ],
|
||||
|
||||
@@ -124,10 +124,24 @@ public sealed class FfmpegMediaProcessor(
|
||||
"48000",
|
||||
};
|
||||
|
||||
// Аудиофильтры: нормализация громкости (EBU R128, чтобы все ролики звучали одинаково) и,
|
||||
// при добивке хвоста, тишина apad. Порядок: сначала loudnorm по реальному звуку, потом apad.
|
||||
var afilters = new List<string>();
|
||||
if (_media.NormalizeLoudness)
|
||||
afilters.Add(
|
||||
$"loudnorm=I={_media.LoudnessTargetLufs.ToString(CultureInfo.InvariantCulture)}:TP=-1.5:LRA=11"
|
||||
);
|
||||
if (padding)
|
||||
afilters.Add($"apad=pad_dur={Fmt(pad)}");
|
||||
|
||||
if (afilters.Count > 0)
|
||||
{
|
||||
args.Add("-af");
|
||||
args.Add($"apad=pad_dur={Fmt(pad)}");
|
||||
args.Add(string.Join(",", afilters));
|
||||
}
|
||||
|
||||
if (padding)
|
||||
{
|
||||
args.Add("-t");
|
||||
args.Add(Fmt(target));
|
||||
}
|
||||
|
||||
@@ -15,4 +15,11 @@ public sealed class MediaOptions
|
||||
|
||||
/// <summary>Период опроса inbox/ сканером, секунды.</summary>
|
||||
public int InboxScanSeconds { get; init; } = 15;
|
||||
|
||||
/// <summary>Нормализовать громкость при обработке (ffmpeg loudnorm, EBU R128) — чтобы все ролики
|
||||
/// звучали одинаково.</summary>
|
||||
public bool NormalizeLoudness { get; init; } = true;
|
||||
|
||||
/// <summary>Целевая интегральная громкость, LUFS (−16 — типично для стриминга; тише — уменьшить).</summary>
|
||||
public int LoudnessTargetLufs { get; init; } = -16;
|
||||
}
|
||||
|
||||
@@ -182,6 +182,7 @@ nice -n 10 ffmpeg -i src \
|
||||
-c:v libx264 -preset veryfast -crf 21 -maxrate 4500k -bufsize 9000k \
|
||||
-vf "scale='min(1920,iw)':-2" \
|
||||
-force_key_frames "expr:gte(t,n_forced*2)" -sc_threshold 0 \
|
||||
-af "loudnorm=I=-16:TP=-1.5:LRA=11" \
|
||||
-c:a aac -b:a 128k -ac 2 -ar 48000 \
|
||||
-f hls -hls_time 2 -hls_playlist_type vod -hls_list_size 0 \
|
||||
-hls_segment_filename seg%05d.ts index.m3u8
|
||||
@@ -191,7 +192,10 @@ nice -n 10 ffmpeg -i src \
|
||||
- `-force_key_frames expr:gte(t,n_forced*2)` надёжнее фиксированного `-g` при нецелых fps.
|
||||
- `-sc_threshold 0` убирает сцен-детект, иначе сегменты перестанут быть ровными.
|
||||
- `maxrate 4500k` — ключевой кадр каждые 2с стоит ~5–10% битрейта.
|
||||
- `-threads 3` + `nice` оставляют ядро эфиру. Финальный шаг — добивка хвоста до кратности 2с.
|
||||
- `loudnorm=I=-16:TP=-1.5:LRA=11` — нормализация громкости (EBU R128), чтобы все ролики звучали
|
||||
одинаково; цель настраивается (`Media__LoudnessTargetLufs`), можно выключить (`Media__NormalizeLoudness`).
|
||||
- `-threads 3` + `nice` оставляют ядро эфиру. Финальный шаг — добивка хвоста до кратности 2с
|
||||
(`-af ...,apad=pad_dur=PAD -t TARGET`).
|
||||
|
||||
Очередь обработки: `System.Threading.Channels` + `BackgroundService`, строго одна задача за раз.
|
||||
Inbox-сканер — второй `BackgroundService`: замечает новый файл, ждёт стабилизации размера, заводит
|
||||
|
||||
Reference in New Issue
Block a user