diff --git a/MediaBrowser.Api/ApiService.cs b/MediaBrowser.Api/ApiService.cs index 852c4e7db6..c14705be67 100644 --- a/MediaBrowser.Api/ApiService.cs +++ b/MediaBrowser.Api/ApiService.cs @@ -13,45 +13,6 @@ namespace MediaBrowser.Api /// public static class ApiService { - private static string _FFMpegDirectory = null; - /// - /// Gets the folder path to ffmpeg - /// - public static string FFMpegDirectory - { - get - { - if (_FFMpegDirectory == null) - { - _FFMpegDirectory = System.IO.Path.Combine(ApplicationPaths.ProgramDataPath, "ffmpeg"); - - if (!Directory.Exists(_FFMpegDirectory)) - { - Directory.CreateDirectory(_FFMpegDirectory); - - // Extract ffmpeg - using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MediaBrowser.Api.ffmpeg.ffmpeg.exe")) - { - using (FileStream fileStream = new FileStream(FFMpegPath, FileMode.Create)) - { - stream.CopyTo(fileStream); - } - } - } - } - - return _FFMpegDirectory; - } - } - - public static string FFMpegPath - { - get - { - return System.IO.Path.Combine(FFMpegDirectory, "ffmpeg.exe"); - } - } - public static BaseItem GetItemById(string id) { Guid guid = string.IsNullOrEmpty(id) ? Guid.Empty : new Guid(id); @@ -138,5 +99,58 @@ namespace MediaBrowser.Api return null; } + + private static string _FFMpegDirectory = null; + /// + /// Gets the folder path to ffmpeg + /// + public static string FFMpegDirectory + { + get + { + if (_FFMpegDirectory == null) + { + _FFMpegDirectory = System.IO.Path.Combine(ApplicationPaths.ProgramDataPath, "ffmpeg"); + + if (!Directory.Exists(_FFMpegDirectory)) + { + Directory.CreateDirectory(_FFMpegDirectory); + } + } + + return _FFMpegDirectory; + } + } + + private static string _FFMpegPath = null; + /// + /// Gets the path to ffmpeg.exe + /// + public static string FFMpegPath + { + get + { + if (_FFMpegPath == null) + { + string filename = "ffmpeg.exe"; + + _FFMpegPath = Path.Combine(FFMpegDirectory, filename); + + if (!File.Exists(_FFMpegPath)) + { + // Extract ffprobe + using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MediaBrowser.Api.FFMpeg." + filename)) + { + using (FileStream fileStream = new FileStream(_FFMpegPath, FileMode.Create)) + { + stream.CopyTo(fileStream); + } + } + } + } + + return _FFMpegPath; + } + } } } diff --git a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs index f3839a8922..294a5b7afc 100644 --- a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs @@ -105,7 +105,7 @@ namespace MediaBrowser.Api.HttpHandlers /// /// Creates arguments to pass to ffmpeg /// - private string GetAudioArguments() + protected override string GetCommandLineArguments() { List audioTranscodeParams = new List(); @@ -132,40 +132,6 @@ namespace MediaBrowser.Api.HttpHandlers return "-i \"" + LibraryItem.Path + "\" -vn " + string.Join(" ", audioTranscodeParams.ToArray()) + " -"; } - - protected async override Task WriteResponseToOutputStream(Stream stream) - { - ProcessStartInfo startInfo = new ProcessStartInfo(); - - startInfo.CreateNoWindow = true; - - startInfo.UseShellExecute = false; - startInfo.RedirectStandardOutput = true; - - startInfo.FileName = ApiService.FFMpegPath; - startInfo.WorkingDirectory = ApiService.FFMpegDirectory; - startInfo.Arguments = GetAudioArguments(); - - Logger.LogInfo(startInfo.FileName + " " + startInfo.Arguments); - - Process process = new Process(); - process.StartInfo = startInfo; - - try - { - process.Start(); - - await process.StandardOutput.BaseStream.CopyToAsync(stream); - } - catch (Exception ex) - { - Logger.LogException(ex); - } - finally - { - process.Dispose(); - } - } } public abstract class BaseMediaHandler : BaseHandler @@ -252,7 +218,48 @@ namespace MediaBrowser.Api.HttpHandlers base.ProcessRequest(ctx); } + protected abstract string GetCommandLineArguments(); protected abstract string GetOutputFormat(); protected abstract bool RequiresConversion(); + + protected async override Task WriteResponseToOutputStream(Stream stream) + { + ProcessStartInfo startInfo = new ProcessStartInfo(); + + startInfo.CreateNoWindow = true; + + startInfo.UseShellExecute = false; + startInfo.RedirectStandardOutput = true; + startInfo.RedirectStandardError = true; + + startInfo.FileName = ApiService.FFMpegPath; + startInfo.WorkingDirectory = ApiService.FFMpegDirectory; + startInfo.Arguments = GetCommandLineArguments(); + + Logger.LogInfo(startInfo.FileName + " " + startInfo.Arguments); + + Process process = new Process(); + process.StartInfo = startInfo; + + try + { + process.Start(); + + // MUST read both stdout and stderr asynchronously or a deadlock may occurr + process.BeginErrorReadLine(); + + await process.StandardOutput.BaseStream.CopyToAsync(stream); + + process.WaitForExit(); + } + catch (Exception ex) + { + Logger.LogException(ex); + } + finally + { + process.Dispose(); + } + } } } diff --git a/MediaBrowser.Api/HttpHandlers/VideoHandler.cs b/MediaBrowser.Api/HttpHandlers/VideoHandler.cs index f94b8fc311..1b5c50c38a 100644 --- a/MediaBrowser.Api/HttpHandlers/VideoHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/VideoHandler.cs @@ -1,20 +1,14 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; using System.Linq; -using System.Net; -using System.Threading.Tasks; -using MediaBrowser.Common.Logging; -using MediaBrowser.Common.Net; -using MediaBrowser.Common.Net.Handlers; -using MediaBrowser.Controller; using MediaBrowser.Model.Entities; namespace MediaBrowser.Api.HttpHandlers { class VideoHandler : BaseMediaHandler