Browse Source

slightly increase throttled readrate in segmenter (#2534)

pull/2535/head
Jason Dove 7 months ago committed by GitHub
parent
commit
9bae8e73bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      ErsatzTV.Application/Streaming/HlsSessionWorker.cs
  2. 4
      ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs
  3. 8
      ErsatzTV.FFmpeg/Capabilities/FFmpegKnownOption.cs
  4. 47
      ErsatzTV.FFmpeg/InputOption/ReadrateInputOption.cs
  5. 28
      ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs

5
ErsatzTV.Application/Streaming/HlsSessionWorker.cs

@ -515,7 +515,10 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -515,7 +515,10 @@ public class HlsSessionWorker : IHlsSessionWorker
if (commandResult.ExitCode == 0)
{
_logger.LogDebug("HLS process has completed for channel {Channel}", _channelNumber);
_logger.LogDebug("Transcoded until: {Until}", processModel.Until);
_logger.LogDebug(
"Transcoded until: {Until} - buffer {Buffer}",
processModel.Until,
DateTimeOffset.Now - processModel.Until);
_transcodedUntil = processModel.Until;
_state = NextState(_state, processModel);
_hasWrittenSegments = true;

4
ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs

@ -118,7 +118,7 @@ public class PipelineBuilderBaseTests @@ -118,7 +118,7 @@ public class PipelineBuilderBaseTests
string command = PrintCommand(videoInputFile, audioInputFile, None, None, None, result);
command.ShouldBe(
"-nostdin -hide_banner -nostats -loglevel error -fflags +genpts+discardcorrupt+igndts -ss 00:00:01 -c:v h264 -readrate 1.0 -i /tmp/whatever.mkv -filter_complex [0:1]aresample=async=1[a] -map 0:0 -map [a] -muxdelay 0 -muxpreload 0 -movflags +faststart -flags cgop -bf 0 -sc_threshold 0 -video_track_timescale 90000 -b:v 2000k -maxrate:v 2000k -bufsize:v 4000k -c:v libx265 -tag:v hvc1 -x265-params log-level=error -c:a aac -b:a 320k -maxrate:a 320k -bufsize:a 640k -ar 48k -f mpegts -mpegts_flags +initial_discontinuity pipe:1");
"-nostdin -hide_banner -nostats -loglevel error -fflags +genpts+discardcorrupt+igndts -ss 00:00:01 -c:v h264 -readrate 1.05 -i /tmp/whatever.mkv -filter_complex [0:1]aresample=async=1[a] -map 0:0 -map [a] -muxdelay 0 -muxpreload 0 -movflags +faststart -flags cgop -bf 0 -sc_threshold 0 -video_track_timescale 90000 -b:v 2000k -maxrate:v 2000k -bufsize:v 4000k -c:v libx265 -tag:v hvc1 -x265-params log-level=error -c:a aac -b:a 320k -maxrate:a 320k -bufsize:a 640k -ar 48k -f mpegts -mpegts_flags +initial_discontinuity pipe:1");
}
[Test]
@ -217,7 +217,7 @@ public class PipelineBuilderBaseTests @@ -217,7 +217,7 @@ public class PipelineBuilderBaseTests
string command = PrintCommand(videoInputFile, audioInputFile, None, None, None, result);
command.ShouldBe(
"-nostdin -hide_banner -nostats -loglevel error -fflags +genpts+discardcorrupt+igndts -ss 00:00:01 -c:v h264 -readrate 1.0 -i /tmp/whatever.mkv -filter_complex [0:1]aresample=async=1[a] -map 0:0 -map [a] -muxdelay 0 -muxpreload 0 -movflags +faststart -flags cgop -bf 0 -sc_threshold 0 -video_track_timescale 90000 -b:v 2000k -maxrate:v 2000k -bufsize:v 4000k -c:v libx265 -tag:v hvc1 -x265-params log-level=error -c:a aac -ac 6 -b:a 320k -maxrate:a 320k -bufsize:a 640k -ar 48k -f mpegts -mpegts_flags +initial_discontinuity pipe:1");
"-nostdin -hide_banner -nostats -loglevel error -fflags +genpts+discardcorrupt+igndts -ss 00:00:01 -c:v h264 -readrate 1.05 -i /tmp/whatever.mkv -filter_complex [0:1]aresample=async=1[a] -map 0:0 -map [a] -muxdelay 0 -muxpreload 0 -movflags +faststart -flags cgop -bf 0 -sc_threshold 0 -video_track_timescale 90000 -b:v 2000k -maxrate:v 2000k -bufsize:v 4000k -c:v libx265 -tag:v hvc1 -x265-params log-level=error -c:a aac -ac 6 -b:a 320k -maxrate:a 320k -bufsize:a 640k -ar 48k -f mpegts -mpegts_flags +initial_discontinuity pipe:1");
}
[Test]

8
ErsatzTV.FFmpeg/Capabilities/FFmpegKnownOption.cs

@ -6,15 +6,11 @@ namespace ErsatzTV.FFmpeg.Capabilities; @@ -6,15 +6,11 @@ namespace ErsatzTV.FFmpeg.Capabilities;
[SuppressMessage("ReSharper", "StringLiteralTypo")]
public record FFmpegKnownOption
{
public static readonly FFmpegKnownOption ReadrateInitialBurst = new("readrate_initial_burst");
private FFmpegKnownOption(string Name) => this.Name = Name;
public string Name { get; }
public static IList<string> AllOptions =>
new[]
{
ReadrateInitialBurst.Name
};
[
];
}

47
ErsatzTV.FFmpeg/InputOption/ReadrateInputOption.cs

@ -1,54 +1,19 @@ @@ -1,54 +1,19 @@
using System.Globalization;
using ErsatzTV.FFmpeg.Capabilities;
using ErsatzTV.FFmpeg.Environment;
using Microsoft.Extensions.Logging;
namespace ErsatzTV.FFmpeg.InputOption;
public class ReadrateInputOption : IInputOption
public class ReadrateInputOption(double readRate) : IInputOption
{
private readonly IFFmpegCapabilities _ffmpegCapabilities;
private readonly int _initialBurstSeconds;
private readonly ILogger _logger;
public ReadrateInputOption(
IFFmpegCapabilities ffmpegCapabilities,
int initialBurstSeconds,
ILogger logger)
{
_ffmpegCapabilities = ffmpegCapabilities;
_initialBurstSeconds = initialBurstSeconds;
_logger = logger;
}
public EnvironmentVariable[] EnvironmentVariables => [];
public string[] GlobalOptions => [];
public string[] InputOptions(InputFile inputFile)
{
var result = new List<string> { "-readrate", "1.0" };
if (_initialBurstSeconds > 0)
{
if (!_ffmpegCapabilities.HasOption(FFmpegKnownOption.ReadrateInitialBurst))
{
_logger.LogWarning(
"FFmpeg is missing {Option} option; unable to transcode faster than realtime",
FFmpegKnownOption.ReadrateInitialBurst.Name);
return result.ToArray();
}
result.AddRange(
[
"-readrate_initial_burst",
_initialBurstSeconds.ToString(CultureInfo.InvariantCulture)
]);
}
return result.ToArray();
}
public string[] InputOptions(InputFile inputFile) =>
[
"-readrate",
readRate.ToString("0.0####", CultureInfo.InvariantCulture)
];
public string[] FilterOptions => [];
public string[] OutputOptions => [];

28
ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs

@ -116,7 +116,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder @@ -116,7 +116,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
};
concatInputFile.AddOption(new ConcatInputFormat());
concatInputFile.AddOption(new ReadrateInputOption(_ffmpegCapabilities, 0, _logger));
concatInputFile.AddOption(new ReadrateInputOption(1.0));
concatInputFile.AddOption(new InfiniteLoopInputOption(HardwareAccelerationMode.None));
foreach (int threadCount in ffmpegState.ThreadCount)
@ -162,7 +162,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder @@ -162,7 +162,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
new EncoderCopyAll()
};
concatInputFile.AddOption(new ReadrateInputOption(_ffmpegCapabilities, 0, _logger));
concatInputFile.AddOption(new ReadrateInputOption(1.0));
SetMetadataServiceProvider(ffmpegState, pipelineSteps);
SetMetadataServiceName(ffmpegState, pipelineSteps);
@ -564,7 +564,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder @@ -564,7 +564,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
: SetDecoder(videoInputFile, videoStream, ffmpegState, context);
//SetStillImageInfiniteLoop(videoInputFile, videoStream, ffmpegState);
SetRealtimeInput(videoInputFile, ffmpegState, desiredState);
SetRealtimeInput(videoInputFile, desiredState);
SetInfiniteLoop(videoInputFile, videoStream, ffmpegState, desiredState);
SetFrameRateOutput(desiredState, pipelineSteps);
SetVideoTrackTimescaleOutput(desiredState, pipelineSteps);
@ -761,30 +761,16 @@ public abstract class PipelineBuilderBase : IPipelineBuilder @@ -761,30 +761,16 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
}
}
private void SetRealtimeInput(VideoInputFile videoInputFile, FFmpegState ffmpegState, FrameState desiredState)
private void SetRealtimeInput(VideoInputFile videoInputFile, FrameState desiredState)
{
if (videoInputFile.StreamInputKind is StreamInputKind.Live || !desiredState.Realtime)
{
return;
}
AudioFilter filter = _audioInputFile
.Map(a => a.DesiredState.NormalizeLoudnessFilter)
.IfNone(AudioFilter.None);
int initialBurst = filter switch
{
AudioFilter.LoudNorm => 5,
_ => 0
};
if (ffmpegState.Finish.Any(finish => finish.TotalSeconds < initialBurst))
{
return;
}
_audioInputFile.Iter(a => a.AddOption(new ReadrateInputOption(_ffmpegCapabilities, initialBurst, _logger)));
videoInputFile.AddOption(new ReadrateInputOption(_ffmpegCapabilities, initialBurst, _logger));
double readRate = desiredState.VideoFormat == VideoFormat.Copy ? 1.0 : 1.05;
_audioInputFile.Iter(a => a.AddOption(new ReadrateInputOption(readRate)));
videoInputFile.AddOption(new ReadrateInputOption(readRate));
}
protected static void SetStillImageLoop(

Loading…
Cancel
Save