diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3fc6ca8b2..27b1f0fda 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj
index de2d502e0..47fbcdfe9 100644
--- a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj
+++ b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj
@@ -14,7 +14,7 @@
-
+
@@ -24,7 +24,7 @@
-
+
diff --git a/ErsatzTV.Core/ErsatzTV.Core.csproj b/ErsatzTV.Core/ErsatzTV.Core.csproj
index 71bd035a1..6c3416b86 100644
--- a/ErsatzTV.Core/ErsatzTV.Core.csproj
+++ b/ErsatzTV.Core/ErsatzTV.Core.csproj
@@ -16,14 +16,14 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs b/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
index e02df834a..8448df0d8 100644
--- a/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
+++ b/ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
@@ -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 { new(0, string.Empty, None, FrameSize.Unknown, string.Empty, None, true) });
+ new List { 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.None,
!options.IsAnimated)
},
diff --git a/ErsatzTV.FFmpeg.Tests/PipelineBuilderTests.cs b/ErsatzTV.FFmpeg.Tests/PipelineBuilderTests.cs
index 95b83a964..799bc22f3 100644
--- a/ErsatzTV.FFmpeg.Tests/PipelineBuilderTests.cs
+++ b/ErsatzTV.FFmpeg.Tests/PipelineBuilderTests.cs
@@ -26,7 +26,7 @@ public class PipelineGeneratorTests
var videoInputFile = new VideoInputFile(
"/tmp/whatever.mkv",
new List
- { 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.None,
2000,
4000,
@@ -99,7 +99,7 @@ public class PipelineGeneratorTests
var videoInputFile = new VideoInputFile(
"/tmp/whatever.mkv",
new List
- { 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.None,
2000,
4000,
@@ -198,7 +198,7 @@ public class PipelineGeneratorTests
var videoInputFile = new VideoInputFile(
"/tmp/whatever.mkv",
new List
- { 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.None,
2000,
4000,
@@ -273,7 +273,7 @@ public class PipelineGeneratorTests
var videoInputFile = new VideoInputFile(
"/tmp/whatever.mkv",
new List
- { 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 = Option.None;
@@ -284,7 +284,7 @@ public class PipelineGeneratorTests
new PixelFormatYuv420P(),
new FrameSize(1920, 1080),
new FrameSize(1920, 1080),
- "16:9",
+ false,
Option.None,
2000,
4000,
@@ -341,7 +341,7 @@ public class PipelineGeneratorTests
"/test/input/file.png",
new List
{
- new(0, string.Empty, Option.None, FrameSize.Unknown, string.Empty, Option.None, true)
+ new(0, string.Empty, Option.None, FrameSize.Unknown, string.Empty, string.Empty, Option.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(
diff --git a/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj b/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj
index 2a391fb85..9d7ade830 100644
--- a/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj
+++ b/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/ErsatzTV.FFmpeg/Filter/AvailableScaleFilters.cs b/ErsatzTV.FFmpeg/Filter/AvailableScaleFilters.cs
index 34c5a9169..6f2d670b2 100644
--- a/ErsatzTV.FFmpeg/Filter/AvailableScaleFilters.cs
+++ b/ErsatzTV.FFmpeg/Filter/AvailableScaleFilters.cs
@@ -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)
};
}
diff --git a/ErsatzTV.FFmpeg/Filter/AvailableSubtitleOverlayFilters.cs b/ErsatzTV.FFmpeg/Filter/AvailableSubtitleOverlayFilters.cs
index 0b12bf9ba..5ac31f5bc 100644
--- a/ErsatzTV.FFmpeg/Filter/AvailableSubtitleOverlayFilters.cs
+++ b/ErsatzTV.FFmpeg/Filter/AvailableSubtitleOverlayFilters.cs
@@ -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()
};
}
diff --git a/ErsatzTV.FFmpeg/Filter/AvailableWatermarkOverlayFilters.cs b/ErsatzTV.FFmpeg/Filter/AvailableWatermarkOverlayFilters.cs
index 398a47066..a2bb71bb3 100644
--- a/ErsatzTV.FFmpeg/Filter/AvailableWatermarkOverlayFilters.cs
+++ b/ErsatzTV.FFmpeg/Filter/AvailableWatermarkOverlayFilters.cs
@@ -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)
};
}
diff --git a/ErsatzTV.FFmpeg/Filter/ComplexFilter.cs b/ErsatzTV.FFmpeg/Filter/ComplexFilter.cs
index 87cf32b83..b3cba1a8c 100644
--- a/ErsatzTV.FFmpeg/Filter/ComplexFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/ComplexFilter.cs
@@ -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 _maybeAudioInputFile;
private readonly Option _maybeSubtitleInputFile;
private readonly Option _maybeVideoInputFile;
@@ -22,7 +24,8 @@ public class ComplexFilter : IPipelineStep
Option maybeWatermarkInputFile,
Option 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 EnvironmentVariables => Array.Empty();
@@ -147,48 +151,56 @@ public class ComplexFilter : IPipelineStep
watermarkLabel = $"[{watermarkLabel}]";
}
- IPipelineFilterStep overlayFilter = AvailableWatermarkOverlayFilters.ForAcceleration(
- _ffmpegState.EncoderHardwareAccelerationMode,
- _currentState,
- watermarkInputFile.DesiredState,
- _resolution);
-
- if (overlayFilter.Filter != string.Empty)
+ foreach (VideoInputFile videoInputFile in _maybeVideoInputFile)
{
- string tempVideoLabel = string.IsNullOrWhiteSpace(videoFilterComplex)
- ? $"[{videoLabel}]"
- : videoLabel;
-
- // vaapi uses software overlay and needs to upload
- // videotoolbox seems to require a hwupload for hevc
- // also wait to upload if a subtitle overlay is coming
- string uploadDownloadFilter = string.Empty;
- if (_maybeSubtitleInputFile.IsNone &&
- (_ffmpegState.EncoderHardwareAccelerationMode == HardwareAccelerationMode.Vaapi ||
- _ffmpegState.EncoderHardwareAccelerationMode == HardwareAccelerationMode.VideoToolbox &&
- _currentState.VideoFormat == VideoFormat.Hevc))
+ foreach (VideoStream stream in videoInputFile.VideoStreams)
{
- uploadDownloadFilter = new HardwareUploadFilter(_ffmpegState).Filter;
+ IPipelineFilterStep overlayFilter = AvailableWatermarkOverlayFilters.ForAcceleration(
+ _ffmpegState.EncoderHardwareAccelerationMode,
+ watermarkInputFile.DesiredState,
+ _resolution,
+ stream.SquarePixelFrameSize(_resolution),
+ _logger);
+
+ if (overlayFilter.Filter != string.Empty)
+ {
+ string tempVideoLabel = string.IsNullOrWhiteSpace(videoFilterComplex)
+ ? $"[{videoLabel}]"
+ : videoLabel;
+
+ // vaapi uses software overlay and needs to upload
+ // videotoolbox seems to require a hwupload for hevc
+ // also wait to upload if a subtitle overlay is coming
+ string uploadDownloadFilter = string.Empty;
+ if (_maybeSubtitleInputFile.IsNone &&
+ (_ffmpegState.EncoderHardwareAccelerationMode == HardwareAccelerationMode.Vaapi ||
+ _ffmpegState.EncoderHardwareAccelerationMode ==
+ HardwareAccelerationMode.VideoToolbox &&
+ _currentState.VideoFormat == VideoFormat.Hevc))
+ {
+ uploadDownloadFilter = new HardwareUploadFilter(_ffmpegState).Filter;
+ }
+
+ if (_maybeSubtitleInputFile.Map(s => !s.IsImageBased).IfNone(false) &&
+ _ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.Vaapi &&
+ _ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.VideoToolbox &&
+ _ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.Amf)
+ {
+ uploadDownloadFilter = new HardwareDownloadFilter(_currentState).Filter;
+ }
+
+ if (!string.IsNullOrWhiteSpace(uploadDownloadFilter))
+ {
+ uploadDownloadFilter = "," + uploadDownloadFilter;
+ }
+
+ watermarkOverlayFilterComplex =
+ $"{tempVideoLabel}{watermarkLabel}{overlayFilter.Filter}{uploadDownloadFilter}[vf]";
+
+ // change the mapped label
+ videoLabel = "[vf]";
+ }
}
-
- if (_maybeSubtitleInputFile.Map(s => !s.IsImageBased).IfNone(false) &&
- _ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.Vaapi &&
- _ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.VideoToolbox &&
- _ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.Amf)
- {
- uploadDownloadFilter = new HardwareDownloadFilter(_currentState).Filter;
- }
-
- if (!string.IsNullOrWhiteSpace(uploadDownloadFilter))
- {
- uploadDownloadFilter = "," + uploadDownloadFilter;
- }
-
- watermarkOverlayFilterComplex =
- $"{tempVideoLabel}{watermarkLabel}{overlayFilter.Filter}{uploadDownloadFilter}[vf]";
-
- // change the mapped label
- videoLabel = "[vf]";
}
}
}
@@ -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
diff --git a/ErsatzTV.FFmpeg/Filter/Cuda/OverlaySubtitleCudaFilter.cs b/ErsatzTV.FFmpeg/Filter/Cuda/OverlaySubtitleCudaFilter.cs
index 7c9aa7f6c..9fe462ee6 100644
--- a/ErsatzTV.FFmpeg/Filter/Cuda/OverlaySubtitleCudaFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/Cuda/OverlaySubtitleCudaFilter.cs
@@ -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;
}
diff --git a/ErsatzTV.FFmpeg/Filter/Cuda/OverlayWatermarkCudaFilter.cs b/ErsatzTV.FFmpeg/Filter/Cuda/OverlayWatermarkCudaFilter.cs
index 8a4163f6c..5d7dcd0fa 100644
--- a/ErsatzTV.FFmpeg/Filter/Cuda/OverlayWatermarkCudaFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/Cuda/OverlayWatermarkCudaFilter.cs
@@ -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)
{
}
diff --git a/ErsatzTV.FFmpeg/Filter/Cuda/ScaleCudaFilter.cs b/ErsatzTV.FFmpeg/Filter/Cuda/ScaleCudaFilter.cs
index 9b72ecbaa..eb611d468 100644
--- a/ErsatzTV.FFmpeg/Filter/Cuda/ScaleCudaFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/Cuda/ScaleCudaFilter.cs
@@ -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
};
}
diff --git a/ErsatzTV.FFmpeg/Filter/Cuda/SubtitleScaleNppFilter.cs b/ErsatzTV.FFmpeg/Filter/Cuda/SubtitleScaleNppFilter.cs
index a9dded557..e66423b06 100644
--- a/ErsatzTV.FFmpeg/Filter/Cuda/SubtitleScaleNppFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/Cuda/SubtitleScaleNppFilter.cs
@@ -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;
diff --git a/ErsatzTV.FFmpeg/Filter/OverlaySubtitleFilter.cs b/ErsatzTV.FFmpeg/Filter/OverlaySubtitleFilter.cs
index abff7d21c..f8a925473 100644
--- a/ErsatzTV.FFmpeg/Filter/OverlaySubtitleFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/OverlaySubtitleFilter.cs
@@ -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;
}
diff --git a/ErsatzTV.FFmpeg/Filter/OverlayWatermarkFilter.cs b/ErsatzTV.FFmpeg/Filter/OverlayWatermarkFilter.cs
index 7b0f19faa..3bfdb0275 100644
--- a/ErsatzTV.FFmpeg/Filter/OverlayWatermarkFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/OverlayWatermarkFilter.cs
@@ -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
{
diff --git a/ErsatzTV.FFmpeg/Filter/Qsv/OverlaySubtitleQsvFilter.cs b/ErsatzTV.FFmpeg/Filter/Qsv/OverlaySubtitleQsvFilter.cs
index 3a40c0d2b..a3eed1255 100644
--- a/ErsatzTV.FFmpeg/Filter/Qsv/OverlaySubtitleQsvFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/Qsv/OverlaySubtitleQsvFilter.cs
@@ -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;
}
diff --git a/ErsatzTV.FFmpeg/Filter/Qsv/OverlayWatermarkQsvFilter.cs b/ErsatzTV.FFmpeg/Filter/Qsv/OverlayWatermarkQsvFilter.cs
index 4ee24fb2d..524e58ce3 100644
--- a/ErsatzTV.FFmpeg/Filter/Qsv/OverlayWatermarkQsvFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/Qsv/OverlayWatermarkQsvFilter.cs
@@ -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)
{
}
diff --git a/ErsatzTV.FFmpeg/Filter/Qsv/ScaleQsvFilter.cs b/ErsatzTV.FFmpeg/Filter/Qsv/ScaleQsvFilter.cs
index 81cedeb62..49c189ba0 100644
--- a/ErsatzTV.FFmpeg/Filter/Qsv/ScaleQsvFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/Qsv/ScaleQsvFilter.cs
@@ -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
};
}
diff --git a/ErsatzTV.FFmpeg/Filter/Qsv/SubtitleScaleQsvFilter.cs b/ErsatzTV.FFmpeg/Filter/Qsv/SubtitleScaleQsvFilter.cs
index b577536b9..e849155fd 100644
--- a/ErsatzTV.FFmpeg/Filter/Qsv/SubtitleScaleQsvFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/Qsv/SubtitleScaleQsvFilter.cs
@@ -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);
diff --git a/ErsatzTV.FFmpeg/Filter/ScaleFilter.cs b/ErsatzTV.FFmpeg/Filter/ScaleFilter.cs
index 1b5f3edfa..cba8db350 100644
--- a/ErsatzTV.FFmpeg/Filter/ScaleFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/ScaleFilter.cs
@@ -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
- {
- ScaledSize = _scaledSize,
- PaddedSize = _scaledSize,
- FrameDataLocation = FrameDataLocation.Software
- };
+ public override FrameState NextState(FrameState currentState) =>
+ currentState with
+ {
+ ScaledSize = _scaledSize,
+ PaddedSize = _scaledSize,
+ FrameDataLocation = FrameDataLocation.Software,
+ IsAnamorphic = false // this filter always outputs square pixels
+ };
}
diff --git a/ErsatzTV.FFmpeg/Filter/ScaleImageFilter.cs b/ErsatzTV.FFmpeg/Filter/ScaleImageFilter.cs
index 2d0b785e1..2428a8c83 100644
--- a/ErsatzTV.FFmpeg/Filter/ScaleImageFilter.cs
+++ b/ErsatzTV.FFmpeg/Filter/ScaleImageFilter.cs
@@ -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 OutputOptions => new List { "-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
{
diff --git a/ErsatzTV.FFmpeg/FrameState.cs b/ErsatzTV.FFmpeg/FrameState.cs
index 160a4945d..9c81536e9 100644
--- a/ErsatzTV.FFmpeg/FrameState.cs
+++ b/ErsatzTV.FFmpeg/FrameState.cs
@@ -9,10 +9,13 @@ public record FrameState(
Option PixelFormat,
FrameSize ScaledSize,
FrameSize PaddedSize,
- string DisplayAspectRatio,
+ bool IsAnamorphic,
Option FrameRate,
Option VideoBitrate,
Option VideoBufferSize,
Option VideoTrackTimeScale,
bool Deinterlaced,
- FrameDataLocation FrameDataLocation = FrameDataLocation.Unknown);
+ FrameDataLocation FrameDataLocation = FrameDataLocation.Unknown)
+{
+ public string FFmpegAspectRatio => PaddedSize.Width == 640 ? "4/3" : "16/9";
+}
diff --git a/ErsatzTV.FFmpeg/InputFile.cs b/ErsatzTV.FFmpeg/InputFile.cs
index 4eb32987d..a2500fe07 100644
--- a/ErsatzTV.FFmpeg/InputFile.cs
+++ b/ErsatzTV.FFmpeg/InputFile.cs
@@ -20,6 +20,7 @@ public record ConcatInputFile(string Url, FrameSize Resolution) : InputFile(
Option.None,
Resolution,
string.Empty,
+ string.Empty,
Option.None,
false)
})
diff --git a/ErsatzTV.FFmpeg/MediaStream.cs b/ErsatzTV.FFmpeg/MediaStream.cs
index 3c90b436b..c5c0986a8 100644
--- a/ErsatzTV.FFmpeg/MediaStream.cs
+++ b/ErsatzTV.FFmpeg/MediaStream.cs
@@ -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 PixelFormat,
FrameSize FrameSize,
+ string SampleAspectRatio,
string DisplayAspectRatio,
Option 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;
+ }
+}
diff --git a/ErsatzTV.FFmpeg/PipelineBuilder.cs b/ErsatzTV.FFmpeg/PipelineBuilder.cs
index bc9fbd4cd..df7403bd2 100644
--- a/ErsatzTV.FFmpeg/PipelineBuilder.cs
+++ b/ErsatzTV.FFmpeg/PipelineBuilder.cs
@@ -192,7 +192,7 @@ public class PipelineBuilder
videoStream.PixelFormat,
videoStream.FrameSize,
videoStream.FrameSize,
- videoStream.DisplayAspectRatio,
+ videoStream.IsAnamorphic,
initialFrameRate,
Option.None,
Option.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);
}
diff --git a/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj b/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj
index 48386c47a..3a5ba2458 100644
--- a/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj
+++ b/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj
@@ -14,12 +14,12 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/ErsatzTV/ErsatzTV.csproj b/ErsatzTV/ErsatzTV.csproj
index 84571e5ca..bfe7adec7 100644
--- a/ErsatzTV/ErsatzTV.csproj
+++ b/ErsatzTV/ErsatzTV.csproj
@@ -55,16 +55,16 @@
-
+
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -73,12 +73,12 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
+
-
+
diff --git a/ErsatzTV/Program.cs b/ErsatzTV/Program.cs
index be718dcff..695ed3c9f 100644
--- a/ErsatzTV/Program.cs
+++ b/ErsatzTV/Program.cs
@@ -64,7 +64,7 @@ public class Program
}
finally
{
- Log.CloseAndFlush();
+ await Log.CloseAndFlushAsync();
}
}