nvidia and software mode scaling improvements (#965)
* convert to square pixels before software scaling * convert to square pixels in nvidia scale filter * more scaling fixes; position watermark within padded content * fix image subtitle scaling * fix qsv scaling * update dependencies
This commit is contained in:
@@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
## [Unreleased]
|
||||
### Fixed
|
||||
- Fix typo introduced in `0.6.7-beta` that stopped QSV HEVC encoder from working
|
||||
- Fix scaling logic for `Nvidia` acceleration and software mode
|
||||
- Attempt to position watermarks within content (not over added black padding)
|
||||
|
||||
## [0.6.7-beta] - 2022-09-05
|
||||
### Fixed
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.3.44">
|
||||
@@ -24,7 +24,7 @@
|
||||
<PackageReference Include="Moq" Version="4.18.2" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
|
||||
<PackageReference Include="Serilog" Version="2.11.0" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.3.44">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Serilog" Version="2.11.0" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -147,6 +147,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
|
||||
videoStream.Codec,
|
||||
AvailablePixelFormats.ForPixelFormat(videoStream.PixelFormat, _logger),
|
||||
new FrameSize(videoVersion.Width, videoVersion.Height),
|
||||
videoVersion.SampleAspectRatio,
|
||||
videoVersion.DisplayAspectRatio,
|
||||
videoVersion.RFrameRate,
|
||||
videoPath != audioPath); // still image when paths are different
|
||||
@@ -214,10 +215,10 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
|
||||
false, // TODO: fallback filler needs to loop
|
||||
videoFormat,
|
||||
desiredPixelFormat,
|
||||
await playbackSettings.ScaledSize.Map(ss => new FrameSize(ss.Width, ss.Height))
|
||||
.IfNoneAsync(new FrameSize(videoVersion.Width, videoVersion.Height)),
|
||||
ffmpegVideoStream.SquarePixelFrameSize(
|
||||
new FrameSize(channel.FFmpegProfile.Resolution.Width, channel.FFmpegProfile.Resolution.Height)),
|
||||
new FrameSize(channel.FFmpegProfile.Resolution.Width, channel.FFmpegProfile.Resolution.Height),
|
||||
channel.FFmpegProfile.Resolution.Width == 640 ? "4:3" : "16:9",
|
||||
false,
|
||||
playbackSettings.FrameRate,
|
||||
playbackSettings.VideoBitrate,
|
||||
playbackSettings.VideoBufferSize,
|
||||
@@ -314,7 +315,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
|
||||
new PixelFormatYuv420P(),
|
||||
new FrameSize(desiredResolution.Width, desiredResolution.Height),
|
||||
new FrameSize(desiredResolution.Width, desiredResolution.Height),
|
||||
desiredResolution.Width == 640 ? "4:3" : "16:9",
|
||||
false,
|
||||
playbackSettings.FrameRate,
|
||||
playbackSettings.VideoBitrate,
|
||||
playbackSettings.VideoBufferSize,
|
||||
@@ -342,6 +343,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
|
||||
VideoFormat.GeneratedImage,
|
||||
new PixelFormatUnknown(), // leave this unknown so we convert to desired yuv420p
|
||||
new FrameSize(videoVersion.Width, videoVersion.Height),
|
||||
videoVersion.SampleAspectRatio,
|
||||
videoVersion.DisplayAspectRatio,
|
||||
None,
|
||||
true);
|
||||
@@ -434,7 +436,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
|
||||
{
|
||||
var videoInputFile = new VideoInputFile(
|
||||
inputFile,
|
||||
new List<VideoStream> { new(0, string.Empty, None, FrameSize.Unknown, string.Empty, None, true) });
|
||||
new List<VideoStream> { new(0, string.Empty, None, FrameSize.Unknown, string.Empty, string.Empty, None, true) });
|
||||
|
||||
var pipelineBuilder = new PipelineBuilder(
|
||||
_runtimeInfo,
|
||||
@@ -516,6 +518,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
|
||||
new PixelFormatUnknown(),
|
||||
new FrameSize(1, 1),
|
||||
string.Empty,
|
||||
string.Empty,
|
||||
Option<string>.None,
|
||||
!options.IsAnimated)
|
||||
},
|
||||
|
||||
@@ -26,7 +26,7 @@ public class PipelineGeneratorTests
|
||||
var videoInputFile = new VideoInputFile(
|
||||
"/tmp/whatever.mkv",
|
||||
new List<VideoStream>
|
||||
{ new(0, VideoFormat.H264, new PixelFormatYuv420P(), new FrameSize(1920, 1080), "16:9", "24", false) });
|
||||
{ new(0, VideoFormat.H264, new PixelFormatYuv420P(), new FrameSize(1920, 1080), "1:1", "16:9", "24", false) });
|
||||
|
||||
var audioInputFile = new AudioInputFile(
|
||||
"/tmp/whatever.mkv",
|
||||
@@ -47,7 +47,7 @@ public class PipelineGeneratorTests
|
||||
new PixelFormatYuv420P(),
|
||||
new FrameSize(1920, 1080),
|
||||
new FrameSize(1920, 1080),
|
||||
"16:9",
|
||||
false,
|
||||
Option<int>.None,
|
||||
2000,
|
||||
4000,
|
||||
@@ -99,7 +99,7 @@ public class PipelineGeneratorTests
|
||||
var videoInputFile = new VideoInputFile(
|
||||
"/tmp/whatever.mkv",
|
||||
new List<VideoStream>
|
||||
{ new(0, VideoFormat.H264, new PixelFormatYuv420P(), new FrameSize(1920, 1080), "16:9", "24", false) });
|
||||
{ new(0, VideoFormat.H264, new PixelFormatYuv420P(), new FrameSize(1920, 1080), "1:1", "16:9", "24", false) });
|
||||
|
||||
var audioInputFile = new AudioInputFile(
|
||||
"/tmp/whatever.mkv",
|
||||
@@ -120,7 +120,7 @@ public class PipelineGeneratorTests
|
||||
new PixelFormatYuv420P(),
|
||||
new FrameSize(1920, 1080),
|
||||
new FrameSize(1920, 1080),
|
||||
"16:9",
|
||||
false,
|
||||
Option<int>.None,
|
||||
2000,
|
||||
4000,
|
||||
@@ -198,7 +198,7 @@ public class PipelineGeneratorTests
|
||||
var videoInputFile = new VideoInputFile(
|
||||
"/tmp/whatever.mkv",
|
||||
new List<VideoStream>
|
||||
{ new(0, VideoFormat.H264, new PixelFormatYuv420P(), new FrameSize(1920, 1080), "16:9", "24", false) });
|
||||
{ new(0, VideoFormat.H264, new PixelFormatYuv420P(), new FrameSize(1920, 1080), "1:1", "16:9", "24", false) });
|
||||
|
||||
var audioInputFile = new AudioInputFile(
|
||||
"/tmp/whatever.mkv",
|
||||
@@ -219,7 +219,7 @@ public class PipelineGeneratorTests
|
||||
new PixelFormatYuv420P(),
|
||||
new FrameSize(1920, 1080),
|
||||
new FrameSize(1920, 1080),
|
||||
"16:9",
|
||||
false,
|
||||
Option<int>.None,
|
||||
2000,
|
||||
4000,
|
||||
@@ -273,7 +273,7 @@ public class PipelineGeneratorTests
|
||||
var videoInputFile = new VideoInputFile(
|
||||
"/tmp/whatever.mkv",
|
||||
new List<VideoStream>
|
||||
{ new(0, VideoFormat.H264, new PixelFormatYuv420P(), new FrameSize(1920, 1080), "16:9", "24", false) });
|
||||
{ new(0, VideoFormat.H264, new PixelFormatYuv420P(), new FrameSize(1920, 1080), "1:1", "16:9", "24", false) });
|
||||
|
||||
Option<AudioInputFile> audioInputFile = Option<AudioInputFile>.None;
|
||||
|
||||
@@ -284,7 +284,7 @@ public class PipelineGeneratorTests
|
||||
new PixelFormatYuv420P(),
|
||||
new FrameSize(1920, 1080),
|
||||
new FrameSize(1920, 1080),
|
||||
"16:9",
|
||||
false,
|
||||
Option<int>.None,
|
||||
2000,
|
||||
4000,
|
||||
@@ -341,7 +341,7 @@ public class PipelineGeneratorTests
|
||||
"/test/input/file.png",
|
||||
new List<VideoStream>
|
||||
{
|
||||
new(0, string.Empty, Option<IPixelFormat>.None, FrameSize.Unknown, string.Empty, Option<string>.None, true)
|
||||
new(0, string.Empty, Option<IPixelFormat>.None, FrameSize.Unknown, string.Empty, string.Empty, Option<string>.None, true)
|
||||
});
|
||||
|
||||
var pipelineBuilder = new PipelineBuilder(
|
||||
@@ -360,7 +360,7 @@ public class PipelineGeneratorTests
|
||||
string command = PrintCommand(videoInputFile, None, None, None, result);
|
||||
|
||||
command.Should().Be(
|
||||
"-nostdin -hide_banner -nostats -loglevel error -i /test/input/file.png -vf scale=-1:200 /test/output/file.jpg");
|
||||
"-nostdin -hide_banner -nostats -loglevel error -i /test/input/file.png -vf scale=-1:200:force_original_aspect_ratio=decrease /test/output/file.jpg");
|
||||
}
|
||||
|
||||
private static string PrintCommand(
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<PackageReference Include="CliWrap" Version="3.5.0" />
|
||||
<PackageReference Include="LanguageExt.Core" Version="4.2.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,19 +8,27 @@ namespace ErsatzTV.FFmpeg.Filter;
|
||||
public static class AvailableScaleFilters
|
||||
{
|
||||
public static IPipelineFilterStep ForAcceleration(
|
||||
IRuntimeInfo runtimeInfo,
|
||||
IRuntimeInfo _,
|
||||
HardwareAccelerationMode accelMode,
|
||||
FrameState currentState,
|
||||
FrameSize scaledSize,
|
||||
FrameSize paddedSize,
|
||||
int extraHardwareFrames) =>
|
||||
int extraHardwareFrames,
|
||||
bool isAnamorphicEdgeCase,
|
||||
string sampleAspectRatio) =>
|
||||
accelMode switch
|
||||
{
|
||||
HardwareAccelerationMode.Nvenc => new ScaleCudaFilter(currentState, scaledSize, paddedSize),
|
||||
HardwareAccelerationMode.Nvenc =>
|
||||
new ScaleCudaFilter(currentState, scaledSize, paddedSize, isAnamorphicEdgeCase),
|
||||
HardwareAccelerationMode.Qsv when currentState.FrameDataLocation == FrameDataLocation.Hardware ||
|
||||
scaledSize == paddedSize =>
|
||||
new ScaleQsvFilter(runtimeInfo, currentState, scaledSize, paddedSize, extraHardwareFrames),
|
||||
new ScaleQsvFilter(
|
||||
currentState,
|
||||
scaledSize,
|
||||
extraHardwareFrames,
|
||||
isAnamorphicEdgeCase,
|
||||
sampleAspectRatio),
|
||||
HardwareAccelerationMode.Vaapi => new ScaleVaapiFilter(currentState, scaledSize, paddedSize),
|
||||
_ => new ScaleFilter(currentState, scaledSize, paddedSize)
|
||||
_ => new ScaleFilter(currentState, scaledSize, paddedSize, isAnamorphicEdgeCase)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ namespace ErsatzTV.FFmpeg.Filter;
|
||||
|
||||
public static class AvailableSubtitleOverlayFilters
|
||||
{
|
||||
public static IPipelineFilterStep ForAcceleration(HardwareAccelerationMode accelMode, FrameState currentState) =>
|
||||
public static IPipelineFilterStep ForAcceleration(HardwareAccelerationMode accelMode) =>
|
||||
accelMode switch
|
||||
{
|
||||
HardwareAccelerationMode.Nvenc => new OverlaySubtitleCudaFilter(),
|
||||
HardwareAccelerationMode.Qsv => new OverlaySubtitleQsvFilter(currentState),
|
||||
HardwareAccelerationMode.Qsv => new OverlaySubtitleQsvFilter(),
|
||||
_ => new OverlaySubtitleFilter()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using ErsatzTV.FFmpeg.Filter.Cuda;
|
||||
using ErsatzTV.FFmpeg.Filter.Qsv;
|
||||
using ErsatzTV.FFmpeg.State;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ErsatzTV.FFmpeg.Filter;
|
||||
|
||||
@@ -8,13 +9,16 @@ public static class AvailableWatermarkOverlayFilters
|
||||
{
|
||||
public static IPipelineFilterStep ForAcceleration(
|
||||
HardwareAccelerationMode accelMode,
|
||||
FrameState currentState,
|
||||
WatermarkState watermarkState,
|
||||
FrameSize resolution) =>
|
||||
FrameSize resolution,
|
||||
FrameSize squarePixelFrameSize,
|
||||
ILogger logger) =>
|
||||
accelMode switch
|
||||
{
|
||||
HardwareAccelerationMode.Nvenc => new OverlayWatermarkCudaFilter(currentState, watermarkState, resolution),
|
||||
HardwareAccelerationMode.Qsv => new OverlayWatermarkQsvFilter(currentState, watermarkState, resolution),
|
||||
_ => new OverlayWatermarkFilter(currentState, watermarkState, resolution)
|
||||
HardwareAccelerationMode.Nvenc =>
|
||||
new OverlayWatermarkCudaFilter(watermarkState, resolution, squarePixelFrameSize, logger),
|
||||
HardwareAccelerationMode.Qsv =>
|
||||
new OverlayWatermarkQsvFilter(watermarkState, resolution, squarePixelFrameSize, logger),
|
||||
_ => new OverlayWatermarkFilter(watermarkState, resolution, squarePixelFrameSize, logger)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using ErsatzTV.FFmpeg.Environment;
|
||||
using ErsatzTV.FFmpeg.Format;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ErsatzTV.FFmpeg.Filter;
|
||||
|
||||
@@ -8,6 +9,7 @@ public class ComplexFilter : IPipelineStep
|
||||
private readonly FrameState _currentState;
|
||||
private readonly FFmpegState _ffmpegState;
|
||||
private readonly string _fontsDir;
|
||||
private readonly ILogger _logger;
|
||||
private readonly Option<AudioInputFile> _maybeAudioInputFile;
|
||||
private readonly Option<SubtitleInputFile> _maybeSubtitleInputFile;
|
||||
private readonly Option<VideoInputFile> _maybeVideoInputFile;
|
||||
@@ -22,7 +24,8 @@ public class ComplexFilter : IPipelineStep
|
||||
Option<WatermarkInputFile> maybeWatermarkInputFile,
|
||||
Option<SubtitleInputFile> maybeSubtitleInputFile,
|
||||
FrameSize resolution,
|
||||
string fontsDir)
|
||||
string fontsDir,
|
||||
ILogger logger)
|
||||
{
|
||||
_currentState = currentState;
|
||||
_ffmpegState = ffmpegState;
|
||||
@@ -32,6 +35,7 @@ public class ComplexFilter : IPipelineStep
|
||||
_maybeSubtitleInputFile = maybeSubtitleInputFile;
|
||||
_resolution = resolution;
|
||||
_fontsDir = fontsDir;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
|
||||
@@ -147,11 +151,16 @@ public class ComplexFilter : IPipelineStep
|
||||
watermarkLabel = $"[{watermarkLabel}]";
|
||||
}
|
||||
|
||||
foreach (VideoInputFile videoInputFile in _maybeVideoInputFile)
|
||||
{
|
||||
foreach (VideoStream stream in videoInputFile.VideoStreams)
|
||||
{
|
||||
IPipelineFilterStep overlayFilter = AvailableWatermarkOverlayFilters.ForAcceleration(
|
||||
_ffmpegState.EncoderHardwareAccelerationMode,
|
||||
_currentState,
|
||||
watermarkInputFile.DesiredState,
|
||||
_resolution);
|
||||
_resolution,
|
||||
stream.SquarePixelFrameSize(_resolution),
|
||||
_logger);
|
||||
|
||||
if (overlayFilter.Filter != string.Empty)
|
||||
{
|
||||
@@ -165,7 +174,8 @@ public class ComplexFilter : IPipelineStep
|
||||
string uploadDownloadFilter = string.Empty;
|
||||
if (_maybeSubtitleInputFile.IsNone &&
|
||||
(_ffmpegState.EncoderHardwareAccelerationMode == HardwareAccelerationMode.Vaapi ||
|
||||
_ffmpegState.EncoderHardwareAccelerationMode == HardwareAccelerationMode.VideoToolbox &&
|
||||
_ffmpegState.EncoderHardwareAccelerationMode ==
|
||||
HardwareAccelerationMode.VideoToolbox &&
|
||||
_currentState.VideoFormat == VideoFormat.Hevc))
|
||||
{
|
||||
uploadDownloadFilter = new HardwareUploadFilter(_ffmpegState).Filter;
|
||||
@@ -192,6 +202,8 @@ public class ComplexFilter : IPipelineStep
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (SubtitleInputFile subtitleInputFile in _maybeSubtitleInputFile.Filter(s => !s.Copy))
|
||||
{
|
||||
@@ -216,10 +228,8 @@ public class ComplexFilter : IPipelineStep
|
||||
string filter;
|
||||
if (subtitleInputFile.IsImageBased)
|
||||
{
|
||||
IPipelineFilterStep overlayFilter =
|
||||
AvailableSubtitleOverlayFilters.ForAcceleration(
|
||||
_ffmpegState.EncoderHardwareAccelerationMode,
|
||||
_currentState);
|
||||
IPipelineFilterStep overlayFilter = AvailableSubtitleOverlayFilters.ForAcceleration(
|
||||
_ffmpegState.EncoderHardwareAccelerationMode);
|
||||
filter = overlayFilter.Filter;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
public class OverlaySubtitleCudaFilter : BaseFilter
|
||||
{
|
||||
public override string Filter => "overlay_cuda";
|
||||
public override string Filter => "overlay_cuda=x=(W-w)/2:y=(H-h)/2";
|
||||
public override FrameState NextState(FrameState currentState) => currentState;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
using ErsatzTV.FFmpeg.State;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ErsatzTV.FFmpeg.Filter.Cuda;
|
||||
|
||||
public class OverlayWatermarkCudaFilter : OverlayWatermarkFilter
|
||||
{
|
||||
public OverlayWatermarkCudaFilter(
|
||||
FrameState currentState,
|
||||
WatermarkState watermarkState,
|
||||
FrameSize resolution) : base(
|
||||
currentState,
|
||||
FrameSize resolution,
|
||||
FrameSize squarePixelFrameSize,
|
||||
ILogger logger) : base(
|
||||
watermarkState,
|
||||
resolution)
|
||||
resolution,
|
||||
squarePixelFrameSize,
|
||||
logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -6,13 +6,19 @@ public class ScaleCudaFilter : BaseFilter
|
||||
{
|
||||
private readonly FrameState _currentState;
|
||||
private readonly FrameSize _paddedSize;
|
||||
private readonly bool _isAnamorphicEdgeCase;
|
||||
private readonly FrameSize _scaledSize;
|
||||
|
||||
public ScaleCudaFilter(FrameState currentState, FrameSize scaledSize, FrameSize paddedSize)
|
||||
public ScaleCudaFilter(
|
||||
FrameState currentState,
|
||||
FrameSize scaledSize,
|
||||
FrameSize paddedSize,
|
||||
bool isAnamorphicEdgeCase)
|
||||
{
|
||||
_currentState = currentState;
|
||||
_scaledSize = scaledSize;
|
||||
_paddedSize = paddedSize;
|
||||
_isAnamorphicEdgeCase = isAnamorphicEdgeCase;
|
||||
}
|
||||
|
||||
public override string Filter
|
||||
@@ -30,6 +36,13 @@ public class ScaleCudaFilter : BaseFilter
|
||||
}
|
||||
else
|
||||
{
|
||||
string aspectRatio = string.Empty;
|
||||
if (_scaledSize != _paddedSize)
|
||||
{
|
||||
aspectRatio = ":force_original_aspect_ratio=decrease";
|
||||
}
|
||||
|
||||
string squareScale = string.Empty;
|
||||
string targetSize = $"{_paddedSize.Width}:{_paddedSize.Height}";
|
||||
string format = string.Empty;
|
||||
foreach (IPixelFormat pixelFormat in _currentState.PixelFormat)
|
||||
@@ -37,7 +50,20 @@ public class ScaleCudaFilter : BaseFilter
|
||||
format = $":format={pixelFormat.FFmpegName}";
|
||||
}
|
||||
|
||||
scale = $"scale_cuda={targetSize}{format}";
|
||||
if (_isAnamorphicEdgeCase)
|
||||
{
|
||||
squareScale = $"scale_cuda=iw:sar*ih{format},setsar=1,";
|
||||
}
|
||||
else if (_currentState.IsAnamorphic)
|
||||
{
|
||||
squareScale = $"scale_cuda=iw*sar:ih{format},setsar=1,";
|
||||
}
|
||||
else
|
||||
{
|
||||
aspectRatio += ",setsar=1";
|
||||
}
|
||||
|
||||
scale = $"{squareScale}scale_cuda={targetSize}{format}{aspectRatio}";
|
||||
}
|
||||
|
||||
// TODO: this might not always upload to hardware, so NextState could be inaccurate
|
||||
@@ -56,6 +82,7 @@ public class ScaleCudaFilter : BaseFilter
|
||||
{
|
||||
ScaledSize = _scaledSize,
|
||||
PaddedSize = _scaledSize,
|
||||
FrameDataLocation = FrameDataLocation.Hardware
|
||||
FrameDataLocation = FrameDataLocation.Hardware,
|
||||
IsAnamorphic = false // this filter always outputs square pixels
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class SubtitleScaleNppFilter : BaseFilter
|
||||
format = $":format={pixelFormat.FFmpegName}";
|
||||
}
|
||||
|
||||
scale = $"scale_npp={targetSize}{format}";
|
||||
scale = $"scale_npp={targetSize}{format}:force_original_aspect_ratio=1";
|
||||
}
|
||||
|
||||
return scale;
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
public class OverlaySubtitleFilter : BaseFilter
|
||||
{
|
||||
public override string Filter => "overlay";
|
||||
public override string Filter => "overlay=x=(W-w)/2:y=(H-h)/2";
|
||||
public override FrameState NextState(FrameState currentState) => currentState;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
using ErsatzTV.FFmpeg.State;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ErsatzTV.FFmpeg.Filter;
|
||||
|
||||
public class OverlayWatermarkFilter : BaseFilter
|
||||
{
|
||||
private readonly FrameState _currentState;
|
||||
private readonly FrameSize _resolution;
|
||||
private readonly FrameSize _squarePixelFrameSize;
|
||||
private readonly ILogger _logger;
|
||||
private readonly WatermarkState _watermarkState;
|
||||
|
||||
public OverlayWatermarkFilter(FrameState currentState, WatermarkState watermarkState, FrameSize resolution)
|
||||
public OverlayWatermarkFilter(
|
||||
WatermarkState watermarkState,
|
||||
FrameSize resolution,
|
||||
FrameSize squarePixelFrameSize,
|
||||
ILogger logger)
|
||||
{
|
||||
_currentState = currentState;
|
||||
_watermarkState = watermarkState;
|
||||
_resolution = resolution;
|
||||
_squarePixelFrameSize = squarePixelFrameSize;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override string Filter => $"overlay={Position}";
|
||||
@@ -21,8 +28,20 @@ public class OverlayWatermarkFilter : BaseFilter
|
||||
{
|
||||
get
|
||||
{
|
||||
double horizontalMargin = Math.Round(_watermarkState.HorizontalMarginPercent / 100.0 * _resolution.Width);
|
||||
double verticalMargin = Math.Round(_watermarkState.VerticalMarginPercent / 100.0 * _resolution.Height);
|
||||
int horizontalPadding = _resolution.Width - _squarePixelFrameSize.Width;
|
||||
int verticalPadding = _resolution.Height - _squarePixelFrameSize.Height;
|
||||
|
||||
_logger.LogDebug(
|
||||
$"Resolution: {_resolution.Width}x{_resolution.Height}");
|
||||
_logger.LogDebug(
|
||||
$"Square Pix: {_squarePixelFrameSize.Width}x{_squarePixelFrameSize.Height}");
|
||||
|
||||
double horizontalMargin = Math.Round(
|
||||
_watermarkState.HorizontalMarginPercent / 100.0 * _squarePixelFrameSize.Width
|
||||
+ horizontalPadding / 2.0);
|
||||
double verticalMargin = Math.Round(
|
||||
_watermarkState.VerticalMarginPercent / 100.0 * _squarePixelFrameSize.Height
|
||||
+ verticalPadding / 2.0);
|
||||
|
||||
return _watermarkState.Location switch
|
||||
{
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
|
||||
public class OverlaySubtitleQsvFilter : BaseFilter
|
||||
{
|
||||
private readonly FrameState _currentState;
|
||||
|
||||
public OverlaySubtitleQsvFilter(FrameState currentState) => _currentState = currentState;
|
||||
|
||||
public override string Filter =>
|
||||
$"overlay_qsv=eof_action=endall:shortest=1:repeatlast=0:w={_currentState.PaddedSize.Width}:h={_currentState.PaddedSize.Height}";
|
||||
$"overlay_qsv=eof_action=endall:shortest=1:repeatlast=0:x=(W-w)/2:y=(H-h)/2";
|
||||
|
||||
public override FrameState NextState(FrameState currentState) => currentState;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
using ErsatzTV.FFmpeg.State;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ErsatzTV.FFmpeg.Filter.Qsv;
|
||||
|
||||
public class OverlayWatermarkQsvFilter : OverlayWatermarkFilter
|
||||
{
|
||||
public OverlayWatermarkQsvFilter(
|
||||
FrameState currentState,
|
||||
WatermarkState watermarkState,
|
||||
FrameSize resolution) : base(
|
||||
currentState,
|
||||
FrameSize resolution,
|
||||
FrameSize squarePixelFrameSize,
|
||||
ILogger logger) : base(
|
||||
watermarkState,
|
||||
resolution)
|
||||
resolution,
|
||||
squarePixelFrameSize,
|
||||
logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using ErsatzTV.FFmpeg.Format;
|
||||
using ErsatzTV.FFmpeg.Runtime;
|
||||
using ErsatzTV.FFmpeg.Format;
|
||||
|
||||
namespace ErsatzTV.FFmpeg.Filter.Qsv;
|
||||
|
||||
public class ScaleQsvFilter : BaseFilter
|
||||
{
|
||||
private readonly IRuntimeInfo _runtimeInfo;
|
||||
private readonly FrameState _currentState;
|
||||
private readonly FrameSize _scaledSize;
|
||||
private readonly FrameSize _paddedSize;
|
||||
private readonly int _extraHardwareFrames;
|
||||
private readonly bool _isAnamorphicEdgeCase;
|
||||
private readonly string _sampleAspectRatio;
|
||||
|
||||
public ScaleQsvFilter(
|
||||
IRuntimeInfo runtimeInfo,
|
||||
FrameState currentState,
|
||||
FrameSize scaledSize,
|
||||
FrameSize paddedSize,
|
||||
int extraHardwareFrames)
|
||||
int extraHardwareFrames,
|
||||
bool isAnamorphicEdgeCase,
|
||||
string sampleAspectRatio)
|
||||
{
|
||||
_runtimeInfo = runtimeInfo;
|
||||
_currentState = currentState;
|
||||
_scaledSize = scaledSize;
|
||||
_paddedSize = paddedSize;
|
||||
_extraHardwareFrames = extraHardwareFrames;
|
||||
_isAnamorphicEdgeCase = isAnamorphicEdgeCase;
|
||||
_sampleAspectRatio = sampleAspectRatio;
|
||||
}
|
||||
|
||||
public override string Filter
|
||||
@@ -44,16 +42,29 @@ public class ScaleQsvFilter : BaseFilter
|
||||
}
|
||||
else
|
||||
{
|
||||
string squareScale = string.Empty;
|
||||
string targetSize = $"w={_scaledSize.Width}:h={_scaledSize.Height}";
|
||||
string format = string.Empty;
|
||||
foreach (IPixelFormat pixelFormat in _currentState.PixelFormat)
|
||||
{
|
||||
format = $":format={pixelFormat.FFmpegName}";
|
||||
}
|
||||
|
||||
string targetSize = _runtimeInfo.IsOSPlatform(OSPlatform.Windows)
|
||||
? $"w={_paddedSize.Width}:h={_paddedSize.Height}"
|
||||
: $"w={_scaledSize.Width}:h={_scaledSize.Height}";
|
||||
scale = $"vpp_qsv={targetSize}{format}";
|
||||
string sar = _sampleAspectRatio.Replace(':', '/');
|
||||
if (_isAnamorphicEdgeCase)
|
||||
{
|
||||
squareScale = $"vpp_qsv=w=iw:h={sar}*ih{format},setsar=1,";
|
||||
}
|
||||
else if (_currentState.IsAnamorphic)
|
||||
{
|
||||
squareScale = $"vpp_qsv=w=iw*{sar}:h=ih{format},setsar=1,";
|
||||
}
|
||||
else
|
||||
{
|
||||
format += ",setsar=1";
|
||||
}
|
||||
|
||||
scale = $"{squareScale}vpp_qsv={targetSize}{format}";
|
||||
}
|
||||
|
||||
if (_currentState.FrameDataLocation == FrameDataLocation.Hardware)
|
||||
@@ -75,6 +86,7 @@ public class ScaleQsvFilter : BaseFilter
|
||||
{
|
||||
ScaledSize = _scaledSize,
|
||||
PaddedSize = _scaledSize,
|
||||
FrameDataLocation = FrameDataLocation.Hardware
|
||||
FrameDataLocation = FrameDataLocation.Hardware,
|
||||
IsAnamorphic = false // this filter always outputs square pixels
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class SubtitleScaleQsvFilter : BaseFilter
|
||||
string targetSize = $"w={_paddedSize.Width}:h={_paddedSize.Height}";
|
||||
|
||||
// use software scaling
|
||||
scale = $"scale={targetSize}";
|
||||
scale = $"scale={targetSize}:force_original_aspect_ratio=decrease";
|
||||
}
|
||||
|
||||
string initialPixelFormat = _currentState.PixelFormat.Match(pf => pf.FFmpegName, FFmpegFormat.NV12);
|
||||
|
||||
@@ -6,13 +6,15 @@ public class ScaleFilter : BaseFilter
|
||||
{
|
||||
private readonly FrameState _currentState;
|
||||
private readonly FrameSize _paddedSize;
|
||||
private readonly bool _isAnamorphicEdgeCase;
|
||||
private readonly FrameSize _scaledSize;
|
||||
|
||||
public ScaleFilter(FrameState currentState, FrameSize scaledSize, FrameSize paddedSize)
|
||||
public ScaleFilter(FrameState currentState, FrameSize scaledSize, FrameSize paddedSize, bool isAnamorphicEdgeCase)
|
||||
{
|
||||
_currentState = currentState;
|
||||
_scaledSize = scaledSize;
|
||||
_paddedSize = paddedSize;
|
||||
_isAnamorphicEdgeCase = isAnamorphicEdgeCase;
|
||||
}
|
||||
|
||||
public override string Filter
|
||||
@@ -25,8 +27,19 @@ public class ScaleFilter : BaseFilter
|
||||
aspectRatio = ":force_original_aspect_ratio=decrease";
|
||||
}
|
||||
|
||||
string scale =
|
||||
$"scale={_paddedSize.Width}:{_paddedSize.Height}:flags=fast_bilinear{aspectRatio}";
|
||||
string scale;
|
||||
if (_isAnamorphicEdgeCase)
|
||||
{
|
||||
scale = $"scale=iw:sar*ih,setsar=1,scale={_paddedSize.Width}:{_paddedSize.Height}:flags=fast_bilinear{aspectRatio}";
|
||||
}
|
||||
else if (_currentState.IsAnamorphic)
|
||||
{
|
||||
scale = $"scale=iw*sar:ih,setsar=1,scale={_paddedSize.Width}:{_paddedSize.Height}:flags=fast_bilinear{aspectRatio}";
|
||||
}
|
||||
else
|
||||
{
|
||||
scale = $"scale={_paddedSize.Width}:{_paddedSize.Height}:flags=fast_bilinear{aspectRatio},setsar=1";
|
||||
}
|
||||
|
||||
string hwdownload = string.Empty;
|
||||
if (_currentState.FrameDataLocation == FrameDataLocation.Hardware)
|
||||
@@ -45,10 +58,12 @@ public class ScaleFilter : BaseFilter
|
||||
}
|
||||
}
|
||||
|
||||
public override FrameState NextState(FrameState currentState) => currentState with
|
||||
public override FrameState NextState(FrameState currentState) =>
|
||||
currentState with
|
||||
{
|
||||
ScaledSize = _scaledSize,
|
||||
PaddedSize = _scaledSize,
|
||||
FrameDataLocation = FrameDataLocation.Software
|
||||
FrameDataLocation = FrameDataLocation.Software,
|
||||
IsAnamorphic = false // this filter always outputs square pixels
|
||||
};
|
||||
}
|
||||
|
||||
@@ -6,9 +6,7 @@ public class ScaleImageFilter : BaseFilter
|
||||
|
||||
public ScaleImageFilter(FrameSize scaledSize) => _scaledSize = scaledSize;
|
||||
|
||||
public override string Filter => $"scale={_scaledSize.Width}:{_scaledSize.Height}";
|
||||
|
||||
// public override IList<string> OutputOptions => new List<string> { "-q:v", "2" };
|
||||
public override string Filter => $"scale={_scaledSize.Width}:{_scaledSize.Height}:force_original_aspect_ratio=decrease";
|
||||
|
||||
public override FrameState NextState(FrameState currentState) => currentState with
|
||||
{
|
||||
|
||||
@@ -9,10 +9,13 @@ public record FrameState(
|
||||
Option<IPixelFormat> PixelFormat,
|
||||
FrameSize ScaledSize,
|
||||
FrameSize PaddedSize,
|
||||
string DisplayAspectRatio,
|
||||
bool IsAnamorphic,
|
||||
Option<int> FrameRate,
|
||||
Option<int> VideoBitrate,
|
||||
Option<int> VideoBufferSize,
|
||||
Option<int> VideoTrackTimeScale,
|
||||
bool Deinterlaced,
|
||||
FrameDataLocation FrameDataLocation = FrameDataLocation.Unknown);
|
||||
FrameDataLocation FrameDataLocation = FrameDataLocation.Unknown)
|
||||
{
|
||||
public string FFmpegAspectRatio => PaddedSize.Width == 640 ? "4/3" : "16/9";
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ public record ConcatInputFile(string Url, FrameSize Resolution) : InputFile(
|
||||
Option<IPixelFormat>.None,
|
||||
Resolution,
|
||||
string.Empty,
|
||||
string.Empty,
|
||||
Option<string>.None,
|
||||
false)
|
||||
})
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using ErsatzTV.FFmpeg.Format;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using ErsatzTV.FFmpeg.Format;
|
||||
|
||||
namespace ErsatzTV.FFmpeg;
|
||||
|
||||
@@ -14,9 +15,98 @@ public record VideoStream(
|
||||
string Codec,
|
||||
Option<IPixelFormat> PixelFormat,
|
||||
FrameSize FrameSize,
|
||||
string SampleAspectRatio,
|
||||
string DisplayAspectRatio,
|
||||
Option<string> FrameRate,
|
||||
bool StillImage) : MediaStream(
|
||||
Index,
|
||||
Codec,
|
||||
StreamKind.Video);
|
||||
StreamKind.Video)
|
||||
{
|
||||
public bool IsAnamorphic
|
||||
{
|
||||
get
|
||||
{
|
||||
// square pixels
|
||||
if (SampleAspectRatio == "1:1")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0:1 is "unspecified", so anything other than that will be non-square/anamorphic
|
||||
if (SampleAspectRatio != "0:1")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// SAR 0:1 && DAR 0:1 (both unspecified) means square
|
||||
if (DisplayAspectRatio == "0:1")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// DAR == W:H is square
|
||||
return DisplayAspectRatio != $"{FrameSize.Width}:{FrameSize.Height}";
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: figure out what's really causing this
|
||||
public bool IsAnamorphicEdgeCase
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] split = SampleAspectRatio.Split(':');
|
||||
var num = double.Parse(split[0]);
|
||||
var den = double.Parse(split[1]);
|
||||
|
||||
if (num <= den)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
double sar = num / den;
|
||||
double res = (double)FrameSize.Width / FrameSize.Height;
|
||||
return res - sar > 0.01;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public FrameSize SquarePixelFrameSize(FrameSize resolution)
|
||||
{
|
||||
int width = FrameSize.Width;
|
||||
int height = FrameSize.Height;
|
||||
|
||||
if (IsAnamorphic)
|
||||
{
|
||||
string[] split = SampleAspectRatio.Split(':');
|
||||
var num = double.Parse(split[0]);
|
||||
var den = double.Parse(split[1]);
|
||||
|
||||
bool edgeCase = IsAnamorphicEdgeCase;
|
||||
|
||||
width = edgeCase
|
||||
? FrameSize.Width
|
||||
: (int)Math.Floor(FrameSize.Width * num / den);
|
||||
|
||||
height = edgeCase
|
||||
? (int)Math.Floor(FrameSize.Height * num / den)
|
||||
: FrameSize.Height;
|
||||
}
|
||||
|
||||
double widthPercent = (double)resolution.Width / width;
|
||||
double heightPercent = (double)resolution.Height / height;
|
||||
double minPercent = Math.Min(widthPercent, heightPercent);
|
||||
|
||||
var result = new FrameSize(
|
||||
(int)Math.Floor(width * minPercent),
|
||||
(int)Math.Floor(height * minPercent));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ public class PipelineBuilder
|
||||
videoStream.PixelFormat,
|
||||
videoStream.FrameSize,
|
||||
videoStream.FrameSize,
|
||||
videoStream.DisplayAspectRatio,
|
||||
videoStream.IsAnamorphic,
|
||||
initialFrameRate,
|
||||
Option<int>.None,
|
||||
Option<int>.None,
|
||||
@@ -376,7 +376,8 @@ public class PipelineBuilder
|
||||
IPipelineFilterStep scaleStep = new ScaleFilter(
|
||||
currentState,
|
||||
desiredState.ScaledSize,
|
||||
desiredState.PaddedSize);
|
||||
desiredState.PaddedSize,
|
||||
videoStream.IsAnamorphicEdgeCase);
|
||||
currentState = scaleStep.NextState(currentState);
|
||||
_videoInputFile.Iter(f => f.FilterSteps.Add(scaleStep));
|
||||
|
||||
@@ -385,12 +386,12 @@ public class PipelineBuilder
|
||||
currentState = padStep.NextState(currentState);
|
||||
_videoInputFile.Iter(f => f.FilterSteps.Add(padStep));
|
||||
|
||||
if (videoStream.DisplayAspectRatio == desiredState.DisplayAspectRatio)
|
||||
{
|
||||
IPipelineFilterStep darStep = new SetDarFilter(desiredState.DisplayAspectRatio);
|
||||
currentState = darStep.NextState(currentState);
|
||||
_videoInputFile.Iter(f => f.FilterSteps.Add(darStep));
|
||||
}
|
||||
// if (videoStream.DisplayAspectRatio == desiredState.DisplayAspectRatio)
|
||||
// {
|
||||
// IPipelineFilterStep darStep = new SetDarFilter(desiredState.DisplayAspectRatio);
|
||||
// currentState = darStep.NextState(currentState);
|
||||
// _videoInputFile.Iter(f => f.FilterSteps.Add(darStep));
|
||||
// }
|
||||
}
|
||||
}
|
||||
else if (currentState.ScaledSize != desiredState.ScaledSize)
|
||||
@@ -401,7 +402,9 @@ public class PipelineBuilder
|
||||
currentState,
|
||||
desiredState.ScaledSize,
|
||||
desiredState.PaddedSize,
|
||||
ffmpegState.QsvExtraHardwareFrames);
|
||||
ffmpegState.QsvExtraHardwareFrames,
|
||||
videoStream.IsAnamorphicEdgeCase,
|
||||
videoStream.SampleAspectRatio);
|
||||
currentState = scaleFilter.NextState(currentState);
|
||||
_videoInputFile.Iter(f => f.FilterSteps.Add(scaleFilter));
|
||||
|
||||
@@ -413,13 +416,13 @@ public class PipelineBuilder
|
||||
_videoInputFile.Iter(f => f.FilterSteps.Add(padStep));
|
||||
}
|
||||
|
||||
if (videoStream.DisplayAspectRatio == desiredState.DisplayAspectRatio ||
|
||||
ffmpegState.EncoderHardwareAccelerationMode == HardwareAccelerationMode.Qsv)
|
||||
{
|
||||
IPipelineFilterStep darStep = new SetDarFilter(desiredState.DisplayAspectRatio);
|
||||
currentState = darStep.NextState(currentState);
|
||||
_videoInputFile.Iter(f => f.FilterSteps.Add(darStep));
|
||||
}
|
||||
// if (videoStream.DisplayAspectRatio == desiredState.DisplayAspectRatio ||
|
||||
// ffmpegState.EncoderHardwareAccelerationMode == HardwareAccelerationMode.Qsv)
|
||||
// {
|
||||
// IPipelineFilterStep darStep = new SetDarFilter(desiredState.DisplayAspectRatio);
|
||||
// currentState = darStep.NextState(currentState);
|
||||
// _videoInputFile.Iter(f => f.FilterSteps.Add(darStep));
|
||||
// }
|
||||
}
|
||||
else if (currentState.PaddedSize != desiredState.PaddedSize)
|
||||
{
|
||||
@@ -429,7 +432,9 @@ public class PipelineBuilder
|
||||
currentState,
|
||||
desiredState.ScaledSize,
|
||||
desiredState.PaddedSize,
|
||||
ffmpegState.QsvExtraHardwareFrames);
|
||||
ffmpegState.QsvExtraHardwareFrames,
|
||||
videoStream.IsAnamorphicEdgeCase,
|
||||
videoStream.SampleAspectRatio);
|
||||
currentState = scaleFilter.NextState(currentState);
|
||||
_videoInputFile.Iter(f => f.FilterSteps.Add(scaleFilter));
|
||||
|
||||
@@ -440,13 +445,13 @@ public class PipelineBuilder
|
||||
_videoInputFile.Iter(f => f.FilterSteps.Add(padStep));
|
||||
}
|
||||
|
||||
if (videoStream.DisplayAspectRatio == desiredState.DisplayAspectRatio ||
|
||||
ffmpegState.EncoderHardwareAccelerationMode == HardwareAccelerationMode.Qsv)
|
||||
{
|
||||
IPipelineFilterStep darStep = new SetDarFilter(desiredState.DisplayAspectRatio);
|
||||
currentState = darStep.NextState(currentState);
|
||||
_videoInputFile.Iter(f => f.FilterSteps.Add(darStep));
|
||||
}
|
||||
// if (videoStream.DisplayAspectRatio == desiredState.DisplayAspectRatio ||
|
||||
// ffmpegState.EncoderHardwareAccelerationMode == HardwareAccelerationMode.Qsv)
|
||||
// {
|
||||
// IPipelineFilterStep darStep = new SetDarFilter(desiredState.DisplayAspectRatio);
|
||||
// currentState = darStep.NextState(currentState);
|
||||
// _videoInputFile.Iter(f => f.FilterSteps.Add(darStep));
|
||||
// }
|
||||
}
|
||||
|
||||
if (hasOverlay && currentState.PixelFormat.Map(pf => pf.FFmpegName) !=
|
||||
@@ -485,7 +490,9 @@ public class PipelineBuilder
|
||||
currentState,
|
||||
desiredState.ScaledSize,
|
||||
desiredState.PaddedSize,
|
||||
ffmpegState.QsvExtraHardwareFrames);
|
||||
ffmpegState.QsvExtraHardwareFrames,
|
||||
videoStream.IsAnamorphicEdgeCase,
|
||||
videoStream.SampleAspectRatio);
|
||||
currentState = scaleFilter.NextState(currentState);
|
||||
_videoInputFile.Iter(f => f.FilterSteps.Add(scaleFilter));
|
||||
}
|
||||
@@ -516,7 +523,9 @@ public class PipelineBuilder
|
||||
currentState,
|
||||
desiredState.ScaledSize,
|
||||
desiredState.PaddedSize,
|
||||
ffmpegState.QsvExtraHardwareFrames);
|
||||
ffmpegState.QsvExtraHardwareFrames,
|
||||
videoStream.IsAnamorphicEdgeCase,
|
||||
videoStream.SampleAspectRatio);
|
||||
currentState = scaleFilter.NextState(currentState);
|
||||
videoInputFile.FilterSteps.Add(scaleFilter);
|
||||
}
|
||||
@@ -670,7 +679,9 @@ public class PipelineBuilder
|
||||
currentState,
|
||||
desiredState.ScaledSize,
|
||||
desiredState.PaddedSize,
|
||||
ffmpegState.QsvExtraHardwareFrames);
|
||||
ffmpegState.QsvExtraHardwareFrames,
|
||||
videoStream.IsAnamorphicEdgeCase,
|
||||
videoStream.SampleAspectRatio);
|
||||
currentState = scaleFilter.NextState(currentState);
|
||||
_videoInputFile.Iter(f => f.FilterSteps.Add(scaleFilter));
|
||||
}
|
||||
@@ -800,7 +811,8 @@ public class PipelineBuilder
|
||||
_watermarkInputFile,
|
||||
_subtitleInputFile,
|
||||
currentState.PaddedSize,
|
||||
_fontsFolder);
|
||||
_fontsFolder,
|
||||
_logger);
|
||||
|
||||
_pipelineSteps.Add(complexFilter);
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
<PackageReference Include="Lucene.Net" Version="4.8.0-beta00016" />
|
||||
<PackageReference Include="Lucene.Net.Analysis.Common" Version="4.8.0-beta00016" />
|
||||
<PackageReference Include="Lucene.Net.QueryParser" Version="4.8.0-beta00016" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.8">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.9">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.3.44">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -55,16 +55,16 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Bugsnag.AspNet.Core" Version="3.1.0" />
|
||||
<PackageReference Include="FluentValidation" Version="11.2.1" />
|
||||
<PackageReference Include="FluentValidation" Version="11.2.2" />
|
||||
<PackageReference Include="FluentValidation.AspNetCore" Version="11.2.2" />
|
||||
<PackageReference Include="HtmlSanitizer" Version="7.1.542" />
|
||||
<PackageReference Include="LanguageExt.Core" Version="4.2.9" />
|
||||
<PackageReference Include="Markdig" Version="0.30.3" />
|
||||
<PackageReference Include="MediatR.Courier.DependencyInjection" Version="5.0.0" />
|
||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.8">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.9" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.9">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
@@ -73,12 +73,12 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MudBlazor" Version="6.0.15" />
|
||||
<PackageReference Include="NaturalSort.Extension" Version="3.2.0" />
|
||||
<PackageReference Include="NaturalSort.Extension" Version="4.0.0" />
|
||||
<PackageReference Include="PPioli.FluentValidation.Blazor" Version="11.1.0" />
|
||||
<PackageReference Include="Refit.HttpClientFactory" Version="6.3.2" />
|
||||
<PackageReference Include="Serilog" Version="2.11.0" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="6.0.1" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" />
|
||||
<PackageReference Include="Serilog.Sinks.SQLite" Version="6.0.1" />
|
||||
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||
<PackageReference Include="System.Text.Encoding.Extensions" Version="4.3.0" />
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ public class Program
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
await Log.CloseAndFlushAsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user