From f49de51225b2206609df6a89f3cbb5fd7459ff68 Mon Sep 17 00:00:00 2001 From: Mohamed Akram Date: Sun, 7 Jan 2024 01:11:08 +0400 Subject: [PATCH] Detect audio spatial format (#9996) * Detect audio spatial format * Update MediaBrowser.Model/Entities/MediaStream.cs * Update MediaStream.cs --------- Co-authored-by: Cody Robibero --- CONTRIBUTORS.md | 1 + Jellyfin.Data/Enums/AudioSpatialFormat.cs | 22 +++++ MediaBrowser.Model/Entities/MediaStream.cs | 22 +++++ .../Probing/ProbeResultNormalizerTests.cs | 10 ++- .../Test Data/Probing/video_metadata.json | 88 ++++++++++++++++++- 5 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 Jellyfin.Data/Enums/AudioSpatialFormat.cs diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index d208879d17..4e45fd24ad 100644 --- a/CONTRIBUTORS.md +++ b/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) diff --git a/Jellyfin.Data/Enums/AudioSpatialFormat.cs b/Jellyfin.Data/Enums/AudioSpatialFormat.cs new file mode 100644 index 0000000000..5e3a123320 --- /dev/null +++ b/Jellyfin.Data/Enums/AudioSpatialFormat.cs @@ -0,0 +1,22 @@ +namespace Jellyfin.Data.Enums; + +/// +/// An enum representing formats of spatial audio. +/// +public enum AudioSpatialFormat +{ + /// + /// None audio spatial format. + /// + None, + + /// + /// Dolby Atmos audio spatial format. + /// + DolbyAtmos, + + /// + /// DTS:X audio spatial format. + /// + DTSX, +} diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 34642b83aa..ae4a008bb3 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/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 } } + /// + /// Gets the audio spatial format. + /// + /// The audio spatial format. + [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; } diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs index 198dc63efe..344ac8971c 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs @@ -46,7 +46,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing var internalMediaInfoResult = JsonSerializer.Deserialize(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); } diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_metadata.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_metadata.json index 519d81179c..a49c686900 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/video_metadata.json +++ b/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",