diff --git a/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs b/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs index d934038b2..d96f95c90 100644 --- a/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs +++ b/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs @@ -226,12 +226,21 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService { var pipelineBuilder = new PipelineBuilder(inputFiles, FileSystemLayout.FFmpegReportsFolder, _logger); - IList pipelineSteps = pipelineBuilder.Build(desiredState); + FFmpegPipeline pipeline = pipelineBuilder.Build(desiredState); - _logger.LogDebug("FFmpeg pipeline {PipelineSteps}", pipelineSteps.Map(ps => ps.GetType().Name)); + IEnumerable loggedSteps = pipeline.PipelineSteps.Map(ps => ps.GetType().Name); + IEnumerable loggedVideoFilters = pipeline.VideoFilterSteps.Map(vf => vf.GetType().Name); + IEnumerable loggedAudioFilters = pipeline.AudioFilterSteps.Map(af => af.GetType().Name); - IList environmentVariables = CommandGenerator.GenerateEnvironmentVariables(pipelineSteps); - IList arguments = CommandGenerator.GenerateArguments(inputFiles, pipelineSteps); + _logger.LogDebug( + "FFmpeg pipeline {PipelineSteps}, {AudioFilters}, {VideoFilters}", + loggedSteps, + loggedAudioFilters, + loggedVideoFilters + ); + + IList environmentVariables = CommandGenerator.GenerateEnvironmentVariables(pipeline.PipelineSteps); + IList arguments = CommandGenerator.GenerateArguments(inputFiles, pipeline.PipelineSteps); var startInfo = new ProcessStartInfo { diff --git a/ErsatzTV.FFmpeg.Tests/PipelineBuilderTests.cs b/ErsatzTV.FFmpeg.Tests/PipelineBuilderTests.cs index 9ae6eae0e..2dfde3f4b 100644 --- a/ErsatzTV.FFmpeg.Tests/PipelineBuilderTests.cs +++ b/ErsatzTV.FFmpeg.Tests/PipelineBuilderTests.cs @@ -64,9 +64,9 @@ public class PipelineGeneratorTests 0); var builder = new PipelineBuilder(inputFiles, "", _logger); - IList result = builder.Build(desiredState); + FFmpegPipeline result = builder.Build(desiredState); - result.Should().HaveCountGreaterThan(0); + result.PipelineSteps.Should().HaveCountGreaterThan(0); PrintCommand(inputFiles, result); } @@ -120,9 +120,9 @@ public class PipelineGeneratorTests 0); var builder = new PipelineBuilder(inputFiles, "", _logger); - IList result = builder.Build(desiredState); + FFmpegPipeline result = builder.Build(desiredState); - result.Should().HaveCountGreaterThan(0); + result.PipelineSteps.Should().HaveCountGreaterThan(0); PrintCommand(inputFiles, result); } @@ -139,16 +139,16 @@ public class PipelineGeneratorTests }; var builder = new PipelineBuilder(inputFiles, "", _logger); - IList result = builder.Build(desiredState); + FFmpegPipeline result = builder.Build(desiredState); - result.Should().HaveCountGreaterThan(0); + result.PipelineSteps.Should().HaveCountGreaterThan(0); PrintCommand(inputFiles, result); } - private static void PrintCommand(IEnumerable inputFiles, IList pipeline) + private static void PrintCommand(IEnumerable inputFiles, FFmpegPipeline pipeline) { - IList arguments = CommandGenerator.GenerateArguments(inputFiles, pipeline); + IList arguments = CommandGenerator.GenerateArguments(inputFiles, pipeline.PipelineSteps); Console.WriteLine($"Generated command: ffmpeg {string.Join(" ", arguments)}"); } } diff --git a/ErsatzTV.FFmpeg/FFmpegPipeline.cs b/ErsatzTV.FFmpeg/FFmpegPipeline.cs new file mode 100644 index 000000000..937c0888a --- /dev/null +++ b/ErsatzTV.FFmpeg/FFmpegPipeline.cs @@ -0,0 +1,6 @@ +namespace ErsatzTV.FFmpeg; + +public record FFmpegPipeline( + IList PipelineSteps, + IList VideoFilterSteps, + IList AudioFilterSteps); diff --git a/ErsatzTV.FFmpeg/Option/HardwareAcceleration/QsvHardwareAccelerationOption.cs b/ErsatzTV.FFmpeg/Option/HardwareAcceleration/QsvHardwareAccelerationOption.cs index 3bc5374b8..af6a86894 100644 --- a/ErsatzTV.FFmpeg/Option/HardwareAcceleration/QsvHardwareAccelerationOption.cs +++ b/ErsatzTV.FFmpeg/Option/HardwareAcceleration/QsvHardwareAccelerationOption.cs @@ -11,11 +11,25 @@ public class QsvHardwareAccelerationOption : GlobalOption FFmpegFormat.P010LE }; - public override IList GlobalOptions => new List + public override IList GlobalOptions { - "-hwaccel", "qsv", - "-init_hw_device", "qsv=qsv:MFX_IMPL_hw_any" - }; + get + { + string[] initDevices = OperatingSystem.IsWindows() + ? new[] { "-init_hw_device", "qsv=hw:hw,child_device_type=dxva2", "-filter_hw_device", "hw" } + : new[] { "-init_hw_device", "qsv=hw", "-filter_hw_device", "hw" }; + + var result = new List + { + "-hwaccel", "qsv", + "-hwaccel_output_format", "qsv" + }; + + result.AddRange(initDevices); + + return result; + } + } // qsv encoders want nv12 public override FrameState NextState(FrameState currentState) @@ -29,13 +43,9 @@ public class QsvHardwareAccelerationOption : GlobalOption return result; } - return currentState with { PixelFormat = new PixelFormatNv12(pixelFormat.Name) }; + return result with { PixelFormat = new PixelFormatNv12(pixelFormat.Name) }; } - return currentState with - { - HardwareAccelerationMode = HardwareAccelerationMode.Qsv, - PixelFormat = new PixelFormatNv12(new PixelFormatUnknown().Name) - }; + return result with { PixelFormat = new PixelFormatNv12(new PixelFormatUnknown().Name) }; } } diff --git a/ErsatzTV.FFmpeg/PipelineBuilder.cs b/ErsatzTV.FFmpeg/PipelineBuilder.cs index 778484b2b..c1bacd6d7 100644 --- a/ErsatzTV.FFmpeg/PipelineBuilder.cs +++ b/ErsatzTV.FFmpeg/PipelineBuilder.cs @@ -44,7 +44,7 @@ public class PipelineBuilder _logger = logger; } - public IList Build(FrameState desiredState) + public FFmpegPipeline Build(FrameState desiredState) { var allVideoStreams = _inputFiles.SelectMany(f => f.Streams) .Filter(s => s.Kind == StreamKind.Video) @@ -499,7 +499,7 @@ public class PipelineBuilder } } - return _pipelineSteps; + return new FFmpegPipeline(_pipelineSteps, _videoFilterSteps, _audioFilterSteps); } private static bool IsDesiredVideoState(FrameState currentState, FrameState desiredState)