diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 8313ab5bca..8c0abe10de 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -612,6 +612,17 @@ namespace MediaBrowser.MediaEncoding.Probing return attachment; } + /// + /// Determines whether a stream code time base is double the frame rate. + /// + /// average frame rate. + /// codec time base string. + /// true if the codec time base is double the frame rate. + internal static bool IsCodecTimeBaseDoubleTheFrameRate(float? averageFrameRate, string codecTimeBase) + { + return MathF.Abs(((averageFrameRate ?? 0) * (GetFrameRate(codecTimeBase) ?? 0)) - 0.5f) <= float.Epsilon; + } + /// /// Converts ffprobe stream info to our MediaStream class. /// @@ -722,17 +733,16 @@ namespace MediaBrowser.MediaEncoding.Probing stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate); stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate); + bool videoInterlaced = !string.IsNullOrWhiteSpace(streamInfo.FieldOrder) + && !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase); + // Some interlaced H.264 files in mp4 containers using MBAFF coding aren't flagged as being interlaced by FFprobe, // so for H.264 files we also calculate the frame rate from the codec time base and check if it is double the reported - // frame rate (both rounded to the nearest integer) to determine if the file is interlaced - int roundedTimeBaseFPS = Convert.ToInt32(1 / GetFrameRate(stream.CodecTimeBase) ?? 0); - int roundedDoubleFrameRate = Convert.ToInt32(stream.AverageFrameRate * 2 ?? 0); + // frame rate to determine if the file is interlaced - bool videoInterlaced = !string.IsNullOrWhiteSpace(streamInfo.FieldOrder) - && !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase); bool h264MbaffCoded = string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase) && string.IsNullOrWhiteSpace(streamInfo.FieldOrder) - && roundedTimeBaseFPS == roundedDoubleFrameRate; + && IsCodecTimeBaseDoubleTheFrameRate(stream.AverageFrameRate, stream.CodecTimeBase); if (videoInterlaced || h264MbaffCoded) { diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs index 0fc8724b6a..53e1550ed1 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs @@ -31,6 +31,16 @@ namespace Jellyfin.MediaEncoding.Tests.Probing public void GetFrameRate_Success(string value, float? expected) => Assert.Equal(expected, ProbeResultNormalizer.GetFrameRate(value)); + [Theory] + [InlineData(0.5f, "0/1", false)] + [InlineData(24.5f, "8/196", false)] + [InlineData(63.5f, "1/127", true)] + [InlineData(null, "1/60", false)] + [InlineData(30f, "2/120", true)] + [InlineData(59.999996f, "1563/187560", true)] + public void IsCodecTimeBaseDoubleTheFrameRate_Success(float? frameRate, string codecTimeBase, bool expected) + => Assert.Equal(expected, ProbeResultNormalizer.IsCodecTimeBaseDoubleTheFrameRate(frameRate, codecTimeBase)); + [Fact] public void GetMediaInfo_MetaData_Success() {