From 444060037932cc2f2c66a28004e97631b887fff9 Mon Sep 17 00:00:00 2001 From: Caidy Date: Tue, 2 Apr 2024 21:04:25 +0800 Subject: fix: rtsp live stream ffprobe timeout (#11279) --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 6c43315a87..8076780250 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -463,6 +463,11 @@ namespace MediaBrowser.MediaEncoding.Encoder extraArgs += " -user_agent " + userAgent; } + if (request.MediaSource.Protocol == MediaProtocol.Rtsp) + { + extraArgs += " -rtsp_transport tcp+udp -rtsp_flags prefer_tcp"; + } + return extraArgs; } -- cgit v1.2.3 From 6b6aab04ceadfd43a6bd0abb416b08006ff1ca6c Mon Sep 17 00:00:00 2001 From: gnattu Date: Mon, 8 Apr 2024 21:42:47 +0800 Subject: Fix apple audio codecs (#11315) --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 10 +++++++++- MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 250e0143f9..717b53a0b6 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -107,7 +107,6 @@ namespace MediaBrowser.Controller.MediaEncoding { "wmav2", 2 }, { "libmp3lame", 2 }, { "libfdk_aac", 6 }, - { "aac_at", 6 }, { "ac3", 6 }, { "eac3", 6 }, { "dca", 6 }, @@ -752,6 +751,15 @@ namespace MediaBrowser.Controller.MediaEncoding return "dca"; } + if (string.Equals(codec, "alac", StringComparison.OrdinalIgnoreCase)) + { + // The ffmpeg upstream breaks the AudioToolbox ALAC encoder in version 6.1 but fixes it in version 7.0. + // Since ALAC is lossless in quality and the AudioToolbox encoder is not faster, + // its only benefit is a smaller file size. + // To prevent problems, use the ffmpeg native encoder instead. + return "alac"; + } + return codec.ToLowerInvariant(); } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index ae0284e3ab..5f0779dc7b 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -69,6 +69,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "aac_at", "libfdk_aac", "ac3", + "alac", "dca", "libmp3lame", "libopus", -- cgit v1.2.3 From e9ae2d6a1e8eba531d9597a886cf3c202ae6bcd2 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 14 Apr 2024 23:19:38 +0200 Subject: Write JSON directly to logfile Can't be worse than serializing to a string, concatenating and converting to utf8, right? --- MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs index a07a0f41bc..ea5dbf7f7f 100644 --- a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs +++ b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs @@ -492,12 +492,11 @@ public sealed class TranscodeManager : ITranscodeManager, IDisposable IODefaults.FileStreamBufferSize, FileOptions.Asynchronous); - var commandLineLogMessage = process.StartInfo.FileName + " " + process.StartInfo.Arguments; + await JsonSerializer.SerializeAsync(logStream, state.MediaSource, cancellationToken: cancellationTokenSource.Token).ConfigureAwait(false); var commandLineLogMessageBytes = Encoding.UTF8.GetBytes( - JsonSerializer.Serialize(state.MediaSource) + Environment.NewLine + Environment.NewLine - + Environment.NewLine - + commandLineLogMessage + + process.StartInfo.FileName + " " + process.StartInfo.Arguments + Environment.NewLine + Environment.NewLine); -- cgit v1.2.3 From 658a454d81ae99e1e860dee9d0e89e617bc2e610 Mon Sep 17 00:00:00 2001 From: gnattu Date: Thu, 18 Apr 2024 00:44:04 +0800 Subject: fix: don't extract external sub (#11373) --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 4b1b1bbc61..21f4cb1cd6 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -463,7 +463,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { var subtitleStreams = mediaSource.MediaStreams - .Where(stream => stream.IsTextSubtitleStream && stream.SupportsExternalStream); + .Where(stream => stream is { IsTextSubtitleStream: true, SupportsExternalStream: true, IsExternal: false }); foreach (var subtitleStream in subtitleStreams) { -- cgit v1.2.3 From ac108690a84a2087811e50018a3f8fa52cbc914d Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 24 Apr 2024 16:35:15 +0200 Subject: Use StringSplitOptions.TrimEntries where possible (#11421) --- .../Probing/ProbeResultNormalizer.cs | 37 ++++++++-------------- .../Plugins/Omdb/OmdbProvider.cs | 5 --- src/Jellyfin.LiveTv/TunerHosts/M3uParser.cs | 4 +-- 3 files changed, 15 insertions(+), 31 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 5397a6752d..a587fa9db9 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -1342,9 +1342,8 @@ namespace MediaBrowser.MediaEncoding.Probing return null; } - return value.Split('/', StringSplitOptions.RemoveEmptyEntries) - .Select(i => i.Trim()) - .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i)); + return value.Split('/', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) + .FirstOrDefault(); } /// @@ -1353,17 +1352,13 @@ namespace MediaBrowser.MediaEncoding.Probing /// The val. /// if set to true [allow comma delimiter]. /// System.String[][]. - private IEnumerable Split(string val, bool allowCommaDelimiter) + private string[] Split(string val, bool allowCommaDelimiter) { // Only use the comma as a delimiter if there are no slashes or pipes. // We want to be careful not to split names that have commas in them - var delimiter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.Contains(i, StringComparison.Ordinal)) ? - _nameDelimiters : - new[] { ',' }; - - return val.Split(delimiter, StringSplitOptions.RemoveEmptyEntries) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(i => i.Trim()); + return !allowCommaDelimiter || _nameDelimiters.Any(i => val.Contains(i, StringComparison.Ordinal)) ? + val.Split(_nameDelimiters, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) : + val.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); } private IEnumerable SplitDistinctArtists(string val, char[] delimiters, bool splitFeaturing) @@ -1387,9 +1382,7 @@ namespace MediaBrowser.MediaEncoding.Probing } } - var artists = val.Split(delimiters, StringSplitOptions.RemoveEmptyEntries) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(i => i.Trim()); + var artists = val.Split(delimiters, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); artistsFound.AddRange(artists); return artistsFound.DistinctNames(); @@ -1514,15 +1507,12 @@ namespace MediaBrowser.MediaEncoding.Probing if (tags.TryGetValue("WM/Genre", out var genres) && !string.IsNullOrWhiteSpace(genres)) { - var genreList = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(i => i.Trim()) - .ToList(); + var genreList = genres.Split(new[] { ';', '/', ',' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); // If this is empty then don't overwrite genres that might have been fetched earlier - if (genreList.Count > 0) + if (genreList.Length > 0) { - video.Genres = genreList.ToArray(); + video.Genres = genreList; } } @@ -1533,10 +1523,9 @@ namespace MediaBrowser.MediaEncoding.Probing if (tags.TryGetValue("WM/MediaCredits", out var people) && !string.IsNullOrEmpty(people)) { - video.People = people.Split(new[] { ';', '/' }, StringSplitOptions.RemoveEmptyEntries) - .Where(i => !string.IsNullOrWhiteSpace(i)) - .Select(i => new BaseItemPerson { Name = i.Trim(), Type = PersonKind.Actor }) - .ToArray(); + video.People = Array.ConvertAll( + people.Split(new[] { ';', '/' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries), + i => new BaseItemPerson { Name = i, Type = PersonKind.Actor }); } if (tags.TryGetValue("WM/OriginalReleaseTime", out var year) && int.TryParse(year, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedYear)) diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 3fd4ae1fc0..c750caa1c9 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -447,11 +447,6 @@ namespace MediaBrowser.Providers.Plugins.Omdb var actorList = result.Actors.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); foreach (var actor in actorList) { - if (string.IsNullOrWhiteSpace(actor)) - { - continue; - } - var person = new PersonInfo { Name = actor, diff --git a/src/Jellyfin.LiveTv/TunerHosts/M3uParser.cs b/src/Jellyfin.LiveTv/TunerHosts/M3uParser.cs index 5900d1c5be..c8d678e2fc 100644 --- a/src/Jellyfin.LiveTv/TunerHosts/M3uParser.cs +++ b/src/Jellyfin.LiveTv/TunerHosts/M3uParser.cs @@ -273,12 +273,12 @@ namespace Jellyfin.LiveTv.TunerHosts var numberIndex = nameInExtInf.IndexOf(' ', StringComparison.Ordinal); if (numberIndex > 0) { - var numberPart = nameInExtInf.Substring(0, numberIndex).Trim(new[] { ' ', '.' }); + var numberPart = nameInExtInf.AsSpan(0, numberIndex).Trim(new[] { ' ', '.' }); if (double.TryParse(numberPart, CultureInfo.InvariantCulture, out _)) { // channel.Number = number.ToString(); - nameInExtInf = nameInExtInf.Substring(numberIndex + 1).Trim(new[] { ' ', '-' }); + nameInExtInf = nameInExtInf.AsSpan(numberIndex + 1).Trim(new[] { ' ', '-' }).ToString(); } } } -- cgit v1.2.3 From af74aa35d76435f5bd01aeec77f406376b3b8c28 Mon Sep 17 00:00:00 2001 From: Mark Cilia Vincenti Date: Mon, 6 May 2024 03:21:54 +0200 Subject: Clean up synchronization (#11458) --- .../Attachments/AttachmentExtractor.cs | 14 +++++--------- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 14 +++++--------- 2 files changed, 10 insertions(+), 18 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index a11440ced2..3b7745b6a1 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -247,7 +247,7 @@ namespace MediaBrowser.MediaEncoding.Attachments MediaSourceInfo mediaSource, CancellationToken cancellationToken) { - var outputFileLocks = new List>(); + var outputFileLocks = new List(); var extractableAttachmentIds = new List(); try @@ -256,16 +256,15 @@ namespace MediaBrowser.MediaEncoding.Attachments { var outputPath = GetAttachmentCachePath(mediaPath, mediaSource, attachment.Index); - var @outputFileLock = _semaphoreLocks.GetOrAdd(outputPath); - await @outputFileLock.SemaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false); + var releaser = await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false); if (File.Exists(outputPath)) { - @outputFileLock.Dispose(); + releaser.Dispose(); continue; } - outputFileLocks.Add(@outputFileLock); + outputFileLocks.Add(releaser); extractableAttachmentIds.Add(attachment.Index); } @@ -280,10 +279,7 @@ namespace MediaBrowser.MediaEncoding.Attachments } finally { - foreach (var @outputFileLock in outputFileLocks) - { - @outputFileLock.Dispose(); - } + outputFileLocks.ForEach(x => x.Dispose()); } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 21f4cb1cd6..16837d98bd 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -457,7 +457,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// Task. private async Task ExtractAllTextSubtitles(MediaSourceInfo mediaSource, CancellationToken cancellationToken) { - var locks = new List>(); + var locks = new List(); var extractableStreams = new List(); try @@ -469,16 +469,15 @@ namespace MediaBrowser.MediaEncoding.Subtitles { var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetTextSubtitleFormat(subtitleStream)); - var @lock = _semaphoreLocks.GetOrAdd(outputPath); - await @lock.SemaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false); + var releaser = await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false); if (File.Exists(outputPath)) { - @lock.Dispose(); + releaser.Dispose(); continue; } - locks.Add(@lock); + locks.Add(releaser); extractableStreams.Add(subtitleStream); } @@ -493,10 +492,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } finally { - foreach (var @lock in locks) - { - @lock.Dispose(); - } + locks.ForEach(x => x.Dispose()); } } -- cgit v1.2.3 From 40444316107bed26e073f43df2bcdc38873da6e8 Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 7 May 2024 21:23:28 +0800 Subject: Fix broken hardware encoder and filter for trickplay (#11506) --- MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs | 2 ++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 5f0779dc7b..ec39f159ed 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -82,6 +82,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "av1_amf", "h264_qsv", "hevc_qsv", + "mjpeg_qsv", "av1_qsv", "h264_nvenc", "hevc_nvenc", @@ -89,6 +90,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "h264_vaapi", "hevc_vaapi", "av1_vaapi", + "mjpeg_vaapi", "h264_v4l2m2m", "h264_videotoolbox", "hevc_videotoolbox", diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 8076780250..39431a9fc6 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -848,7 +848,7 @@ namespace MediaBrowser.MediaEncoding.Encoder inputArg = "-threads " + threads + " " + inputArg; // HW accel args set a different input thread count, only set if disabled } - var filterParam = encodingHelper.GetVideoProcessingFilterParam(jobState, options, jobState.OutputVideoCodec).Trim(); + var filterParam = encodingHelper.GetVideoProcessingFilterParam(jobState, options, vidEncoder).Trim(); if (string.IsNullOrWhiteSpace(filterParam)) { throw new InvalidOperationException("EncodingHelper returned empty or invalid filter parameters."); -- cgit v1.2.3 From 7336427ce661fd9c8bd78eeb23b750321d7387f6 Mon Sep 17 00:00:00 2001 From: gnattu Date: Fri, 17 May 2024 13:51:51 -0400 Subject: Backport pull request #11675 from jellyfin/release-10.9.z Fix quality parameter for vaapi_mjpeg Original-merge: ddd5c302b4fb7b07a5a46aa6d0026d9b37aa9b2c Merged-by: nielsvanvelzen Backported-by: Joshua M. Boniface --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 39431a9fc6..8ea0f58ea3 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -871,6 +871,15 @@ namespace MediaBrowser.MediaEncoding.Encoder throw new InvalidOperationException("Empty or invalid input argument."); } + float? encoderQuality = qualityScale; + if (vidEncoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase)) + { + // vaapi's mjpeg encoder uses jpeg quality divided by QP2LAMBDA (118) as input, instead of ffmpeg defined qscale + // ffmpeg qscale is a value from 1-31, with 1 being best quality and 31 being worst + // jpeg quality is a value from 0-100, with 0 being worst quality and 100 being best + encoderQuality = (100 - ((qualityScale - 1) * (100 / 30))) / 118; + } + // Output arguments var targetDirectory = Path.Combine(_configurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N")); Directory.CreateDirectory(targetDirectory); @@ -884,7 +893,7 @@ namespace MediaBrowser.MediaEncoding.Encoder filterParam, outputThreads.GetValueOrDefault(_threads), vidEncoder, - qualityScale.HasValue ? "-qscale:v " + qualityScale.Value.ToString(CultureInfo.InvariantCulture) + " " : string.Empty, + qualityScale.HasValue ? "-qscale:v " + encoderQuality.Value.ToString(CultureInfo.InvariantCulture) + " " : string.Empty, "image2", outputPath); -- cgit v1.2.3 From debd9eb8ce3ee2731ee71f508b4260f654b12d02 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sat, 25 May 2024 11:46:12 -0400 Subject: Backport pull request #11754 from jellyfin/release-10.9.z Fix BD/DVD folder chapter image extraction Original-merge: 52be8be28fa27c0c7b4f53dc32e00ec0543616a9 Merged-by: Bond-009 Backported-by: Joshua M. Boniface --- .../MediaEncoding/EncodingHelper.cs | 12 +----------- .../MediaEncoding/IMediaEncoder.cs | 15 +++++++++++++++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 19 ++++++++++++++++--- 3 files changed, 32 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index ed64156d69..5d5b645f6a 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -680,16 +680,6 @@ namespace MediaBrowser.Controller.MediaEncoding return -1; } - public string GetInputPathArgument(EncodingJobInfo state) - { - return state.MediaSource.VideoType switch - { - 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) - }; - } - /// /// Gets the audio encoder. /// @@ -1203,7 +1193,7 @@ namespace MediaBrowser.Controller.MediaEncoding else { arg.Append(" -i ") - .Append(GetInputPathArgument(state)); + .Append(_mediaEncoder.GetInputPathArgument(state)); } // sub2video for external graphical subtitles diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index e696fa52ce..26c353a54f 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -245,6 +245,21 @@ namespace MediaBrowser.Controller.MediaEncoding /// A playlist. IReadOnlyList GetPrimaryPlaylistM2tsFiles(string path); + /// + /// Gets the input path argument from . + /// + /// The . + /// The input path argument. + string GetInputPathArgument(EncodingJobInfo state); + + /// + /// Gets the input path argument. + /// + /// The item path. + /// The . + /// The input path argument. + string GetInputPathArgument(string path, MediaSourceInfo mediaSource); + /// /// Generates a FFmpeg concat config for the source. /// diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 8ea0f58ea3..1197fc84c9 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -30,10 +30,8 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; -using Microsoft.AspNetCore.Components.Forms; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using static Nikse.SubtitleEdit.Core.Common.IfoParser; namespace MediaBrowser.MediaEncoding.Encoder { @@ -621,7 +619,7 @@ namespace MediaBrowser.MediaEncoding.Encoder ImageFormat? targetFormat, CancellationToken cancellationToken) { - var inputArgument = GetInputArgument(inputFile, mediaSource); + var inputArgument = GetInputPathArgument(inputFile, mediaSource); if (!isAudio) { @@ -1147,6 +1145,21 @@ namespace MediaBrowser.MediaEncoding.Encoder .ToList(); } + /// + public string GetInputPathArgument(EncodingJobInfo state) + => GetInputPathArgument(state.MediaPath, state.MediaSource); + + /// + public string GetInputPathArgument(string path, MediaSourceInfo mediaSource) + { + return mediaSource.VideoType switch + { + VideoType.Dvd => GetInputArgument(GetPrimaryPlaylistVobFiles(path, null).ToList(), mediaSource), + VideoType.BluRay => GetInputArgument(GetPrimaryPlaylistM2tsFiles(path).ToList(), mediaSource), + _ => GetInputArgument(path, mediaSource) + }; + } + /// public void GenerateConcatConfig(MediaSourceInfo source, string concatFilePath) { -- cgit v1.2.3 From 5c828df5670aafa9e79786a8310ff103cc57e05d Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Sat, 25 May 2024 11:46:16 -0400 Subject: Backport pull request #11781 from jellyfin/release-10.9.z Retain order blu-ray segments Original-merge: 2ddf2a7866a9010191de1057f7c7bbbc3cb6e93d Merged-by: Bond-009 Backported-by: Joshua M. Boniface --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 1197fc84c9..b84baaa380 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -1135,13 +1135,11 @@ namespace MediaBrowser.MediaEncoding.Encoder 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)) + return validPlaybackFiles + .Select(f => _fileSystem.GetFileInfo(Path.Join(path, "BDMV", "STREAM", f))) + .Where(f => f.Exists) .Select(f => f.FullName) - .Order() .ToList(); } -- cgit v1.2.3 From 833a1da355f7e1d4c734df94d1e286015403427b Mon Sep 17 00:00:00 2001 From: NotSaifA <69015839+NotSaifA@users.noreply.github.com> Date: Sat, 25 May 2024 11:46:19 -0400 Subject: Backport pull request #11790 from jellyfin/release-10.9.z Trickplay: kill ffmpeg when task is cancelled Original-merge: 4a344bebc08303edf888000bf52e64b1a4e8036f Merged-by: crobibero Backported-by: Joshua M. Boniface --- CONTRIBUTORS.md | 1 + MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 47c06998c0..76d57a4783 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -183,6 +183,7 @@ - [btopherjohnson](https://github.com/btopherjohnson) - [GeorgeH005](https://github.com/GeorgeH005) - [Vedant](https://github.com/viktory36/) + - [NotSaifA](https://github.com/NotSaifA) # Emby Contributors diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index b84baaa380..79abb13ac1 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -943,7 +943,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var timeoutMs = _configurationManager.Configuration.ImageExtractionTimeoutMs; timeoutMs = timeoutMs <= 0 ? DefaultHdrImageExtractionTimeout : timeoutMs; - while (isResponsive) + while (isResponsive && !cancellationToken.IsCancellationRequested) { try { @@ -957,8 +957,6 @@ namespace MediaBrowser.MediaEncoding.Encoder // We don't actually expect the process to be finished in one timeout span, just that one image has been generated. } - cancellationToken.ThrowIfCancellationRequested(); - var jpegCount = _fileSystem.GetFilePaths(targetDirectory).Count(); isResponsive = jpegCount > lastCount; @@ -967,7 +965,12 @@ namespace MediaBrowser.MediaEncoding.Encoder if (!ranToCompletion) { - _logger.LogInformation("Stopping trickplay extraction due to process inactivity."); + if (!isResponsive) + { + _logger.LogInformation("Trickplay process unresponsive."); + } + + _logger.LogInformation("Stopping trickplay extraction."); StopProcess(processWrapper, 1000); } } -- cgit v1.2.3 From ac0064110b78b5d2cc7d7bfffb1b18c6193cfaeb Mon Sep 17 00:00:00 2001 From: gnattu Date: Sat, 25 May 2024 11:46:22 -0400 Subject: Backport pull request #11798 from jellyfin/release-10.9.z Recalculate trickplay image height for anamorphic videos Original-merge: d9232e05f1280f8f4315ca5b8fc92ddc4a71a96a Merged-by: Bond-009 Backported-by: Joshua M. Boniface --- .../MediaEncoding/EncodingHelper.cs | 27 ++++++++++++++-------- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 16 +++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index bef2944291..90d448c58d 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -3162,7 +3162,9 @@ namespace MediaBrowser.Controller.MediaEncoding int? requestedMaxHeight) { var isV4l2 = string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase); + var isMjpeg = videoEncoder is not null && videoEncoder.Contains("mjpeg", StringComparison.OrdinalIgnoreCase); var scaleVal = isV4l2 ? 64 : 2; + var targetAr = isMjpeg ? "(a*sar)" : "a"; // manually calculate AR when using mjpeg encoder // If fixed dimensions were supplied if (requestedWidth.HasValue && requestedHeight.HasValue) @@ -3191,10 +3193,11 @@ namespace MediaBrowser.Controller.MediaEncoding return string.Format( CultureInfo.InvariantCulture, - @"scale=trunc(min(max(iw\,ih*a)\,min({0}\,{1}*a))/{2})*{2}:trunc(min(max(iw/a\,ih)\,min({0}/a\,{1}))/2)*2", + @"scale=trunc(min(max(iw\,ih*{3})\,min({0}\,{1}*{3}))/{2})*{2}:trunc(min(max(iw/{3}\,ih)\,min({0}/{3}\,{1}))/2)*2", maxWidthParam, maxHeightParam, - scaleVal); + scaleVal, + targetAr); } // If a fixed width was requested @@ -3210,8 +3213,9 @@ namespace MediaBrowser.Controller.MediaEncoding return string.Format( CultureInfo.InvariantCulture, - "scale={0}:trunc(ow/a/2)*2", - widthParam); + "scale={0}:trunc(ow/{1}/2)*2", + widthParam, + targetAr); } // If a fixed height was requested @@ -3221,9 +3225,10 @@ namespace MediaBrowser.Controller.MediaEncoding return string.Format( CultureInfo.InvariantCulture, - "scale=trunc(oh*a/{1})*{1}:{0}", + "scale=trunc(oh*{2}/{1})*{1}:{0}", heightParam, - scaleVal); + scaleVal, + targetAr); } // If a max width was requested @@ -3233,9 +3238,10 @@ namespace MediaBrowser.Controller.MediaEncoding return string.Format( CultureInfo.InvariantCulture, - @"scale=trunc(min(max(iw\,ih*a)\,{0})/{1})*{1}:trunc(ow/a/2)*2", + @"scale=trunc(min(max(iw\,ih*{2})\,{0})/{1})*{1}:trunc(ow/{2}/2)*2", maxWidthParam, - scaleVal); + scaleVal, + targetAr); } // If a max height was requested @@ -3245,9 +3251,10 @@ namespace MediaBrowser.Controller.MediaEncoding return string.Format( CultureInfo.InvariantCulture, - @"scale=trunc(oh*a/{1})*{1}:min(max(iw/a\,ih)\,{0})", + @"scale=trunc(oh*{2}/{1})*{1}:min(max(iw/{2}\,ih)\,{0})", maxHeightParam, - scaleVal); + scaleVal, + targetAr); } return string.Empty; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 79abb13ac1..80ef6ecf77 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -822,6 +822,22 @@ namespace MediaBrowser.MediaEncoding.Encoder options.EnableTonemapping = false; } + if (imageStream.Width is not null && imageStream.Height is not null && !string.IsNullOrEmpty(imageStream.AspectRatio)) + { + // For hardware trickplay encoders, we need to re-calculate the size because they used fixed scale dimensions + var darParts = imageStream.AspectRatio.Split(':'); + var (wa, ha) = (double.Parse(darParts[0], CultureInfo.InvariantCulture), double.Parse(darParts[1], CultureInfo.InvariantCulture)); + // When dimension / DAR does not equal to 1:1, then the frames are most likely stored stretched. + // Note: this might be incorrect for 3D videos as the SAR stored might be per eye instead of per video, but we really can do little about it. + var shouldResetHeight = Math.Abs((imageStream.Width.Value * ha) - (imageStream.Height.Value * wa)) > .05; + if (shouldResetHeight) + { + // SAR = DAR * Height / Width + // RealHeight = Height / SAR = Height / (DAR * Height / Width) = Width / DAR + imageStream.Height = Convert.ToInt32(imageStream.Width.Value * ha / wa); + } + } + var baseRequest = new BaseEncodingJobOptions { MaxWidth = maxWidth, MaxFramerate = (float)(1.0 / interval.TotalSeconds) }; var jobState = new EncodingJobInfo(TranscodingJobType.Progressive) { -- cgit v1.2.3 From c4b7c91f3a4f4219f88166f87d84f045231a6271 Mon Sep 17 00:00:00 2001 From: gnattu Date: Sat, 1 Jun 2024 18:41:00 -0400 Subject: Backport pull request #11812 from jellyfin/release-10.9.z Extract media attachment one by one if the filename appears to be a path Original-merge: 45e8872cc086fe2b086e209a08839b3ff689ecf3 Merged-by: crobibero Backported-by: Joshua M. Boniface --- .../Attachments/AttachmentExtractor.cs | 27 ++++++++++++++++------ 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 3b7745b6a1..9149905586 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -89,15 +89,28 @@ namespace MediaBrowser.MediaEncoding.Attachments string outputPath, CancellationToken cancellationToken) { - using (await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false)) + var shouldExtractOneByOne = mediaSource.MediaAttachments.Any(a => a.FileName.Contains('/', StringComparison.OrdinalIgnoreCase) || a.FileName.Contains('\\', StringComparison.OrdinalIgnoreCase)); + if (shouldExtractOneByOne) { - if (!Directory.Exists(outputPath)) + var attachmentIndexes = mediaSource.MediaAttachments.Select(a => a.Index); + foreach (var i in attachmentIndexes) { - await ExtractAllAttachmentsInternal( - _mediaEncoder.GetInputArgument(inputFile, mediaSource), - outputPath, - false, - cancellationToken).ConfigureAwait(false); + var newName = Path.Join(outputPath, i.ToString(CultureInfo.InvariantCulture)); + await ExtractAttachment(inputFile, mediaSource, i, newName, cancellationToken).ConfigureAwait(false); + } + } + else + { + using (await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false)) + { + if (!Directory.Exists(outputPath)) + { + await ExtractAllAttachmentsInternal( + _mediaEncoder.GetInputArgument(inputFile, mediaSource), + outputPath, + false, + cancellationToken).ConfigureAwait(false); + } } } } -- cgit v1.2.3 From 8424ff5b61e6275025398c36edc9608a2acd89ba Mon Sep 17 00:00:00 2001 From: gnattu Date: Sat, 1 Jun 2024 18:41:05 -0400 Subject: Backport pull request #11857 from jellyfin/release-10.9.z Fix ffprobe -user_agent parameter Original-merge: d0336cd67edb3c70b9a0ec03a5ef1f991e3c9b84 Merged-by: Bond-009 Backported-by: Joshua M. Boniface --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 4 ++-- .../Jellyfin.MediaEncoding.Tests/Probing/ProbeExternalSourcesTests.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 80ef6ecf77..f85510dac7 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -456,9 +456,9 @@ namespace MediaBrowser.MediaEncoding.Encoder extraArgs += " -probesize " + ffmpegProbeSize; } - if (request.MediaSource.RequiredHttpHeaders.TryGetValue("user_agent", out var userAgent)) + if (request.MediaSource.RequiredHttpHeaders.TryGetValue("User-Agent", out var userAgent)) { - extraArgs += " -user_agent " + userAgent; + extraArgs += $" -user_agent \"{userAgent}\""; } if (request.MediaSource.Protocol == MediaProtocol.Rtsp) diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeExternalSourcesTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeExternalSourcesTests.cs index 263f74c900..84008cffdc 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeExternalSourcesTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeExternalSourcesTests.cs @@ -35,7 +35,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing Protocol = MediaProtocol.Http, RequiredHttpHeaders = new Dictionary() { - { "user_agent", userAgent }, + { "User-Agent", userAgent }, } }, ExtractChapters = false, @@ -44,7 +44,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing var extraArg = encoder.GetExtraArguments(req); - Assert.Contains(userAgent, extraArg, StringComparison.InvariantCulture); + Assert.Contains($"-user_agent \"{userAgent}\"", extraArg, StringComparison.InvariantCulture); } } } -- cgit v1.2.3 From b0f2135762c2249f58244568d0202be343f7a8dc Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Sun, 23 Jun 2024 11:40:44 -0400 Subject: Backport pull request #12031 from jellyfin/release-10.9.z Fix video embedded image detection Original-merge: 37b7e953f73532aad5e87dd62d8b6b63d8e52ed6 Merged-by: Bond-009 Backported-by: Joshua M. Boniface --- MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index a587fa9db9..f634d37c7e 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -779,11 +779,10 @@ namespace MediaBrowser.MediaEncoding.Probing && !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase); if (isAudio - && (string.Equals(stream.Codec, "bmp", StringComparison.OrdinalIgnoreCase) - || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) - || string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase) - || string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase) - || string.Equals(stream.Codec, "webp", StringComparison.OrdinalIgnoreCase))) + || string.Equals(stream.Codec, "bmp", StringComparison.OrdinalIgnoreCase) + || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) + || string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase) + || string.Equals(stream.Codec, "webp", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.EmbeddedImage; } -- cgit v1.2.3 From 91f5f0bfc4255c516f08bbedb6356a2f4634eb49 Mon Sep 17 00:00:00 2001 From: gnattu Date: Sun, 23 Jun 2024 11:40:50 -0400 Subject: Backport pull request #12046 from jellyfin/release-10.9.z Fix mpeg-ts detection Original-merge: 78eb9b2f78edcec869845bce1a96528985a66f12 Merged-by: Bond-009 Backported-by: Joshua M. Boniface --- MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index f634d37c7e..7d3f9327c2 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -280,8 +280,8 @@ namespace MediaBrowser.MediaEncoding.Probing splitFormat[i] = "mpeg"; } - // Handle MPEG-2 container - else if (string.Equals(splitFormat[i], "mpeg", StringComparison.OrdinalIgnoreCase)) + // Handle MPEG-TS container + else if (string.Equals(splitFormat[i], "mpegts", StringComparison.OrdinalIgnoreCase)) { splitFormat[i] = "ts"; } -- cgit v1.2.3 From 7d438a748fb9e37840c29c4761ee86c5b5b7cb09 Mon Sep 17 00:00:00 2001 From: Rivenlalala Date: Sun, 23 Jun 2024 11:40:51 -0400 Subject: Backport pull request #12065 from jellyfin/release-10.9.z Make m2ts extension case-insensitive Original-merge: f2a5ccf10206218e1084ee53aaa7284b7be3ddec Merged-by: Bond-009 Backported-by: Joshua M. Boniface --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index f85510dac7..d0d41c2d38 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -1155,10 +1155,10 @@ namespace MediaBrowser.MediaEncoding.Encoder // Get all files from the BDMV/STREAMING directory // Only return playable local .m2ts files + var files = _fileSystem.GetFiles(Path.Join(path, "BDMV", "STREAM")).ToList(); return validPlaybackFiles - .Select(f => _fileSystem.GetFileInfo(Path.Join(path, "BDMV", "STREAM", f))) - .Where(f => f.Exists) - .Select(f => f.FullName) + .Select(validFile => files.FirstOrDefault(f => Path.GetFileName(f.FullName.AsSpan()).Equals(validFile, StringComparison.OrdinalIgnoreCase))?.FullName) + .Where(f => f is not null) .ToList(); } -- cgit v1.2.3 From d37c5d8921488c4d3602f7ed84e2dc0ae694b06c Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Sun, 23 Jun 2024 11:40:59 -0400 Subject: Backport pull request #12149 from jellyfin/release-10.9.z Fix MicroDVD being recognized as DVDSUB subtitles Original-merge: 6010bc01c321ea85935314191f5f8c19fd4b3bfb Merged-by: crobibero Backported-by: Joshua M. Boniface --- MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 4 ++-- .../Probing/ProbeResultNormalizer.cs | 14 +++++++++----- MediaBrowser.Model/Entities/MediaStream.cs | 16 ++++++++-------- 3 files changed, 19 insertions(+), 15 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index a845c81244..9d7d2fd127 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1209,8 +1209,8 @@ namespace MediaBrowser.Controller.MediaEncoding var subtitlePath = state.SubtitleStream.Path; var subtitleExtension = Path.GetExtension(subtitlePath.AsSpan()); - if (subtitleExtension.Equals(".sub", StringComparison.OrdinalIgnoreCase) - || subtitleExtension.Equals(".sup", StringComparison.OrdinalIgnoreCase)) + // dvdsub/vobsub graphical subtitles use .sub+.idx pairs + if (subtitleExtension.Equals(".sub", StringComparison.OrdinalIgnoreCase)) { var idxFile = Path.ChangeExtension(subtitlePath, ".idx"); if (File.Exists(idxFile)) diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 7d3f9327c2..8b2685fe15 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -624,15 +624,19 @@ namespace MediaBrowser.MediaEncoding.Probing { if (string.Equals(codec, "dvb_subtitle", StringComparison.OrdinalIgnoreCase)) { - codec = "dvbsub"; + codec = "DVBSUB"; } - else if ((codec ?? string.Empty).Contains("PGS", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(codec, "dvb_teletext", StringComparison.OrdinalIgnoreCase)) { - codec = "PGSSUB"; + codec = "DVBTXT"; } - else if ((codec ?? string.Empty).Contains("DVD", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(codec, "dvd_subtitle", StringComparison.OrdinalIgnoreCase)) { - codec = "DVDSUB"; + codec = "DVDSUB"; // .sub+.idx + } + else if (string.Equals(codec, "hdmv_pgs_subtitle", StringComparison.OrdinalIgnoreCase)) + { + codec = "PGSSUB"; // .sup } return codec; diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 3e01c6efc2..e1082adead 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -656,14 +656,14 @@ namespace MediaBrowser.Model.Entities { string codec = format ?? string.Empty; - // sub = external .sub file - - return !codec.Contains("pgs", StringComparison.OrdinalIgnoreCase) - && !codec.Contains("dvd", StringComparison.OrdinalIgnoreCase) - && !codec.Contains("dvbsub", StringComparison.OrdinalIgnoreCase) - && !string.Equals(codec, "sub", StringComparison.OrdinalIgnoreCase) - && !string.Equals(codec, "sup", StringComparison.OrdinalIgnoreCase) - && !string.Equals(codec, "dvb_subtitle", StringComparison.OrdinalIgnoreCase); + // microdvd and dvdsub/vobsub share the ".sub" file extension, but it's text-based. + + return codec.Contains("microdvd", StringComparison.OrdinalIgnoreCase) + || (!codec.Contains("pgs", StringComparison.OrdinalIgnoreCase) + && !codec.Contains("dvdsub", StringComparison.OrdinalIgnoreCase) + && !codec.Contains("dvbsub", StringComparison.OrdinalIgnoreCase) + && !string.Equals(codec, "sup", StringComparison.OrdinalIgnoreCase) + && !string.Equals(codec, "sub", StringComparison.OrdinalIgnoreCase)); } public bool SupportsSubtitleConversionTo(string toCodec) -- cgit v1.2.3 From 60c45d6273c4c3d55d0170ca75f2d8ec57f0c0b4 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Mon, 1 Jul 2024 00:21:06 +0200 Subject: Use complete paths in BD info This way we don't need to find the complete path later --- MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 17 +++-------------- MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs | 7 ++----- 3 files changed, 6 insertions(+), 20 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs index 8ebb59c59e..5bae4fbd5a 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs @@ -86,7 +86,7 @@ public class BdInfoExaminer : IBlurayExaminer 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(); + outputStream.Files = playlist.StreamClips.Select(i => i.StreamFile.FileInfo.FullName).ToArray(); } return outputStream; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index d0d41c2d38..0e0676b8bc 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -1149,18 +1149,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// public IReadOnlyList GetPrimaryPlaylistM2tsFiles(string path) - { - // Get all playable .m2ts files - var validPlaybackFiles = _blurayExaminer.GetDiscInfo(path).Files; - - // Get all files from the BDMV/STREAMING directory - // Only return playable local .m2ts files - var files = _fileSystem.GetFiles(Path.Join(path, "BDMV", "STREAM")).ToList(); - return validPlaybackFiles - .Select(validFile => files.FirstOrDefault(f => Path.GetFileName(f.FullName.AsSpan()).Equals(validFile, StringComparison.OrdinalIgnoreCase))?.FullName) - .Where(f => f is not null) - .ToList(); - } + => _blurayExaminer.GetDiscInfo(path).Files; /// public string GetInputPathArgument(EncodingJobInfo state) @@ -1171,8 +1160,8 @@ namespace MediaBrowser.MediaEncoding.Encoder { return mediaSource.VideoType switch { - VideoType.Dvd => GetInputArgument(GetPrimaryPlaylistVobFiles(path, null).ToList(), mediaSource), - VideoType.BluRay => GetInputArgument(GetPrimaryPlaylistM2tsFiles(path).ToList(), mediaSource), + VideoType.Dvd => GetInputArgument(GetPrimaryPlaylistVobFiles(path, null), mediaSource), + VideoType.BluRay => GetInputArgument(GetPrimaryPlaylistM2tsFiles(path), mediaSource), _ => GetInputArgument(path, mediaSource) }; } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 1d4e665703..246ba2733f 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -124,11 +124,8 @@ namespace MediaBrowser.Providers.MediaInfo // Get BD disc information blurayDiscInfo = GetBDInfo(item.Path); - // Get playable .m2ts files - var m2ts = _mediaEncoder.GetPrimaryPlaylistM2tsFiles(item.Path); - // Return if no playable .m2ts files are found - if (blurayDiscInfo is null || blurayDiscInfo.Files.Length == 0 || m2ts.Count == 0) + if (blurayDiscInfo is null || blurayDiscInfo.Files.Length == 0) { _logger.LogError("No playable .m2ts files found in Blu-ray structure, skipping FFprobe."); return ItemUpdateType.MetadataImport; @@ -138,7 +135,7 @@ namespace MediaBrowser.Providers.MediaInfo mediaInfoResult = await GetMediaInfo( new Video { - Path = m2ts[0] + Path = blurayDiscInfo.Files[0] }, cancellationToken).ConfigureAwait(false); } -- cgit v1.2.3 From 1f32f95b9c99199657055d230a951f9be56ef86a Mon Sep 17 00:00:00 2001 From: gnattu Date: Tue, 2 Jul 2024 12:26:31 +0800 Subject: Add tonemapx to filter list Signed-off-by: gnattu --- MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index ec39f159ed..30bb21dcb1 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -103,6 +103,7 @@ namespace MediaBrowser.MediaEncoding.Encoder // sw "alphasrc", "zscale", + "tonemapx", // qsv "scale_qsv", "vpp_qsv", -- cgit v1.2.3 From 518c166a3921fb7c398522680e56c849cbb77199 Mon Sep 17 00:00:00 2001 From: gnattu Date: Fri, 12 Jul 2024 23:15:41 +0800 Subject: Prefer tonemapx during HDR image extraction Signed-off-by: gnattu --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index d0d41c2d38..e02f2116aa 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -708,16 +708,22 @@ namespace MediaBrowser.MediaEncoding.Encoder filters.Add("thumbnail=n=" + (useLargerBatchSize ? "50" : "24")); } - // Use SW tonemap on HDR10/HLG video stream only when the zscale filter is available. + // Use SW tonemap on HDR10/HLG video stream only when the zscale or tonemapx filter is available. var enableHdrExtraction = false; - if ((string.Equals(videoStream?.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) + if (string.Equals(videoStream?.ColorTransfer, "smpte2084", StringComparison.OrdinalIgnoreCase) || string.Equals(videoStream?.ColorTransfer, "arib-std-b67", StringComparison.OrdinalIgnoreCase)) - && SupportsFilter("zscale")) { - enableHdrExtraction = true; - - filters.Add("zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0:peak=100,zscale=t=bt709:m=bt709,format=yuv420p"); + if (SupportsFilter("tonemapx")) + { + enableHdrExtraction = true; + filters.Add("tonemapx=tonemap=bt2390:desat=0:peak=100:t=bt709:m=bt709:p=bt709:format=yuv420p"); + } + else if (SupportsFilter("zscale")) + { + enableHdrExtraction = true; + filters.Add("zscale=t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0:peak=100,zscale=t=bt709:m=bt709,format=yuv420p"); + } } var vf = string.Join(',', filters); -- cgit v1.2.3 From c666f9d0501bbe0235315d2c2e668ec6f86eb345 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Mon, 15 Jul 2024 14:44:14 +0200 Subject: Use real temp dir instead of cache dir for temp files (#12226) --- Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs | 2 +- Emby.Server.Implementations/IO/ManagedFileSystem.cs | 2 +- .../Images/BaseDynamicImageProvider.cs | 1 + .../ScheduledTasks/Tasks/AudioNormalizationTask.cs | 12 +++++++----- .../Trickplay/TrickplayManager.cs | 2 +- Jellyfin.Server/Helpers/StartupHelpers.cs | 1 + MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs | 10 +++++++--- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 1 + MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs | 11 +---------- src/Jellyfin.Drawing.Skia/SkiaEncoder.cs | 2 +- 10 files changed, 22 insertions(+), 22 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs index 39524be1d4..dc845b2d7e 100644 --- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs +++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs @@ -104,6 +104,6 @@ namespace Emby.Server.Implementations.AppBase /// Gets the folder path to the temp directory within the cache folder. /// /// The temp directory. - public string TempDirectory => Path.Combine(CachePath, "temp"); + public string TempDirectory => Path.Join(Path.GetTempPath(), "jellyfin"); } } diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 250bec9ea9..28bb29df85 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -466,7 +466,7 @@ namespace Emby.Server.Implementations.IO File.Copy(file1, temp1, true); File.Copy(file2, file1, true); - File.Copy(temp1, file2, true); + File.Move(temp1, file2, true); } /// diff --git a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs index 0a3d740ccf..82db7c46b3 100644 --- a/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs +++ b/Emby.Server.Implementations/Images/BaseDynamicImageProvider.cs @@ -122,6 +122,7 @@ namespace Emby.Server.Implementations.Images } await ProviderManager.SaveImage(item, outputPath, mimeType, imageType, null, false, cancellationToken).ConfigureAwait(false); + File.Delete(outputPath); return ItemUpdateType.ImageUpdate; } diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs index df0fdcab81..301c049154 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/AudioNormalizationTask.cs @@ -29,7 +29,7 @@ public partial class AudioNormalizationTask : IScheduledTask private readonly IItemRepository _itemRepository; private readonly ILibraryManager _libraryManager; private readonly IMediaEncoder _mediaEncoder; - private readonly IConfigurationManager _configurationManager; + private readonly IApplicationPaths _applicationPaths; private readonly ILocalizationManager _localization; private readonly ILogger _logger; @@ -39,21 +39,21 @@ public partial class AudioNormalizationTask : IScheduledTask /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. - /// Instance of the interface. + /// Instance of the interface. /// Instance of the interface. /// Instance of the interface. public AudioNormalizationTask( IItemRepository itemRepository, ILibraryManager libraryManager, IMediaEncoder mediaEncoder, - IConfigurationManager configurationManager, + IApplicationPaths applicationPaths, ILocalizationManager localizationManager, ILogger logger) { _itemRepository = itemRepository; _libraryManager = libraryManager; _mediaEncoder = mediaEncoder; - _configurationManager = configurationManager; + _applicationPaths = applicationPaths; _localization = localizationManager; _logger = logger; } @@ -107,7 +107,9 @@ public partial class AudioNormalizationTask : IScheduledTask } _logger.LogInformation("Calculating LUFS for album: {Album} with id: {Id}", a.Name, a.Id); - var tempFile = Path.Join(_configurationManager.GetTranscodePath(), a.Id + ".concat"); + var tempDir = _applicationPaths.TempDirectory; + Directory.CreateDirectory(tempDir); + var tempFile = Path.Join(tempDir, a.Id + ".concat"); var inputLines = albumTracks.Select(x => string.Format(CultureInfo.InvariantCulture, "file '{0}'", x.Path.Replace("'", @"'\''", StringComparison.Ordinal))); await File.WriteAllLinesAsync(tempFile, inputLines, cancellationToken).ConfigureAwait(false); try diff --git a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs index efdfc745f0..c14be032e5 100644 --- a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs +++ b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs @@ -230,7 +230,7 @@ public class TrickplayManager : ITrickplayManager throw new ArgumentException("Can't create trickplay from 0 images."); } - var workDir = Path.Combine(_appPaths.TempDirectory, Guid.NewGuid().ToString("N")); + var workDir = Path.Combine(_appPaths.TempDirectory, "trickplay_" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(workDir); var trickplayInfo = new TrickplayInfo diff --git a/Jellyfin.Server/Helpers/StartupHelpers.cs b/Jellyfin.Server/Helpers/StartupHelpers.cs index 5311a30e41..5518d6ba89 100644 --- a/Jellyfin.Server/Helpers/StartupHelpers.cs +++ b/Jellyfin.Server/Helpers/StartupHelpers.cs @@ -60,6 +60,7 @@ public static class StartupHelpers logger.LogInformation("Log directory path: {LogDirectoryPath}", appPaths.LogDirectoryPath); logger.LogInformation("Config directory path: {ConfigurationDirectoryPath}", appPaths.ConfigurationDirectoryPath); logger.LogInformation("Cache path: {CachePath}", appPaths.CachePath); + logger.LogInformation("Temp directory path: {TempDirPath}", appPaths.TempDirectory); logger.LogInformation("Web resources path: {WebPath}", appPaths.WebPath); logger.LogInformation("Application directory: {ApplicationPath}", appPaths.ProgramSystemPath); } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 0bb7100dea..b175dc4034 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -1203,10 +1203,14 @@ namespace MediaBrowser.Controller.MediaEncoding if (state.MediaSource.VideoType == VideoType.Dvd || state.MediaSource.VideoType == VideoType.BluRay) { - var tmpConcatPath = Path.Join(_configurationManager.GetTranscodePath(), state.MediaSource.Id + ".concat"); - _mediaEncoder.GenerateConcatConfig(state.MediaSource, tmpConcatPath); + var concatFilePath = Path.Join(_configurationManager.CommonApplicationPaths.CachePath, "concat", state.MediaSource.Id + ".concat"); + if (!File.Exists(concatFilePath)) + { + _mediaEncoder.GenerateConcatConfig(state.MediaSource, concatFilePath); + } + arg.Append(" -f concat -safe 0 -i \"") - .Append(tmpConcatPath) + .Append(concatFilePath) .Append("\" "); } else diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index e02f2116aa..a7b8812219 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -1203,6 +1203,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } // Generate concat configuration entries for each file and write to file + Directory.CreateDirectory(Path.GetDirectoryName(concatFilePath)); using StreamWriter sw = new StreamWriter(concatFilePath); foreach (var path in files) { diff --git a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs index ea5dbf7f7f..0b09e57b56 100644 --- a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs +++ b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs @@ -235,15 +235,6 @@ public sealed class TranscodeManager : ITranscodeManager, 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 concatFilePath = Path.Join(_serverConfigurationManager.GetTranscodePath(), job.MediaSource.Id + ".concat"); - if (File.Exists(concatFilePath)) - { - _logger.LogInformation("Deleting ffmpeg concat configuration at {Path}", concatFilePath); - File.Delete(concatFilePath); - } - } } if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId)) @@ -419,7 +410,7 @@ public sealed class TranscodeManager : ITranscodeManager, IDisposable var attachmentPath = Path.Combine(_appPaths.CachePath, "attachments", state.MediaSource.Id); if (state.MediaSource.VideoType == VideoType.Dvd || state.MediaSource.VideoType == VideoType.BluRay) { - var concatPath = Path.Join(_serverConfigurationManager.GetTranscodePath(), state.MediaSource.Id + ".concat"); + var concatPath = Path.Join(_appPaths.CachePath, "concat", state.MediaSource.Id + ".concat"); await _attachmentExtractor.ExtractAllAttachments(concatPath, state.MediaSource, attachmentPath, cancellationTokenSource.Token).ConfigureAwait(false); } else diff --git a/src/Jellyfin.Drawing.Skia/SkiaEncoder.cs b/src/Jellyfin.Drawing.Skia/SkiaEncoder.cs index 75963226a8..ede93aaa55 100644 --- a/src/Jellyfin.Drawing.Skia/SkiaEncoder.cs +++ b/src/Jellyfin.Drawing.Skia/SkiaEncoder.cs @@ -219,7 +219,7 @@ public class SkiaEncoder : IImageEncoder return path; } - var tempPath = Path.Combine(_appPaths.TempDirectory, string.Concat(Guid.NewGuid().ToString(), Path.GetExtension(path.AsSpan()))); + var tempPath = Path.Join(_appPaths.TempDirectory, string.Concat("skia_", Guid.NewGuid().ToString(), Path.GetExtension(path.AsSpan()))); var directory = Path.GetDirectoryName(tempPath) ?? throw new ResourceNotFoundException($"Provided path ({tempPath}) is not valid."); Directory.CreateDirectory(directory); File.Copy(path, tempPath, true); -- cgit v1.2.3 From fc1bee30a62e2e31682809c8245a117f7ecbddd5 Mon Sep 17 00:00:00 2001 From: David Schulte Date: Mon, 15 Jul 2024 14:48:09 +0200 Subject: Allow streaming of raw PGS subtitles without transcoding (#12056) --- .../Library/MediaSourceManager.cs | 5 ++ .../Subtitles/SubtitleEncoder.cs | 54 ++++++++++++++++------ MediaBrowser.Model/Entities/MediaStream.cs | 33 +++++++++++++ 3 files changed, 79 insertions(+), 13 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 5ec333cb16..bb22ca82fa 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -113,6 +113,11 @@ namespace Emby.Server.Implementations.Library return true; } + if (stream.IsPgsSubtitleStream) + { + return true; + } + return false; } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 16837d98bd..9ecbfa9cf5 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -198,10 +198,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles { if (!subtitleStream.IsExternal || subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) { - await ExtractAllTextSubtitles(mediaSource, cancellationToken).ConfigureAwait(false); + await ExtractAllExtractableSubtitles(mediaSource, cancellationToken).ConfigureAwait(false); - var outputFormat = GetTextSubtitleFormat(subtitleStream); - var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + outputFormat); + var outputFileExtension = GetExtractableSubtitleFileExtension(subtitleStream); + var outputFormat = GetExtractableSubtitleFormat(subtitleStream); + var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + outputFileExtension); return new SubtitleInfo() { @@ -215,6 +216,18 @@ namespace MediaBrowser.MediaEncoding.Subtitles var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec) .TrimStart('.'); + // Handle PGS subtitles as raw streams for the client to render + if (MediaStream.IsPgsFormat(currentFormat)) + { + return new SubtitleInfo() + { + Path = subtitleStream.Path, + Protocol = _mediaSourceManager.GetPathProtocol(subtitleStream.Path), + Format = "pgssub", + IsExternal = true + }; + } + // Fallback to ffmpeg conversion if (!_subtitleParser.SupportsFileExtension(currentFormat)) { @@ -428,10 +441,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger.LogInformation("ffmpeg subtitle conversion succeeded for {Path}", inputPath); } - private string GetTextSubtitleFormat(MediaStream subtitleStream) + private string GetExtractableSubtitleFormat(MediaStream subtitleStream) { if (string.Equals(subtitleStream.Codec, "ass", StringComparison.OrdinalIgnoreCase) - || string.Equals(subtitleStream.Codec, "ssa", StringComparison.OrdinalIgnoreCase)) + || string.Equals(subtitleStream.Codec, "ssa", StringComparison.OrdinalIgnoreCase) + || string.Equals(subtitleStream.Codec, "pgssub", StringComparison.OrdinalIgnoreCase)) { return subtitleStream.Codec; } @@ -441,21 +455,35 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } + private string GetExtractableSubtitleFileExtension(MediaStream subtitleStream) + { + // Using .pgssub as file extension is not allowed by ffmpeg. The file extension for pgs subtitles is .sup. + if (string.Equals(subtitleStream.Codec, "pgssub", StringComparison.OrdinalIgnoreCase)) + { + return "sup"; + } + else + { + return GetExtractableSubtitleFormat(subtitleStream); + } + } + private bool IsCodecCopyable(string codec) { return string.Equals(codec, "ass", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "ssa", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "srt", StringComparison.OrdinalIgnoreCase) - || string.Equals(codec, "subrip", StringComparison.OrdinalIgnoreCase); + || string.Equals(codec, "subrip", StringComparison.OrdinalIgnoreCase) + || string.Equals(codec, "pgssub", StringComparison.OrdinalIgnoreCase); } /// - /// Extracts all text subtitles. + /// Extracts all extractable subtitles (text and pgs). /// /// The mediaSource. /// The cancellation token. /// Task. - private async Task ExtractAllTextSubtitles(MediaSourceInfo mediaSource, CancellationToken cancellationToken) + private async Task ExtractAllExtractableSubtitles(MediaSourceInfo mediaSource, CancellationToken cancellationToken) { var locks = new List(); var extractableStreams = new List(); @@ -463,11 +491,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { var subtitleStreams = mediaSource.MediaStreams - .Where(stream => stream is { IsTextSubtitleStream: true, SupportsExternalStream: true, IsExternal: false }); + .Where(stream => stream is { IsExtractableSubtitleStream: true, SupportsExternalStream: true, IsExternal: false }); foreach (var subtitleStream in subtitleStreams) { - var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetTextSubtitleFormat(subtitleStream)); + var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetExtractableSubtitleFileExtension(subtitleStream)); var releaser = await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false); @@ -483,7 +511,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (extractableStreams.Count > 0) { - await ExtractAllTextSubtitlesInternal(mediaSource, extractableStreams, cancellationToken).ConfigureAwait(false); + await ExtractAllExtractableSubtitlesInternal(mediaSource, extractableStreams, cancellationToken).ConfigureAwait(false); } } catch (Exception ex) @@ -496,7 +524,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - private async Task ExtractAllTextSubtitlesInternal( + private async Task ExtractAllExtractableSubtitlesInternal( MediaSourceInfo mediaSource, List subtitleStreams, CancellationToken cancellationToken) @@ -510,7 +538,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles foreach (var subtitleStream in subtitleStreams) { - var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetTextSubtitleFormat(subtitleStream)); + var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetExtractableSubtitleFileExtension(subtitleStream)); var outputCodec = IsCodecCopyable(subtitleStream.Codec) ? "copy" : "srt"; var streamIndex = EncodingHelper.FindIndex(mediaSource.MediaStreams, subtitleStream); diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index e1082adead..9044c0524e 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -585,6 +585,31 @@ namespace MediaBrowser.Model.Entities } } + public bool IsPgsSubtitleStream + { + get + { + if (Type != MediaStreamType.Subtitle) + { + return false; + } + + if (string.IsNullOrEmpty(Codec) && !IsExternal) + { + return false; + } + + return IsPgsFormat(Codec); + } + } + + /// + /// Gets a value indicating whether this is a subtitle steam that is extractable by ffmpeg. + /// All text-based and pgs subtitles can be extracted. + /// + /// true if this is a extractable subtitle steam otherwise, false. + public bool IsExtractableSubtitleStream => IsTextSubtitleStream || IsPgsSubtitleStream; + /// /// Gets or sets a value indicating whether [supports external stream]. /// @@ -666,6 +691,14 @@ namespace MediaBrowser.Model.Entities && !string.Equals(codec, "sub", StringComparison.OrdinalIgnoreCase)); } + public static bool IsPgsFormat(string format) + { + string codec = format ?? string.Empty; + + return codec.Contains("pgs", StringComparison.OrdinalIgnoreCase) + || string.Equals(codec, "sup", StringComparison.OrdinalIgnoreCase); + } + public bool SupportsSubtitleConversionTo(string toCodec) { if (!IsTextSubtitleStream) -- cgit v1.2.3 From 19dc0872a9f468c8814d51fd5568d7d740c36fff Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 16 Jul 2024 18:23:21 +0200 Subject: Fix ArgumentNullException while scanning music ``` [2024-07-16 18:00:20.517 +02:00] [ERR] [65] MediaBrowser.Providers.Music.AudioMetadataService: Error in "Probe Provider" System.ArgumentNullException: Value cannot be null. (Parameter 'value') at System.ArgumentNullException.Throw(String paramName) at System.ArgumentNullException.ThrowIfNull(Object argument, String paramName) at System.ArgumentException.ThrowNullOrEmptyException(String argument, String paramName) at MediaBrowser.Model.Entities.ProviderIdsExtensions.SetProviderId(IHasProviderIds instance, String name, String value) in /home/loma/dev/jellyfin/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs:line 121 at MediaBrowser.Model.Entities.ProviderIdsExtensions.SetProviderId(IHasProviderIds instance, MetadataProvider provider, String value) in /home/loma/dev/jellyfin/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs:line 151 at MediaBrowser.MediaEncoding.Probing.ProbeResultNormalizer.SetAudioInfoFromTags(MediaInfo audio, Dictionary`2 tags) in /home/loma/dev/jellyfin/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs:line 1322 at MediaBrowser.MediaEncoding.Probing.ProbeResultNormalizer.GetMediaInfo(InternalMediaInfoResult data, Nullable`1 videoType, Boolean isAudio, String path, MediaProtocol protocol) in /home/loma/dev/jellyfin/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs:line 199 ``` --- .../Probing/ProbeResultNormalizer.cs | 25 +++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 8b2685fe15..f5185398cd 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -1319,23 +1319,38 @@ namespace MediaBrowser.MediaEncoding.Probing // These support multiple values, but for now we only store the first. var mb = GetMultipleMusicBrainzId(tags.GetValueOrDefault("MusicBrainz Album Artist Id")) ?? GetMultipleMusicBrainzId(tags.GetValueOrDefault("MUSICBRAINZ_ALBUMARTISTID")); - audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, mb); + if (!string.IsNullOrEmpty(mb)) + { + audio.SetProviderId(MetadataProvider.MusicBrainzAlbumArtist, mb); + } mb = GetMultipleMusicBrainzId(tags.GetValueOrDefault("MusicBrainz Artist Id")) ?? GetMultipleMusicBrainzId(tags.GetValueOrDefault("MUSICBRAINZ_ARTISTID")); - audio.SetProviderId(MetadataProvider.MusicBrainzArtist, mb); + if (!string.IsNullOrEmpty(mb)) + { + audio.SetProviderId(MetadataProvider.MusicBrainzArtist, mb); + } mb = GetMultipleMusicBrainzId(tags.GetValueOrDefault("MusicBrainz Album Id")) ?? GetMultipleMusicBrainzId(tags.GetValueOrDefault("MUSICBRAINZ_ALBUMID")); - audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, mb); + if (!string.IsNullOrEmpty(mb)) + { + audio.SetProviderId(MetadataProvider.MusicBrainzAlbum, mb); + } mb = GetMultipleMusicBrainzId(tags.GetValueOrDefault("MusicBrainz Release Group Id")) ?? GetMultipleMusicBrainzId(tags.GetValueOrDefault("MUSICBRAINZ_RELEASEGROUPID")); - audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, mb); + if (!string.IsNullOrEmpty(mb)) + { + audio.SetProviderId(MetadataProvider.MusicBrainzReleaseGroup, mb); + } mb = GetMultipleMusicBrainzId(tags.GetValueOrDefault("MusicBrainz Release Track Id")) ?? GetMultipleMusicBrainzId(tags.GetValueOrDefault("MUSICBRAINZ_RELEASETRACKID")); - audio.SetProviderId(MetadataProvider.MusicBrainzTrack, mb); + if (!string.IsNullOrEmpty(mb)) + { + audio.SetProviderId(MetadataProvider.MusicBrainzTrack, mb); + } } private string GetMultipleMusicBrainzId(string value) -- cgit v1.2.3 From 68bfabbaba2fc6f7b5b6cd63b388f4669a476713 Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 8 May 2024 13:50:03 +0800 Subject: Add option to extract keyframe only during trickplay image generation This would be significantly faster than decoding every frame, but it does have compatibility issues. Not all decoders support this mode, notably the VP9 decoder, CUVID decoders, and QSV decoders. Some videos with very long key-frame intervals may also perform poorly with this mode, as the image timing could become too inaccurate to reflect the actual frame. Signed-off-by: gnattu --- Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs | 1 + MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs | 2 ++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 6 ++++++ MediaBrowser.Model/Configuration/TrickplayOptions.cs | 6 ++++++ 4 files changed, 15 insertions(+) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs index efdfc745f0..69c402f63b 100644 --- a/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs +++ b/Jellyfin.Server.Implementations/Trickplay/TrickplayManager.cs @@ -168,6 +168,7 @@ public class TrickplayManager : ITrickplayManager options.ProcessThreads, options.Qscale, options.ProcessPriority, + options.EnableKeyFrameOnlyExtraction, _encodingHelper, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 26c353a54f..038c6c7f69 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -153,6 +153,7 @@ namespace MediaBrowser.Controller.MediaEncoding /// The input/output thread count for ffmpeg. /// The qscale value for ffmpeg. /// The process priority for the ffmpeg process. + /// Whether to only extract key frames. /// EncodingHelper instance. /// The cancellation token. /// Directory where images where extracted. A given image made before another will always be named with a lower number. @@ -168,6 +169,7 @@ namespace MediaBrowser.Controller.MediaEncoding int? threads, int? qualityScale, ProcessPriorityClass? priority, + bool enableKeyFrameOnlyExtraction, EncodingHelper encodingHelper, CancellationToken cancellationToken); diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index d0d41c2d38..db4e21705a 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -807,6 +807,7 @@ namespace MediaBrowser.MediaEncoding.Encoder int? threads, int? qualityScale, ProcessPriorityClass? priority, + bool enableKeyFrameOnlyExtraction, EncodingHelper encodingHelper, CancellationToken cancellationToken) { @@ -862,6 +863,11 @@ namespace MediaBrowser.MediaEncoding.Encoder inputArg = "-threads " + threads + " " + inputArg; // HW accel args set a different input thread count, only set if disabled } + if (enableKeyFrameOnlyExtraction) + { + inputArg = "-skip_frame nokey " + inputArg; + } + var filterParam = encodingHelper.GetVideoProcessingFilterParam(jobState, options, vidEncoder).Trim(); if (string.IsNullOrWhiteSpace(filterParam)) { diff --git a/MediaBrowser.Model/Configuration/TrickplayOptions.cs b/MediaBrowser.Model/Configuration/TrickplayOptions.cs index a151d3429b..578bb306a0 100644 --- a/MediaBrowser.Model/Configuration/TrickplayOptions.cs +++ b/MediaBrowser.Model/Configuration/TrickplayOptions.cs @@ -18,6 +18,12 @@ public class TrickplayOptions /// public bool EnableHwEncoding { get; set; } = false; + /// + /// Gets or sets a value indicating whether to only extract key frames. + /// Significantly faster, but is not compatible with all decoders and/or video files. + /// + public bool EnableKeyFrameOnlyExtraction { get; set; } = false; + /// /// Gets or sets the behavior used by trickplay provider on library scan/update. /// -- cgit v1.2.3 From 0340eccb523a33a7a777a3e06383df4900965895 Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 17 Jul 2024 00:35:59 +0800 Subject: Force software decoding when hardware decoder does not support keyframe only mode but requested by user Signed-off-by: gnattu --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index db4e21705a..f101bbb148 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -814,6 +814,22 @@ namespace MediaBrowser.MediaEncoding.Encoder var options = allowHwAccel ? _configurationManager.GetEncodingOptions() : new EncodingOptions(); threads ??= _threads; + if (enableKeyFrameOnlyExtraction) + { + var supportsKeyFrameOnly = !allowHwAccel + || (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && options.EnableEnhancedNvdecDecoder) + || (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && OperatingSystem.IsWindows() && options.PreferSystemNativeHwDecoder) + || (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && options.PreferSystemNativeHwDecoder) + || string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) + || string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase); + if (!supportsKeyFrameOnly) + { + // Disable hardware acceleration when the hardware decoder does not support keyframe only mode. + allowHwAccel = false; + options = new EncodingOptions(); + } + } + // A new EncodingOptions instance must be used as to not disable HW acceleration for all of Jellyfin. // Additionally, we must set a few fields without defaults to prevent null pointer exceptions. if (!allowHwAccel) -- cgit v1.2.3 From e4101128e011c089bad46a524856438154cfbd3d Mon Sep 17 00:00:00 2001 From: gnattu Date: Mon, 22 Apr 2024 06:19:17 +0800 Subject: feat: add audio remux to UniversalAudioController Signed-off-by: gnattu --- .../Controllers/UniversalAudioController.cs | 16 ++++-- Jellyfin.Api/Helpers/DynamicHlsHelper.cs | 8 +++ .../Transcoding/TranscodeManager.cs | 5 ++ MediaBrowser.Model/Dlna/StreamBuilder.cs | 63 +++++++++++++++++++++- 4 files changed, 86 insertions(+), 6 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs index 1d4adae067..3115c4750a 100644 --- a/Jellyfin.Api/Controllers/UniversalAudioController.cs +++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs @@ -17,6 +17,7 @@ using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Streaming; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Session; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -137,6 +138,8 @@ public class UniversalAudioController : BaseJellyfinApiController // set device specific data foreach (var sourceInfo in info.MediaSources) { + sourceInfo.TranscodingContainer = transcodingContainer; + sourceInfo.TranscodingSubProtocol = transcodingProtocol ?? sourceInfo.TranscodingSubProtocol; _mediaInfoHelper.SetDeviceSpecificData( item, sourceInfo, @@ -171,27 +174,30 @@ public class UniversalAudioController : BaseJellyfinApiController return Redirect(mediaSource.Path); } + // This one is currently very misleading as the SupportsDirectStream is always false + // The definition of DirectStream also seems changed during development + // It used to mean HTTP direct streaming, but now HLS is used even for DirectStream var isStatic = mediaSource.SupportsDirectStream; - if (!isStatic && mediaSource.TranscodingSubProtocol == MediaStreamProtocol.hls) + if (mediaSource.TranscodingSubProtocol == MediaStreamProtocol.hls) { // hls segment container can only be mpegts or fmp4 per ffmpeg documentation // ffmpeg option -> file extension // mpegts -> ts // fmp4 -> mp4 - // TODO: remove this when we switch back to the segment muxer var supportedHlsContainers = new[] { "ts", "mp4" }; + // fallback to mpegts if device reports some weird value unsupported by hls + var segmentContainer = Array.Exists(supportedHlsContainers, element => element == transcodingContainer) ? transcodingContainer : "ts"; var dynamicHlsRequestDto = new HlsAudioRequestDto { Id = itemId, Container = ".m3u8", Static = isStatic, PlaySessionId = info.PlaySessionId, - // fallback to mpegts if device reports some weird value unsupported by hls - SegmentContainer = Array.Exists(supportedHlsContainers, element => element == transcodingContainer) ? transcodingContainer : "ts", + SegmentContainer = segmentContainer, MediaSourceId = mediaSourceId, DeviceId = deviceId, - AudioCodec = audioCodec, + AudioCodec = mediaSource.TranscodeReasons == TranscodeReason.ContainerNotSupported ? "copy" : audioCodec, EnableAutoStreamCopy = true, AllowAudioStreamCopy = true, AllowVideoStreamCopy = true, diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs index f8d89119a4..8df4caea5a 100644 --- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs +++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs @@ -151,6 +151,14 @@ public class DynamicHlsHelper var queryString = _httpContextAccessor.HttpContext.Request.QueryString.ToString(); + // from universal audio service, need to override the AudioCodec when the actual request differs from original query + if (!string.Equals(state.OutputAudioCodec, _httpContextAccessor.HttpContext.Request.Query["AudioCodec"].ToString(), StringComparison.OrdinalIgnoreCase)) + { + var newQuery = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(_httpContextAccessor.HttpContext.Request.QueryString.ToString()); + newQuery["AudioCodec"] = state.OutputAudioCodec; + queryString = Microsoft.AspNetCore.WebUtilities.QueryHelpers.AddQueryString(string.Empty, newQuery); + } + // from universal audio service if (!string.IsNullOrWhiteSpace(state.Request.SegmentContainer) && !queryString.Contains("SegmentContainer", StringComparison.OrdinalIgnoreCase)) diff --git a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs index ea5dbf7f7f..e45e8507a1 100644 --- a/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs +++ b/MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs @@ -479,6 +479,11 @@ public sealed class TranscodeManager : ITranscodeManager, IDisposable : "FFmpeg.DirectStream-"; } + if (state.VideoRequest is null && EncodingHelper.IsCopyCodec(state.OutputAudioCodec)) + { + logFilePrefix = "FFmpeg.Remux-"; + } + var logFilePath = Path.Combine( _serverConfigurationManager.ApplicationPaths.LogDirectoryPath, $"{logFilePrefix}{DateTime.Now:yyyy-MM-dd_HH-mm-ss}_{state.Request.MediaSourceId}_{Guid.NewGuid().ToString()[..8]}.log"); diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index 55d1c3d51a..f9fe7d351a 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -108,7 +108,7 @@ namespace MediaBrowser.Model.Dlna var inputAudioSampleRate = audioStream?.SampleRate; var inputAudioBitDepth = audioStream?.BitDepth; - if (directPlayMethod.HasValue) + if (directPlayMethod is PlayMethod.DirectPlay) { var profile = options.Profile; var audioFailureConditions = GetProfileConditionsForAudio(profile.CodecProfiles, item.Container, audioStream?.Codec, inputAudioChannels, inputAudioBitrate, inputAudioSampleRate, inputAudioBitDepth, true); @@ -124,6 +124,41 @@ namespace MediaBrowser.Model.Dlna } } + if (directPlayMethod is PlayMethod.DirectStream) + { + var remuxContainer = item.TranscodingContainer ?? "ts"; + bool codeIsSupported; + if (item.TranscodingSubProtocol == MediaStreamProtocol.hls) + { + // Enforce HLS audio codec restrictions + if (string.Equals(remuxContainer, "mp4", StringComparison.OrdinalIgnoreCase)) + { + codeIsSupported = _supportedHlsAudioCodecsMp4.Contains(directPlayInfo.Profile?.AudioCodec ?? directPlayInfo.Profile?.Container); + } + else + { + codeIsSupported = _supportedHlsAudioCodecsTs.Contains(directPlayInfo.Profile?.AudioCodec ?? directPlayInfo.Profile?.Container); + } + } + else + { + // Let's assume the client has given a correct container for http + codeIsSupported = true; + } + + if (codeIsSupported) + { + playlistItem.PlayMethod = directPlayMethod.Value; + playlistItem.Container = remuxContainer; + playlistItem.TranscodeReasons = transcodeReasons; + playlistItem.SubProtocol = item.TranscodingSubProtocol; + return playlistItem; + } + + transcodeReasons |= TranscodeReason.AudioCodecNotSupported; + playlistItem.TranscodeReasons = transcodeReasons; + } + TranscodingProfile? transcodingProfile = null; foreach (var tcProfile in options.Profile.TranscodingProfiles) { @@ -387,6 +422,14 @@ namespace MediaBrowser.Model.Dlna item.Path ?? "Unknown path", audioStream.Codec ?? "Unknown codec"); + var directStreamProfile = options.Profile.DirectPlayProfiles + .FirstOrDefault(x => x.Type == DlnaProfileType.Audio && IsAudioDirectStreamSupported(x, item, audioStream)); + + if (directStreamProfile is not null) + { + return (directStreamProfile, PlayMethod.DirectStream, TranscodeReason.ContainerNotSupported); + } + return (null, null, GetTranscodeReasonsFromDirectPlayProfile(item, null, audioStream, options.Profile.DirectPlayProfiles)); } @@ -2129,5 +2172,23 @@ namespace MediaBrowser.Model.Dlna return true; } + + private static bool IsAudioDirectStreamSupported(DirectPlayProfile profile, MediaSourceInfo item, MediaStream audioStream) + { + // Check container type, this should NOT be supported + if (!profile.SupportsContainer(item.Container)) + { + // Check audio codec, we cannot use the SupportsAudioCodec here + // Because that one assumes empty container supports all codec, which is just useless + string? audioCodec = audioStream?.Codec; + if (string.Equals(profile.AudioCodec, audioCodec, StringComparison.OrdinalIgnoreCase) || + string.Equals(profile.Container, audioCodec, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + + return false; + } } } -- cgit v1.2.3 From b28d22545a59da010ce1b949c0aac76d19c61e95 Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 17 Jul 2024 21:25:29 +0800 Subject: Simplify condition check Signed-off-by: gnattu --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index f101bbb148..fd6bef1ad7 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -814,10 +814,9 @@ namespace MediaBrowser.MediaEncoding.Encoder var options = allowHwAccel ? _configurationManager.GetEncodingOptions() : new EncodingOptions(); threads ??= _threads; - if (enableKeyFrameOnlyExtraction) + if (allowHwAccel && enableKeyFrameOnlyExtraction) { - var supportsKeyFrameOnly = !allowHwAccel - || (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && options.EnableEnhancedNvdecDecoder) + var supportsKeyFrameOnly = (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && options.EnableEnhancedNvdecDecoder) || (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && OperatingSystem.IsWindows() && options.PreferSystemNativeHwDecoder) || (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && options.PreferSystemNativeHwDecoder) || string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) -- cgit v1.2.3 From e851bb869b0c9295372b6f9f47d78a4ea1401cea Mon Sep 17 00:00:00 2001 From: gnattu Date: Wed, 17 Jul 2024 22:25:28 +0800 Subject: Simply AMF Windows checking Co-authored-by: Nyanmisaka --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index fd6bef1ad7..390891fcf1 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -817,7 +817,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (allowHwAccel && enableKeyFrameOnlyExtraction) { var supportsKeyFrameOnly = (string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && options.EnableEnhancedNvdecDecoder) - || (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && OperatingSystem.IsWindows() && options.PreferSystemNativeHwDecoder) + || (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && OperatingSystem.IsWindows()) || (string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && options.PreferSystemNativeHwDecoder) || string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) || string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase); -- cgit v1.2.3 From 8851ace5436c6a22b9489f88d20e1aab582ffddf Mon Sep 17 00:00:00 2001 From: gnattu Date: Thu, 18 Jul 2024 00:35:40 +0800 Subject: Enable Dolby AC-4 decoder (#11486) --- Jellyfin.Api/Controllers/DynamicHlsController.cs | 7 +++++++ MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs | 1 + 2 files changed, 8 insertions(+) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 68602c80d5..2201225a8a 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -1735,6 +1735,13 @@ public class DynamicHlsController : BaseJellyfinApiController } } + if (state.AudioStream is not null && state.AudioStream.CodecTag.Equals("ac-4", StringComparison.Ordinal)) + { + // ac-4 audio tends to hava a super weird sample rate that will fail most encoders + // force resample it to 48KHz + args += " -ar 48000"; + } + if (state.OutputAudioSampleRate.HasValue) { args += " -ar " + state.OutputAudioSampleRate.Value.ToString(CultureInfo.InvariantCulture); diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 30bb21dcb1..06e2d37830 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -27,6 +27,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "msmpeg4", "dca", "ac3", + "ac4", "aac", "mp3", "flac", -- cgit v1.2.3 From 5262439300884680b1425b94de9c2f9c898d83ae Mon Sep 17 00:00:00 2001 From: gnattu Date: Thu, 18 Jul 2024 01:50:32 +0800 Subject: Enable hardware Trickplay processing pipeline for VideoToolbox (#11510) --- .../MediaEncoding/EncodingHelper.cs | 3 ++- .../Encoder/EncoderValidator.cs | 31 ++++++++++++++++++++++ MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 19 ++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index b175dc4034..98351377e6 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -120,7 +120,8 @@ namespace MediaBrowser.Controller.MediaEncoding private static readonly Dictionary _mjpegCodecMap = new(StringComparer.OrdinalIgnoreCase) { { "vaapi", _defaultMjpegEncoder + "_vaapi" }, - { "qsv", _defaultMjpegEncoder + "_qsv" } + { "qsv", _defaultMjpegEncoder + "_qsv" }, + { "videotoolbox", _defaultMjpegEncoder + "_videotoolbox" } }; public static readonly string[] LosslessAudioCodecs = new string[] diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 06e2d37830..a865b0e4cb 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -95,6 +95,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "h264_v4l2m2m", "h264_videotoolbox", "hevc_videotoolbox", + "mjpeg_videotoolbox", "h264_rkmpp", "hevc_rkmpp" }; @@ -500,6 +501,11 @@ namespace MediaBrowser.MediaEncoding.Encoder return output.Contains(keyDesc, StringComparison.Ordinal); } + public bool CheckSupportedHwaccelFlag(string flag) + { + return !string.IsNullOrEmpty(flag) && GetProcessExitCode(_encoderPath, $"-loglevel quiet -hwaccel_flags +{flag} -hide_banner -f lavfi -i nullsrc=s=1x1:d=100 -f null -"); + } + private IEnumerable GetCodecs(Codec codec) { string codecstr = codec == Codec.Encoder ? "encoders" : "decoders"; @@ -605,6 +611,31 @@ namespace MediaBrowser.MediaEncoding.Encoder } } + private bool GetProcessExitCode(string path, string arguments) + { + using var process = new Process(); + process.StartInfo = new ProcessStartInfo(path, arguments) + { + CreateNoWindow = true, + UseShellExecute = false, + WindowStyle = ProcessWindowStyle.Hidden, + ErrorDialog = false + }; + _logger.LogDebug("Running {Path} {Arguments}", path, arguments); + + try + { + process.Start(); + process.WaitForExit(); + return process.ExitCode == 0; + } + catch (Exception ex) + { + _logger.LogError("Running {Path} {Arguments} failed with exception {Exception}", path, arguments, ex.Message); + return false; + } + } + [GeneratedRegex("^\\s\\S{6}\\s(?[\\w|-]+)\\s+.+$", RegexOptions.Multiline)] private static partial Regex CodecRegex(); diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index de1b654822..e7e48d6d89 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -74,6 +74,7 @@ namespace MediaBrowser.MediaEncoding.Encoder private IDictionary _filtersWithOption = new Dictionary(); private bool _isPkeyPauseSupported = false; + private bool _isLowPriorityHwDecodeSupported = false; private bool _isVaapiDeviceAmd = false; private bool _isVaapiDeviceInteliHD = false; @@ -194,6 +195,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _threads = EncodingHelper.GetNumberOfThreads(null, options, null); _isPkeyPauseSupported = validator.CheckSupportedRuntimeKey("p pause transcoding"); + _isLowPriorityHwDecodeSupported = validator.CheckSupportedHwaccelFlag("low_priority"); // Check the Vaapi device vendor if (OperatingSystem.IsLinux() @@ -884,6 +886,12 @@ namespace MediaBrowser.MediaEncoding.Encoder inputArg = "-threads " + threads + " " + inputArg; // HW accel args set a different input thread count, only set if disabled } + if (options.HardwareAccelerationType.Contains("videotoolbox", StringComparison.OrdinalIgnoreCase) && _isLowPriorityHwDecodeSupported) + { + // VideoToolbox supports low priority decoding, which is useful for trickplay + inputArg = "-hwaccel_flags +low_priority " + inputArg; + } + if (enableKeyFrameOnlyExtraction) { inputArg = "-skip_frame nokey " + inputArg; @@ -921,6 +929,14 @@ namespace MediaBrowser.MediaEncoding.Encoder encoderQuality = (100 - ((qualityScale - 1) * (100 / 30))) / 118; } + if (vidEncoder.Contains("videotoolbox", StringComparison.OrdinalIgnoreCase)) + { + // videotoolbox's mjpeg encoder uses jpeg quality scaled to QP2LAMBDA (118) instead of ffmpeg defined qscale + // ffmpeg qscale is a value from 1-31, with 1 being best quality and 31 being worst + // jpeg quality is a value from 0-100, with 0 being worst quality and 100 being best + encoderQuality = 118 - ((qualityScale - 1) * (118 / 30)); + } + // Output arguments var targetDirectory = Path.Combine(_configurationManager.ApplicationPaths.TempDirectory, Guid.NewGuid().ToString("N")); Directory.CreateDirectory(targetDirectory); @@ -929,12 +945,13 @@ namespace MediaBrowser.MediaEncoding.Encoder // Final command arguments var args = string.Format( CultureInfo.InvariantCulture, - "-loglevel error {0} -an -sn {1} -threads {2} -c:v {3} {4}-f {5} \"{6}\"", + "-loglevel error {0} -an -sn {1} -threads {2} -c:v {3} {4}{5}-f {6} \"{7}\"", inputArg, filterParam, outputThreads.GetValueOrDefault(_threads), vidEncoder, qualityScale.HasValue ? "-qscale:v " + encoderQuality.Value.ToString(CultureInfo.InvariantCulture) + " " : string.Empty, + vidEncoder.Contains("videotoolbox", StringComparison.InvariantCultureIgnoreCase) ? "-allow_sw 1 " : string.Empty, // allow_sw fallback for some intel macs "image2", outputPath); -- cgit v1.2.3 From 1e7aca8a3dae9c9b4a37d99a7575ce8cd966da85 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 20 Jul 2024 17:32:09 +0200 Subject: Fix BDMV stream indexes Also fixes the subtitle codec for PGS subtitles from PGS to PGSSUB --- .../BdInfo/BdInfoExaminer.cs | 55 ++++++++++------------ 1 file changed, 25 insertions(+), 30 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs index 5bae4fbd5a..0b17cffb5b 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs @@ -60,21 +60,20 @@ public class BdInfoExaminer : IBlurayExaminer var sortedStreams = playlist.SortedStreams; var mediaStreams = new List(sortedStreams.Count); - foreach (var stream in sortedStreams) + for (int i = 0; i < sortedStreams.Count; i++) { + var stream = sortedStreams[i]; switch (stream) { case TSVideoStream videoStream: - AddVideoStream(mediaStreams, videoStream); + AddVideoStream(mediaStreams, i, videoStream); break; case TSAudioStream audioStream: - AddAudioStream(mediaStreams, audioStream); + AddAudioStream(mediaStreams, i, audioStream); break; - case TSTextStream textStream: - AddSubtitleStream(mediaStreams, textStream); - break; - case TSGraphicsStream graphicStream: - AddSubtitleStream(mediaStreams, graphicStream); + case TSTextStream: + case TSGraphicsStream: + AddSubtitleStream(mediaStreams, i, stream); break; } } @@ -96,8 +95,9 @@ public class BdInfoExaminer : IBlurayExaminer /// Adds the video stream. /// /// The streams. + /// The stream index. /// The video stream. - private void AddVideoStream(List streams, TSVideoStream videoStream) + private void AddVideoStream(List streams, int index, TSVideoStream videoStream) { var mediaStream = new MediaStream { @@ -107,7 +107,7 @@ public class BdInfoExaminer : IBlurayExaminer Codec = videoStream.CodecShortName, IsInterlaced = videoStream.IsInterlaced, Type = MediaStreamType.Video, - Index = streams.Count + Index = index }; if (videoStream.FrameRateDenominator > 0) @@ -125,8 +125,9 @@ public class BdInfoExaminer : IBlurayExaminer /// Adds the audio stream. /// /// The streams. + /// The stream index. /// The audio stream. - private void AddAudioStream(List streams, TSAudioStream audioStream) + private void AddAudioStream(List streams, int index, TSAudioStream audioStream) { var stream = new MediaStream { @@ -135,7 +136,7 @@ public class BdInfoExaminer : IBlurayExaminer Channels = audioStream.ChannelCount, SampleRate = audioStream.SampleRate, Type = MediaStreamType.Audio, - Index = streams.Count + Index = index }; var bitrate = Convert.ToInt32(audioStream.BitRate); @@ -157,31 +158,25 @@ public class BdInfoExaminer : IBlurayExaminer /// Adds the subtitle stream. /// /// The streams. - /// The text stream. - private void AddSubtitleStream(List streams, TSTextStream textStream) + /// The stream index. + /// The stream. + private void AddSubtitleStream(List streams, int index, TSStream textStream) { streams.Add(new MediaStream { Language = textStream.LanguageCode, - Codec = textStream.CodecShortName, + Codec = NormalizeSubtitleCodec(textStream.StreamType), Type = MediaStreamType.Subtitle, - Index = streams.Count + Index = index }); } - /// - /// Adds the subtitle stream. - /// - /// The streams. - /// The text stream. - private void AddSubtitleStream(List streams, TSGraphicsStream textStream) - { - streams.Add(new MediaStream + private string NormalizeSubtitleCodec(TSStreamType codec) + => codec switch { - Language = textStream.LanguageCode, - Codec = textStream.CodecShortName, - Type = MediaStreamType.Subtitle, - Index = streams.Count - }); - } + TSStreamType.INTERACTIVE_GRAPHICS => "igs", + TSStreamType.PRESENTATION_GRAPHICS => "pgssub", + TSStreamType.SUBTITLE => "sub", + _ => throw new ArgumentOutOfRangeException(nameof(codec), $"Invalid stream type for subtitle: {codec}") + }; } -- cgit v1.2.3 From 406320cb9807f401764ef786058b33fb1484a9ee Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 20 Jul 2024 19:50:14 +0200 Subject: Fix more codec names --- .../BdInfo/BdInfoExaminer.cs | 34 +++++++++++----------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs index 0b17cffb5b..e1a5d1d2bd 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using BDInfo; +using Jellyfin.Extensions; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; @@ -104,7 +106,7 @@ public class BdInfoExaminer : IBlurayExaminer BitRate = Convert.ToInt32(videoStream.BitRate), Width = videoStream.Width, Height = videoStream.Height, - Codec = videoStream.CodecShortName, + Codec = GetNormalizedCodec(videoStream), IsInterlaced = videoStream.IsInterlaced, Type = MediaStreamType.Video, Index = index @@ -131,9 +133,10 @@ public class BdInfoExaminer : IBlurayExaminer { var stream = new MediaStream { - Codec = audioStream.CodecShortName, + Codec = GetNormalizedCodec(audioStream), Language = audioStream.LanguageCode, - Channels = audioStream.ChannelCount, + ChannelLayout = string.Format(CultureInfo.InvariantCulture, "{0:D}.{1:D}", audioStream.ChannelCount, audioStream.LFE), + Channels = audioStream.ChannelCount + audioStream.LFE, SampleRate = audioStream.SampleRate, Type = MediaStreamType.Audio, Index = index @@ -146,11 +149,6 @@ public class BdInfoExaminer : IBlurayExaminer stream.BitRate = bitrate; } - if (audioStream.LFE > 0) - { - stream.Channels = audioStream.ChannelCount + 1; - } - streams.Add(stream); } @@ -159,24 +157,26 @@ public class BdInfoExaminer : IBlurayExaminer /// /// The streams. /// The stream index. - /// The stream. - private void AddSubtitleStream(List streams, int index, TSStream textStream) + /// The stream. + private void AddSubtitleStream(List streams, int index, TSStream stream) { streams.Add(new MediaStream { - Language = textStream.LanguageCode, - Codec = NormalizeSubtitleCodec(textStream.StreamType), + Language = stream.LanguageCode, + Codec = GetNormalizedCodec(stream), Type = MediaStreamType.Subtitle, Index = index }); } - private string NormalizeSubtitleCodec(TSStreamType codec) - => codec switch + private string GetNormalizedCodec(TSStream stream) + => stream.StreamType switch { - TSStreamType.INTERACTIVE_GRAPHICS => "igs", + TSStreamType.MPEG1_VIDEO => "mpeg1video", + TSStreamType.MPEG2_VIDEO => "mpeg2video", + TSStreamType.VC1_VIDEO => "vc1", + TSStreamType.AC3_PLUS_AUDIO | TSStreamType.AC3_PLUS_SECONDARY_AUDIO => "eac3", TSStreamType.PRESENTATION_GRAPHICS => "pgssub", - TSStreamType.SUBTITLE => "sub", - _ => throw new ArgumentOutOfRangeException(nameof(codec), $"Invalid stream type for subtitle: {codec}") + _ => stream.CodecShortName }; } -- cgit v1.2.3 From f308a01e5930625692932585a35703f8a9e5fa4c Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 20 Jul 2024 20:22:51 +0200 Subject: Fix DTS codec name --- MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs index e1a5d1d2bd..d9e266e5ca 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs @@ -176,6 +176,7 @@ public class BdInfoExaminer : IBlurayExaminer TSStreamType.MPEG2_VIDEO => "mpeg2video", TSStreamType.VC1_VIDEO => "vc1", TSStreamType.AC3_PLUS_AUDIO | TSStreamType.AC3_PLUS_SECONDARY_AUDIO => "eac3", + TSStreamType.DTS_AUDIO | TSStreamType.DTS_HD_AUDIO | TSStreamType.DTS_HD_MASTER_AUDIO | TSStreamType.DTS_HD_MASTER_AUDIO => "dts", TSStreamType.PRESENTATION_GRAPHICS => "pgssub", _ => stream.CodecShortName }; -- cgit v1.2.3 From 99bba2971535e6c21f568e25cf5f8e3ba36be7d1 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sat, 20 Jul 2024 20:37:44 +0200 Subject: Fix switch expression --- MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs index d9e266e5ca..6ca994fb7e 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs @@ -175,8 +175,8 @@ public class BdInfoExaminer : IBlurayExaminer TSStreamType.MPEG1_VIDEO => "mpeg1video", TSStreamType.MPEG2_VIDEO => "mpeg2video", TSStreamType.VC1_VIDEO => "vc1", - TSStreamType.AC3_PLUS_AUDIO | TSStreamType.AC3_PLUS_SECONDARY_AUDIO => "eac3", - TSStreamType.DTS_AUDIO | TSStreamType.DTS_HD_AUDIO | TSStreamType.DTS_HD_MASTER_AUDIO | TSStreamType.DTS_HD_MASTER_AUDIO => "dts", + TSStreamType.AC3_PLUS_AUDIO or TSStreamType.AC3_PLUS_SECONDARY_AUDIO => "eac3", + TSStreamType.DTS_AUDIO or TSStreamType.DTS_HD_AUDIO or TSStreamType.DTS_HD_MASTER_AUDIO or TSStreamType.DTS_HD_SECONDARY_AUDIO => "dts", TSStreamType.PRESENTATION_GRAPHICS => "pgssub", _ => stream.CodecShortName }; -- cgit v1.2.3 From 46fde9aa04377d151cce128978e4eb9c54b86d98 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Sun, 21 Jul 2024 00:58:05 -0400 Subject: Backport pull request #12278 from jellyfin/release-10.9.z Fix localization of audio title Original-merge: f7a90b6383aed557c0c2d3a824fc00340f72fe40 Merged-by: Bond-009 Backported-by: Joshua M. Boniface --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 12 ++++++++---- MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs | 2 ++ .../Probing/ProbeResultNormalizerTests.cs | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index c2e3312ab2..5094dcf0d3 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -5694,13 +5694,17 @@ AND Type = @InternalPersonType)"); item.IsHearingImpaired = reader.TryGetBoolean(43, out var result) && result; - if (item.Type == MediaStreamType.Subtitle) + if (item.Type is MediaStreamType.Audio or MediaStreamType.Subtitle) { - item.LocalizedUndefined = _localization.GetLocalizedString("Undefined"); item.LocalizedDefault = _localization.GetLocalizedString("Default"); - item.LocalizedForced = _localization.GetLocalizedString("Forced"); item.LocalizedExternal = _localization.GetLocalizedString("External"); - item.LocalizedHearingImpaired = _localization.GetLocalizedString("HearingImpaired"); + + if (item.Type is MediaStreamType.Subtitle) + { + item.LocalizedUndefined = _localization.GetLocalizedString("Undefined"); + item.LocalizedForced = _localization.GetLocalizedString("Forced"); + item.LocalizedHearingImpaired = _localization.GetLocalizedString("HearingImpaired"); + } } return item; diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index f5185398cd..c8bd1eb7f5 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -721,6 +721,8 @@ namespace MediaBrowser.MediaEncoding.Probing if (streamInfo.CodecType == CodecType.Audio) { stream.Type = MediaStreamType.Audio; + stream.LocalizedDefault = _localization.GetLocalizedString("Default"); + stream.LocalizedExternal = _localization.GetLocalizedString("External"); stream.Channels = streamInfo.Channels; diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs index 020e20fb8a..612064190e 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs @@ -18,7 +18,7 @@ namespace Jellyfin.MediaEncoding.Tests.Probing public class ProbeResultNormalizerTests { private readonly JsonSerializerOptions _jsonOptions; - private readonly ProbeResultNormalizer _probeResultNormalizer = new ProbeResultNormalizer(new NullLogger(), null); + private readonly ProbeResultNormalizer _probeResultNormalizer = new ProbeResultNormalizer(new NullLogger(), new Mock().Object); public ProbeResultNormalizerTests() { -- cgit v1.2.3 From 1dc0a1de6c2646a686f75e23c83a194bd69aec4b Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Sun, 21 Jul 2024 00:58:06 -0400 Subject: Backport pull request #12296 from jellyfin/release-10.9.z Properly escape paths in concat file for BDMV Original-merge: 4afa6db108e2071a335e7f6f7bb3fa7b50d9b7f7 Merged-by: crobibero Backported-by: Joshua M. Boniface --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'MediaBrowser.MediaEncoding') diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index e7e48d6d89..5cfead5026 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -1250,7 +1250,7 @@ namespace MediaBrowser.MediaEncoding.Encoder var duration = TimeSpan.FromTicks(mediaInfoResult.RunTimeTicks.Value).TotalSeconds; // Add file path stanza to concat configuration - sw.WriteLine("file '{0}'", path); + sw.WriteLine("file '{0}'", path.Replace("'", @"'\''", StringComparison.Ordinal)); // Add duration stanza to concat configuration sw.WriteLine("duration {0}", duration); -- cgit v1.2.3