From 128d54622ad07985688cccf30a897257bf9ea2c2 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Fri, 1 Apr 2022 02:59:51 +0200 Subject: [PATCH] Fix stream index and subtitle container handling, preserve attachments and nonexternal streams between scans --- .../Library/MediaSourceManager.cs | 6 ++-- .../MediaEncoding/EncodingHelper.cs | 30 ++++++++++++------- .../MediaEncoding/IMediaEncoder.cs | 7 +++++ .../Encoder/MediaEncoder.cs | 13 ++++++++ .../Subtitles/SubtitleEncoder.cs | 19 ++++++++---- .../MediaInfo/FFProbeVideoInfo.cs | 15 ++++++++-- 6 files changed, 70 insertions(+), 20 deletions(-) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 41f0401615..4af8c9feb5 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -151,9 +151,11 @@ namespace Emby.Server.Implementations.Library { var mediaSources = GetStaticMediaSources(item, enablePathSubstitution, user); + // If file is strm or main media stream is missing, force a metadata refresh with remote probing if (allowMediaProbe && mediaSources[0].Type != MediaSourceType.Placeholder - && (item.MediaType == MediaType.Video && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Video) - || item.MediaType == MediaType.Audio && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Audio))) + && (item.Path.EndsWith(".strm") + || (item.MediaType == MediaType.Video && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Video)) + || (item.MediaType == MediaType.Audio && !mediaSources[0].MediaStreams.Any(i => i.Type == MediaStreamType.Audio)))) { await item.RefreshMetadata( new MetadataRefreshOptions(_directoryService) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 897fd82b48..adac6d280a 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -2228,14 +2228,14 @@ namespace MediaBrowser.Controller.MediaEncoding } var args = string.Empty; - var numberOfExternalStreams = state.MediaSource.MediaStreams.Where(stream => stream.IsExternal == true).Count(); + int videoStreamIndex = state.MediaSource.MediaStreams.Where(i => i.Path == state.VideoStream.Path).ToList().IndexOf(state.VideoStream); if (state.VideoStream != null) { args += string.Format( CultureInfo.InvariantCulture, "-map 0:{0}", - state.VideoStream.Index - numberOfExternalStreams); + videoStreamIndex); } else { @@ -2249,20 +2249,22 @@ namespace MediaBrowser.Controller.MediaEncoding { bool hasExternalGraphicsSubs = state.SubtitleStream != null && state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream; int externalAudioMapIndex = hasExternalGraphicsSubs ? 2 : 1; - int externalAudioStream = state.MediaSource.MediaStreams.Where(i => i.Path == state.AudioStream.Path).ToList().IndexOf(state.AudioStream); + int externalAudioStreamIndex = state.MediaSource.MediaStreams.Where(i => i.Path == state.AudioStream.Path).ToList().IndexOf(state.AudioStream); args += string.Format( CultureInfo.InvariantCulture, " -map {0}:{1}", externalAudioMapIndex, - externalAudioStream); + externalAudioStreamIndex); } else { + int subtitleStreamIndex = state.MediaSource.MediaStreams.Where(i => i.Path == state.AudioStream.Path).ToList().IndexOf(state.AudioStream); + args += string.Format( CultureInfo.InvariantCulture, " -map 0:{0}", - state.AudioStream.Index); + subtitleStreamIndex); } } else @@ -2277,14 +2279,21 @@ namespace MediaBrowser.Controller.MediaEncoding } else if (subtitleMethod == SubtitleDeliveryMethod.Embed) { + int subtitleStreamIndex = state.MediaSource.MediaStreams.Where(i => i.Path == state.SubtitleStream.Path).ToList().IndexOf(state.SubtitleStream); + args += string.Format( CultureInfo.InvariantCulture, " -map 0:{0}", - state.SubtitleStream.Index); + subtitleStreamIndex); } else if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream) { - args += " -map 1:0 -sn"; + int externalSubtitleStreamIndex = state.MediaSource.MediaStreams.Where(i => i.Path == state.SubtitleStream.Path).ToList().IndexOf(state.SubtitleStream); + + args += string.Format( + CultureInfo.InvariantCulture, + " -map 1:{0} -sn", + externalSubtitleStreamIndex); } return args; @@ -4130,9 +4139,8 @@ namespace MediaBrowser.Controller.MediaEncoding string.Join(',', overlayFilters)); var mapPrefix = Convert.ToInt32(state.SubtitleStream.IsExternal); - var subtitleStreamIndex = state.SubtitleStream.IsExternal - ? 0 - : state.SubtitleStream.Index; + var subtitleStreamIndex = state.MediaSource.MediaStreams.Where(i => i.Path == state.SubtitleStream.Path).ToList().IndexOf(state.SubtitleStream); + var videoStreamIndex = state.MediaSource.MediaStreams.Where(i => i.Path == state.VideoStream.Path).ToList().IndexOf(state.VideoStream); if (hasSubs) { @@ -4153,7 +4161,7 @@ namespace MediaBrowser.Controller.MediaEncoding filterStr, mapPrefix, subtitleStreamIndex, - state.VideoStream.Index, + videoStreamIndex, mainStr, subStr, overlayStr); diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 6bf3e7b469..dae30cd8b3 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -141,6 +141,13 @@ namespace MediaBrowser.Controller.MediaEncoding /// System.String. string GetInputArgument(string inputFile, MediaSourceInfo mediaSource); + /// + /// Gets the input argument for an external subtitle file. + /// + /// The input file. + /// System.String. + string GetExternalSubtitleInputArgument(string inputFile); + /// /// Gets the time parameter. /// diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index c796ee7806..7e5d7a25f8 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -411,6 +411,19 @@ namespace MediaBrowser.MediaEncoding.Encoder return EncodingUtils.GetInputArgument(prefix, inputFile, mediaSource.Protocol); } + /// + /// Gets the input argument for an external subtitle file. + /// + /// The input file. + /// System.String. + /// Unrecognized InputType. + public string GetExternalSubtitleInputArgument(string inputFile) + { + var prefix = "file"; + + return EncodingUtils.GetInputArgument(prefix, inputFile, MediaProtocol.File); + } + /// /// Gets the media info internal. /// diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index f4842d3682..717624279a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -195,7 +195,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles MediaStream subtitleStream, CancellationToken cancellationToken) { - if (!subtitleStream.IsExternal) + if (!subtitleStream.IsExternal || subtitleStream.Path.EndsWith(".mks")) { string outputFormat; string outputCodec; @@ -224,7 +224,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles // Extract var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + outputFormat); - await ExtractTextSubtitle(mediaSource, subtitleStream.Index, outputCodec, outputPath, cancellationToken) + await ExtractTextSubtitle(mediaSource, subtitleStream, outputCodec, outputPath, cancellationToken) .ConfigureAwait(false); return new SubtitleInfo(outputPath, MediaProtocol.File, outputFormat, false); @@ -494,7 +494,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// Extracts the text subtitle. /// /// The mediaSource. - /// Index of the subtitle stream. + /// The subtitle stream. /// The output codec. /// The output path. /// The cancellation token. @@ -502,7 +502,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// Must use inputPath list overload. private async Task ExtractTextSubtitle( MediaSourceInfo mediaSource, - int subtitleStreamIndex, + MediaStream subtitleStream, string outputCodec, string outputPath, CancellationToken cancellationToken) @@ -511,12 +511,21 @@ namespace MediaBrowser.MediaEncoding.Subtitles await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + var subtitleStreamIndex = mediaSource.MediaStreams.Where(i => i.Path == subtitleStream.Path).ToList().IndexOf(subtitleStream); + try { if (!File.Exists(outputPath)) { + var args = _mediaEncoder.GetInputArgument(mediaSource.Path, mediaSource); + + if (subtitleStream.IsExternal) + { + args = _mediaEncoder.GetExternalSubtitleInputArgument(subtitleStream.Path); + } + await ExtractTextSubtitleInternal( - _mediaEncoder.GetInputArgument(mediaSource.Path, mediaSource), + args, subtitleStreamIndex, outputCodec, outputPath, diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 6208186ab9..c9f7870483 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -180,9 +180,10 @@ namespace MediaBrowser.Providers.MediaInfo await AddExternalAudioAsync(video, mediaStreams, options, cancellationToken).ConfigureAwait(false); + var startIndex = mediaStreams.Count == 0 ? 0 : (mediaStreams.Select(i => i.Index).Max() + 1); + if (mediaInfo != null) { - var startIndex = mediaStreams.Count == 0 ? 0 : (mediaStreams.Select(i => i.Index).Max() + 1); foreach (var mediaStream in mediaInfo.MediaStreams) { mediaStream.Index = startIndex++; @@ -226,6 +227,12 @@ namespace MediaBrowser.Providers.MediaInfo } else { + var nonExternalMediaStreams = video.GetMediaStreams().Where(i => !i.IsExternal); + foreach (var mediaStream in nonExternalMediaStreams) + { + mediaStream.Index = startIndex++; + mediaStreams.Add(mediaStream); + } mediaAttachments = Array.Empty(); chapters = Array.Empty(); } @@ -262,7 +269,11 @@ namespace MediaBrowser.Providers.MediaInfo video.HasSubtitles = mediaStreams.Any(i => i.Type == MediaStreamType.Subtitle); _itemRepo.SaveMediaStreams(video.Id, mediaStreams, cancellationToken); - _itemRepo.SaveMediaAttachments(video.Id, mediaAttachments, cancellationToken); + + if (mediaAttachments.Any()) + { + _itemRepo.SaveMediaAttachments(video.Id, mediaAttachments, cancellationToken); + } if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || options.MetadataRefreshMode == MetadataRefreshMode.Default)