From bda2c81dab2a1df11ba853a34e047a5be41e0827 Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Fri, 10 Aug 2012 23:13:56 -0400 Subject: Reworked audio transcoding to output directly to response --- MediaBrowser.Api/HttpHandlers/AudioHandler.cs | 230 +++++++++----------------- 1 file changed, 82 insertions(+), 148 deletions(-) (limited to 'MediaBrowser.Api/HttpHandlers') diff --git a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs index 76a48308b9..5bfbfd1a45 100644 --- a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs +++ b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs @@ -1,16 +1,18 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.IO; -using System.Reflection; -using MediaBrowser.Api.Transcoding; -using MediaBrowser.Common.Configuration; +using System.Linq; +using System.Net; +using MediaBrowser.Common.Logging; +using MediaBrowser.Common.Net; using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Controller; using MediaBrowser.Model.Entities; namespace MediaBrowser.Api.HttpHandlers { - public class AudioHandler : StaticFileHandler + public class AudioHandler : BaseHandler { private Audio _LibraryItem; /// @@ -34,68 +36,42 @@ namespace MediaBrowser.Api.HttpHandlers } } - public override string Path + public override bool CompressResponse { get { - return TranscodedPath; + return false; } } - private string _TranscodedPath; - /// - /// Gets the library item that will be played, if any - /// - private string TranscodedPath + protected override bool IsAsyncHandler { get { - if (_TranscodedPath == null) - { - string originalMediaPath = LibraryItem == null ? base.Path : LibraryItem.Path; - - if (!RequiresTranscoding()) - { - _TranscodedPath = originalMediaPath; - } - else - { - string outputPath = GetOutputFilePath(originalMediaPath); - - // Find the job in the list - TranscodingJob job = ApiService.GetTranscodingJob(outputPath); - - if (job == null && !File.Exists(outputPath)) - { - job = GetNewTranscodingJob(originalMediaPath, outputPath); - job.Start(); - } - - if (job != null) - { - job.WaitForExit(); - } - - _TranscodedPath = outputPath; - } - } + return true; + } + } - return _TranscodedPath; + public override string ContentType + { + get + { + return MimeTypes.GetMimeType("." + GetOutputFormat()); } } - public string AudioFormat + public IEnumerable AudioFormats { get { - string val = QueryString["audiobitrate"]; + string val = QueryString["audioformat"]; if (string.IsNullOrEmpty(val)) { - return "mp3"; + return new string[] { "mp3" }; } - return val; + return val.Split(','); } } @@ -114,7 +90,7 @@ namespace MediaBrowser.Api.HttpHandlers } } - public int? NumAudioChannels + public int? AudioChannels { get { @@ -144,87 +120,17 @@ namespace MediaBrowser.Api.HttpHandlers } } - private static string _StreamsDirectory = null; - /// - /// Gets the folder path to where transcodes will be cached - /// - public static string StreamsDirectory - { - get - { - if (_StreamsDirectory == null) - { - _StreamsDirectory = System.IO.Path.Combine(ApplicationPaths.ProgramDataPath, "streams"); - - if (!Directory.Exists(_StreamsDirectory)) - { - Directory.CreateDirectory(_StreamsDirectory); - } - } - - return _StreamsDirectory; - } - } - - 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; - } - } - - private static string FFMpegPath + public override void ProcessRequest(HttpListenerContext ctx) { - get - { - return System.IO.Path.Combine(FFMpegDirectory, "ffmpeg.exe"); - } - } + HttpListenerContext = ctx; - private string GetOutputFilePath(string input) - { - string hash = Kernel.GetMD5(input).ToString(); - - if (AudioBitRate.HasValue) + if (!RequiresTranscoding()) { - hash += "_ab" + AudioBitRate; + new StaticFileHandler() { Path = LibraryItem.Path }.ProcessRequest(ctx); + return; } - if (NumAudioChannels.HasValue) - { - hash += "_ac" + NumAudioChannels; - } - if (AudioSampleRate.HasValue) - { - hash += "_ar" + AudioSampleRate; - } - - string filename = hash + "." + AudioFormat.ToLower(); - return System.IO.Path.Combine(StreamsDirectory, filename); + base.ProcessRequest(ctx); } /// @@ -232,14 +138,8 @@ namespace MediaBrowser.Api.HttpHandlers /// private bool RequiresTranscoding() { - // Only support skipping transcoding for library items - if (LibraryItem == null) - { - return true; - } - - // If it's not in the same format, we need to transcode - if (!LibraryItem.Path.EndsWith(AudioFormat, StringComparison.OrdinalIgnoreCase)) + // If it's not in a format the consumer accepts, return true + if (!AudioFormats.Any(f => LibraryItem.Path.EndsWith(f, StringComparison.OrdinalIgnoreCase))) { return true; } @@ -254,9 +154,9 @@ namespace MediaBrowser.Api.HttpHandlers } // If the number of channels is greater than our desired channels, we need to transcode - if (NumAudioChannels.HasValue) + if (AudioChannels.HasValue) { - if (NumAudioChannels.Value < LibraryItem.Channels) + if (AudioChannels.Value < LibraryItem.Channels) { return true; } @@ -270,29 +170,27 @@ namespace MediaBrowser.Api.HttpHandlers return true; } } - + // Yay return false; } - /// - /// Creates a new transcoding job - /// - private TranscodingJob GetNewTranscodingJob(string input, string output) + private string GetOutputFormat() { - return new TranscodingJob() + string format = AudioFormats.FirstOrDefault(f => LibraryItem.Path.EndsWith(f, StringComparison.OrdinalIgnoreCase)); + + if (!string.IsNullOrWhiteSpace(format)) { - InputFile = input, - OutputFile = output, - TranscoderPath = FFMpegPath, - Arguments = GetAudioArguments(input, output) - }; + return format; + } + + return AudioFormats.First(); } /// /// Creates arguments to pass to ffmpeg /// - private string GetAudioArguments(string input, string output) + private string GetAudioArguments() { List audioTranscodeParams = new List(); @@ -301,9 +199,9 @@ namespace MediaBrowser.Api.HttpHandlers audioTranscodeParams.Add("-ab " + AudioBitRate.Value); } - if (NumAudioChannels.HasValue) + if (AudioChannels.HasValue) { - audioTranscodeParams.Add("-ac " + NumAudioChannels.Value); + audioTranscodeParams.Add("-ac " + AudioChannels.Value); } if (AudioSampleRate.HasValue) @@ -311,9 +209,45 @@ namespace MediaBrowser.Api.HttpHandlers audioTranscodeParams.Add("-ar " + AudioSampleRate.Value); } - audioTranscodeParams.Add("-f " + AudioFormat); + audioTranscodeParams.Add("-f " + GetOutputFormat()); + + return "-i \"" + LibraryItem.Path + "\" -vn " + string.Join(" ", audioTranscodeParams.ToArray()) + " -"; + } + + protected async override void WriteResponseToOutputStream(Stream stream) + { + ProcessStartInfo startInfo = new ProcessStartInfo(); + + startInfo.CreateNoWindow = true; + + startInfo.UseShellExecute = false; + startInfo.RedirectStandardOutput = true; - return "-i \"" + input + "\" -vn " + string.Join(" ", audioTranscodeParams.ToArray()) + " \"" + output + "\""; + startInfo.FileName = ApiService.FFMpegPath; + startInfo.WorkingDirectory = ApiService.FFMpegDirectory; + startInfo.Arguments = GetAudioArguments(); + + Logger.LogInfo("Audio Handler Transcode: " + ApiService.FFMpegPath + " " + 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 + { + DisposeResponseStream(); + + process.Dispose(); + } } } } -- cgit v1.2.3