Browse Source

optimize qsv h264 stream startup (#2835)

pull/2838/head
Jason Dove 1 month ago committed by GitHub
parent
commit
fd86cb55f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 7
      ErsatzTV.Application/Streaming/HlsSessionWorker.cs
  2. 54
      ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs

7
ErsatzTV.Application/Streaming/HlsSessionWorker.cs

@ -313,9 +313,6 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -313,9 +313,6 @@ public class HlsSessionWorker : IHlsSessionWorker
var sw = Stopwatch.StartNew();
try
{
DateTimeOffset start = DateTimeOffset.Now;
DateTimeOffset finish = start.AddSeconds(8);
string playlistFileName = Path.Combine(_workingDirectory, "live.m3u8");
_logger.LogDebug("Waiting for playlist to exist");
@ -326,6 +323,10 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -326,6 +323,10 @@ public class HlsSessionWorker : IHlsSessionWorker
_logger.LogDebug("Playlist exists");
// start the segment-wait deadline only after the playlist file appears,
// so slow pipeline setup (e.g. h264 profile probing) doesn't consume the budget
DateTimeOffset finish = DateTimeOffset.Now.AddSeconds(8);
var segmentCount = 0;
int lastSegmentCount = -1;
while (DateTimeOffset.Now < finish && segmentCount < initialSegmentCount)

54
ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs

@ -359,9 +359,11 @@ public partial class LocalStatisticsProvider : ILocalStatisticsProvider @@ -359,9 +359,11 @@ public partial class LocalStatisticsProvider : ILocalStatisticsProvider
string filePath,
CancellationToken cancellationToken)
{
// only scans first 30 seconds
string[] arguments =
[
"-hide_banner",
"-t", "30",
"-i", filePath,
"-c", "copy",
"-bsf:v", "trace_headers",
@ -370,28 +372,42 @@ public partial class LocalStatisticsProvider : ILocalStatisticsProvider @@ -370,28 +372,42 @@ public partial class LocalStatisticsProvider : ILocalStatisticsProvider
var uniqueProfiles = new System.Collections.Generic.HashSet<string>();
CommandResult traceHeaders = await Cli.Wrap(ffmpegPath)
.WithArguments(arguments)
.WithValidation(CommandResultValidation.None)
.WithStandardErrorPipe(
PipeTarget.ToDelegate(line =>
{
int idx = line.IndexOf("profile_idc", StringComparison.Ordinal);
if (idx >= 0)
{
uniqueProfiles.Add(line[idx..]);
}
}))
.ExecuteAsync(cancellationToken);
// cancel as soon as we find a second distinct profile_idc
using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
if (traceHeaders.ExitCode != 0)
try
{
_logger.LogInformation(
"FFmpeg trace headers with arguments {Arguments} exited with code {ExitCode}",
arguments,
traceHeaders.ExitCode);
CommandResult traceHeaders = await Cli.Wrap(ffmpegPath)
.WithArguments(arguments)
.WithValidation(CommandResultValidation.None)
.WithStandardErrorPipe(
PipeTarget.ToDelegate(line =>
{
int idx = line.IndexOf("profile_idc", StringComparison.Ordinal);
if (idx >= 0)
{
uniqueProfiles.Add(line[idx..]);
if (uniqueProfiles.Count > 1)
{
linkedCts.Cancel();
}
}
}))
.ExecuteAsync(linkedCts.Token);
if (traceHeaders.ExitCode != 0)
{
_logger.LogInformation(
"FFmpeg trace headers with arguments {Arguments} exited with code {ExitCode}",
arguments,
traceHeaders.ExitCode);
return Option<int>.None;
return Option<int>.None;
}
}
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
{
// nothing to do here - canceled because a second profile was found
}
return uniqueProfiles.Count;

Loading…
Cancel
Save