diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs index 1d74e87886..e4eb41e3a2 100644 --- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs +++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs @@ -142,7 +142,7 @@ namespace Emby.Server.Implementations.MediaEncoder var container = video.Container; - var tempFile = await _encoder.ExtractVideoImage(inputPath, container, protocol, video.Video3DFormat, time, cancellationToken).ConfigureAwait(false); + var tempFile = await _encoder.ExtractVideoImage(inputPath, container, protocol, video.GetDefaultVideoStream(), video.Video3DFormat, time, cancellationToken).ConfigureAwait(false); _fileSystem.CopyFile(tempFile, path, true); try diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index c300fcce3e..4fde66d1ac 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -95,7 +95,7 @@ namespace MediaBrowser.Api.Playback LibraryManager = libraryManager; IsoManager = isoManager; MediaEncoder = mediaEncoder; - EncodingHelper = new EncodingHelper(MediaEncoder, serverConfig, FileSystem, SubtitleEncoder); + EncodingHelper = new EncodingHelper(MediaEncoder, FileSystem, SubtitleEncoder); } /// diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 6d2ec2eaba..4b3e340c99 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -4,7 +4,6 @@ using System.Globalization; using System.IO; using System.Linq; using System.Threading; -using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; @@ -19,14 +18,12 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IMediaEncoder _mediaEncoder; - private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; private readonly ISubtitleEncoder _subtitleEncoder; - public EncodingHelper(IMediaEncoder mediaEncoder, IServerConfigurationManager config, IFileSystem fileSystem, ISubtitleEncoder subtitleEncoder) + public EncodingHelper(IMediaEncoder mediaEncoder, IFileSystem fileSystem, ISubtitleEncoder subtitleEncoder) { _mediaEncoder = mediaEncoder; - _config = config; _fileSystem = fileSystem; _subtitleEncoder = subtitleEncoder; } @@ -1771,29 +1768,34 @@ namespace MediaBrowser.Controller.MediaEncoding return null; } + return GetVideoDecoder(state.MediaSource.VideoType ?? VideoType.VideoFile, state.VideoStream, encodingOptions); + } + + public string GetVideoDecoder(VideoType videoType, MediaStream videoStream, EncodingOptions encodingOptions) + { // Only use alternative encoders for video files. // When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully // Since transcoding of folder rips is expiremental anyway, it's not worth adding additional variables such as this. - if (state.VideoType != VideoType.VideoFile) + if (videoType != VideoType.VideoFile) { return null; } - if (state.VideoStream != null && - !string.IsNullOrWhiteSpace(state.VideoStream.Codec) && + if (videoStream != null && + !string.IsNullOrWhiteSpace(videoStream.Codec) && !string.IsNullOrWhiteSpace(encodingOptions.HardwareAccelerationType) && encodingOptions.EnableHardwareDecoding) { if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { - switch (state.MediaSource.VideoStream.Codec.ToLower()) + switch (videoStream.Codec.ToLower()) { case "avc": case "h264": if (_mediaEncoder.SupportsDecoder("h264_qsv")) { // qsv decoder does not support 10-bit input - if ((state.VideoStream.BitDepth ?? 8) > 8) + if ((videoStream.BitDepth ?? 8) > 8) { return null; } @@ -1824,7 +1826,7 @@ namespace MediaBrowser.Controller.MediaEncoding else if (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)) { - switch (state.MediaSource.VideoStream.Codec.ToLower()) + switch (videoStream.Codec.ToLower()) { case "avc": case "h264": diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index 10d7b9a7e3..05bb35771e 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -39,29 +39,16 @@ namespace MediaBrowser.Controller.MediaEncoding /// /// Extracts the video image. /// - /// The input files. - /// The protocol. - /// The threed format. - /// The offset. - /// The cancellation token. - /// Task{Stream}. - Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); + Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken); - Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken); + Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken); /// /// Extracts the video images on interval. /// - /// The input files. - /// The protocol. - /// The threed format. - /// The interval. - /// The target directory. - /// The filename prefix. - /// The maximum width. - /// The cancellation token. - /// Task. Task ExtractVideoImagesOnInterval(string[] inputFiles, + string container, + MediaStream videoStream, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan interval, diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 3672e4e845..a291a98526 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -59,7 +59,7 @@ namespace MediaBrowser.MediaEncoding.Encoder MediaSourceManager = mediaSourceManager; ProcessFactory = processFactory; - EncodingHelper = new EncodingHelper(MediaEncoder, ConfigurationManager, FileSystem, SubtitleEncoder); + EncodingHelper = new EncodingHelper(MediaEncoder, FileSystem, SubtitleEncoder); } public async Task Start(EncodingJobOptions options, diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index f416ea4178..a2ebe08327 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -615,20 +615,20 @@ namespace MediaBrowser.MediaEncoding.Encoder public Task ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken) { - return ExtractImage(new[] { path }, null, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken); + return ExtractImage(new[] { path }, null, null, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken); } - public Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) + public Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) { - return ExtractImage(inputFiles, container, null, protocol, false, threedFormat, offset, cancellationToken); + return ExtractImage(inputFiles, container, videoStream, null, protocol, false, threedFormat, offset, cancellationToken); } - public Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, int? imageStreamIndex, CancellationToken cancellationToken) + public Task ExtractVideoImage(string[] inputFiles, string container, MediaProtocol protocol, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken) { - return ExtractImage(inputFiles, container, imageStreamIndex, protocol, false, null, null, cancellationToken); + return ExtractImage(inputFiles, container, imageStream, imageStreamIndex, protocol, false, null, null, cancellationToken); } - private async Task ExtractImage(string[] inputFiles, string container, int? imageStreamIndex, MediaProtocol protocol, bool isAudio, + private async Task ExtractImage(string[] inputFiles, string container, MediaStream videoStream, int? imageStreamIndex, MediaProtocol protocol, bool isAudio, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) { var inputArgument = GetInputArgument(inputFiles, protocol); @@ -645,7 +645,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { try { - return await ExtractImageInternal(inputArgument, container, imageStreamIndex, protocol, threedFormat, offset, true, cancellationToken).ConfigureAwait(false); + return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, true, cancellationToken).ConfigureAwait(false); } catch (ArgumentException) { @@ -657,10 +657,10 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - return await ExtractImageInternal(inputArgument, container, imageStreamIndex, protocol, threedFormat, offset, false, cancellationToken).ConfigureAwait(false); + return await ExtractImageInternal(inputArgument, container, videoStream, imageStreamIndex, threedFormat, offset, false, cancellationToken).ConfigureAwait(false); } - private async Task ExtractImageInternal(string inputPath, string container, int? imageStreamIndex, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, CancellationToken cancellationToken) + private async Task ExtractImageInternal(string inputPath, string container, MediaStream videoStream, int? imageStreamIndex, Video3DFormat? threedFormat, TimeSpan? offset, bool useIFrame, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(inputPath)) { @@ -698,7 +698,7 @@ namespace MediaBrowser.MediaEncoding.Encoder break; } } - + var mapArg = imageStreamIndex.HasValue ? (" -map 0:v:" + imageStreamIndex.Value.ToString(CultureInfo.InvariantCulture)) : string.Empty; var enableThumbnail = !new List { "wtv" }.Contains(container ?? string.Empty, StringComparer.OrdinalIgnoreCase); @@ -726,6 +726,25 @@ namespace MediaBrowser.MediaEncoding.Encoder args = string.Format("-ss {0} ", GetTimeParameter(offset.Value)) + args; } + var encodinghelper = new EncodingHelper(this, FileSystem, SubtitleEncoder()); + if (videoStream != null) + { + var decoder = encodinghelper.GetVideoDecoder(VideoType.VideoFile, videoStream, GetEncodingOptions()); + if (!string.IsNullOrWhiteSpace(decoder)) + { + args = decoder + " " + args; + } + } + + if (!string.IsNullOrWhiteSpace(container)) + { + var inputFormat = encodinghelper.GetInputFormat(container); + if (!string.IsNullOrWhiteSpace(inputFormat)) + { + args = "-f " + inputFormat + " " + args; + } + } + var process = _processFactory.Create(new ProcessOptions { CreateNoWindow = true, @@ -786,6 +805,8 @@ namespace MediaBrowser.MediaEncoding.Encoder } public async Task ExtractVideoImagesOnInterval(string[] inputFiles, + string container, + MediaStream videoStream, MediaProtocol protocol, Video3DFormat? threedFormat, TimeSpan interval, @@ -825,6 +846,25 @@ namespace MediaBrowser.MediaEncoding.Encoder args = analyzeDurationArgument + " " + args; } + var encodinghelper = new EncodingHelper(this, FileSystem, SubtitleEncoder()); + if (videoStream != null) + { + var decoder = encodinghelper.GetVideoDecoder(VideoType.VideoFile, videoStream, GetEncodingOptions()); + if (!string.IsNullOrWhiteSpace(decoder)) + { + args = decoder + " " + args; + } + } + + if (!string.IsNullOrWhiteSpace(container)) + { + var inputFormat = encodinghelper.GetInputFormat(container); + if (!string.IsNullOrWhiteSpace(inputFormat)) + { + args = "-f " + inputFormat + " " + args; + } + } + var process = _processFactory.Create(new ProcessOptions { CreateNoWindow = true, diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs index ca701b70f6..bb1c4e6472 100644 --- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs +++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs @@ -133,7 +133,7 @@ namespace MediaBrowser.Providers.MediaInfo } } - extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, videoIndex, cancellationToken).ConfigureAwait(false); + extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, imageStream, videoIndex, cancellationToken).ConfigureAwait(false); } else { @@ -144,7 +144,9 @@ namespace MediaBrowser.Providers.MediaInfo ? TimeSpan.FromTicks(Convert.ToInt64(item.RunTimeTicks.Value * .1)) : TimeSpan.FromSeconds(10); - extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); + var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); + + extractedImagePath = await _mediaEncoder.ExtractVideoImage(inputPath, item.Container, protocol, videoStream, item.Video3DFormat, imageOffset, cancellationToken).ConfigureAwait(false); } return new DynamicImageResponse