Browse Source

limit hls direct streams to realtime speed (#1237)

pull/1238/head
Jason Dove 3 years ago committed by GitHub
parent
commit
cf1552910a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      CHANGELOG.md
  2. 7
      ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs
  3. 53
      ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs

3
CHANGELOG.md

@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased] ## [Unreleased]
### Fixed
- Limit `HLS Direct` streams to realtime speed
## [0.7.7-beta] - 2023-04-07 ## [0.7.7-beta] - 2023-04-07
### Added ### Added
- Use `plot` field from Other Video NFO metadata as XMLTV description - Use `plot` field from Other Video NFO metadata as XMLTV description

7
ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using ErsatzTV.FFmpeg.Capabilities; using ErsatzTV.FFmpeg.Capabilities;
using ErsatzTV.FFmpeg.Encoder; using ErsatzTV.FFmpeg.Encoder;
using ErsatzTV.FFmpeg.Format; using ErsatzTV.FFmpeg.Format;
using ErsatzTV.FFmpeg.Option;
using ErsatzTV.FFmpeg.OutputFormat; using ErsatzTV.FFmpeg.OutputFormat;
using ErsatzTV.FFmpeg.Pipeline; using ErsatzTV.FFmpeg.Pipeline;
using ErsatzTV.FFmpeg.State; using ErsatzTV.FFmpeg.State;
@ -325,11 +326,13 @@ public class PipelineBuilderBaseTests
result.PipelineSteps.Should().HaveCountGreaterThan(0); result.PipelineSteps.Should().HaveCountGreaterThan(0);
result.PipelineSteps.Should().Contain(ps => ps is EncoderCopyVideo); result.PipelineSteps.Should().Contain(ps => ps is EncoderCopyVideo);
result.PipelineSteps.Should().Contain(ps => ps is EncoderCopyAudio); result.PipelineSteps.Should().Contain(ps => ps is EncoderCopyAudio);
videoInputFile.InputOptions.Should().Contain(io => io is RealtimeInputOption);
string command = PrintCommand(videoInputFile, audioInputFile, None, None, result); string command = PrintCommand(videoInputFile, audioInputFile, None, None, result);
// 0.4.0 reference: "-nostdin -threads 1 -hide_banner -loglevel error -nostats -fflags +genpts+discardcorrupt+igndts -re -ss 00:14:33.6195516 -i /tmp/whatever.mkv -map 0:0 -map 0:a -c:v copy -flags cgop -sc_threshold 0 -c:a copy -movflags +faststart -muxdelay 0 -muxpreload 0 -metadata service_provider="ErsatzTV" -metadata service_name="ErsatzTV" -t 00:06:39.6934484 -f mpegts -mpegts_flags +initial_discontinuity pipe:1"
command.Should().Be( command.Should().Be(
"-nostdin -hide_banner -nostats -loglevel error -fflags +genpts+discardcorrupt+igndts -i /tmp/whatever.mkv -map 0:1 -map 0:0 -muxdelay 0 -muxpreload 0 -movflags +faststart -flags cgop -sc_threshold 0 -c:v copy -c:a copy -f mpegts -mpegts_flags +initial_discontinuity pipe:1"); "-nostdin -hide_banner -nostats -loglevel error -fflags +genpts+discardcorrupt+igndts -re -i /tmp/whatever.mkv -map 0:1 -map 0:0 -muxdelay 0 -muxpreload 0 -movflags +faststart -flags cgop -sc_threshold 0 -c:v copy -c:a copy -f mpegts -mpegts_flags +initial_discontinuity pipe:1");
} }
[Test] [Test]
@ -407,7 +410,7 @@ public class PipelineBuilderBaseTests
string command = PrintCommand(videoInputFile, audioInputFile, None, None, result); string command = PrintCommand(videoInputFile, audioInputFile, None, None, result);
command.Should().Be( command.Should().Be(
"-nostdin -hide_banner -nostats -loglevel error -fflags +genpts+discardcorrupt+igndts -i /tmp/whatever.mkv -map 0:a -map 0:0 -muxdelay 0 -muxpreload 0 -movflags +faststart -flags cgop -sc_threshold 0 -c:v copy -c:a copy -f mpegts -mpegts_flags +initial_discontinuity pipe:1"); "-nostdin -hide_banner -nostats -loglevel error -fflags +genpts+discardcorrupt+igndts -re -i /tmp/whatever.mkv -map 0:a -map 0:0 -muxdelay 0 -muxpreload 0 -movflags +faststart -flags cgop -sc_threshold 0 -c:v copy -c:a copy -f mpegts -mpegts_flags +initial_discontinuity pipe:1");
} }
[Test] [Test]

53
ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs

@ -174,22 +174,13 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
SetStreamSeek(ffmpegState, videoInputFile, context, pipelineSteps); SetStreamSeek(ffmpegState, videoInputFile, context, pipelineSteps);
SetTimeLimit(ffmpegState, pipelineSteps); SetTimeLimit(ffmpegState, pipelineSteps);
FilterChain filterChain = FilterChain.Empty; FilterChain filterChain = BuildVideoPipeline(
videoInputFile,
if (desiredState.VideoFormat == VideoFormat.Copy) videoStream,
{ ffmpegState,
pipelineSteps.Add(new EncoderCopyVideo()); desiredState,
} context,
else pipelineSteps);
{
filterChain = BuildVideoPipeline(
videoInputFile,
videoStream,
ffmpegState,
desiredState,
context,
pipelineSteps);
}
if (_audioInputFile.IsNone) if (_audioInputFile.IsNone)
{ {
@ -398,7 +389,10 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
ffmpegState = SetAccelState(videoStream, ffmpegState, desiredState, context, pipelineSteps); ffmpegState = SetAccelState(videoStream, ffmpegState, desiredState, context, pipelineSteps);
Option<IDecoder> maybeDecoder = SetDecoder(videoInputFile, videoStream, ffmpegState, context); // don't use explicit decoder with HLS Direct
Option<IDecoder> maybeDecoder = desiredState.VideoFormat == VideoFormat.Copy
? None
: SetDecoder(videoInputFile, videoStream, ffmpegState, context);
SetStillImageInfiniteLoop(videoInputFile, videoStream, ffmpegState); SetStillImageInfiniteLoop(videoInputFile, videoStream, ffmpegState);
SetRealtimeInput(videoInputFile, desiredState); SetRealtimeInput(videoInputFile, desiredState);
@ -473,6 +467,11 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
private static void SetOutputTsOffset(FFmpegState ffmpegState, FrameState desiredState, ICollection<IPipelineStep> pipelineSteps) private static void SetOutputTsOffset(FFmpegState ffmpegState, FrameState desiredState, ICollection<IPipelineStep> pipelineSteps)
{ {
if (desiredState.VideoFormat == VideoFormat.Copy)
{
return;
}
if (ffmpegState.PtsOffset > 0) if (ffmpegState.PtsOffset > 0)
{ {
foreach (int videoTrackTimeScale in desiredState.VideoTrackTimeScale) foreach (int videoTrackTimeScale in desiredState.VideoTrackTimeScale)
@ -484,6 +483,11 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
private static void SetVideoBufferSizeOutput(FrameState desiredState, ICollection<IPipelineStep> pipelineSteps) private static void SetVideoBufferSizeOutput(FrameState desiredState, ICollection<IPipelineStep> pipelineSteps)
{ {
if (desiredState.VideoFormat == VideoFormat.Copy)
{
return;
}
foreach (int desiredBufferSize in desiredState.VideoBufferSize) foreach (int desiredBufferSize in desiredState.VideoBufferSize)
{ {
pipelineSteps.Add(new VideoBufferSizeOutputOption(desiredBufferSize)); pipelineSteps.Add(new VideoBufferSizeOutputOption(desiredBufferSize));
@ -492,6 +496,11 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
private static void SetVideoBitrateOutput(FrameState desiredState, ICollection<IPipelineStep> pipelineSteps) private static void SetVideoBitrateOutput(FrameState desiredState, ICollection<IPipelineStep> pipelineSteps)
{ {
if (desiredState.VideoFormat == VideoFormat.Copy)
{
return;
}
foreach (int desiredBitrate in desiredState.VideoBitrate) foreach (int desiredBitrate in desiredState.VideoBitrate)
{ {
pipelineSteps.Add(new VideoBitrateOutputOption(desiredBitrate)); pipelineSteps.Add(new VideoBitrateOutputOption(desiredBitrate));
@ -500,6 +509,11 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
private static void SetVideoTrackTimescaleOutput(FrameState desiredState, ICollection<IPipelineStep> pipelineSteps) private static void SetVideoTrackTimescaleOutput(FrameState desiredState, ICollection<IPipelineStep> pipelineSteps)
{ {
if (desiredState.VideoFormat == VideoFormat.Copy)
{
return;
}
foreach (int desiredTimeScale in desiredState.VideoTrackTimeScale) foreach (int desiredTimeScale in desiredState.VideoTrackTimeScale)
{ {
pipelineSteps.Add(new VideoTrackTimescaleOutputOption(desiredTimeScale)); pipelineSteps.Add(new VideoTrackTimescaleOutputOption(desiredTimeScale));
@ -508,6 +522,11 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
private static void SetFrameRateOutput(FrameState desiredState, ICollection<IPipelineStep> pipelineSteps) private static void SetFrameRateOutput(FrameState desiredState, ICollection<IPipelineStep> pipelineSteps)
{ {
if (desiredState.VideoFormat == VideoFormat.Copy)
{
return;
}
foreach (int desiredFrameRate in desiredState.FrameRate) foreach (int desiredFrameRate in desiredState.FrameRate)
{ {
pipelineSteps.Add(new FrameRateOutputOption(desiredFrameRate)); pipelineSteps.Add(new FrameRateOutputOption(desiredFrameRate));

Loading…
Cancel
Save