aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukePulverenti Luke Pulverenti luke pulverenti <LukePulverenti Luke Pulverenti luke.pulverenti@gmail.com>2012-08-11 14:07:07 -0400
committerLukePulverenti Luke Pulverenti luke pulverenti <LukePulverenti Luke Pulverenti luke.pulverenti@gmail.com>2012-08-11 14:07:07 -0400
commit24d2c441b3d265026ee77297ea4b7a3ffb47918b (patch)
treebdea0879028a40c597c3d1836e7326d00f9d1b6d
parent51227bef6fb1f7ebd4dbb599e9c1692f3fb2e981 (diff)
Re-worked async actions in BaseHandler, and changed AudioBitRate to AudioBitRates.
-rw-r--r--MediaBrowser.Api/HttpHandlers/AudioHandler.cs244
-rw-r--r--MediaBrowser.Api/HttpHandlers/ImageHandler.cs8
-rw-r--r--MediaBrowser.Api/HttpHandlers/JsonHandler.cs8
-rw-r--r--MediaBrowser.Api/HttpHandlers/VideoHandler.cs62
-rw-r--r--MediaBrowser.Api/MediaBrowser.Api.csproj4
-rw-r--r--MediaBrowser.Api/Plugin.cs4
-rw-r--r--MediaBrowser.Api/ffmpeg/readme.txt3
-rw-r--r--MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs5
-rw-r--r--MediaBrowser.Common/Net/Handlers/BaseHandler.cs37
-rw-r--r--MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs12
10 files changed, 224 insertions, 163 deletions
diff --git a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs
index a4afe1a1d..61f6e7fbc 100644
--- a/MediaBrowser.Api/HttpHandlers/AudioHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/AudioHandler.cs
@@ -4,6 +4,7 @@ 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;
@@ -12,54 +13,8 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Api.HttpHandlers
{
- public class AudioHandler : BaseHandler
+ public class AudioHandler : BaseMediaHandler<Audio>
{
- private Audio _LibraryItem;
- /// <summary>
- /// Gets the library item that will be played, if any
- /// </summary>
- private Audio LibraryItem
- {
- get
- {
- if (_LibraryItem == null)
- {
- string id = QueryString["id"];
-
- if (!string.IsNullOrEmpty(id))
- {
- _LibraryItem = Kernel.Instance.GetItemById(Guid.Parse(id)) as Audio;
- }
- }
-
- return _LibraryItem;
- }
- }
-
- public override bool CompressResponse
- {
- get
- {
- return false;
- }
- }
-
- protected override bool IsAsyncHandler
- {
- get
- {
- return true;
- }
- }
-
- public override string ContentType
- {
- get
- {
- return MimeTypes.GetMimeType("." + GetOutputFormat());
- }
- }
-
public IEnumerable<string> AudioFormats
{
get
@@ -75,115 +30,70 @@ namespace MediaBrowser.Api.HttpHandlers
}
}
- public int? AudioBitRate
+ public IEnumerable<int> AudioBitRates
{
get
{
- string val = QueryString["audiobitrate"];
-
- if (string.IsNullOrEmpty(val))
- {
- return null;
- }
-
- return int.Parse(val);
- }
- }
-
- public int? AudioChannels
- {
- get
- {
- string val = QueryString["audiochannels"];
-
- if (string.IsNullOrEmpty(val))
- {
- return null;
- }
-
- return int.Parse(val);
- }
- }
-
- public int? AudioSampleRate
- {
- get
- {
- string val = QueryString["audiosamplerate"];
+ string val = QueryString["audioformats"];
if (string.IsNullOrEmpty(val))
{
- return 44100;
+ return new int[] { };
}
- return int.Parse(val);
+ return val.Split(',').Select(v => int.Parse(v));
}
}
- public override void ProcessRequest(HttpListenerContext ctx)
+ private int? GetMaxAcceptedBitRate(string audioFormat)
{
- HttpListenerContext = ctx;
-
- if (!RequiresTranscoding())
- {
- new StaticFileHandler() { Path = LibraryItem.Path }.ProcessRequest(ctx);
- return;
- }
+ int index = AudioFormats.ToList().IndexOf(audioFormat);
- base.ProcessRequest(ctx);
+ return AudioBitRates.ElementAtOrDefault(index);
}
/// <summary>
/// Determines whether or not the original file requires transcoding
/// </summary>
- private bool RequiresTranscoding()
+ protected override bool RequiresConversion()
{
+ string currentFormat = Path.GetExtension(LibraryItem.Path).Replace(".", string.Empty);
+
// If it's not in a format the consumer accepts, return true
- if (!AudioFormats.Any(f => LibraryItem.Path.EndsWith(f, StringComparison.OrdinalIgnoreCase)))
+ if (!AudioFormats.Any(f => currentFormat.EndsWith(f, StringComparison.OrdinalIgnoreCase)))
{
return true;
}
+ int? bitrate = GetMaxAcceptedBitRate(currentFormat);
+
// If the bitrate is greater than our desired bitrate, we need to transcode
- if (AudioBitRate.HasValue)
+ if (bitrate.HasValue && bitrate.Value < LibraryItem.BitRate)
{
- if (AudioBitRate.Value < LibraryItem.BitRate)
- {
- return true;
- }
+ return true;
}
// If the number of channels is greater than our desired channels, we need to transcode
- if (AudioChannels.HasValue)
+ if (AudioChannels.HasValue && AudioChannels.Value < LibraryItem.Channels)
{
- if (AudioChannels.Value < LibraryItem.Channels)
- {
- return true;
- }
+ return true;
}
// If the sample rate is greater than our desired sample rate, we need to transcode
- if (AudioSampleRate.HasValue)
+ if (AudioSampleRate.HasValue && AudioSampleRate.Value < LibraryItem.SampleRate)
{
- if (AudioSampleRate.Value < LibraryItem.SampleRate)
- {
- return true;
- }
+ return true;
}
// Yay
return false;
}
- private string GetOutputFormat()
+ /// <summary>
+ /// Gets the format we'll be converting to
+ /// </summary>
+ protected override string GetOutputFormat()
{
- string format = AudioFormats.FirstOrDefault(f => LibraryItem.Path.EndsWith(f, StringComparison.OrdinalIgnoreCase));
-
- if (!string.IsNullOrWhiteSpace(format))
- {
- return format;
- }
-
return AudioFormats.First();
}
@@ -194,9 +104,13 @@ namespace MediaBrowser.Api.HttpHandlers
{
List<string> audioTranscodeParams = new List<string>();
- if (AudioBitRate.HasValue)
+ string outputFormat = GetOutputFormat();
+
+ int? bitrate = GetMaxAcceptedBitRate(outputFormat);
+
+ if (bitrate.HasValue)
{
- audioTranscodeParams.Add("-ab " + AudioBitRate.Value);
+ audioTranscodeParams.Add("-ab " + bitrate.Value);
}
if (AudioChannels.HasValue)
@@ -209,12 +123,12 @@ namespace MediaBrowser.Api.HttpHandlers
audioTranscodeParams.Add("-ar " + AudioSampleRate.Value);
}
- audioTranscodeParams.Add("-f " + GetOutputFormat());
+ audioTranscodeParams.Add("-f " + outputFormat);
return "-i \"" + LibraryItem.Path + "\" -vn " + string.Join(" ", audioTranscodeParams.ToArray()) + " -";
}
- protected async override void WriteResponseToOutputStream(Stream stream)
+ protected async override Task WriteResponseToOutputStream(Stream stream)
{
ProcessStartInfo startInfo = new ProcessStartInfo();
@@ -227,7 +141,7 @@ namespace MediaBrowser.Api.HttpHandlers
startInfo.WorkingDirectory = ApiService.FFMpegDirectory;
startInfo.Arguments = GetAudioArguments();
- Logger.LogInfo("Audio Handler Transcode: " + ApiService.FFMpegPath + " " + startInfo.Arguments);
+ Logger.LogInfo(startInfo.FileName + " " + startInfo.Arguments);
Process process = new Process();
process.StartInfo = startInfo;
@@ -244,10 +158,96 @@ namespace MediaBrowser.Api.HttpHandlers
}
finally
{
- DisposeResponseStream();
-
process.Dispose();
}
}
}
+
+ public abstract class BaseMediaHandler<T> : BaseHandler
+ where T : BaseItem, new()
+ {
+ private T _LibraryItem;
+ /// <summary>
+ /// Gets the library item that will be played, if any
+ /// </summary>
+ protected T LibraryItem
+ {
+ get
+ {
+ if (_LibraryItem == null)
+ {
+ string id = QueryString["id"];
+
+ if (!string.IsNullOrEmpty(id))
+ {
+ _LibraryItem = Kernel.Instance.GetItemById(Guid.Parse(id)) as T;
+ }
+ }
+
+ return _LibraryItem;
+ }
+ }
+
+ public int? AudioChannels
+ {
+ get
+ {
+ string val = QueryString["audiochannels"];
+
+ if (string.IsNullOrEmpty(val))
+ {
+ return null;
+ }
+
+ return int.Parse(val);
+ }
+ }
+
+ public int? AudioSampleRate
+ {
+ get
+ {
+ string val = QueryString["audiosamplerate"];
+
+ if (string.IsNullOrEmpty(val))
+ {
+ return 44100;
+ }
+
+ return int.Parse(val);
+ }
+ }
+
+ public override string ContentType
+ {
+ get
+ {
+ return MimeTypes.GetMimeType("." + GetOutputFormat());
+ }
+ }
+
+ public override bool CompressResponse
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public override void ProcessRequest(HttpListenerContext ctx)
+ {
+ HttpListenerContext = ctx;
+
+ if (!RequiresConversion())
+ {
+ new StaticFileHandler() { Path = LibraryItem.Path }.ProcessRequest(ctx);
+ return;
+ }
+
+ base.ProcessRequest(ctx);
+ }
+
+ protected abstract string GetOutputFormat();
+ protected abstract bool RequiresConversion();
+ }
}
diff --git a/MediaBrowser.Api/HttpHandlers/ImageHandler.cs b/MediaBrowser.Api/HttpHandlers/ImageHandler.cs
index 0427a2d06..c5e5d2c86 100644
--- a/MediaBrowser.Api/HttpHandlers/ImageHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/ImageHandler.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.Entities;
@@ -148,9 +149,12 @@ namespace MediaBrowser.Api.HttpHandlers
}
}
- protected override void WriteResponseToOutputStream(Stream stream)
+ protected override Task WriteResponseToOutputStream(Stream stream)
{
- ImageProcessor.ProcessImage(ImagePath, stream, Width, Height, MaxWidth, MaxHeight, Quality);
+ return Task.Run(() =>
+ {
+ ImageProcessor.ProcessImage(ImagePath, stream, Width, Height, MaxWidth, MaxHeight, Quality);
+ });
}
private string GetImagePath()
diff --git a/MediaBrowser.Api/HttpHandlers/JsonHandler.cs b/MediaBrowser.Api/HttpHandlers/JsonHandler.cs
index 06ce4c2d4..bffa84174 100644
--- a/MediaBrowser.Api/HttpHandlers/JsonHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/JsonHandler.cs
@@ -1,4 +1,5 @@
using System.IO;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Common.Serialization;
@@ -8,9 +9,12 @@ namespace MediaBrowser.Api.HttpHandlers
{
protected abstract object ObjectToSerialize { get; }
- protected override void WriteResponseToOutputStream(Stream stream)
+ protected override Task WriteResponseToOutputStream(Stream stream)
{
- JsonSerializer.SerializeToStream(ObjectToSerialize, stream);
+ return Task.Run(() =>
+ {
+ JsonSerializer.SerializeToStream(ObjectToSerialize, stream);
+ });
}
}
}
diff --git a/MediaBrowser.Api/HttpHandlers/VideoHandler.cs b/MediaBrowser.Api/HttpHandlers/VideoHandler.cs
new file mode 100644
index 000000000..f94b8fc31
--- /dev/null
+++ b/MediaBrowser.Api/HttpHandlers/VideoHandler.cs
@@ -0,0 +1,62 @@
+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<Video>
+ {
+ public IEnumerable<string> VideoFormats
+ {
+ get
+ {
+ return QueryString["videoformats"].Split(',');
+ }
+ }
+
+ /// <summary>
+ /// Gets the format we'll be converting to
+ /// </summary>
+ protected override string GetOutputFormat()
+ {
+ return VideoFormats.First();
+ }
+
+ protected override bool RequiresConversion()
+ {
+ // If it's not in a format the consumer accepts, return true
+ if (!VideoFormats.Any(f => LibraryItem.Path.EndsWith(f, StringComparison.OrdinalIgnoreCase)))
+ {
+ return true;
+ }
+
+ AudioStream audio = LibraryItem.AudioStreams.FirstOrDefault();
+
+ if (audio != null)
+ {
+ // If the number of channels is greater than our desired channels, we need to transcode
+ if (AudioChannels.HasValue && AudioChannels.Value < audio.Channels)
+ {
+ return true;
+ }
+ }
+
+ // Yay
+ return false;
+ }
+
+ protected override Task WriteResponseToOutputStream(Stream stream)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index 83ab5a7ee..c628d01d9 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -63,6 +63,7 @@
<Compile Include="HttpHandlers\StudiosHandler.cs" />
<Compile Include="HttpHandlers\UserConfigurationHandler.cs" />
<Compile Include="HttpHandlers\UsersHandler.cs" />
+ <Compile Include="HttpHandlers\VideoHandler.cs" />
<Compile Include="ImageProcessor.cs" />
<Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -87,6 +88,9 @@
<ItemGroup>
<EmbeddedResource Include="ffmpeg\ffmpeg.exe" />
</ItemGroup>
+ <ItemGroup>
+ <Content Include="ffmpeg\readme.txt" />
+ </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>xcopy "$(TargetPath)" "$(SolutionDir)\ProgramData\Plugins\$(ProjectName)\" /y</PostBuildEvent>
diff --git a/MediaBrowser.Api/Plugin.cs b/MediaBrowser.Api/Plugin.cs
index 02546c693..353325316 100644
--- a/MediaBrowser.Api/Plugin.cs
+++ b/MediaBrowser.Api/Plugin.cs
@@ -93,6 +93,10 @@ namespace MediaBrowser.Api
{
return new AudioHandler();
}
+ else if (localPath.EndsWith("/api/video", StringComparison.OrdinalIgnoreCase))
+ {
+ return new VideoHandler();
+ }
return null;
}
diff --git a/MediaBrowser.Api/ffmpeg/readme.txt b/MediaBrowser.Api/ffmpeg/readme.txt
new file mode 100644
index 000000000..cdb039bdc
--- /dev/null
+++ b/MediaBrowser.Api/ffmpeg/readme.txt
@@ -0,0 +1,3 @@
+This is the 32-bit static build of ffmpeg, located at:
+
+http://ffmpeg.zeranoe.com/builds/ \ No newline at end of file
diff --git a/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs
index d8347db30..2fcead05b 100644
--- a/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs
+++ b/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using System.Threading.Tasks;
namespace MediaBrowser.Common.Net.Handlers
{
@@ -48,9 +49,9 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
- protected override void WriteResponseToOutputStream(Stream stream)
+ protected override Task WriteResponseToOutputStream(Stream stream)
{
- GetEmbeddedResourceStream().CopyTo(stream);
+ return GetEmbeddedResourceStream().CopyToAsync(stream);
}
protected abstract Stream GetEmbeddedResourceStream();
diff --git a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs
index 120d2ce7b..89803d8d7 100644
--- a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs
+++ b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs
@@ -5,6 +5,7 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
+using System.Threading.Tasks;
using MediaBrowser.Common.Logging;
namespace MediaBrowser.Common.Net.Handlers
@@ -36,18 +37,6 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
- /// <summary>
- /// Returns true or false indicating if the handler writes to the stream asynchronously.
- /// If so the subclass will be responsible for disposing the stream when complete.
- /// </summary>
- protected virtual bool IsAsyncHandler
- {
- get
- {
- return false;
- }
- }
-
protected virtual bool SupportsByteRangeRequests
{
get
@@ -246,7 +235,7 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
- private void ProcessUncachedResponse(HttpListenerContext ctx, TimeSpan cacheDuration)
+ private async void ProcessUncachedResponse(HttpListenerContext ctx, TimeSpan cacheDuration)
{
long? totalContentLength = TotalContentLength;
@@ -277,8 +266,6 @@ namespace MediaBrowser.Common.Net.Handlers
CacheResponse(ctx.Response, cacheDuration, LastDateModified);
}
- PrepareUncachedResponse(ctx, cacheDuration);
-
// Set the status code
ctx.Response.StatusCode = StatusCode;
@@ -301,9 +288,15 @@ namespace MediaBrowser.Common.Net.Handlers
outputStream = CompressedStream;
}
- WriteResponseToOutputStream(outputStream);
-
- if (!IsAsyncHandler)
+ try
+ {
+ await WriteResponseToOutputStream(outputStream);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogException(ex);
+ }
+ finally
{
DisposeResponseStream();
}
@@ -315,10 +308,6 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
- protected virtual void PrepareUncachedResponse(HttpListenerContext ctx, TimeSpan cacheDuration)
- {
- }
-
private void CacheResponse(HttpListenerResponse response, TimeSpan duration, DateTime? dateModified)
{
DateTime lastModified = dateModified ?? DateTime.Now;
@@ -328,9 +317,9 @@ namespace MediaBrowser.Common.Net.Handlers
response.Headers[HttpResponseHeader.LastModified] = lastModified.ToString("r");
}
- protected abstract void WriteResponseToOutputStream(Stream stream);
+ protected abstract Task WriteResponseToOutputStream(Stream stream);
- protected void DisposeResponseStream()
+ private void DisposeResponseStream()
{
if (CompressedStream != null)
{
diff --git a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs
index 35d38fb4a..3eb908938 100644
--- a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs
+++ b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs
@@ -117,14 +117,6 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
- protected override bool IsAsyncHandler
- {
- get
- {
- return true;
- }
- }
-
public override string ContentType
{
get
@@ -133,7 +125,7 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
- protected async override void WriteResponseToOutputStream(Stream stream)
+ protected async override Task WriteResponseToOutputStream(Stream stream)
{
try
{
@@ -175,8 +167,6 @@ namespace MediaBrowser.Common.Net.Handlers
{
FileStream.Dispose();
}
-
- DisposeResponseStream();
}
}