From bc8ef94f0d6b3c56eef69f7f8287674ab7a7c6dc Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 1 Jun 2024 17:50:12 +0200 Subject: [PATCH] Audio normalization: parse ffmpeg output line by line Should prevent OOM error Also optimized the regex so it can bail out earlier --- .../Tasks/AudioNormalizationTask.cs | 18 ++++++++++-------- src/Jellyfin.Extensions/StreamExtensions.cs | 7 +++++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs index 04d6ed0f2..7f3a8e291 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs @@ -8,6 +8,7 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Enums; +using Jellyfin.Extensions; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -69,7 +70,7 @@ public partial class AudioNormalizationTask : IScheduledTask /// public string Key => "AudioNormalization"; - [GeneratedRegex(@"I:\s+(.*?)\s+LUFS")] + [GeneratedRegex(@"^\s+I:\s+(.*?)\s+LUFS")] private static partial Regex LUFSRegex(); /// @@ -179,16 +180,17 @@ public partial class AudioNormalizationTask : IScheduledTask } using var reader = process.StandardError; - var output = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false); - cancellationToken.ThrowIfCancellationRequested(); - MatchCollection split = LUFSRegex().Matches(output); - - if (split.Count != 0) + await foreach (var line in reader.ReadAllLinesAsync(cancellationToken)) { - return float.Parse(split[0].Groups[1].ValueSpan, CultureInfo.InvariantCulture.NumberFormat); + Match match = LUFSRegex().Match(line); + + if (match.Success) + { + return float.Parse(match.Groups[1].ValueSpan, CultureInfo.InvariantCulture.NumberFormat); + } } - _logger.LogError("Failed to find LUFS value in output:\n{Output}", output); + _logger.LogError("Failed to find LUFS value in output"); return null; } } diff --git a/src/Jellyfin.Extensions/StreamExtensions.cs b/src/Jellyfin.Extensions/StreamExtensions.cs index 182996852..0cfac384e 100644 --- a/src/Jellyfin.Extensions/StreamExtensions.cs +++ b/src/Jellyfin.Extensions/StreamExtensions.cs @@ -1,7 +1,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; +using System.Threading; namespace Jellyfin.Extensions { @@ -48,11 +50,12 @@ namespace Jellyfin.Extensions /// Reads all lines in the . /// /// The to read from. + /// The token to monitor for cancellation requests. /// All lines in the stream. - public static async IAsyncEnumerable ReadAllLinesAsync(this TextReader reader) + public static async IAsyncEnumerable ReadAllLinesAsync(this TextReader reader, [EnumeratorCancellation] CancellationToken cancellationToken = default) { string? line; - while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) is not null) + while ((line = await reader.ReadLineAsync(cancellationToken).ConfigureAwait(false)) is not null) { yield return line; }