diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj
index cdc0cd6ae..db8961a66 100644
--- a/MediaBrowser.Api/MediaBrowser.Api.csproj
+++ b/MediaBrowser.Api/MediaBrowser.Api.csproj
@@ -80,8 +80,6 @@
-
-
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index 9e9bfd728..dfa279019 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -1026,7 +1026,7 @@ namespace MediaBrowser.Api.Playback
StartStreamingLog(transcodingJob, state, process.StandardError.BaseStream, state.LogFileStream);
// Wait for the file to exist before proceeeding
- while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
+ while (!FileSystem.FileExists(state.WaitForPath ?? outputPath) && !transcodingJob.HasExited)
{
await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
}
@@ -1651,9 +1651,9 @@ namespace MediaBrowser.Api.Playback
if (state.OutputVideoBitrate.HasValue)
{
var resolution = ResolutionNormalizer.Normalize(
- state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
- state.OutputVideoBitrate.Value,
- state.VideoStream == null ? null : state.VideoStream.Codec,
+ state.VideoStream == null ? (int?)null : state.VideoStream.BitRate,
+ state.OutputVideoBitrate.Value,
+ state.VideoStream == null ? null : state.VideoStream.Codec,
state.OutputVideoCodec,
videoRequest.MaxWidth,
videoRequest.MaxHeight);
@@ -1682,7 +1682,7 @@ namespace MediaBrowser.Api.Playback
state.OutputVideoCodec = "copy";
}
- if (state.AudioStream != null && CanStreamCopyAudio(videoRequest, state.AudioStream, state.SupportedAudioCodecs))
+ if (state.AudioStream != null && CanStreamCopyAudio(state, state.SupportedAudioCodecs))
{
state.OutputAudioCodec = "copy";
}
@@ -1784,7 +1784,7 @@ namespace MediaBrowser.Api.Playback
{
return false;
}
-
+
// Can't stream copy if we're burning in subtitles
if (request.SubtitleStreamIndex.HasValue)
{
@@ -1913,8 +1913,11 @@ namespace MediaBrowser.Api.Playback
return Array.FindIndex(list.ToArray(), t => string.Equals(t, profile, StringComparison.OrdinalIgnoreCase));
}
- protected virtual bool CanStreamCopyAudio(VideoStreamRequest request, MediaStream audioStream, List supportedAudioCodecs)
+ protected virtual bool CanStreamCopyAudio(StreamState state, List supportedAudioCodecs)
{
+ var request = state.VideoRequest;
+ var audioStream = state.AudioStream;
+
// Source and target codecs must match
if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase))
{
@@ -2213,7 +2216,7 @@ namespace MediaBrowser.Api.Playback
inputModifier += " -noaccurate_seek";
}
}
-
+
return inputModifier;
}
diff --git a/MediaBrowser.Api/Playback/Dash/ManifestBuilder.cs b/MediaBrowser.Api/Playback/Dash/ManifestBuilder.cs
deleted file mode 100644
index 35e252a19..000000000
--- a/MediaBrowser.Api/Playback/Dash/ManifestBuilder.cs
+++ /dev/null
@@ -1,224 +0,0 @@
-using System;
-using System.Globalization;
-using System.Security;
-using System.Text;
-
-namespace MediaBrowser.Api.Playback.Dash
-{
- public class ManifestBuilder
- {
- protected readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- public string GetManifestText(StreamState state, string playlistUrl)
- {
- var builder = new StringBuilder();
-
- var time = TimeSpan.FromTicks(state.RunTimeTicks.Value);
-
- var duration = "PT" + time.Hours.ToString("00", UsCulture) + "H" + time.Minutes.ToString("00", UsCulture) + "M" + time.Seconds.ToString("00", UsCulture) + ".00S";
-
- builder.Append("");
-
- builder.AppendFormat(
- "",
- duration);
-
- builder.Append("");
- builder.Append("");
-
- builder.Append("");
- builder.Append(GetVideoAdaptationSet(state, playlistUrl));
- builder.Append(GetAudioAdaptationSet(state, playlistUrl));
- builder.Append("");
-
- builder.Append("");
-
- return builder.ToString();
- }
-
- private string GetVideoAdaptationSet(StreamState state, string playlistUrl)
- {
- var builder = new StringBuilder();
-
- builder.Append("");
- builder.Append(GetVideoRepresentationOpenElement(state));
-
- AppendSegmentList(state, builder, "0", playlistUrl);
-
- builder.Append("");
- builder.Append("");
-
- return builder.ToString();
- }
-
- private string GetAudioAdaptationSet(StreamState state, string playlistUrl)
- {
- var builder = new StringBuilder();
-
- builder.Append("");
- builder.Append(GetAudioRepresentationOpenElement(state));
-
- builder.Append("");
-
- AppendSegmentList(state, builder, "1", playlistUrl);
-
- builder.Append("");
- builder.Append("");
-
- return builder.ToString();
- }
-
- private string GetVideoRepresentationOpenElement(StreamState state)
- {
- var codecs = GetVideoCodecDescriptor(state);
-
- var mime = "video/mp4";
-
- var xml = "";
-
- return xml;
- }
-
- private string GetAudioRepresentationOpenElement(StreamState state)
- {
- var codecs = GetAudioCodecDescriptor(state);
-
- var mime = "audio/mp4";
-
- var xml = "";
-
- return xml;
- }
-
- private string GetVideoCodecDescriptor(StreamState state)
- {
- // https://developer.apple.com/library/ios/documentation/networkinginternet/conceptual/streamingmediaguide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html
- // http://www.chipwreck.de/blog/2010/02/25/html-5-video-tag-and-attributes/
-
- var level = state.TargetVideoLevel ?? 0;
- var profile = state.TargetVideoProfile ?? string.Empty;
-
- if (profile.IndexOf("high", StringComparison.OrdinalIgnoreCase) != -1)
- {
- if (level >= 4.1)
- {
- return "avc1.640028";
- }
-
- if (level >= 4)
- {
- return "avc1.640028";
- }
-
- return "avc1.64001f";
- }
-
- if (profile.IndexOf("main", StringComparison.OrdinalIgnoreCase) != -1)
- {
- if (level >= 4)
- {
- return "avc1.4d0028";
- }
-
- if (level >= 3.1)
- {
- return "avc1.4d001f";
- }
-
- return "avc1.4d001e";
- }
-
- if (level >= 3.1)
- {
- return "avc1.42001f";
- }
-
- return "avc1.42E01E";
- }
-
- private string GetAudioCodecDescriptor(StreamState state)
- {
- // https://developer.apple.com/library/ios/documentation/networkinginternet/conceptual/streamingmediaguide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html
-
- if (string.Equals(state.OutputAudioCodec, "mp3", StringComparison.OrdinalIgnoreCase))
- {
- return "mp4a.40.34";
- }
-
- // AAC 5ch
- if (state.OutputAudioChannels.HasValue && state.OutputAudioChannels.Value >= 5)
- {
- return "mp4a.40.5";
- }
-
- // AAC 2ch
- return "mp4a.40.2";
- }
-
- private void AppendSegmentList(StreamState state, StringBuilder builder, string type, string playlistUrl)
- {
- var extension = ".m4s";
-
- var seconds = TimeSpan.FromTicks(state.RunTimeTicks ?? 0).TotalSeconds;
-
- var queryStringIndex = playlistUrl.IndexOf('?');
- var queryString = queryStringIndex == -1 ? string.Empty : playlistUrl.Substring(queryStringIndex);
-
- var index = 0;
- var duration = 1000000 * state.SegmentLength;
- builder.AppendFormat("", duration.ToString(CultureInfo.InvariantCulture));
-
- while (seconds > 0)
- {
- var filename = index == 0
- ? "init"
- : (index - 1).ToString(UsCulture);
-
- var segmentUrl = string.Format("dash/{3}/{0}{1}{2}",
- filename,
- extension,
- SecurityElement.Escape(queryString),
- type);
-
- if (index == 0)
- {
- builder.AppendFormat("", segmentUrl);
- }
- else
- {
- builder.AppendFormat("", segmentUrl);
- }
-
- seconds -= state.SegmentLength;
- index++;
- }
- builder.Append("");
- }
- }
-}
diff --git a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs
deleted file mode 100644
index a35d13c5b..000000000
--- a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs
+++ /dev/null
@@ -1,547 +0,0 @@
-using MediaBrowser.Api.Playback.Hls;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Dlna;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
-using ServiceStack;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-using CommonIO;
-using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
-
-namespace MediaBrowser.Api.Playback.Dash
-{
- ///
- /// Options is needed for chromecast. Threw Head in there since it's related
- ///
- [Route("/Videos/{Id}/master.mpd", "GET", Summary = "Gets a video stream using Mpeg dash.")]
- [Route("/Videos/{Id}/master.mpd", "HEAD", Summary = "Gets a video stream using Mpeg dash.")]
- public class GetMasterManifest : VideoStreamRequest
- {
- public bool EnableAdaptiveBitrateStreaming { get; set; }
-
- public GetMasterManifest()
- {
- EnableAdaptiveBitrateStreaming = true;
- }
- }
-
- [Route("/Videos/{Id}/dash/{RepresentationId}/{SegmentId}.m4s", "GET")]
- public class GetDashSegment : VideoStreamRequest
- {
- ///
- /// Gets or sets the segment id.
- ///
- /// The segment id.
- public string SegmentId { get; set; }
-
- ///
- /// Gets or sets the representation identifier.
- ///
- /// The representation identifier.
- public string RepresentationId { get; set; }
- }
-
- public class MpegDashService : BaseHlsService
- {
- public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
- {
- NetworkManager = networkManager;
- }
-
- protected INetworkManager NetworkManager { get; private set; }
-
- public object Get(GetMasterManifest request)
- {
- var result = GetAsync(request, "GET").Result;
-
- return result;
- }
-
- public object Head(GetMasterManifest request)
- {
- var result = GetAsync(request, "HEAD").Result;
-
- return result;
- }
-
- protected override bool EnableOutputInSubFolder
- {
- get
- {
- return true;
- }
- }
-
- private async Task