瀏覽代碼

Fix stream index and subtitle container handling, preserve attachments and nonexternal streams between scans

Shadowghost 3 年之前
父節點
當前提交
128d54622a

+ 4 - 2
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)

+ 19 - 11
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);

+ 7 - 0
MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs

@@ -141,6 +141,13 @@ namespace MediaBrowser.Controller.MediaEncoding
         /// <returns>System.String.</returns>
         string GetInputArgument(string inputFile, MediaSourceInfo mediaSource);
 
+        /// <summary>
+        /// Gets the input argument for an external subtitle file.
+        /// </summary>
+        /// <param name="inputFile">The input file.</param>
+        /// <returns>System.String.</returns>
+        string GetExternalSubtitleInputArgument(string inputFile);
+
         /// <summary>
         /// Gets the time parameter.
         /// </summary>

+ 13 - 0
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -411,6 +411,19 @@ namespace MediaBrowser.MediaEncoding.Encoder
             return EncodingUtils.GetInputArgument(prefix, inputFile, mediaSource.Protocol);
         }
 
+        /// <summary>
+        /// Gets the input argument for an external subtitle file.
+        /// </summary>
+        /// <param name="inputFile">The input file.</param>
+        /// <returns>System.String.</returns>
+        /// <exception cref="ArgumentException">Unrecognized InputType.</exception>
+        public string GetExternalSubtitleInputArgument(string inputFile)
+        {
+            var prefix = "file";
+
+            return EncodingUtils.GetInputArgument(prefix, inputFile, MediaProtocol.File);
+        }
+
         /// <summary>
         /// Gets the media info internal.
         /// </summary>

+ 14 - 5
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.
         /// </summary>
         /// <param name="mediaSource">The mediaSource.</param>
-        /// <param name="subtitleStreamIndex">Index of the subtitle stream.</param>
+        /// <param name="subtitleStream">The subtitle stream.</param>
         /// <param name="outputCodec">The output codec.</param>
         /// <param name="outputPath">The output path.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
@@ -502,7 +502,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
         /// <exception cref="ArgumentException">Must use inputPath list overload.</exception>
         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,

+ 13 - 2
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<MediaAttachment>();
                 chapters = Array.Empty<ChapterInfo>();
             }
@@ -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)