diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index d21a9dc3b9..503399f8db 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -8,6 +8,7 @@ using MediaBrowser.Controller.Session; using MediaBrowser.MediaEncoding.Probing; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Extensions; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; @@ -242,21 +243,27 @@ namespace MediaBrowser.MediaEncoding.Encoder if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue) { - foreach (var stream in mediaInfo.MediaStreams) + if (ConfigurationManager.Configuration.EnableVideoFrameAnalysis && mediaInfo.Size.HasValue && mediaInfo.Size.Value <= ConfigurationManager.Configuration.VideoFrameAnalysisLimitBytes) { - if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase) && !stream.IsInterlaced) + foreach (var stream in mediaInfo.MediaStreams) { - try - { - //stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) + if (stream.Type == MediaStreamType.Video && + string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase) && + !stream.IsInterlaced && + !(stream.IsAnamorphic ?? false)) { + try + { + stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) + { - } - catch (Exception ex) - { - _logger.ErrorException("Error getting key frame interval", ex); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting key frame interval", ex); + } } } } @@ -296,7 +303,6 @@ namespace MediaBrowser.MediaEncoding.Encoder // Must consume both or ffmpeg may hang due to deadlocks. See comments below. RedirectStandardOutput = true, RedirectStandardError = true, - RedirectStandardInput = true, FileName = FFProbePath, Arguments = string.Format(args, inputPath, videoStreamIndex.ToString(CultureInfo.InvariantCulture)).Trim(), @@ -309,9 +315,11 @@ namespace MediaBrowser.MediaEncoding.Encoder _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - using (var processWrapper = new ProcessWrapper(process, this, _logger)) + using (process) { - StartProcess(processWrapper); + var start = DateTime.UtcNow; + + process.Start(); var lines = new List(); @@ -328,27 +336,26 @@ namespace MediaBrowser.MediaEncoding.Encoder throw; } } - finally - { - StopProcess(processWrapper, 100, true); - } + + process.WaitForExit(); + + _logger.Debug("Keyframe extraction took {0} seconds", (DateTime.UtcNow - start).TotalSeconds); //_logger.Debug("Found keyframes {0}", string.Join(",", lines.ToArray())); return lines; } } - private async Task StartReadingOutput(Stream source, List lines, CancellationToken cancellationToken) + private async Task StartReadingOutput(Stream source, List keyframes, CancellationToken cancellationToken) { try { using (var reader = new StreamReader(source)) { - while (!reader.EndOfStream) + var text = await reader.ReadToEndAsync().ConfigureAwait(false); + + var lines = StringHelper.RegexSplit(text, "\r\n"); + foreach (var line in lines) { - cancellationToken.ThrowIfCancellationRequested(); - - var line = await reader.ReadLineAsync().ConfigureAwait(false); - if (string.IsNullOrWhiteSpace(line)) { continue; @@ -368,7 +375,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (values.TryGetValue("pts_time", out pts_time) && double.TryParse(pts_time, NumberStyles.Any, CultureInfo.InvariantCulture, out frameSeconds)) { var ms = frameSeconds * 1000; - lines.Add(Convert.ToInt32(ms)); + keyframes.Add(Convert.ToInt32(ms)); } } } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 07d5905c69..9f95953cf9 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -222,11 +222,13 @@ namespace MediaBrowser.Model.Configuration public bool DisableXmlSavers { get; set; } public bool EnableWindowsShortcuts { get; set; } + public bool EnableVideoFrameAnalysis { get; set; } + public long VideoFrameAnalysisLimitBytes { get; set; } + /// /// Initializes a new instance of the class. /// public ServerConfiguration() - : base() { ImageSavingConvention = ImageSavingConvention.Compatible; PublicPort = 8096; @@ -271,6 +273,9 @@ namespace MediaBrowser.Model.Configuration PeopleMetadataOptions = new PeopleMetadataOptions(); + EnableVideoFrameAnalysis = true; + VideoFrameAnalysisLimitBytes = 600000000; + InsecureApps9 = new[] { "Chromecast", diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 453e07987a..fe0e4890c2 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -189,7 +189,7 @@ namespace MediaBrowser.Providers.Manager var results = await Task.WhenAll(tasks).ConfigureAwait(false); - var images = results.SelectMany(i => i); + var images = results.SelectMany(i => i.ToList()); return images; }