diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index fa6f88cc41..c188376fe6 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -825,6 +825,23 @@ namespace MediaBrowser.Api.Playback
return MediaEncoder.GetInputArgument(inputPath, protocol);
}
+ private MediaProtocol GetProtocol(string path)
+ {
+ if (path.StartsWith("Http", StringComparison.OrdinalIgnoreCase))
+ {
+ return MediaProtocol.Http;
+ }
+ if (path.StartsWith("Rtsp", StringComparison.OrdinalIgnoreCase))
+ {
+ return MediaProtocol.Rtsp;
+ }
+ if (path.StartsWith("Rtmp", StringComparison.OrdinalIgnoreCase))
+ {
+ return MediaProtocol.Rtmp;
+ }
+ return MediaProtocol.File;
+ }
+
private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource)
{
if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath))
@@ -845,16 +862,15 @@ namespace MediaBrowser.Api.Playback
if (!string.IsNullOrEmpty(streamInfo.Path))
{
state.MediaPath = streamInfo.Path;
- state.InputProtocol = MediaProtocol.File;
-
- await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
}
else if (!string.IsNullOrEmpty(streamInfo.Url))
{
state.MediaPath = streamInfo.Url;
- state.InputProtocol = MediaProtocol.Http;
}
+ await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
+
+ state.InputProtocol = GetProtocol(state.MediaPath);
AttachMediaStreamInfo(state, streamInfo.MediaStreams, state.VideoRequest, state.RequestedUrl);
checkCodecs = true;
}
@@ -869,16 +885,15 @@ namespace MediaBrowser.Api.Playback
if (!string.IsNullOrEmpty(streamInfo.Path))
{
state.MediaPath = streamInfo.Path;
- state.InputProtocol = MediaProtocol.File;
-
- await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
}
else if (!string.IsNullOrEmpty(streamInfo.Url))
{
state.MediaPath = streamInfo.Url;
- state.InputProtocol = MediaProtocol.Http;
}
+ await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
+
+ state.InputProtocol = GetProtocol(state.MediaPath);
AttachMediaStreamInfo(state, streamInfo.MediaStreams, state.VideoRequest, state.RequestedUrl);
checkCodecs = true;
}
@@ -991,6 +1006,16 @@ namespace MediaBrowser.Api.Playback
await Task.Delay(100, cancellationTokenSource.Token).ConfigureAwait(false);
}
+ if (state.IsInputVideo && transcodingJob.Type == Api.TranscodingJobType.Progressive)
+ {
+ await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
+
+ if (state.ReadInputAtNativeFramerate)
+ {
+ await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
+ }
+ }
+
return transcodingJob;
}
@@ -1610,11 +1635,6 @@ namespace MediaBrowser.Api.Playback
{
state.InputTimestamp = mediaSource.Timestamp.Value;
}
-
- if (video.IsShortcut)
- {
- state.MediaPath = File.ReadAllText(video.Path);
- }
}
state.RunTimeTicks = mediaSource.RunTimeTicks;
diff --git a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
index caddbd9a13..1150220158 100644
--- a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
+++ b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Common.IO;
+using System.Security;
+using MediaBrowser.Common.IO;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
@@ -41,7 +42,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// The segment id.
public string SegmentId { get; set; }
}
-
+
public class MpegDashService : BaseHlsService
{
protected INetworkManager NetworkManager { get; private set; }
@@ -104,8 +105,9 @@ namespace MediaBrowser.Api.Playback.Hls
var duration = "PT0H02M11.00S";
+ builder.Append("");
builder.AppendFormat(
- "",
+ "",
duration,
state.SegmentLength.ToString(CultureInfo.InvariantCulture));
@@ -116,9 +118,13 @@ namespace MediaBrowser.Api.Playback.Hls
builder.Append("");
builder.Append("");
- builder.Append("");
- builder.Append(GetRepresentationOpenElement(state));
+ var lang = state.AudioStream != null ? state.AudioStream.Language : null;
+ if (string.IsNullOrWhiteSpace(lang)) lang = "und";
+
+ builder.AppendFormat("", lang);
+
+ builder.Append(GetRepresentationOpenElement(state, lang));
AppendSegmentList(state, builder);
@@ -131,10 +137,97 @@ namespace MediaBrowser.Api.Playback.Hls
return builder.ToString();
}
- private string GetRepresentationOpenElement(StreamState state)
+ private string GetRepresentationOpenElement(StreamState state, string language)
{
- return
- "";
+ var codecs = GetVideoCodecDescriptor(state) + "," + GetAudioCodecDescriptor(state);
+
+ var xml = "";
+
+ return xml;
+ }
+
+ private string GetVideoCodecDescriptor(StreamState state)
+ {
+ // https://developer.apple.com/library/ios/documentation/networkinginternet/conceptual/streamingmediaguide/FrequentlyAskedQuestions/FrequentlyAskedQuestions.html
+
+ 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.42001e";
+ }
+
+ 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";
}
public object Get(GetDashSegment request)
@@ -147,7 +240,7 @@ namespace MediaBrowser.Api.Playback.Hls
var seconds = TimeSpan.FromTicks(state.RunTimeTicks ?? 0).TotalSeconds;
builder.Append("");
-
+
var queryStringIndex = Request.RawUrl.IndexOf('?');
var queryString = queryStringIndex == -1 ? string.Empty : Request.RawUrl.Substring(queryStringIndex);
@@ -155,7 +248,7 @@ namespace MediaBrowser.Api.Playback.Hls
while (seconds > 0)
{
- builder.AppendFormat("", index.ToString(UsCulture), queryString);
+ builder.AppendFormat("", index.ToString(UsCulture), SecurityElement.Escape(queryString));
seconds -= state.SegmentLength;
index++;