diff options
Diffstat (limited to 'MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs')
| -rw-r--r-- | MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 296 |
1 files changed, 160 insertions, 136 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index a01f37f91..4d5b669e2 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -199,82 +199,83 @@ namespace MediaBrowser.MediaEncoding.Encoder await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - var processWrapper = new ProcessWrapper(process, this); - - try - { - StartProcess(processWrapper); - } - catch (Exception ex) + using (var processWrapper = new ProcessWrapper(process, this)) { - _ffProbeResourcePool.Release(); + try + { + StartProcess(processWrapper); + } + catch (Exception ex) + { + _ffProbeResourcePool.Release(); - _logger.ErrorException("Error starting ffprobe", ex); + _logger.ErrorException("Error starting ffprobe", ex); - throw; - } + throw; + } - try - { - process.BeginErrorReadLine(); + try + { + process.BeginErrorReadLine(); - var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream); + var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream); - if (result != null) - { - if (result.streams != null) + if (result != null) { - // Normalize aspect ratio if invalid - foreach (var stream in result.streams) + if (result.streams != null) { - if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) - { - stream.display_aspect_ratio = string.Empty; - } - if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) + // Normalize aspect ratio if invalid + foreach (var stream in result.streams) { - stream.sample_aspect_ratio = string.Empty; + if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) + { + stream.display_aspect_ratio = string.Empty; + } + if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) + { + stream.sample_aspect_ratio = string.Empty; + } } } - } - var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol); + var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol); - if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue) - { - foreach (var stream in mediaInfo.MediaStreams) + if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue) { - if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase)) + foreach (var stream in mediaInfo.MediaStreams) { - try - { - //stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken) - // .ConfigureAwait(false); - } - catch (OperationCanceledException) - { - - } - catch (Exception ex) + if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase)) { - _logger.ErrorException("Error getting key frame interval", ex); + try + { + //stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken) + // .ConfigureAwait(false); + } + catch (OperationCanceledException) + { + + } + catch (Exception ex) + { + _logger.ErrorException("Error getting key frame interval", ex); + } } } } - } - return mediaInfo; + return mediaInfo; + } } - } - catch - { - StopProcess(processWrapper, 100, true); + catch + { + StopProcess(processWrapper, 100, true); - throw; - } - finally - { - _ffProbeResourcePool.Release(); + throw; + } + finally + { + _ffProbeResourcePool.Release(); + } } throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath)); @@ -307,31 +308,32 @@ namespace MediaBrowser.MediaEncoding.Encoder _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - var processWrapper = new ProcessWrapper(process, this); - - StartProcess(processWrapper); + using (var processWrapper = new ProcessWrapper(process, this)) + { + StartProcess(processWrapper); - var lines = new List<int>(); + var lines = new List<int>(); - try - { - process.BeginErrorReadLine(); + try + { + process.BeginErrorReadLine(); - await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - if (cancellationToken.IsCancellationRequested) + await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) { - throw; + if (cancellationToken.IsCancellationRequested) + { + throw; + } + } + finally + { + StopProcess(processWrapper, 100, true); } - } - finally - { - StopProcess(processWrapper, 100, true); - } - return lines; + return lines; + } } private async Task StartReadingOutput(Stream source, List<int> lines, int timeoutMs, CancellationToken cancellationToken) @@ -490,51 +492,53 @@ namespace MediaBrowser.MediaEncoding.Encoder await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - var processWrapper = new ProcessWrapper(process, this); - bool ranToCompletion; + using (var processWrapper = new ProcessWrapper(process, this)) + { + bool ranToCompletion; - var memoryStream = new MemoryStream(); + var memoryStream = new MemoryStream(); - try - { - StartProcess(processWrapper); + try + { + StartProcess(processWrapper); #pragma warning disable 4014 - // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback - process.StandardOutput.BaseStream.CopyToAsync(memoryStream); + // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback + process.StandardOutput.BaseStream.CopyToAsync(memoryStream); #pragma warning restore 4014 - // MUST read both stdout and stderr asynchronously or a deadlock may occurr - process.BeginErrorReadLine(); + // MUST read both stdout and stderr asynchronously or a deadlock may occurr + process.BeginErrorReadLine(); - ranToCompletion = process.WaitForExit(10000); + ranToCompletion = process.WaitForExit(10000); - if (!ranToCompletion) + if (!ranToCompletion) + { + StopProcess(processWrapper, 1000, false); + } + + } + finally { - StopProcess(processWrapper, 1000, false); + resourcePool.Release(); } - } - finally - { - resourcePool.Release(); - } + var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; - var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; + if (exitCode == -1 || memoryStream.Length == 0) + { + memoryStream.Dispose(); - if (exitCode == -1 || memoryStream.Length == 0) - { - memoryStream.Dispose(); + var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath); - var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath); + _logger.Error(msg); - _logger.Error(msg); + throw new ApplicationException(msg); + } - throw new ApplicationException(msg); + memoryStream.Position = 0; + return memoryStream; } - - memoryStream.Position = 0; - return memoryStream; } public string GetTimeParameter(long ticks) @@ -603,55 +607,56 @@ namespace MediaBrowser.MediaEncoding.Encoder bool ranToCompletion = false; - var processWrapper = new ProcessWrapper(process, this); - - try + using (var processWrapper = new ProcessWrapper(process, this)) { - StartProcess(processWrapper); + try + { + StartProcess(processWrapper); - // Need to give ffmpeg enough time to make all the thumbnails, which could be a while, - // but we still need to detect if the process hangs. - // Making the assumption that as long as new jpegs are showing up, everything is good. + // Need to give ffmpeg enough time to make all the thumbnails, which could be a while, + // but we still need to detect if the process hangs. + // Making the assumption that as long as new jpegs are showing up, everything is good. - bool isResponsive = true; - int lastCount = 0; + bool isResponsive = true; + int lastCount = 0; - while (isResponsive) - { - if (process.WaitForExit(30000)) + while (isResponsive) { - ranToCompletion = true; - break; - } + if (process.WaitForExit(30000)) + { + ranToCompletion = true; + break; + } + + cancellationToken.ThrowIfCancellationRequested(); - cancellationToken.ThrowIfCancellationRequested(); + var jpegCount = Directory.GetFiles(targetDirectory) + .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase)); - var jpegCount = Directory.GetFiles(targetDirectory) - .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase)); + isResponsive = (jpegCount > lastCount); + lastCount = jpegCount; + } - isResponsive = (jpegCount > lastCount); - lastCount = jpegCount; + if (!ranToCompletion) + { + StopProcess(processWrapper, 1000, false); + } } - - if (!ranToCompletion) + finally { - StopProcess(processWrapper, 1000, false); + resourcePool.Release(); } - } - finally - { - resourcePool.Release(); - } - var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; + var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1; - if (exitCode == -1) - { - var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument); + if (exitCode == -1) + { + var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument); - _logger.Error(msg); + _logger.Error(msg); - throw new ApplicationException(msg); + throw new ApplicationException(msg); + } } } @@ -781,7 +786,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - private class ProcessWrapper + private class ProcessWrapper : IDisposable { public readonly Process Process; public bool HasExited; @@ -810,6 +815,25 @@ namespace MediaBrowser.MediaEncoding.Encoder process.Dispose(); } + + private bool _disposed; + private readonly object _syncLock = new object(); + public void Dispose() + { + lock (_syncLock) + { + if (!_disposed) + { + if (Process != null) + { + Process.Exited -= Process_Exited; + Process.Dispose(); + } + } + + _disposed = true; + } + } } } } |
