From ddfdec7f46dd31d437dc6210658392fc7f894138 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Fri, 3 Feb 2023 20:03:55 +0100 Subject: Fix BD and DVD folder probing and playback --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index a844e6443..b3a1b2a99 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -535,6 +535,16 @@ namespace MediaBrowser.Controller.MediaEncoding { var mediaPath = state.MediaPath ?? string.Empty; + if (state.MediaSource.VideoType == VideoType.Dvd) + { + return _mediaEncoder.GetInputArgument(_mediaEncoder.GetPrimaryPlaylistVobFiles(state.MediaPath, null).ToList(), state.MediaSource); + } + + if (state.MediaSource.VideoType == VideoType.BluRay) + { + return _mediaEncoder.GetInputArgument(_mediaEncoder.GetPrimaryPlaylistM2TsFiles(state.MediaPath, null).ToList(), state.MediaSource); + } + return _mediaEncoder.GetInputArgument(mediaPath, state.MediaSource); } -- cgit v1.2.3 From edf3909157a5ef10436b7ebf5717b36a6bac9e7c Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sat, 4 Feb 2023 00:08:51 +0100 Subject: Use FFmpeg concat for DVD and BD folder playback --- Jellyfin.Api/Helpers/TranscodingJobHelper.cs | 5 +++ .../MediaEncoding/EncodingHelper.cs | 14 ++++++-- .../MediaEncoding/IMediaEncoder.cs | 7 ++++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 40 ++++++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index 29cb3d2f9..cb73ad765 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -323,6 +323,11 @@ public class TranscodingJobHelper : IDisposable if (delete(job.Path!)) { await DeletePartialStreamFiles(job.Path!, job.Type, 0, 1500).ConfigureAwait(false); + if (job.MediaSource?.VideoType == VideoType.Dvd || job.MediaSource?.VideoType == VideoType.BluRay) + { + var path = Path.GetDirectoryName(job.Path) + "/" + job.MediaSource.Id + ".concat"; + File.Delete(path); + } } if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId)) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index b3a1b2a99..7c4892ea5 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -941,8 +941,18 @@ namespace MediaBrowser.Controller.MediaEncoding arg.Append(canvasArgs); } - arg.Append(" -i ") - .Append(GetInputPathArgument(state)); + if (state.MediaSource.VideoType == VideoType.Dvd || state.MediaSource.VideoType == VideoType.BluRay) + { + var tmpConcatPath = options.TranscodingTempPath + "/" + state.MediaSource.Id + ".concat"; + _mediaEncoder.GenerateConcatConfig(state.MediaSource, tmpConcatPath); + arg.Append(" -f concat -safe 0 "); + arg.Append(" -i " + tmpConcatPath + " "); + } + else + { + arg.Append(" -i ") + .Append(GetInputPathArgument(state)); + } // sub2video for external graphical subtitles if (state.SubtitleStream is not null diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index c34ce5d29..716adc8f0 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -211,5 +211,12 @@ namespace MediaBrowser.Controller.MediaEncoding /// The title number to start with. /// A playlist. IEnumerable GetPrimaryPlaylistM2TsFiles(string path, uint? titleNumber); + + /// + /// Generates a FFmpeg concat config for the source. + /// + /// The . + /// The path the config should be written to. + void GenerateConcatConfig(MediaSourceInfo source, string concatFilePath); } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index df31ba83e..f4e6ea428 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -918,6 +918,46 @@ namespace MediaBrowser.MediaEncoding.Encoder .Select(f => f.FullName); } + public void GenerateConcatConfig(MediaSourceInfo source, string concatFilePath) + { + var files = new List(); + var videoType = source.VideoType; + if (videoType == VideoType.Dvd) + { + files = GetPrimaryPlaylistVobFiles(source.Path, null).ToList(); + } + else if (videoType == VideoType.BluRay) + { + files = GetPrimaryPlaylistM2TsFiles(source.Path, null).ToList(); + } + + var lines = new List(); + + foreach (var path in files) + { + var fileinfo = _fileSystem.GetFileInfo(path); + var mediaInfoResult = GetMediaInfo( + new MediaInfoRequest + { + MediaType = DlnaProfileType.Video, + MediaSource = new MediaSourceInfo + { + Path = path, + Protocol = MediaProtocol.File, + VideoType = videoType + } + }, + CancellationToken.None).GetAwaiter().GetResult(); + + var duration = TimeSpan.FromTicks(mediaInfoResult.RunTimeTicks.Value).TotalSeconds; + + lines.Add("file " + "'" + path + "'"); + lines.Add("duration " + duration); + } + + File.WriteAllLinesAsync(concatFilePath, lines, CancellationToken.None).GetAwaiter().GetResult(); + } + public bool CanExtractSubtitles(string codec) { // TODO is there ever a case when a subtitle can't be extracted?? -- cgit v1.2.3 From f2b7f664aa9b3ade38a2402faf95ba9b6989fc41 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sat, 4 Feb 2023 20:16:45 +0100 Subject: Apply review suggestions --- Jellyfin.Api/Helpers/TranscodingJobHelper.cs | 2 +- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 8 +++++--- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index cb73ad765..1ba739550 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -325,7 +325,7 @@ public class TranscodingJobHelper : IDisposable await DeletePartialStreamFiles(job.Path!, job.Type, 0, 1500).ConfigureAwait(false); if (job.MediaSource?.VideoType == VideoType.Dvd || job.MediaSource?.VideoType == VideoType.BluRay) { - var path = Path.GetDirectoryName(job.Path) + "/" + job.MediaSource.Id + ".concat"; + var path = Path.Join(job.Path, "/" + job.MediaSource.Id + ".concat"); File.Delete(path); } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 7c4892ea5..075e33cb8 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -943,10 +943,12 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.MediaSource.VideoType == VideoType.Dvd || state.MediaSource.VideoType == VideoType.BluRay) { - var tmpConcatPath = options.TranscodingTempPath + "/" + state.MediaSource.Id + ".concat"; + var tmpConcatPath = Path.Join(options.TranscodingTempPath, "/" + state.MediaSource.Id + ".concat"); _mediaEncoder.GenerateConcatConfig(state.MediaSource, tmpConcatPath); - arg.Append(" -f concat -safe 0 "); - arg.Append(" -i " + tmpConcatPath + " "); + arg.Append(" -f concat -safe 0 ") + .Append(" -i ") + .Append(tmpConcatPath) + .Append(' '); } else { diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 0bf89ec47..347e1de50 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -450,7 +450,7 @@ namespace MediaBrowser.MediaEncoding.Encoder prefix = "bluray"; } - return EncodingUtils.GetInputArgument(prefix, new List() { inputFile }, mediaSource.Protocol); + return EncodingUtils.GetInputArgument(prefix, new[] { inputFile }, mediaSource.Protocol); } /// @@ -458,7 +458,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { const string Prefix = "file"; - return EncodingUtils.GetInputArgument(Prefix, new List { inputFile }, MediaProtocol.File); + return EncodingUtils.GetInputArgument(Prefix, new[] { inputFile }, MediaProtocol.File); } /// -- cgit v1.2.3 From 2403a0a36792d060d913abbd86bec03816da750b Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sun, 5 Feb 2023 17:24:13 +0100 Subject: Apply review suggestions --- Jellyfin.Api/Helpers/TranscodingJobHelper.cs | 2 +- .../MediaEncoding/EncodingHelper.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 12 ++-- MediaBrowser.Model/Dlna/StreamBuilder.cs | 1 - .../MediaInfo/FFProbeVideoInfo.cs | 81 +++++++++++----------- 5 files changed, 48 insertions(+), 50 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index 1ba739550..3bb3ad358 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -325,7 +325,7 @@ public class TranscodingJobHelper : IDisposable await DeletePartialStreamFiles(job.Path!, job.Type, 0, 1500).ConfigureAwait(false); if (job.MediaSource?.VideoType == VideoType.Dvd || job.MediaSource?.VideoType == VideoType.BluRay) { - var path = Path.Join(job.Path, "/" + job.MediaSource.Id + ".concat"); + var path = Path.Join(job.Path, job.MediaSource.Id + ".concat"); File.Delete(path); } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 075e33cb8..3789bcac9 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -943,7 +943,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.MediaSource.VideoType == VideoType.Dvd || state.MediaSource.VideoType == VideoType.BluRay) { - var tmpConcatPath = Path.Join(options.TranscodingTempPath, "/" + state.MediaSource.Id + ".concat"); + var tmpConcatPath = Path.Join(options.TranscodingTempPath, state.MediaSource.Id + ".concat"); _mediaEncoder.GenerateConcatConfig(state.MediaSource, tmpConcatPath); arg.Append(" -f concat -safe 0 ") .Append(" -i ") diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 347e1de50..49c81923b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -11,6 +11,7 @@ using System.Text.Json; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Extensions; using Jellyfin.Extensions.Json; using Jellyfin.Extensions.Json.Converters; using MediaBrowser.Common; @@ -896,7 +897,7 @@ namespace MediaBrowser.MediaEncoding.Encoder // Check for multiple big titles (> 900 MB) var titles = allVobs .Where(vob => vob.Length >= 900 * 1024 * 1024) - .Select(vob => _fileSystem.GetFileNameWithoutExtension(vob).Split('_')[1]) + .Select(vob => _fileSystem.GetFileNameWithoutExtension(vob).AsSpan().RightPart('_').ToString()) .GroupBy(x => x) .Select(y => y.First()) .ToList(); @@ -904,12 +905,12 @@ namespace MediaBrowser.MediaEncoding.Encoder // Fall back to first title if no big title is found if (titles.FirstOrDefault() == null) { - titles.Add(_fileSystem.GetFileNameWithoutExtension(allVobs[0]).Split('_')[1]); + titles.Add(_fileSystem.GetFileNameWithoutExtension(allVobs[0]).AsSpan().RightPart('_').ToString()); } // Aggregate all VOBs of the titles return allVobs - .Where(vob => titles.Contains(_fileSystem.GetFileNameWithoutExtension(vob).Split('_')[1])) + .Where(vob => titles.Contains(_fileSystem.GetFileNameWithoutExtension(vob).AsSpan().RightPart('_').ToString())) .Select(i => i.FullName) .ToList(); } @@ -917,7 +918,7 @@ namespace MediaBrowser.MediaEncoding.Encoder public IEnumerable GetPrimaryPlaylistM2TsFiles(string path, uint? titleNumber) { var validPlaybackFiles = _blurayExaminer.GetDiscInfo(path).Files; - var directoryFiles = _fileSystem.GetFiles(path + "/BDMV/STREAM/"); + var directoryFiles = _fileSystem.GetFiles(Path.Join(path, "BDMV", "STREAM")); return directoryFiles .Where(f => validPlaybackFiles.Contains(f.Name, StringComparer.OrdinalIgnoreCase)) @@ -941,7 +942,6 @@ namespace MediaBrowser.MediaEncoding.Encoder foreach (var path in files) { - var fileinfo = _fileSystem.GetFileInfo(path); var mediaInfoResult = GetMediaInfo( new MediaInfoRequest { @@ -961,7 +961,7 @@ namespace MediaBrowser.MediaEncoding.Encoder lines.Add("duration " + duration); } - File.WriteAllLinesAsync(concatFilePath, lines, CancellationToken.None).GetAwaiter().GetResult(); + File.WriteAllLines(concatFilePath, lines); } public bool CanExtractSubtitles(string codec) diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index f6c930f5c..ef73096b4 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -639,7 +639,6 @@ namespace MediaBrowser.Model.Dlna if (item.VideoType == VideoType.Dvd || item.VideoType == VideoType.BluRay) { isEligibleForDirectPlay = false; - isEligibleForDirectStream = false; } if (bitrateLimitExceeded) diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 0ec7b368b..f75de47f3 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -328,54 +328,56 @@ namespace MediaBrowser.Providers.MediaInfo { var video = (Video)item; - // Use BD Info if it has multiple m2ts. Otherwise, treat it like a video file and rely more on ffprobe output - if (blurayInfo.Files.Length > 1) + if (blurayInfo.Files.Length <= 1) { - int? currentHeight = null; - int? currentWidth = null; - int? currentBitRate = null; + return; + } - var videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video); + // Use BD Info if it has multiple m2ts. Otherwise, treat it like a video file and rely more on ffprobe output + int? currentHeight = null; + int? currentWidth = null; + int? currentBitRate = null; - // Grab the values that ffprobe recorded - if (videoStream is not null) - { - currentBitRate = videoStream.BitRate; - currentWidth = videoStream.Width; - currentHeight = videoStream.Height; - } + var videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video); - // Fill video properties from the BDInfo result - mediaStreams.Clear(); - mediaStreams.AddRange(blurayInfo.MediaStreams); + // Grab the values that ffprobe recorded + if (videoStream is not null) + { + currentBitRate = videoStream.BitRate; + currentWidth = videoStream.Width; + currentHeight = videoStream.Height; + } - if (blurayInfo.RunTimeTicks.HasValue && blurayInfo.RunTimeTicks.Value > 0) - { - video.RunTimeTicks = blurayInfo.RunTimeTicks; - } + // Fill video properties from the BDInfo result + mediaStreams.Clear(); + mediaStreams.AddRange(blurayInfo.MediaStreams); - if (blurayInfo.Chapters is not null) + if (blurayInfo.RunTimeTicks.HasValue && blurayInfo.RunTimeTicks.Value > 0) + { + video.RunTimeTicks = blurayInfo.RunTimeTicks; + } + + if (blurayInfo.Chapters is not null) + { + double[] brChapter = blurayInfo.Chapters; + chapters = new ChapterInfo[brChapter.Length]; + for (int i = 0; i < brChapter.Length; i++) { - double[] brChapter = blurayInfo.Chapters; - chapters = new ChapterInfo[brChapter.Length]; - for (int i = 0; i < brChapter.Length; i++) + chapters[i] = new ChapterInfo { - chapters[i] = new ChapterInfo - { - StartPositionTicks = TimeSpan.FromSeconds(brChapter[i]).Ticks - }; - } + StartPositionTicks = TimeSpan.FromSeconds(brChapter[i]).Ticks + }; } + } - videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video); + videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video); - // Use the ffprobe values if these are empty - if (videoStream is not null) - { - videoStream.BitRate = IsEmpty(videoStream.BitRate) ? currentBitRate : videoStream.BitRate; - videoStream.Width = IsEmpty(videoStream.Width) ? currentWidth : videoStream.Width; - videoStream.Height = IsEmpty(videoStream.Height) ? currentHeight : videoStream.Height; - } + // Use the ffprobe values if these are empty + if (videoStream is not null) + { + videoStream.BitRate = IsEmpty(videoStream.BitRate) ? currentBitRate : videoStream.BitRate; + videoStream.Width = IsEmpty(videoStream.Width) ? currentWidth : videoStream.Width; + videoStream.Height = IsEmpty(videoStream.Height) ? currentHeight : videoStream.Height; } } @@ -391,10 +393,7 @@ namespace MediaBrowser.Providers.MediaInfo /// VideoStream. private BlurayDiscInfo GetBDInfo(string path) { - if (string.IsNullOrWhiteSpace(path)) - { - throw new ArgumentNullException(nameof(path)); - } + ArgumentException.ThrowIfNullOrEmpty(path); try { -- cgit v1.2.3 From cd852d43c16f0e038ba547053bd4c80794ba990c Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sun, 5 Feb 2023 22:59:58 +0100 Subject: Add more comments and logging, streamline code --- .../MediaEncoding/EncodingHelper.cs | 2 +- .../MediaEncoding/IMediaEncoder.cs | 3 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 21 +++++++++---- .../MediaInfo/FFProbeVideoInfo.cs | 35 +++++++++++++++------- 4 files changed, 42 insertions(+), 19 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 3789bcac9..2b39c74e2 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -542,7 +542,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.MediaSource.VideoType == VideoType.BluRay) { - return _mediaEncoder.GetInputArgument(_mediaEncoder.GetPrimaryPlaylistM2TsFiles(state.MediaPath, null).ToList(), state.MediaSource); + return _mediaEncoder.GetInputArgument(_mediaEncoder.GetPrimaryPlaylistM2tsFiles(state.MediaPath).ToList(), state.MediaSource); } return _mediaEncoder.GetInputArgument(mediaPath, state.MediaSource); diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 716adc8f0..83be267a7 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -208,9 +208,8 @@ namespace MediaBrowser.Controller.MediaEncoding /// Gets the primary playlist of .m2ts files. /// /// The to the .m2ts files. - /// The title number to start with. /// A playlist. - IEnumerable GetPrimaryPlaylistM2TsFiles(string path, uint? titleNumber); + IEnumerable GetPrimaryPlaylistM2tsFiles(string path); /// /// Generates a FFmpeg concat config for the source. diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 49c81923b..05ea7a86d 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -873,7 +873,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// public IEnumerable GetPrimaryPlaylistVobFiles(string path, uint? titleNumber) { - // Eliminate menus and intros by omitting VIDEO_TS.VOB and all subsequent title VOBs ending with _0.VOB + // Eliminate menus and intros by omitting VIDEO_TS.VOB and all subsequent title .vob files ending with _0.VOB var allVobs = _fileSystem.GetFiles(path, true) .Where(file => string.Equals(file.Extension, ".VOB", StringComparison.OrdinalIgnoreCase)) .Where(file => !string.Equals(file.Name, "VIDEO_TS.VOB", StringComparison.OrdinalIgnoreCase)) @@ -891,7 +891,7 @@ namespace MediaBrowser.MediaEncoding.Encoder return vobs.Select(i => i.FullName); } - _logger.LogWarning("Could not determine VOB file list for title {Title} of {Path}.", titleNumber, path); + _logger.LogWarning("Could not determine .vob files for title {Title} of {Path}.", titleNumber, path); } // Check for multiple big titles (> 900 MB) @@ -908,18 +908,22 @@ namespace MediaBrowser.MediaEncoding.Encoder titles.Add(_fileSystem.GetFileNameWithoutExtension(allVobs[0]).AsSpan().RightPart('_').ToString()); } - // Aggregate all VOBs of the titles + // Aggregate all .vob files of the titles return allVobs .Where(vob => titles.Contains(_fileSystem.GetFileNameWithoutExtension(vob).AsSpan().RightPart('_').ToString())) .Select(i => i.FullName) .ToList(); } - public IEnumerable GetPrimaryPlaylistM2TsFiles(string path, uint? titleNumber) + public IEnumerable GetPrimaryPlaylistM2tsFiles(string path) { + // Get all playable .m2ts files var validPlaybackFiles = _blurayExaminer.GetDiscInfo(path).Files; + + // Get all files from the BDMV/STREAMING directory var directoryFiles = _fileSystem.GetFiles(Path.Join(path, "BDMV", "STREAM")); + // Only return playable local .m2ts files return directoryFiles .Where(f => validPlaybackFiles.Contains(f.Name, StringComparer.OrdinalIgnoreCase)) .Select(f => f.FullName); @@ -927,6 +931,7 @@ namespace MediaBrowser.MediaEncoding.Encoder public void GenerateConcatConfig(MediaSourceInfo source, string concatFilePath) { + // Get all playable files var files = new List(); var videoType = source.VideoType; if (videoType == VideoType.Dvd) @@ -935,11 +940,11 @@ namespace MediaBrowser.MediaEncoding.Encoder } else if (videoType == VideoType.BluRay) { - files = GetPrimaryPlaylistM2TsFiles(source.Path, null).ToList(); + files = GetPrimaryPlaylistM2tsFiles(source.Path).ToList(); } + // Generate concat configuration entries for each file var lines = new List(); - foreach (var path in files) { var mediaInfoResult = GetMediaInfo( @@ -957,10 +962,14 @@ namespace MediaBrowser.MediaEncoding.Encoder var duration = TimeSpan.FromTicks(mediaInfoResult.RunTimeTicks.Value).TotalSeconds; + // Add file path stanza to concat configuration lines.Add("file " + "'" + path + "'"); + + // Add duration stanza to concat configuration lines.Add("duration " + duration); } + // Write concat configuration File.WriteAllLines(concatFilePath, lines); } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index f75de47f3..7200d674c 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -91,8 +91,17 @@ namespace MediaBrowser.Providers.MediaInfo { if (item.VideoType == VideoType.Dvd) { - // Fetch metadata of first VOB + // Get list of playable .vob files var vobs = _mediaEncoder.GetPrimaryPlaylistVobFiles(item.Path, null).ToList(); + + // Return if no playable .vob files are found + if (vobs.Count == 0) + { + _logger.LogError("No playable .vob files found in DVD structure, skipping FFprobe."); + return ItemUpdateType.MetadataImport; + } + + // Fetch metadata of first .vob file mediaInfoResult = await GetMediaInfo( new Video { @@ -100,10 +109,10 @@ namespace MediaBrowser.Providers.MediaInfo }, cancellationToken).ConfigureAwait(false); - // Remove first VOB + // Remove first .vob file vobs.RemoveAt(0); - // Add runtime from all other VOBs + // Sum up the runtime of all .vob files foreach (var vob in vobs) { var tmpMediaInfo = await GetMediaInfo( @@ -118,20 +127,26 @@ namespace MediaBrowser.Providers.MediaInfo } else if (item.VideoType == VideoType.BluRay) { + // Get BD disc information blurayDiscInfo = GetBDInfo(item.Path); - var m2ts = _mediaEncoder.GetPrimaryPlaylistM2TsFiles(item.Path, null).ToList(); + + // Get playable .m2ts files + var m2ts = _mediaEncoder.GetPrimaryPlaylistM2tsFiles(item.Path).ToList(); + + // Return if no playable .m2ts files are found + if (blurayDiscInfo.Files.Length == 0 || m2ts.Count == 0) + { + _logger.LogError("No playable .m2ts files found in Blu-ray structure, skipping FFprobe."); + return ItemUpdateType.MetadataImport; + } + + // Fetch metadata of first .m2ts file mediaInfoResult = await GetMediaInfo( new Video { Path = m2ts.First() }, cancellationToken).ConfigureAwait(false); - - if (blurayDiscInfo.Files.Length == 0) - { - _logger.LogError("No playable vobs found in bluray structure, skipping ffprobe."); - return ItemUpdateType.MetadataImport; - } } else { -- cgit v1.2.3 From 0da5255f1291ba510f829d36a3ca1a9eb65590dc Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sat, 18 Feb 2023 14:42:35 +0100 Subject: Apply review suggestions --- Jellyfin.Api/Helpers/TranscodingJobHelper.cs | 2 +- .../MediaEncoding/EncodingHelper.cs | 23 +- .../MediaEncoding/IMediaEncoder.cs | 4 +- .../BdInfo/BdInfoDirectoryInfo.cs | 160 +++++++----- .../BdInfo/BdInfoExaminer.cs | 283 ++++++++++----------- .../BdInfo/BdInfoFileInfo.cs | 81 ++++-- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 75 +++--- MediaBrowser.Model/Dlna/StreamInfo.cs | 7 +- MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs | 56 ++-- MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs | 21 +- .../MediaInfo/FFProbeVideoInfo.cs | 30 +-- 11 files changed, 395 insertions(+), 347 deletions(-) (limited to 'MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs') diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index ee210117e..73e8f34ad 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -329,7 +329,7 @@ public class TranscodingJobHelper : IDisposable if (File.Exists(concatFilePath)) { _logger.LogInformation("Deleting ffmpeg concat configuration at {Path}", concatFilePath); - _fileSystem.DeleteFile(concatFilePath); + File.Delete(concatFilePath); } } } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 2b39c74e2..a4e4648b1 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -533,19 +533,12 @@ namespace MediaBrowser.Controller.MediaEncoding public string GetInputPathArgument(EncodingJobInfo state) { - var mediaPath = state.MediaPath ?? string.Empty; - - if (state.MediaSource.VideoType == VideoType.Dvd) + return state.MediaSource.VideoType switch { - return _mediaEncoder.GetInputArgument(_mediaEncoder.GetPrimaryPlaylistVobFiles(state.MediaPath, null).ToList(), state.MediaSource); - } - - if (state.MediaSource.VideoType == VideoType.BluRay) - { - return _mediaEncoder.GetInputArgument(_mediaEncoder.GetPrimaryPlaylistM2tsFiles(state.MediaPath).ToList(), state.MediaSource); - } - - return _mediaEncoder.GetInputArgument(mediaPath, state.MediaSource); + VideoType.Dvd => _mediaEncoder.GetInputArgument(_mediaEncoder.GetPrimaryPlaylistVobFiles(state.MediaPath, null).ToList(), state.MediaSource), + VideoType.BluRay => _mediaEncoder.GetInputArgument(_mediaEncoder.GetPrimaryPlaylistM2tsFiles(state.MediaPath).ToList(), state.MediaSource), + _ => _mediaEncoder.GetInputArgument(state.MediaPath, state.MediaSource) + }; } /// @@ -945,10 +938,8 @@ namespace MediaBrowser.Controller.MediaEncoding { var tmpConcatPath = Path.Join(options.TranscodingTempPath, state.MediaSource.Id + ".concat"); _mediaEncoder.GenerateConcatConfig(state.MediaSource, tmpConcatPath); - arg.Append(" -f concat -safe 0 ") - .Append(" -i ") - .Append(tmpConcatPath) - .Append(' '); + arg.Append(" -f concat -safe 0 -i ") + .Append(tmpConcatPath); } else { diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 83be267a7..f830b9f29 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -202,14 +202,14 @@ namespace MediaBrowser.Controller.MediaEncoding /// The to the .vob files. /// The title number to start with. /// A playlist. - IEnumerable GetPrimaryPlaylistVobFiles(string path, uint? titleNumber); + IReadOnlyList GetPrimaryPlaylistVobFiles(string path, uint? titleNumber); /// /// Gets the primary playlist of .m2ts files. /// /// The to the .m2ts files. /// A playlist. - IEnumerable GetPrimaryPlaylistM2tsFiles(string path); + IReadOnlyList GetPrimaryPlaylistM2tsFiles(string path); /// /// Generates a FFmpeg concat config for the source. diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs index 7e026b42e..ea520b1d6 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs @@ -1,83 +1,123 @@ -#pragma warning disable CS1591 - using System; +using System.IO; using System.Linq; using BDInfo.IO; using MediaBrowser.Model.IO; -namespace MediaBrowser.MediaEncoding.BdInfo +namespace MediaBrowser.MediaEncoding.BdInfo; + +/// +/// Class BdInfoDirectoryInfo. +/// +public class BdInfoDirectoryInfo : IDirectoryInfo { - public class BdInfoDirectoryInfo : IDirectoryInfo - { - private readonly IFileSystem _fileSystem; + private readonly IFileSystem _fileSystem; - private readonly FileSystemMetadata _impl; + private readonly FileSystemMetadata _impl; - public BdInfoDirectoryInfo(IFileSystem fileSystem, string path) - { - _fileSystem = fileSystem; - _impl = _fileSystem.GetDirectoryInfo(path); - } + /// + /// Initializes a new instance of the class. + /// + /// The filesystem. + /// The path. + public BdInfoDirectoryInfo(IFileSystem fileSystem, string path) + { + _fileSystem = fileSystem; + _impl = _fileSystem.GetDirectoryInfo(path); + } - private BdInfoDirectoryInfo(IFileSystem fileSystem, FileSystemMetadata impl) - { - _fileSystem = fileSystem; - _impl = impl; - } + private BdInfoDirectoryInfo(IFileSystem fileSystem, FileSystemMetadata impl) + { + _fileSystem = fileSystem; + _impl = impl; + } - public string Name => _impl.Name; + /// + /// Gets the name. + /// + public string Name => _impl.Name; - public string FullName => _impl.FullName; + /// + /// Gets the full name. + /// + public string FullName => _impl.FullName; - public IDirectoryInfo? Parent + /// + /// Gets the parent directory information. + /// + public IDirectoryInfo? Parent + { + get { - get + var parentFolder = Path.GetDirectoryName(_impl.FullName); + if (parentFolder is not null) { - var parentFolder = System.IO.Path.GetDirectoryName(_impl.FullName); - if (parentFolder is not null) - { - return new BdInfoDirectoryInfo(_fileSystem, parentFolder); - } - - return null; + return new BdInfoDirectoryInfo(_fileSystem, parentFolder); } - } - public IDirectoryInfo[] GetDirectories() - { - return Array.ConvertAll( - _fileSystem.GetDirectories(_impl.FullName).ToArray(), - x => new BdInfoDirectoryInfo(_fileSystem, x)); + return null; } + } - public IFileInfo[] GetFiles() - { - return Array.ConvertAll( - _fileSystem.GetFiles(_impl.FullName).ToArray(), - x => new BdInfoFileInfo(x)); - } + /// + /// Gets the directories. + /// + /// An array with all directories. + public IDirectoryInfo[] GetDirectories() + { + return _fileSystem.GetDirectories(_impl.FullName) + .Select(x => new BdInfoDirectoryInfo(_fileSystem, x)) + .ToArray(); + } - public IFileInfo[] GetFiles(string searchPattern) - { - return Array.ConvertAll( - _fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, false).ToArray(), - x => new BdInfoFileInfo(x)); - } + /// + /// Gets the files. + /// + /// All files of the directory. + public IFileInfo[] GetFiles() + { + return _fileSystem.GetFiles(_impl.FullName) + .Select(x => new BdInfoFileInfo(x)) + .ToArray(); + } - public IFileInfo[] GetFiles(string searchPattern, System.IO.SearchOption searchOption) - { - return Array.ConvertAll( - _fileSystem.GetFiles( - _impl.FullName, - new[] { searchPattern }, - false, - (searchOption & System.IO.SearchOption.AllDirectories) == System.IO.SearchOption.AllDirectories).ToArray(), - x => new BdInfoFileInfo(x)); - } + /// + /// Gets the files matching a pattern. + /// + /// The search pattern. + /// All files of the directory matchign the search pattern. + public IFileInfo[] GetFiles(string searchPattern) + { + return _fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, false) + .Select(x => new BdInfoFileInfo(x)) + .ToArray(); + } - public static IDirectoryInfo FromFileSystemPath(IFileSystem fs, string path) - { - return new BdInfoDirectoryInfo(fs, path); - } + /// + /// Gets the files matching a pattern and search options. + /// + /// The search pattern. + /// The search optin. + /// All files of the directory matchign the search pattern and options. + public IFileInfo[] GetFiles(string searchPattern, SearchOption searchOption) + { + return _fileSystem.GetFiles( + _impl.FullName, + new[] { searchPattern }, + false, + (searchOption & SearchOption.AllDirectories) == SearchOption.AllDirectories) + .Select(x => new BdInfoFileInfo(x)) + .ToArray(); + } + + /// + /// Gets the bdinfo of a file system path. + /// + /// The file system. + /// The path. + /// The BD directory information of the path on the file system. + public static IDirectoryInfo FromFileSystemPath(IFileSystem fs, string path) + { + return new BdInfoDirectoryInfo(fs, path); } } diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs index 3e53cbf29..8ebb59c59 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs @@ -6,189 +6,182 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; -namespace MediaBrowser.MediaEncoding.BdInfo +namespace MediaBrowser.MediaEncoding.BdInfo; + +/// +/// Class BdInfoExaminer. +/// +public class BdInfoExaminer : IBlurayExaminer { + private readonly IFileSystem _fileSystem; + /// - /// Class BdInfoExaminer. + /// Initializes a new instance of the class. /// - public class BdInfoExaminer : IBlurayExaminer + /// The filesystem. + public BdInfoExaminer(IFileSystem fileSystem) { - private readonly IFileSystem _fileSystem; + _fileSystem = fileSystem; + } - /// - /// Initializes a new instance of the class. - /// - /// The filesystem. - public BdInfoExaminer(IFileSystem fileSystem) + /// + /// Gets the disc info. + /// + /// The path. + /// BlurayDiscInfo. + public BlurayDiscInfo GetDiscInfo(string path) + { + if (string.IsNullOrWhiteSpace(path)) { - _fileSystem = fileSystem; + throw new ArgumentNullException(nameof(path)); } - /// - /// Gets the disc info. - /// - /// The path. - /// BlurayDiscInfo. - public BlurayDiscInfo GetDiscInfo(string path) - { - if (string.IsNullOrWhiteSpace(path)) - { - throw new ArgumentNullException(nameof(path)); - } - - var bdrom = new BDROM(BdInfoDirectoryInfo.FromFileSystemPath(_fileSystem, path)); + var bdrom = new BDROM(BdInfoDirectoryInfo.FromFileSystemPath(_fileSystem, path)); - bdrom.Scan(); + bdrom.Scan(); - // Get the longest playlist - var playlist = bdrom.PlaylistFiles.Values.OrderByDescending(p => p.TotalLength).FirstOrDefault(p => p.IsValid); + // Get the longest playlist + var playlist = bdrom.PlaylistFiles.Values.OrderByDescending(p => p.TotalLength).FirstOrDefault(p => p.IsValid); - var outputStream = new BlurayDiscInfo - { - MediaStreams = Array.Empty() - }; + var outputStream = new BlurayDiscInfo + { + MediaStreams = Array.Empty() + }; - if (playlist is null) - { - return outputStream; - } + if (playlist is null) + { + return outputStream; + } - outputStream.Chapters = playlist.Chapters.ToArray(); + outputStream.Chapters = playlist.Chapters.ToArray(); - outputStream.RunTimeTicks = TimeSpan.FromSeconds(playlist.TotalLength).Ticks; + outputStream.RunTimeTicks = TimeSpan.FromSeconds(playlist.TotalLength).Ticks; - var mediaStreams = new List(); + var sortedStreams = playlist.SortedStreams; + var mediaStreams = new List(sortedStreams.Count); - foreach (var stream in playlist.SortedStreams) + foreach (var stream in sortedStreams) + { + switch (stream) { - if (stream is TSVideoStream videoStream) - { + case TSVideoStream videoStream: AddVideoStream(mediaStreams, videoStream); - continue; - } - - if (stream is TSAudioStream audioStream) - { + break; + case TSAudioStream audioStream: AddAudioStream(mediaStreams, audioStream); - continue; - } - - if (stream is TSTextStream textStream) - { + break; + case TSTextStream textStream: AddSubtitleStream(mediaStreams, textStream); - continue; - } - - if (stream is TSGraphicsStream graphicsStream) - { - AddSubtitleStream(mediaStreams, graphicsStream); - } + break; + case TSGraphicsStream graphicStream: + AddSubtitleStream(mediaStreams, graphicStream); + break; } + } - outputStream.MediaStreams = mediaStreams.ToArray(); - - outputStream.PlaylistName = playlist.Name; + outputStream.MediaStreams = mediaStreams.ToArray(); - if (playlist.StreamClips is not null && playlist.StreamClips.Any()) - { - // Get the files in the playlist - outputStream.Files = playlist.StreamClips.Select(i => i.StreamFile.Name).ToArray(); - } + outputStream.PlaylistName = playlist.Name; - return outputStream; + if (playlist.StreamClips is not null && playlist.StreamClips.Count > 0) + { + // Get the files in the playlist + outputStream.Files = playlist.StreamClips.Select(i => i.StreamFile.Name).ToArray(); } - /// - /// Adds the video stream. - /// - /// The streams. - /// The video stream. - private void AddVideoStream(List streams, TSVideoStream videoStream) - { - var mediaStream = new MediaStream - { - BitRate = Convert.ToInt32(videoStream.BitRate), - Width = videoStream.Width, - Height = videoStream.Height, - Codec = videoStream.CodecShortName, - IsInterlaced = videoStream.IsInterlaced, - Type = MediaStreamType.Video, - Index = streams.Count - }; - - if (videoStream.FrameRateDenominator > 0) - { - float frameRateEnumerator = videoStream.FrameRateEnumerator; - float frameRateDenominator = videoStream.FrameRateDenominator; + return outputStream; + } - mediaStream.AverageFrameRate = mediaStream.RealFrameRate = frameRateEnumerator / frameRateDenominator; - } + /// + /// Adds the video stream. + /// + /// The streams. + /// The video stream. + private void AddVideoStream(List streams, TSVideoStream videoStream) + { + var mediaStream = new MediaStream + { + BitRate = Convert.ToInt32(videoStream.BitRate), + Width = videoStream.Width, + Height = videoStream.Height, + Codec = videoStream.CodecShortName, + IsInterlaced = videoStream.IsInterlaced, + Type = MediaStreamType.Video, + Index = streams.Count + }; + + if (videoStream.FrameRateDenominator > 0) + { + float frameRateEnumerator = videoStream.FrameRateEnumerator; + float frameRateDenominator = videoStream.FrameRateDenominator; - streams.Add(mediaStream); + mediaStream.AverageFrameRate = mediaStream.RealFrameRate = frameRateEnumerator / frameRateDenominator; } - /// - /// Adds the audio stream. - /// - /// The streams. - /// The audio stream. - private void AddAudioStream(List streams, TSAudioStream audioStream) - { - var stream = new MediaStream - { - Codec = audioStream.CodecShortName, - Language = audioStream.LanguageCode, - Channels = audioStream.ChannelCount, - SampleRate = audioStream.SampleRate, - Type = MediaStreamType.Audio, - Index = streams.Count - }; - - var bitrate = Convert.ToInt32(audioStream.BitRate); + streams.Add(mediaStream); + } - if (bitrate > 0) - { - stream.BitRate = bitrate; - } + /// + /// Adds the audio stream. + /// + /// The streams. + /// The audio stream. + private void AddAudioStream(List streams, TSAudioStream audioStream) + { + var stream = new MediaStream + { + Codec = audioStream.CodecShortName, + Language = audioStream.LanguageCode, + Channels = audioStream.ChannelCount, + SampleRate = audioStream.SampleRate, + Type = MediaStreamType.Audio, + Index = streams.Count + }; - if (audioStream.LFE > 0) - { - stream.Channels = audioStream.ChannelCount + 1; - } + var bitrate = Convert.ToInt32(audioStream.BitRate); - streams.Add(stream); + if (bitrate > 0) + { + stream.BitRate = bitrate; } - /// - /// Adds the subtitle stream. - /// - /// The streams. - /// The text stream. - private void AddSubtitleStream(List streams, TSTextStream textStream) + if (audioStream.LFE > 0) { - streams.Add(new MediaStream - { - Language = textStream.LanguageCode, - Codec = textStream.CodecShortName, - Type = MediaStreamType.Subtitle, - Index = streams.Count - }); + stream.Channels = audioStream.ChannelCount + 1; } - /// - /// Adds the subtitle stream. - /// - /// The streams. - /// The text stream. - private void AddSubtitleStream(List streams, TSGraphicsStream textStream) + streams.Add(stream); + } + + /// + /// Adds the subtitle stream. + /// + /// The streams. + /// The text stream. + private void AddSubtitleStream(List streams, TSTextStream textStream) + { + streams.Add(new MediaStream + { + Language = textStream.LanguageCode, + Codec = textStream.CodecShortName, + Type = MediaStreamType.Subtitle, + Index = streams.Count + }); + } + + /// + /// Adds the subtitle stream. + /// + /// The streams. + /// The text stream. + private void AddSubtitleStream(List streams, TSGraphicsStream textStream) + { + streams.Add(new MediaStream { - streams.Add(new MediaStream - { - Language = textStream.LanguageCode, - Codec = textStream.CodecShortName, - Type = MediaStreamType.Subtitle, - Index = streams.Count - }); - } + Language = textStream.LanguageCode, + Codec = textStream.CodecShortName, + Type = MediaStreamType.Subtitle, + Index = streams.Count + }); } } diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs index d55688e3d..9e7a1d50a 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs @@ -1,41 +1,68 @@ -#pragma warning disable CS1591 - using System.IO; using MediaBrowser.Model.IO; -namespace MediaBrowser.MediaEncoding.BdInfo +namespace MediaBrowser.MediaEncoding.BdInfo; + +/// +/// Class BdInfoFileInfo. +/// +public class BdInfoFileInfo : BDInfo.IO.IFileInfo { - public class BdInfoFileInfo : BDInfo.IO.IFileInfo - { - private FileSystemMetadata _impl; + private FileSystemMetadata _impl; - public BdInfoFileInfo(FileSystemMetadata impl) - { - _impl = impl; - } + /// + /// Initializes a new instance of the class. + /// + /// The . + public BdInfoFileInfo(FileSystemMetadata impl) + { + _impl = impl; + } - public string Name => _impl.Name; + /// + /// Gets the name. + /// + public string Name => _impl.Name; - public string FullName => _impl.FullName; + /// + /// Gets the full name. + /// + public string FullName => _impl.FullName; - public string Extension => _impl.Extension; + /// + /// Gets the extension. + /// + public string Extension => _impl.Extension; - public long Length => _impl.Length; + /// + /// Gets the length. + /// + public long Length => _impl.Length; - public bool IsDir => _impl.IsDirectory; + /// + /// Gets a value indicating whether this is a directory. + /// + public bool IsDir => _impl.IsDirectory; - public Stream OpenRead() - { - return new FileStream( - FullName, - FileMode.Open, - FileAccess.Read, - FileShare.Read); - } + /// + /// Gets a file as file stream. + /// + /// A for the file. + public Stream OpenRead() + { + return new FileStream( + FullName, + FileMode.Open, + FileAccess.Read, + FileShare.Read); + } - public StreamReader OpenText() - { - return new StreamReader(OpenRead()); - } + /// + /// Gets a files's content with a stream reader. + /// + /// A for the file's content. + public StreamReader OpenText() + { + return new StreamReader(OpenRead()); } } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 05ea7a86d..d2112e5dc 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -871,7 +871,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } /// - public IEnumerable GetPrimaryPlaylistVobFiles(string path, uint? titleNumber) + public IReadOnlyList GetPrimaryPlaylistVobFiles(string path, uint? titleNumber) { // Eliminate menus and intros by omitting VIDEO_TS.VOB and all subsequent title .vob files ending with _0.VOB var allVobs = _fileSystem.GetFiles(path, true) @@ -888,7 +888,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (vobs.Count > 0) { - return vobs.Select(i => i.FullName); + return vobs.Select(i => i.FullName).ToList(); } _logger.LogWarning("Could not determine .vob files for title {Title} of {Path}.", titleNumber, path); @@ -898,12 +898,11 @@ namespace MediaBrowser.MediaEncoding.Encoder var titles = allVobs .Where(vob => vob.Length >= 900 * 1024 * 1024) .Select(vob => _fileSystem.GetFileNameWithoutExtension(vob).AsSpan().RightPart('_').ToString()) - .GroupBy(x => x) - .Select(y => y.First()) + .Distinct() .ToList(); // Fall back to first title if no big title is found - if (titles.FirstOrDefault() == null) + if (titles.Count == 0) { titles.Add(_fileSystem.GetFileNameWithoutExtension(allVobs[0]).AsSpan().RightPart('_').ToString()); } @@ -915,7 +914,8 @@ namespace MediaBrowser.MediaEncoding.Encoder .ToList(); } - public IEnumerable GetPrimaryPlaylistM2tsFiles(string path) + /// + public IReadOnlyList GetPrimaryPlaylistM2tsFiles(string path) { // Get all playable .m2ts files var validPlaybackFiles = _blurayExaminer.GetDiscInfo(path).Files; @@ -926,51 +926,56 @@ namespace MediaBrowser.MediaEncoding.Encoder // Only return playable local .m2ts files return directoryFiles .Where(f => validPlaybackFiles.Contains(f.Name, StringComparer.OrdinalIgnoreCase)) - .Select(f => f.FullName); + .Select(f => f.FullName) + .ToList(); } + /// public void GenerateConcatConfig(MediaSourceInfo source, string concatFilePath) { // Get all playable files - var files = new List(); + IReadOnlyList files; var videoType = source.VideoType; if (videoType == VideoType.Dvd) { - files = GetPrimaryPlaylistVobFiles(source.Path, null).ToList(); + files = GetPrimaryPlaylistVobFiles(source.Path, null); } else if (videoType == VideoType.BluRay) { - files = GetPrimaryPlaylistM2tsFiles(source.Path).ToList(); + files = GetPrimaryPlaylistM2tsFiles(source.Path); + } + else + { + return; } - // Generate concat configuration entries for each file - var lines = new List(); - foreach (var path in files) + // Generate concat configuration entries for each file and write to file + using (StreamWriter sw = new StreamWriter(concatFilePath)) { - var mediaInfoResult = GetMediaInfo( - new MediaInfoRequest - { - MediaType = DlnaProfileType.Video, - MediaSource = new MediaSourceInfo + foreach (var path in files) + { + var mediaInfoResult = GetMediaInfo( + new MediaInfoRequest { - Path = path, - Protocol = MediaProtocol.File, - VideoType = videoType - } - }, - CancellationToken.None).GetAwaiter().GetResult(); - - var duration = TimeSpan.FromTicks(mediaInfoResult.RunTimeTicks.Value).TotalSeconds; - - // Add file path stanza to concat configuration - lines.Add("file " + "'" + path + "'"); - - // Add duration stanza to concat configuration - lines.Add("duration " + duration); + MediaType = DlnaProfileType.Video, + MediaSource = new MediaSourceInfo + { + Path = path, + Protocol = MediaProtocol.File, + VideoType = videoType + } + }, + CancellationToken.None).GetAwaiter().GetResult(); + + var duration = TimeSpan.FromTicks(mediaInfoResult.RunTimeTicks.Value).TotalSeconds; + + // Add file path stanza to concat configuration + sw.WriteLine("file '{0}'", path); + + // Add duration stanza to concat configuration + sw.WriteLine("duration {0}", duration); + } } - - // Write concat configuration - File.WriteAllLines(concatFilePath, lines); } public bool CanExtractSubtitles(string codec) diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index fdf3afe97..0e814f036 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -107,11 +107,8 @@ namespace MediaBrowser.Model.Dlna public string MediaSourceId => MediaSource?.Id; - public bool IsDirectStream => - !(MediaSource?.VideoType == VideoType.Dvd - || MediaSource?.VideoType == VideoType.BluRay) - && (PlayMethod == PlayMethod.DirectStream - || PlayMethod == PlayMethod.DirectPlay); + public bool IsDirectStream => MediaSource?.VideoType is not (VideoType.Dvd or VideoType.BluRay) + && PlayMethod is PlayMethod.DirectStream or PlayMethod.DirectPlay; /// /// Gets the audio stream that will be used. diff --git a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs index 83f982a5c..d546ffccd 100644 --- a/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs +++ b/MediaBrowser.Model/MediaInfo/BlurayDiscInfo.cs @@ -1,39 +1,41 @@ #nullable disable -#pragma warning disable CS1591 using MediaBrowser.Model.Entities; -namespace MediaBrowser.Model.MediaInfo +namespace MediaBrowser.Model.MediaInfo; + +/// +/// Represents the result of BDInfo output. +/// +public class BlurayDiscInfo { /// - /// Represents the result of BDInfo output. + /// Gets or sets the media streams. /// - public class BlurayDiscInfo - { - /// - /// Gets or sets the media streams. - /// - /// The media streams. - public MediaStream[] MediaStreams { get; set; } + /// The media streams. + public MediaStream[] MediaStreams { get; set; } - /// - /// Gets or sets the run time ticks. - /// - /// The run time ticks. - public long? RunTimeTicks { get; set; } + /// + /// Gets or sets the run time ticks. + /// + /// The run time ticks. + public long? RunTimeTicks { get; set; } - /// - /// Gets or sets the files. - /// - /// The files. - public string[] Files { get; set; } + /// + /// Gets or sets the files. + /// + /// The files. + public string[] Files { get; set; } - public string PlaylistName { get; set; } + /// + /// Gets or sets the playlist name. + /// + /// The playlist name. + public string PlaylistName { get; set; } - /// - /// Gets or sets the chapters. - /// - /// The chapters. - public double[] Chapters { get; set; } - } + /// + /// Gets or sets the chapters. + /// + /// The chapters. + public double[] Chapters { get; set; } } diff --git a/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs b/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs index 5b7d1d03c..d39725301 100644 --- a/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs +++ b/MediaBrowser.Model/MediaInfo/IBlurayExaminer.cs @@ -1,15 +1,14 @@ -namespace MediaBrowser.Model.MediaInfo +namespace MediaBrowser.Model.MediaInfo; + +/// +/// Interface IBlurayExaminer. +/// +public interface IBlurayExaminer { /// - /// Interface IBlurayExaminer. + /// Gets the disc info. /// - public interface IBlurayExaminer - { - /// - /// Gets the disc info. - /// - /// The path. - /// BlurayDiscInfo. - BlurayDiscInfo GetDiscInfo(string path); - } + /// The path. + /// BlurayDiscInfo. + BlurayDiscInfo GetDiscInfo(string path); } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 7200d674c..e199db7f2 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -92,7 +92,7 @@ namespace MediaBrowser.Providers.MediaInfo if (item.VideoType == VideoType.Dvd) { // Get list of playable .vob files - var vobs = _mediaEncoder.GetPrimaryPlaylistVobFiles(item.Path, null).ToList(); + var vobs = _mediaEncoder.GetPrimaryPlaylistVobFiles(item.Path, null); // Return if no playable .vob files are found if (vobs.Count == 0) @@ -105,22 +105,19 @@ namespace MediaBrowser.Providers.MediaInfo mediaInfoResult = await GetMediaInfo( new Video { - Path = vobs.First() + Path = vobs[0] }, cancellationToken).ConfigureAwait(false); - // Remove first .vob file - vobs.RemoveAt(0); - - // Sum up the runtime of all .vob files - foreach (var vob in vobs) + // Sum up the runtime of all .vob files skipping the first .vob + for (var i = 1; i < vobs.Count; i++) { var tmpMediaInfo = await GetMediaInfo( - new Video - { - Path = vob - }, - cancellationToken).ConfigureAwait(false); + new Video + { + Path = vobs[i] + }, + cancellationToken).ConfigureAwait(false); mediaInfoResult.RunTimeTicks += tmpMediaInfo.RunTimeTicks; } @@ -131,7 +128,7 @@ namespace MediaBrowser.Providers.MediaInfo blurayDiscInfo = GetBDInfo(item.Path); // Get playable .m2ts files - var m2ts = _mediaEncoder.GetPrimaryPlaylistM2tsFiles(item.Path).ToList(); + var m2ts = _mediaEncoder.GetPrimaryPlaylistM2tsFiles(item.Path); // Return if no playable .m2ts files are found if (blurayDiscInfo.Files.Length == 0 || m2ts.Count == 0) @@ -144,14 +141,13 @@ namespace MediaBrowser.Providers.MediaInfo mediaInfoResult = await GetMediaInfo( new Video { - Path = m2ts.First() + Path = m2ts[0] }, cancellationToken).ConfigureAwait(false); } else { mediaInfoResult = await GetMediaInfo(item, cancellationToken).ConfigureAwait(false); - cancellationToken.ThrowIfCancellationRequested(); } cancellationToken.ThrowIfCancellationRequested(); @@ -339,10 +335,8 @@ namespace MediaBrowser.Providers.MediaInfo } } - private void FetchBdInfo(BaseItem item, ref ChapterInfo[] chapters, List mediaStreams, BlurayDiscInfo blurayInfo) + private void FetchBdInfo(Video video, ref ChapterInfo[] chapters, List mediaStreams, BlurayDiscInfo blurayInfo) { - var video = (Video)item; - if (blurayInfo.Files.Length <= 1) { return; -- cgit v1.2.3