Browse Source

refactor parsing ffmpeg progress/speed

pull/2808/head
Jason Dove 6 months ago
parent
commit
e6daa12abd
No known key found for this signature in database
  1. 27
      ErsatzTV.Application/Troubleshooting/Commands/StartTroubleshootingPlaybackHandler.cs
  2. 20
      ErsatzTV.Core/FFmpeg/FFmpegProgressParser.cs
  3. 2
      ErsatzTV.FFmpeg/GlobalOption/NoStatsOption.cs
  4. 6
      ErsatzTV.FFmpeg/GlobalOption/ProgressOption.cs
  5. 1
      ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs

27
ErsatzTV.Application/Troubleshooting/Commands/StartTroubleshootingPlaybackHandler.cs

@ -2,10 +2,10 @@ using System.IO.Pipelines;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using CliWrap; using CliWrap;
using ErsatzTV.Core; using ErsatzTV.Core;
using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain;
using ErsatzTV.Core.FFmpeg;
using ErsatzTV.Core.Interfaces.Locking; using ErsatzTV.Core.Interfaces.Locking;
using ErsatzTV.Core.Interfaces.Streaming; using ErsatzTV.Core.Interfaces.Streaming;
using ErsatzTV.Core.Interfaces.Troubleshooting; using ErsatzTV.Core.Interfaces.Troubleshooting;
@ -17,7 +17,7 @@ using Serilog.Events;
namespace ErsatzTV.Application.Troubleshooting; namespace ErsatzTV.Application.Troubleshooting;
public partial class StartTroubleshootingPlaybackHandler( public class StartTroubleshootingPlaybackHandler(
ITroubleshootingNotifier notifier, ITroubleshootingNotifier notifier,
IMediator mediator, IMediator mediator,
IEntityLocker entityLocker, IEntityLocker entityLocker,
@ -138,9 +138,12 @@ public partial class StartTroubleshootingPlaybackHandler(
linkedCts.Token); linkedCts.Token);
} }
var progressParser = new FFmpegProgressParser();
CommandResult commandResult = await processWithPipe CommandResult commandResult = await processWithPipe
.WithWorkingDirectory(FileSystemLayout.TranscodeTroubleshootingFolder) .WithWorkingDirectory(FileSystemLayout.TranscodeTroubleshootingFolder)
.WithStandardErrorPipe(PipeTarget.Null) .WithStandardErrorPipe(PipeTarget.Null)
.WithStandardOutputPipe(PipeTarget.ToDelegate(progressParser.ParseLine))
.WithValidation(CommandResultValidation.None) .WithValidation(CommandResultValidation.None)
.ExecuteAsync(linkedCts.Token); .ExecuteAsync(linkedCts.Token);
@ -160,26 +163,11 @@ public partial class StartTroubleshootingPlaybackHandler(
// do nothing // do nothing
} }
Option<double> maybeSpeed = Option<double>.None;
Option<string> maybeFile = Directory.GetFiles(FileSystemLayout.TranscodeTroubleshootingFolder, "ffmpeg*.log").HeadOrNone();
foreach (string file in maybeFile)
{
await foreach (string line in File.ReadLinesAsync(file, linkedCts.Token))
{
Match match = FFmpegSpeed().Match(line);
if (match.Success && double.TryParse(match.Groups[1].Value, out double speed))
{
maybeSpeed = speed;
break;
}
}
}
await mediator.Publish( await mediator.Publish(
new PlaybackTroubleshootingCompletedNotification( new PlaybackTroubleshootingCompletedNotification(
commandResult.ExitCode, commandResult.ExitCode,
Option<Exception>.None, Option<Exception>.None,
maybeSpeed), progressParser.Speed),
linkedCts.Token); linkedCts.Token);
if (commandResult.ExitCode != 0) if (commandResult.ExitCode != 0)
@ -210,7 +198,4 @@ public partial class StartTroubleshootingPlaybackHandler(
loggingLevelSwitches.StreamingLevelSwitch.MinimumLevel = currentStreamingLevel; loggingLevelSwitches.StreamingLevelSwitch.MinimumLevel = currentStreamingLevel;
} }
} }
[GeneratedRegex(@"speed=\s*([\d\.]+)x", RegexOptions.IgnoreCase)]
private static partial Regex FFmpegSpeed();
} }

20
ErsatzTV.Core/FFmpeg/FFmpegProgressParser.cs

@ -0,0 +1,20 @@
using System.Text.RegularExpressions;
namespace ErsatzTV.Core.FFmpeg;
public partial class FFmpegProgressParser
{
public Option<double> Speed { get; private set; } = Option<double>.None;
public void ParseLine(string line)
{
Match match = FFmpegSpeed().Match(line);
if (match.Success && double.TryParse(match.Groups[1].Value, out double speed))
{
Speed = speed;
}
}
[GeneratedRegex(@"speed=\s*([\d\.]+)x", RegexOptions.IgnoreCase)]
private static partial Regex FFmpegSpeed();
}

2
ErsatzTV.FFmpeg/GlobalOption/NoStatsOption.cs

@ -2,5 +2,5 @@
public class NoStatsOption : GlobalOption public class NoStatsOption : GlobalOption
{ {
public override string[] GlobalOptions => new[] { "-nostats" }; public override string[] GlobalOptions => ["-nostats"];
} }

6
ErsatzTV.FFmpeg/GlobalOption/ProgressOption.cs

@ -0,0 +1,6 @@
namespace ErsatzTV.FFmpeg.GlobalOption;
public class ProgressOption : GlobalOption
{
public override string[] GlobalOptions => ["-progress", "-"];
}

1
ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs

@ -211,6 +211,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
new NoStandardInputOption(), new NoStandardInputOption(),
new HideBannerOption(), new HideBannerOption(),
new NoStatsOption(), new NoStatsOption(),
new ProgressOption(),
new LoglevelErrorOption(), new LoglevelErrorOption(),
new StandardFormatFlags(), new StandardFormatFlags(),
new NoDemuxDecodeDelayOutputOption(), new NoDemuxDecodeDelayOutputOption(),

Loading…
Cancel
Save