Fix near-1:1 SAR values falsely flagged as anamorphic

Encoders sometimes produce sample aspect ratios like 3201:3200
(0.03% off square) for content that has effectively square pixels.
The exact string comparison against "1:1" marks these as anamorphic,
which triggers unnecessary transcoding on clients that require
non-anamorphic video.

Parse the SAR ratio numerically and treat values within 1% of 1:1
as square pixels. This threshold is well clear of the nearest real
anamorphic SAR (PAL 4:3 at 16:15 = 6.67% off).
This commit is contained in:
NoFear0411
2026-03-01 00:00:05 +04:00
parent e6d73ae367
commit bc316b3dc8
2 changed files with 45 additions and 1 deletions

View File

@@ -863,7 +863,7 @@ namespace MediaBrowser.MediaEncoding.Probing
{
stream.IsAnamorphic = false;
}
else if (string.Equals(streamInfo.SampleAspectRatio, "1:1", StringComparison.Ordinal))
else if (IsNearSquarePixelSar(streamInfo.SampleAspectRatio))
{
stream.IsAnamorphic = false;
}
@@ -1154,6 +1154,32 @@ namespace MediaBrowser.MediaEncoding.Probing
return Math.Abs(d1 - d2) <= variance;
}
/// <summary>
/// Determines whether a sample aspect ratio represents square (or near-square) pixels.
/// Some encoders produce SARs like 3201:3200 for content that is effectively 1:1,
/// which would be falsely classified as anamorphic by an exact string comparison.
/// A 1% tolerance safely covers encoder rounding artifacts while preserving detection
/// of genuine anamorphic content (closest standard is PAL 4:3 at 16:15 = 6.67% off).
/// </summary>
internal static bool IsNearSquarePixelSar(string sar)
{
if (string.IsNullOrEmpty(sar))
{
return false;
}
var parts = sar.Split(':');
if (parts.Length == 2
&& double.TryParse(parts[0], CultureInfo.InvariantCulture, out var num)
&& double.TryParse(parts[1], CultureInfo.InvariantCulture, out var den)
&& den > 0)
{
return IsClose(num / den, 1.0, 0.01);
}
return string.Equals(sar, "1:1", StringComparison.Ordinal);
}
/// <summary>
/// Gets a frame rate from a string value in ffprobe output
/// This could be a number or in the format of 2997/125.

View File

@@ -39,6 +39,23 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
public void GetFrameRate_Success(string value, float? expected)
=> Assert.Equal(expected, ProbeResultNormalizer.GetFrameRate(value));
[Theory]
[InlineData("1:1", true)] // exact square pixels
[InlineData("3201:3200", true)] // 0.03% off — encoder rounding artifact (4K HEVC)
[InlineData("1215:1216", true)] // 0.08% off — encoder rounding artifact
[InlineData("1001:1000", true)] // 0.1% off — encoder rounding artifact
[InlineData("16:15", false)] // 6.67% off — PAL DVD 4:3, genuinely anamorphic
[InlineData("8:9", false)] // 11.1% off — NTSC DVD 4:3
[InlineData("32:27", false)] // 18.5% off — NTSC DVD 16:9
[InlineData("10:11", false)] // 9.1% off — DV NTSC
[InlineData("64:45", false)] // 42.2% off — PAL DVD 16:9
[InlineData("4:3", false)] // 33.3% off — classic anamorphic
[InlineData("0:1", false)] // invalid/unknown SAR
[InlineData("", false)] // empty
[InlineData(null, false)] // null
public void IsNearSquarePixelSar_DetectsCorrectly(string sar, bool expected)
=> Assert.Equal(expected, ProbeResultNormalizer.IsNearSquarePixelSar(sar));
[Fact]
public void GetMediaInfo_MetaData_Success()
{
@@ -123,6 +140,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
Assert.Equal(358, res.VideoStream.Height);
Assert.Equal(720, res.VideoStream.Width);
Assert.Equal("2.40:1", res.VideoStream.AspectRatio);
Assert.True(res.VideoStream.IsAnamorphic); // SAR 32:27 — genuinely anamorphic NTSC DVD 16:9
Assert.Equal("yuv420p", res.VideoStream.PixelFormat);
Assert.Equal(31d, res.VideoStream.Level);
Assert.Equal(1, res.VideoStream.RefFrames);