Jelajahi Sumber

Detect audio spatial format (#9996)

* Detect audio spatial format

* Update MediaBrowser.Model/Entities/MediaStream.cs

* Update MediaStream.cs

---------

Co-authored-by: Cody Robibero <cody@robibe.ro>
Mohamed Akram 1 tahun lalu
induk
melakukan
f49de51225

+ 1 - 0
CONTRIBUTORS.md

@@ -81,6 +81,7 @@
  - [Maxr1998](https://github.com/Maxr1998)
  - [mcarlton00](https://github.com/mcarlton00)
  - [mitchfizz05](https://github.com/mitchfizz05)
+ - [mohd-akram](https://github.com/mohd-akram)
  - [MrTimscampi](https://github.com/MrTimscampi)
  - [n8225](https://github.com/n8225)
  - [Nalsai](https://github.com/Nalsai)

+ 22 - 0
Jellyfin.Data/Enums/AudioSpatialFormat.cs

@@ -0,0 +1,22 @@
+namespace Jellyfin.Data.Enums;
+
+/// <summary>
+/// An enum representing formats of spatial audio.
+/// </summary>
+public enum AudioSpatialFormat
+{
+    /// <summary>
+    /// None audio spatial format.
+    /// </summary>
+    None,
+
+    /// <summary>
+    /// Dolby Atmos audio spatial format.
+    /// </summary>
+    DolbyAtmos,
+
+    /// <summary>
+    /// DTS:X audio spatial format.
+    /// </summary>
+    DTSX,
+}

+ 22 - 0
MediaBrowser.Model/Entities/MediaStream.cs

@@ -3,6 +3,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Globalization;
 using System.Linq;
 using System.Text;
@@ -214,6 +215,27 @@ namespace MediaBrowser.Model.Entities
             }
         }
 
+        /// <summary>
+        /// Gets the audio spatial format.
+        /// </summary>
+        /// <value>The audio spatial format.</value>
+        [DefaultValue(AudioSpatialFormat.None)]
+        public AudioSpatialFormat AudioSpatialFormat
+        {
+            get
+            {
+                if (Type != MediaStreamType.Audio || string.IsNullOrEmpty(Profile))
+                {
+                    return AudioSpatialFormat.None;
+                }
+
+                return
+                    Profile.Contains("Dolby Atmos", StringComparison.OrdinalIgnoreCase) ? AudioSpatialFormat.DolbyAtmos :
+                    Profile.Contains("DTS:X", StringComparison.OrdinalIgnoreCase) ? AudioSpatialFormat.DTSX :
+                    AudioSpatialFormat.None;
+            }
+        }
+
         public string LocalizedUndefined { get; set; }
 
         public string LocalizedDefault { get; set; }

+ 9 - 1
tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs

@@ -46,7 +46,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
             var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions);
             MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, VideoType.VideoFile, false, "Test Data/Probing/video_metadata.mkv", MediaProtocol.File);
 
-            Assert.Single(res.MediaStreams);
+            Assert.Equal(3, res.MediaStreams.Count);
 
             Assert.NotNull(res.VideoStream);
             Assert.Equal("4:3", res.VideoStream.AspectRatio);
@@ -83,6 +83,14 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
             Assert.Equal(1, res.VideoStream.BlPresentFlag);
             Assert.Equal(0, res.VideoStream.DvBlSignalCompatibilityId);
 
+            var audio1 = res.MediaStreams[1];
+            Assert.Equal("eac3", audio1.Codec);
+            Assert.Equal(AudioSpatialFormat.DolbyAtmos, audio1.AudioSpatialFormat);
+
+            var audio2 = res.MediaStreams[2];
+            Assert.Equal("dts", audio2.Codec);
+            Assert.Equal(AudioSpatialFormat.DTSX, audio2.AudioSpatialFormat);
+
             Assert.Empty(res.Chapters);
             Assert.Equal("Just color bars", res.Overview);
         }

+ 87 - 1
tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_metadata.json

@@ -61,6 +61,92 @@
                     "dv_bl_signal_compatibility_id": 0
                 }
             ]
+        },
+        {
+            "index": 1,
+            "codec_name": "eac3",
+            "codec_long_name": "ATSC A/52B (AC-3, E-AC-3)",
+            "profile": "Dolby Digital Plus + Dolby Atmos",
+            "codec_type": "audio",
+            "codec_tag_string": "[0][0][0][0]",
+            "codec_tag": "0x0000",
+            "sample_fmt": "fltp",
+            "sample_rate": "48000",
+            "channels": 6,
+            "channel_layout": "5.1(side)",
+            "bits_per_sample": 0,
+            "initial_padding": 0,
+            "r_frame_rate": "0/0",
+            "avg_frame_rate": "0/0",
+            "time_base": "1/1000",
+            "start_pts": 0,
+            "start_time": "0.000000",
+            "bit_rate": "640000",
+            "disposition": {
+                "default": 1,
+                "dub": 0,
+                "original": 1,
+                "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": "eng"
+            }
+        },
+        {
+            "index": 2,
+            "codec_name": "dts",
+            "codec_long_name": "DCA (DTS Coherent Acoustics)",
+            "profile": "DTS-HD MA + DTS:X",
+            "codec_type": "audio",
+            "codec_tag_string": "[0][0][0][0]",
+            "codec_tag": "0x0000",
+            "sample_fmt": "s32p",
+            "sample_rate": "48000",
+            "channels": 8,
+            "channel_layout": "7.1",
+            "bits_per_sample": 0,
+            "initial_padding": 0,
+            "r_frame_rate": "0/0",
+            "avg_frame_rate": "0/0",
+            "time_base": "1/1000",
+            "start_pts": 0,
+            "start_time": "0.000000",
+            "bits_per_raw_sample": "24",
+            "disposition": {
+                "default": 0,
+                "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": "eng"
+            }
         }
     ],
     "chapters": [
@@ -68,7 +154,7 @@
     ],
     "format": {
         "filename": "some_metadata.mkv",
-        "nb_streams": 1,
+        "nb_streams": 3,
         "nb_programs": 0,
         "format_name": "matroska,webm",
         "format_long_name": "Matroska / WebM",