diff options
Diffstat (limited to 'MediaBrowser.MediaEncoding')
| -rw-r--r-- | MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs | 79 | ||||
| -rw-r--r-- | MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs | 2 | ||||
| -rw-r--r-- | MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs | 106 |
3 files changed, 68 insertions, 119 deletions
diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 81f7c16d3..b231938b5 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -1,5 +1,5 @@ using System; -using System.Globalization; +using System.Diagnostics; using System.IO; using System.Text; using System.Threading; @@ -31,11 +31,10 @@ namespace MediaBrowser.MediaEncoding.Encoder protected readonly IMediaSourceManager MediaSourceManager; protected IProcessFactory ProcessFactory; - protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - protected EncodingHelper EncodingHelper; - protected BaseEncoder(MediaEncoder mediaEncoder, + protected BaseEncoder( + MediaEncoder mediaEncoder, ILogger logger, IServerConfigurationManager configurationManager, IFileSystem fileSystem, @@ -43,7 +42,8 @@ namespace MediaBrowser.MediaEncoding.Encoder ILibraryManager libraryManager, ISessionManager sessionManager, ISubtitleEncoder subtitleEncoder, - IMediaSourceManager mediaSourceManager, IProcessFactory processFactory) + IMediaSourceManager mediaSourceManager, + IProcessFactory processFactory) { MediaEncoder = mediaEncoder; Logger = logger; @@ -59,11 +59,12 @@ namespace MediaBrowser.MediaEncoding.Encoder EncodingHelper = new EncodingHelper(MediaEncoder, FileSystem, SubtitleEncoder); } - public async Task<EncodingJob> Start(EncodingJobOptions options, + public async Task<EncodingJob> Start( + EncodingJobOptions options, IProgress<double> progress, CancellationToken cancellationToken) { - var encodingJob = await new EncodingJobFactory(Logger, LibraryManager, MediaSourceManager, ConfigurationManager, MediaEncoder) + var encodingJob = await new EncodingJobFactory(Logger, LibraryManager, MediaSourceManager, MediaEncoder) .CreateJob(options, EncodingHelper, IsVideoEncoder, progress, cancellationToken).ConfigureAwait(false); encodingJob.OutputFilePath = GetOutputFilePath(encodingJob); @@ -75,8 +76,9 @@ namespace MediaBrowser.MediaEncoding.Encoder var commandLineArgs = GetCommandLineArguments(encodingJob); - var process = ProcessFactory.Create(new ProcessOptions + Process process = Process.Start(new ProcessStartInfo { + WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, UseShellExecute = false, @@ -88,11 +90,11 @@ namespace MediaBrowser.MediaEncoding.Encoder FileName = MediaEncoder.EncoderPath, Arguments = commandLineArgs, - IsHidden = true, - ErrorDialog = false, - EnableRaisingEvents = true + ErrorDialog = false }); + process.EnableRaisingEvents = true; + var workingDirectory = GetWorkingDirectory(options); if (!string.IsNullOrWhiteSpace(workingDirectory)) { @@ -128,29 +130,60 @@ namespace MediaBrowser.MediaEncoding.Encoder throw; } - cancellationToken.Register(() => Cancel(process, encodingJob)); + cancellationToken.Register(async () => await Cancel(process, encodingJob)); - // MUST read both stdout and stderr asynchronously or a deadlock may occurr + // MUST read both stdout and stderr asynchronously or a deadlock may occur //process.BeginOutputReadLine(); // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback new JobLogger(Logger).StartStreamingLog(encodingJob, process.StandardError.BaseStream, encodingJob.LogFileStream); - // Wait for the file to exist before proceeeding - while (!File.Exists(encodingJob.OutputFilePath) && !encodingJob.HasExited) + // Wait for the file to or for the process to stop + Task file = WaitForFileAsync(encodingJob.OutputFilePath); + await Task.WhenAny(encodingJob.TaskCompletionSource.Task, file).ConfigureAwait(false); + + return encodingJob; + } + + public static Task WaitForFileAsync(string path) + { + if (File.Exists(path)) { - await Task.Delay(100, cancellationToken).ConfigureAwait(false); + return Task.CompletedTask; } - return encodingJob; + var tcs = new TaskCompletionSource<bool>(); + FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(path)); + + watcher.Created += (s, e) => + { + if (e.Name == Path.GetFileName(path)) + { + watcher.Dispose(); + tcs.TrySetResult(true); + } + }; + + watcher.Renamed += (s, e) => + { + if (e.Name == Path.GetFileName(path)) + { + watcher.Dispose(); + tcs.TrySetResult(true); + } + }; + + watcher.EnableRaisingEvents = true; + + return tcs.Task; } - private void Cancel(IProcess process, EncodingJob job) + private async Task Cancel(Process process, EncodingJob job) { Logger.LogInformation("Killing ffmpeg process for {0}", job.OutputFilePath); //process.Kill(); - process.StandardInput.WriteLine("q"); + await process.StandardInput.WriteLineAsync("q"); job.IsCancelled = true; } @@ -160,28 +193,28 @@ namespace MediaBrowser.MediaEncoding.Encoder /// </summary> /// <param name="process">The process.</param> /// <param name="job">The job.</param> - private void OnFfMpegProcessExited(IProcess process, EncodingJob job) + private void OnFfMpegProcessExited(Process process, EncodingJob job) { job.HasExited = true; Logger.LogDebug("Disposing stream resources"); job.Dispose(); - var isSuccesful = false; + var isSuccessful = false; try { var exitCode = process.ExitCode; Logger.LogInformation("FFMpeg exited with code {0}", exitCode); - isSuccesful = exitCode == 0; + isSuccessful = exitCode == 0; } catch (Exception ex) { Logger.LogError(ex, "FFMpeg exited with an error."); } - if (isSuccesful && !job.IsCancelled) + if (isSuccessful && !job.IsCancelled) { job.TaskCompletionSource.TrySetResult(true); } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs index d4040cd31..cd7de94ce 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJob.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Net; using Microsoft.Extensions.Logging; namespace MediaBrowser.MediaEncoding.Encoder @@ -40,7 +39,6 @@ namespace MediaBrowser.MediaEncoding.Encoder _mediaSourceManager = mediaSourceManager; Id = Guid.NewGuid(); - _logger = logger; TaskCompletionSource = new TaskCompletionSource<bool>(); } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs index 95454c447..5f84a0322 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs @@ -1,13 +1,10 @@ using System; -using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; using Microsoft.Extensions.Logging; @@ -19,17 +16,13 @@ namespace MediaBrowser.MediaEncoding.Encoder private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly IMediaSourceManager _mediaSourceManager; - private readonly IConfigurationManager _config; private readonly IMediaEncoder _mediaEncoder; - protected static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - public EncodingJobFactory(ILogger logger, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager, IConfigurationManager config, IMediaEncoder mediaEncoder) + public EncodingJobFactory(ILogger logger, ILibraryManager libraryManager, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder) { _logger = logger; _libraryManager = libraryManager; _mediaSourceManager = mediaSourceManager; - _config = config; _mediaEncoder = mediaEncoder; } @@ -118,11 +111,11 @@ namespace MediaBrowser.MediaEncoding.Encoder if (state.OutputVideoBitrate.HasValue) { var resolution = ResolutionNormalizer.Normalize( - state.VideoStream == null ? (int?)null : state.VideoStream.BitRate, - state.VideoStream == null ? (int?)null : state.VideoStream.Width, - state.VideoStream == null ? (int?)null : state.VideoStream.Height, + state.VideoStream?.BitRate, + state.VideoStream?.Width, + state.VideoStream?.Height, state.OutputVideoBitrate.Value, - state.VideoStream == null ? null : state.VideoStream.Codec, + state.VideoStream?.Codec, state.OutputVideoCodec, videoRequest.MaxWidth, videoRequest.MaxHeight); @@ -144,40 +137,6 @@ namespace MediaBrowser.MediaEncoding.Encoder return state; } - protected EncodingOptions GetEncodingOptions() - { - return _config.GetConfiguration<EncodingOptions>("encoding"); - } - - /// <summary> - /// Infers the video codec. - /// </summary> - /// <param name="container">The container.</param> - /// <returns>System.Nullable{VideoCodecs}.</returns> - private static string InferVideoCodec(string container) - { - var ext = "." + (container ?? string.Empty); - - if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase)) - { - return "wmv"; - } - if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase)) - { - return "vpx"; - } - if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase)) - { - return "theora"; - } - if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase)) - { - return "h264"; - } - - return "copy"; - } - private string InferAudioCodec(string container) { var ext = "." + (container ?? string.Empty); @@ -186,31 +145,19 @@ namespace MediaBrowser.MediaEncoding.Encoder { return "mp3"; } - if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(ext, ".aac", StringComparison.OrdinalIgnoreCase)) { return "aac"; } - if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(ext, ".wma", StringComparison.OrdinalIgnoreCase)) { return "wma"; } - if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase)) - { - return "vorbis"; - } - if (string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase)) - { - return "vorbis"; - } - if (string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase)) - { - return "vorbis"; - } - if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase)) - { - return "vorbis"; - } - if (string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) + || string.Equals(ext, ".oga", StringComparison.OrdinalIgnoreCase) + || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase) + || string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase) + || string.Equals(ext, ".webma", StringComparison.OrdinalIgnoreCase)) { return "vorbis"; } @@ -218,35 +165,6 @@ namespace MediaBrowser.MediaEncoding.Encoder return "copy"; } - /// <summary> - /// Determines whether the specified stream is H264. - /// </summary> - /// <param name="stream">The stream.</param> - /// <returns><c>true</c> if the specified stream is H264; otherwise, <c>false</c>.</returns> - protected bool IsH264(MediaStream stream) - { - var codec = stream.Codec ?? string.Empty; - - return codec.IndexOf("264", StringComparison.OrdinalIgnoreCase) != -1 || - codec.IndexOf("avc", StringComparison.OrdinalIgnoreCase) != -1; - } - - private static int GetVideoProfileScore(string profile) - { - var list = new List<string> - { - "Constrained Baseline", - "Baseline", - "Extended", - "Main", - "High", - "Progressive High", - "Constrained High" - }; - - return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase)); - } - private void ApplyDeviceProfileSettings(EncodingJob state) { var profile = state.Options.DeviceProfile; |
