Browse Source

Revert 'Fix interlace check for H.264 MBAFF coded MP4 files' (#6222)

Bond_009 2 years ago
parent
commit
75fe640f2b

+ 1 - 25
MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs

@@ -625,17 +625,6 @@ namespace MediaBrowser.MediaEncoding.Probing
             return attachment;
         }
 
-        /// <summary>
-        /// Determines whether a stream code time base is double the frame rate.
-        /// </summary>
-        /// <param name="averageFrameRate">average frame rate.</param>
-        /// <param name="codecTimeBase">codec time base string.</param>
-        /// <returns>true if the codec time base is double the frame rate.</returns>
-        internal static bool IsCodecTimeBaseDoubleTheFrameRate(float? averageFrameRate, string codecTimeBase)
-        {
-            return MathF.Abs(((averageFrameRate ?? 0) * (GetFrameRate(codecTimeBase) ?? 0)) - 0.5f) <= float.Epsilon;
-        }
-
         /// <summary>
         /// Converts ffprobe stream info to our MediaStream class.
         /// </summary>
@@ -748,22 +737,9 @@ namespace MediaBrowser.MediaEncoding.Probing
                 stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate);
                 stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate);
 
-                bool videoInterlaced = !string.IsNullOrWhiteSpace(streamInfo.FieldOrder)
+                stream.IsInterlaced = !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 to determine if the file is interlaced
-
-                bool h264MbaffCoded = string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase)
-                    && string.IsNullOrWhiteSpace(streamInfo.FieldOrder)
-                    && IsCodecTimeBaseDoubleTheFrameRate(stream.AverageFrameRate, stream.CodecTimeBase);
-
-                if (videoInterlaced || h264MbaffCoded)
-                {
-                    stream.IsInterlaced = true;
-                }
-
                 if (isAudio
                     || string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase)
                     || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase)

+ 93 - 10
tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs

@@ -31,16 +31,6 @@ 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()
         {
@@ -158,6 +148,99 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
             Assert.False(res.MediaStreams[5].IsHearingImpaired);
         }
 
+        [Fact]
+        public void GetMediaInfo_ProgressiveVideoNoFieldOrder_Success()
+        {
+            var bytes = File.ReadAllBytes("Test Data/Probing/video_progressive_no_field_order.json");
+
+            var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions);
+            MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_progressive_no_field_order.mp4", MediaProtocol.File);
+
+            Assert.Equal(2, res.MediaStreams.Count);
+
+            Assert.NotNull(res.VideoStream);
+            Assert.Equal(res.MediaStreams[0], res.VideoStream);
+            Assert.Equal(0, res.VideoStream.Index);
+            Assert.Equal("h264", res.VideoStream.Codec);
+            Assert.Equal("Main", res.VideoStream.Profile);
+            Assert.Equal(MediaStreamType.Video, res.VideoStream.Type);
+            Assert.Equal(1080, res.VideoStream.Height);
+            Assert.Equal(1920, res.VideoStream.Width);
+            Assert.False(res.VideoStream.IsInterlaced);
+            Assert.Equal("16:9", res.VideoStream.AspectRatio);
+            Assert.Equal("yuv420p", res.VideoStream.PixelFormat);
+            Assert.Equal(41d, res.VideoStream.Level);
+            Assert.Equal(1, res.VideoStream.RefFrames);
+            Assert.True(res.VideoStream.IsAVC);
+            Assert.Equal(23.9760246f, res.VideoStream.RealFrameRate);
+            Assert.Equal("1/24000", res.VideoStream.TimeBase);
+            Assert.Equal(3948341, res.VideoStream.BitRate);
+            Assert.Equal(8, res.VideoStream.BitDepth);
+            Assert.True(res.VideoStream.IsDefault);
+        }
+
+        [Fact]
+        public void GetMediaInfo_ProgressiveVideoNoFieldOrder2_Success()
+        {
+            var bytes = File.ReadAllBytes("Test Data/Probing/video_progressive_no_field_order2.json");
+
+            var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions);
+            MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_progressive_no_field_order2.mp4", MediaProtocol.File);
+
+            Assert.Single(res.MediaStreams);
+
+            Assert.NotNull(res.VideoStream);
+            Assert.Equal(res.MediaStreams[0], res.VideoStream);
+            Assert.Equal(0, res.VideoStream.Index);
+            Assert.Equal("h264", res.VideoStream.Codec);
+            Assert.Equal("High", res.VideoStream.Profile);
+            Assert.Equal(MediaStreamType.Video, res.VideoStream.Type);
+            Assert.Equal(720, res.VideoStream.Height);
+            Assert.Equal(1280, res.VideoStream.Width);
+            Assert.False(res.VideoStream.IsInterlaced);
+            Assert.Equal("16:9", res.VideoStream.AspectRatio);
+            Assert.Equal("yuv420p", res.VideoStream.PixelFormat);
+            Assert.Equal(31d, res.VideoStream.Level);
+            Assert.Equal(1, res.VideoStream.RefFrames);
+            Assert.True(res.VideoStream.IsAVC);
+            Assert.Equal(25f, res.VideoStream.RealFrameRate);
+            Assert.Equal("1/12800", res.VideoStream.TimeBase);
+            Assert.Equal(53288, res.VideoStream.BitRate);
+            Assert.Equal(8, res.VideoStream.BitDepth);
+            Assert.True(res.VideoStream.IsDefault);
+        }
+
+        [Fact]
+        public void GetMediaInfo_InterlacedVideo_Success()
+        {
+            var bytes = File.ReadAllBytes("Test Data/Probing/video_interlaced.json");
+
+            var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions);
+            MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_interlaced.mp4", MediaProtocol.File);
+
+            Assert.Single(res.MediaStreams);
+
+            Assert.NotNull(res.VideoStream);
+            Assert.Equal(res.MediaStreams[0], res.VideoStream);
+            Assert.Equal(0, res.VideoStream.Index);
+            Assert.Equal("h264", res.VideoStream.Codec);
+            Assert.Equal("High", res.VideoStream.Profile);
+            Assert.Equal(MediaStreamType.Video, res.VideoStream.Type);
+            Assert.Equal(720, res.VideoStream.Height);
+            Assert.Equal(1280, res.VideoStream.Width);
+            Assert.True(res.VideoStream.IsInterlaced);
+            Assert.Equal("16:9", res.VideoStream.AspectRatio);
+            Assert.Equal("yuv420p", res.VideoStream.PixelFormat);
+            Assert.Equal(40d, res.VideoStream.Level);
+            Assert.Equal(1, res.VideoStream.RefFrames);
+            Assert.True(res.VideoStream.IsAVC);
+            Assert.Equal(25f, res.VideoStream.RealFrameRate);
+            Assert.Equal("1/12800", res.VideoStream.TimeBase);
+            Assert.Equal(56945, res.VideoStream.BitRate);
+            Assert.Equal(8, res.VideoStream.BitDepth);
+            Assert.True(res.VideoStream.IsDefault);
+        }
+
         [Fact]
         public void GetMediaInfo_MusicVideo_Success()
         {

+ 81 - 0
tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_interlaced.json

@@ -0,0 +1,81 @@
+{
+    "streams": [
+        {
+            "index": 0,
+            "codec_name": "h264",
+            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
+            "profile": "High",
+            "codec_type": "video",
+            "codec_tag_string": "avc1",
+            "codec_tag": "0x31637661",
+            "width": 1280,
+            "height": 720,
+            "coded_width": 1280,
+            "coded_height": 720,
+            "closed_captions": 0,
+            "film_grain": 0,
+            "has_b_frames": 2,
+            "pix_fmt": "yuv420p",
+            "level": 40,
+            "chroma_location": "left",
+            "field_order": "tt",
+            "refs": 1,
+            "is_avc": "true",
+            "nal_length_size": "4",
+            "id": "0x1",
+            "r_frame_rate": "25/1",
+            "avg_frame_rate": "25/1",
+            "time_base": "1/12800",
+            "start_pts": 0,
+            "start_time": "0.000000",
+            "duration_ts": 3840000,
+            "duration": "300.000000",
+            "bit_rate": "56945",
+            "bits_per_raw_sample": "8",
+            "nb_frames": "7500",
+            "extradata_size": 42,
+            "disposition": {
+                "default": 1,
+                "dub": 0,
+                "original": 0,
+                "comment": 0,
+                "lyrics": 0,
+                "karaoke": 0,
+                "forced": 0,
+                "hearing_impaired": 0,
+                "visual_impaired": 0,
+                "clean_effects": 0,
+                "attached_pic": 0,
+                "timed_thumbnails": 0,
+                "captions": 0,
+                "descriptions": 0,
+                "metadata": 0,
+                "dependent": 0,
+                "still_image": 0
+            },
+            "tags": {
+                "language": "und",
+                "handler_name": "VideoHandler",
+                "vendor_id": "[0][0][0][0]"
+            }
+        }
+    ],
+    "format": {
+        "filename": "test-gray.720i.mp4",
+        "nb_streams": 1,
+        "nb_programs": 0,
+        "format_name": "mov,mp4,m4a,3gp,3g2,mj2",
+        "format_long_name": "QuickTime / MOV",
+        "start_time": "0.000000",
+        "duration": "300.000000",
+        "size": "2223957",
+        "bit_rate": "59305",
+        "probe_score": 100,
+        "tags": {
+            "major_brand": "isom",
+            "minor_version": "512",
+            "compatible_brands": "isomiso2avc1mp41",
+            "encoder": "Lavf58.20.100"
+        }
+    }
+}

+ 133 - 0
tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order.json

@@ -0,0 +1,133 @@
+{
+    "streams": [
+        {
+            "index": 0,
+            "codec_name": "h264",
+            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
+            "profile": "Main",
+            "codec_type": "video",
+            "codec_time_base": "1001/48000",
+            "codec_tag_string": "avc1",
+            "codec_tag": "0x31637661",
+            "width": 1920,
+            "height": 1080,
+            "coded_width": 1920,
+            "coded_height": 1088,
+            "closed_captions": 0,
+            "has_b_frames": 1,
+            "sample_aspect_ratio": "1:1",
+            "display_aspect_ratio": "16:9",
+            "pix_fmt": "yuv420p",
+            "level": 41,
+            "chroma_location": "left",
+            "refs": 1,
+            "is_avc": "true",
+            "nal_length_size": "4",
+            "r_frame_rate": "24000/1001",
+            "avg_frame_rate": "24000/1001",
+            "time_base": "1/24000",
+            "start_pts": 1000,
+            "start_time": "0.041667",
+            "duration_ts": 29095066,
+            "duration": "1212.294417",
+            "bit_rate": "3948341",
+            "bits_per_raw_sample": "8",
+            "nb_frames": "29066",
+            "disposition": {
+                "default": 1,
+                "dub": 0,
+                "original": 0,
+                "comment": 0,
+                "lyrics": 0,
+                "karaoke": 0,
+                "forced": 0,
+                "hearing_impaired": 0,
+                "visual_impaired": 0,
+                "clean_effects": 0,
+                "attached_pic": 0,
+                "timed_thumbnails": 0
+            },
+            "tags": {
+                "creation_time": "2020-01-20T13:56:34.000000Z",
+                "language": "eng",
+                "handler_name": "\fVideoHandler",
+                "encoder": "h264"
+            }
+        },
+        {
+            "index": 1,
+            "codec_name": "ac3",
+            "codec_long_name": "ATSC A/52A (AC-3)",
+            "codec_type": "audio",
+            "codec_time_base": "1/48000",
+            "codec_tag_string": "ac-3",
+            "codec_tag": "0x332d6361",
+            "sample_fmt": "fltp",
+            "sample_rate": "48000",
+            "channels": 2,
+            "channel_layout": "stereo",
+            "bits_per_sample": 0,
+            "dmix_mode": "-1",
+            "ltrt_cmixlev": "-1.000000",
+            "ltrt_surmixlev": "-1.000000",
+            "loro_cmixlev": "-1.000000",
+            "loro_surmixlev": "-1.000000",
+            "r_frame_rate": "0/0",
+            "avg_frame_rate": "0/0",
+            "time_base": "1/48000",
+            "start_pts": 0,
+            "start_time": "0.000000",
+            "duration_ts": 58232832,
+            "duration": "1213.184000",
+            "bit_rate": "224000",
+            "nb_frames": "37912",
+            "disposition": {
+                "default": 1,
+                "dub": 0,
+                "original": 0,
+                "comment": 0,
+                "lyrics": 0,
+                "karaoke": 0,
+                "forced": 0,
+                "hearing_impaired": 0,
+                "visual_impaired": 0,
+                "clean_effects": 0,
+                "attached_pic": 0,
+                "timed_thumbnails": 0
+            },
+            "tags": {
+                "creation_time": "2020-01-20T13:56:34.000000Z",
+                "language": "eng",
+                "handler_name": "\fSoundHandler"
+            },
+            "side_data_list": [
+                {
+                    "side_data_type": "Audio Service Type"
+                }
+            ]
+        }
+    ],
+    "format": {
+        "filename": "The Big Bang Theory - S01E17.mp4",
+        "nb_streams": 2,
+        "nb_programs": 0,
+        "format_name": "mov,mp4,m4a,3gp,3g2,mj2",
+        "format_long_name": "QuickTime / MOV",
+        "start_time": "0.000000",
+        "duration": "1213.184000",
+        "size": "633084606",
+        "bit_rate": "4174698",
+        "probe_score": 100,
+        "tags": {
+            "major_brand": "mp42",
+            "minor_version": "512",
+            "compatible_brands": "mp42",
+            "creation_time": "2020-01-20T13:56:34.000000Z",
+            "media_type": "9",
+            "season_number": "0",
+            "episode_sort": "0",
+            "hd_video": "0",
+            "iTunMOVI": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\"  \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"><plist version=\"1.0\"><dict><key>studio</key><string>studio</string><key>cast</key><array><dict><key>name</key><string></string></dict></array><key>directors</key><array><dict><key>name</key><string></string></dict></array><key>producers</key><array><dict><key>name</key><string></string></dict></array><key>codirectors</key><array><dict><key>name</key><string>codirector</string></dict></array><key>screenwriters</key><array><dict><key>name</key><string></string></dict></array></dict></plist>"
+        }
+    }
+}

+ 72 - 0
tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_progressive_no_field_order2.json

@@ -0,0 +1,72 @@
+{
+    "streams": [
+        {
+            "index": 0,
+            "codec_name": "h264",
+            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
+            "profile": "High",
+            "codec_type": "video",
+            "codec_time_base": "1/50",
+            "codec_tag_string": "avc1",
+            "codec_tag": "0x31637661",
+            "width": 1280,
+            "height": 720,
+            "coded_width": 1280,
+            "coded_height": 720,
+            "closed_captions": 0,
+            "has_b_frames": 2,
+            "pix_fmt": "yuv420p",
+            "level": 31,
+            "chroma_location": "left",
+            "refs": 1,
+            "is_avc": "true",
+            "nal_length_size": "4",
+            "r_frame_rate": "25/1",
+            "avg_frame_rate": "25/1",
+            "time_base": "1/12800",
+            "start_pts": 0,
+            "start_time": "0.000000",
+            "duration_ts": 3840000,
+            "duration": "300.000000",
+            "bit_rate": "53288",
+            "bits_per_raw_sample": "8",
+            "nb_frames": "7500",
+            "disposition": {
+                "default": 1,
+                "dub": 0,
+                "original": 0,
+                "comment": 0,
+                "lyrics": 0,
+                "karaoke": 0,
+                "forced": 0,
+                "hearing_impaired": 0,
+                "visual_impaired": 0,
+                "clean_effects": 0,
+                "attached_pic": 0,
+                "timed_thumbnails": 0
+            },
+            "tags": {
+                "language": "und",
+                "handler_name": "VideoHandler"
+            }
+        }
+    ],
+    "format": {
+        "filename": "test-gray.720p.mp4",
+        "nb_streams": 1,
+        "nb_programs": 0,
+        "format_name": "mov,mp4,m4a,3gp,3g2,mj2",
+        "format_long_name": "QuickTime / MOV",
+        "start_time": "0.000000",
+        "duration": "300.000000",
+        "size": "2086818",
+        "bit_rate": "55648",
+        "probe_score": 100,
+        "tags": {
+            "major_brand": "isom",
+            "minor_version": "512",
+            "compatible_brands": "isomiso2avc1mp41",
+            "encoder": "Lavf58.20.100"
+        }
+    }
+}