Browse Source

fix scaling behavior crop (#1928)

pull/1932/head
Jason Dove 9 months ago committed by GitHub
parent
commit
6c4f63ad91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 60
      ErsatzTV.Core.Tests/FFmpeg/FFmpegPlaybackSettingsCalculatorTests.cs
  3. 16
      ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
  4. 25
      ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs

2
CHANGELOG.md

@ -18,6 +18,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -18,6 +18,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- This bug made it difficult to "stop" a channel after previewing it
- Fix bug where deco default filler would never use hardware acceleration
- Fix deleting local libraries with MySql backend
- Fix `Scaling Behavior` `Crop` when content is smaller than FFmpeg Profile resolution
- Now, content will properly scale beyond the desired resolution before cropping
## [0.8.8-beta] - 2024-09-19
### Added

60
ErsatzTV.Core.Tests/FFmpeg/FFmpegPlaybackSettingsCalculatorTests.cs

@ -356,6 +356,66 @@ public class FFmpegPlaybackSettingsCalculatorTests @@ -356,6 +356,66 @@ public class FFmpegPlaybackSettingsCalculatorTests
actual.PadToDesiredResolution.Should().BeTrue();
}
[Test]
public void Should_ScaleBeyondMinSize_ForCrop_ForTransportStream()
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
Resolution = new Resolution { Width = 1280, Height = 720 },
ScalingBehavior = ScalingBehavior.Crop
};
var version = new MediaVersion { Width = 944, Height = 720, SampleAspectRatio = "1:1" };
FFmpegPlaybackSettings actual = FFmpegPlaybackSettingsCalculator.CalculateSettings(
StreamingMode.TransportStream,
ffmpegProfile,
version,
new MediaStream(),
new MediaStream(),
DateTimeOffset.Now,
DateTimeOffset.Now,
TimeSpan.Zero,
TimeSpan.Zero,
false,
None);
IDisplaySize scaledSize = actual.ScaledSize.IfNone(new MediaVersion { Width = 0, Height = 0 });
scaledSize.Width.Should().Be(1280);
scaledSize.Height.Should().Be(976);
actual.PadToDesiredResolution.Should().BeFalse();
}
[Test]
public void Should_ScaleDownToMinSize_ForCrop_ForTransportStream()
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
Resolution = new Resolution { Width = 1280, Height = 720 },
ScalingBehavior = ScalingBehavior.Crop
};
var version = new MediaVersion { Width = 1920, Height = 816, SampleAspectRatio = "1:1" };
FFmpegPlaybackSettings actual = FFmpegPlaybackSettingsCalculator.CalculateSettings(
StreamingMode.TransportStream,
ffmpegProfile,
version,
new MediaStream(),
new MediaStream(),
DateTimeOffset.Now,
DateTimeOffset.Now,
TimeSpan.Zero,
TimeSpan.Zero,
false,
None);
IDisplaySize scaledSize = actual.ScaledSize.IfNone(new MediaVersion { Width = 0, Height = 0 });
scaledSize.Width.Should().Be(1694);
scaledSize.Height.Should().Be(720);
actual.PadToDesiredResolution.Should().BeFalse();
}
[Test]
public void Should_NotPadToDesiredResolution_When_UnscaledContentIsUnderSized_ForHttpLiveStreaming()
{

16
ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

@ -334,9 +334,25 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -334,9 +334,25 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
}
if (channel.FFmpegProfile.ScalingBehavior is ScalingBehavior.Crop)
{
bool isTooSmallToCrop = videoVersion.Height < channel.FFmpegProfile.Resolution.Height ||
videoVersion.Width < channel.FFmpegProfile.Resolution.Width;
// if any dimension is smaller than the crop, scale beyond the crop (beyond the target resolution)
if (isTooSmallToCrop)
{
foreach (IDisplaySize size in playbackSettings.ScaledSize)
{
scaledSize = new FrameSize(size.Width, size.Height);
}
paddedSize = scaledSize;
}
else
{
paddedSize = ffmpegVideoStream.SquarePixelFrameSizeForCrop(
new FrameSize(channel.FFmpegProfile.Resolution.Width, channel.FFmpegProfile.Resolution.Height));
}
cropSize = new FrameSize(
channel.FFmpegProfile.Resolution.Width,

25
ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs

@ -99,7 +99,7 @@ public static class FFmpegPlaybackSettingsCalculator @@ -99,7 +99,7 @@ public static class FFmpegPlaybackSettingsCalculator
}
IDisplaySize sizeAfterScaling = result.ScaledSize.IfNone(videoVersion);
if (!sizeAfterScaling.IsSameSizeAs(ffmpegProfile.Resolution))
if (!sizeAfterScaling.IsSameSizeAs(ffmpegProfile.Resolution) && ffmpegProfile.ScalingBehavior is not ScalingBehavior.Crop)
{
result.PadToDesiredResolution = true;
}
@ -229,7 +229,8 @@ public static class FFmpegPlaybackSettingsCalculator @@ -229,7 +229,8 @@ public static class FFmpegPlaybackSettingsCalculator
private static bool NeedToScale(FFmpegProfile ffmpegProfile, MediaVersion version) =>
IsIncorrectSize(ffmpegProfile.Resolution, version) ||
IsTooLarge(ffmpegProfile.Resolution, version) ||
IsOddSize(version);
IsOddSize(version) ||
TooSmallToCrop(ffmpegProfile, version);
private static bool IsIncorrectSize(IDisplaySize desiredResolution, MediaVersion version) =>
IsAnamorphic(version) ||
@ -243,6 +244,16 @@ public static class FFmpegPlaybackSettingsCalculator @@ -243,6 +244,16 @@ public static class FFmpegPlaybackSettingsCalculator
private static bool IsOddSize(MediaVersion version) =>
version.Height % 2 == 1 || version.Width % 2 == 1;
private static bool TooSmallToCrop(FFmpegProfile ffmpegProfile, MediaVersion version)
{
if (ffmpegProfile.ScalingBehavior is not ScalingBehavior.Crop)
{
return false;
}
return version.Height < ffmpegProfile.Resolution.Height || version.Width < ffmpegProfile.Resolution.Width;
}
private static DisplaySize CalculateScaledSize(FFmpegProfile ffmpegProfile, MediaVersion version)
{
IDisplaySize sarSize = SARSize(version);
@ -256,7 +267,12 @@ public static class FFmpegPlaybackSettingsCalculator @@ -256,7 +267,12 @@ public static class FFmpegPlaybackSettingsCalculator
int hh1 = hw1 * q / p;
int hh2 = targetSize.Height;
int hw2 = targetSize.Height * p / q;
if (hh1 <= targetSize.Height)
// crop needs to return whichever version has *both* dimensions >= required
// because it will never pad
if (ffmpegProfile.ScalingBehavior is ScalingBehavior.Crop)
{
if (hw1 >= targetSize.Width && hh1 >= targetSize.Height)
{
return new DisplaySize(hw1, hh1);
}
@ -264,6 +280,9 @@ public static class FFmpegPlaybackSettingsCalculator @@ -264,6 +280,9 @@ public static class FFmpegPlaybackSettingsCalculator
return new DisplaySize(hw2, hh2);
}
return hh1 <= targetSize.Height ? new DisplaySize(hw1, hh1) : new DisplaySize(hw2, hh2);
}
private static int Gcd(int a, int b)
{
while (a != 0 && b != 0)

Loading…
Cancel
Save