Browse Source

optimize image playback (#1609)

pull/1610/head
Jason Dove 1 year ago committed by GitHub
parent
commit
9587692486
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 8
      ErsatzTV.FFmpeg/Filter/LoopFilter.cs
  2. 4
      ErsatzTV.FFmpeg/InputOption/InfiniteLoopInputOption.cs
  3. 2
      ErsatzTV.FFmpeg/InputOption/ReadrateInputOption.cs
  4. 1
      ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs
  5. 9
      ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs
  6. 1
      ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs
  7. 1
      ErsatzTV.FFmpeg/Pipeline/SoftwarePipelineBuilder.cs
  8. 2
      ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs

8
ErsatzTV.FFmpeg/Filter/LoopFilter.cs

@ -0,0 +1,8 @@
namespace ErsatzTV.FFmpeg.Filter;
public class LoopFilter : BaseFilter
{
public override FrameState NextState(FrameState currentState) => currentState;
public override string Filter => "loop=-1:1";
}

4
ErsatzTV.FFmpeg/InputOption/InfiniteLoopInputOption.cs

@ -17,11 +17,11 @@ public class InfiniteLoopInputOption : IInputOption
// loop 1 for still images // loop 1 for still images
if (inputFile.Streams.OfType<VideoStream>().Any(s => s.StillImage)) if (inputFile.Streams.OfType<VideoStream>().Any(s => s.StillImage))
{ {
return new[] { "-loop", "1" }; return ["-loop", "1"];
} }
// stream_loop for looped video i.e. filler // stream_loop for looped video i.e. filler
return new[] { "-stream_loop", "-1" }; return ["-stream_loop", "-1"];
} }
public string[] FilterOptions => Array.Empty<string>(); public string[] FilterOptions => Array.Empty<string>();

2
ErsatzTV.FFmpeg/InputOption/ReadrateInputOption.cs

@ -55,7 +55,7 @@ public class ReadrateInputOption : IInputOption
public string[] OutputOptions => Array.Empty<string>(); public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState with { Realtime = true }; public FrameState NextState(FrameState currentState) => currentState with { Realtime = true };
public bool AppliesTo(AudioInputFile audioInputFile) => true; public bool AppliesTo(AudioInputFile audioInputFile) => audioInputFile is not NullAudioInputFile;
// don't use realtime input for a still image // don't use realtime input for a still image
public bool AppliesTo(VideoInputFile videoInputFile) => videoInputFile.VideoStreams.All(s => !s.StillImage); public bool AppliesTo(VideoInputFile videoInputFile) => videoInputFile.VideoStreams.All(s => !s.StillImage);

1
ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs

@ -161,6 +161,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder
currentState = SetScale(videoInputFile, videoStream, context, ffmpegState, desiredState, currentState); currentState = SetScale(videoInputFile, videoStream, context, ffmpegState, desiredState, currentState);
currentState = SetPad(videoInputFile, videoStream, desiredState, currentState); currentState = SetPad(videoInputFile, videoStream, desiredState, currentState);
currentState = SetCrop(videoInputFile, desiredState, currentState); currentState = SetCrop(videoInputFile, desiredState, currentState);
SetStillImageLoop(videoInputFile, videoStream);
if (currentState.BitDepth == 8 && context.HasSubtitleOverlay || context.HasWatermark) if (currentState.BitDepth == 8 && context.HasSubtitleOverlay || context.HasWatermark)
{ {

9
ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs

@ -440,7 +440,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
? None ? None
: SetDecoder(videoInputFile, videoStream, ffmpegState, context); : SetDecoder(videoInputFile, videoStream, ffmpegState, context);
SetStillImageInfiniteLoop(videoInputFile, videoStream, ffmpegState); //SetStillImageInfiniteLoop(videoInputFile, videoStream, ffmpegState);
SetRealtimeInput(videoInputFile, ffmpegState, desiredState); SetRealtimeInput(videoInputFile, ffmpegState, desiredState);
SetInfiniteLoop(videoInputFile, videoStream, ffmpegState, desiredState); SetInfiniteLoop(videoInputFile, videoStream, ffmpegState, desiredState);
SetFrameRateOutput(desiredState, pipelineSteps); SetFrameRateOutput(desiredState, pipelineSteps);
@ -643,14 +643,11 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
videoInputFile.AddOption(new ReadrateInputOption(_ffmpegCapabilities, initialBurst, _logger)); videoInputFile.AddOption(new ReadrateInputOption(_ffmpegCapabilities, initialBurst, _logger));
} }
private static void SetStillImageInfiniteLoop( protected static void SetStillImageLoop(VideoInputFile videoInputFile, VideoStream videoStream)
VideoInputFile videoInputFile,
VideoStream videoStream,
FFmpegState ffmpegState)
{ {
if (videoStream.StillImage) if (videoStream.StillImage)
{ {
videoInputFile.AddOption(new InfiniteLoopInputOption(ffmpegState.EncoderHardwareAccelerationMode)); videoInputFile.FilterSteps.Add(new LoopFilter());
} }
} }

1
ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs

@ -166,6 +166,7 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder
currentState = SetPad(videoInputFile, videoStream, desiredState, currentState); currentState = SetPad(videoInputFile, videoStream, desiredState, currentState);
// _logger.LogDebug("After pad: {PixelFormat}", currentState.PixelFormat); // _logger.LogDebug("After pad: {PixelFormat}", currentState.PixelFormat);
currentState = SetCrop(videoInputFile, desiredState, currentState); currentState = SetCrop(videoInputFile, desiredState, currentState);
SetStillImageLoop(videoInputFile, videoStream);
// need to download for any sort of overlay // need to download for any sort of overlay
if (currentState.FrameDataLocation == FrameDataLocation.Hardware && if (currentState.FrameDataLocation == FrameDataLocation.Hardware &&

1
ErsatzTV.FFmpeg/Pipeline/SoftwarePipelineBuilder.cs

@ -105,6 +105,7 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase
currentState = SetScale(videoInputFile, videoStream, desiredState, currentState); currentState = SetScale(videoInputFile, videoStream, desiredState, currentState);
currentState = SetPad(videoInputFile, videoStream, desiredState, currentState); currentState = SetPad(videoInputFile, videoStream, desiredState, currentState);
currentState = SetCrop(videoInputFile, desiredState, currentState); currentState = SetCrop(videoInputFile, desiredState, currentState);
SetStillImageLoop(videoInputFile, videoStream);
SetSubtitle( SetSubtitle(
videoInputFile, videoInputFile,
subtitleInputFile, subtitleInputFile,

2
ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs

@ -170,6 +170,8 @@ public class VaapiPipelineBuilder : SoftwarePipelineBuilder
currentState = SetCrop(videoInputFile, desiredState, currentState); currentState = SetCrop(videoInputFile, desiredState, currentState);
SetStillImageLoop(videoInputFile, videoStream);
// need to upload for hardware overlay // need to upload for hardware overlay
bool forceSoftwareOverlay = context is { HasSubtitleOverlay: true, HasWatermark: true } bool forceSoftwareOverlay = context is { HasSubtitleOverlay: true, HasWatermark: true }
|| ffmpegState.VaapiDriver == "radeonsi"; || ffmpegState.VaapiDriver == "radeonsi";

Loading…
Cancel
Save