use server to build initial stream url's

pull/702/head
Luke Pulverenti 9 years ago
parent 46c9210749
commit 348b8c4414

@ -1,8 +1,11 @@
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Session;
using ServiceStack; using ServiceStack;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -13,7 +16,7 @@ using System.Threading.Tasks;
namespace MediaBrowser.Api.Playback namespace MediaBrowser.Api.Playback
{ {
[Route("/Items/{Id}/MediaInfo", "GET", Summary = "Gets live playback media info for an item")] [Route("/Items/{Id}/MediaInfo", "GET", Summary = "Gets live playback media info for an item")]
public class GetLiveMediaInfo : IReturn<LiveMediaInfoResult> public class GetLiveMediaInfo : IReturn<PlaybackInfoResponse>
{ {
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; } public string Id { get; set; }
@ -23,7 +26,17 @@ namespace MediaBrowser.Api.Playback
} }
[Route("/Items/{Id}/PlaybackInfo", "GET", Summary = "Gets live playback media info for an item")] [Route("/Items/{Id}/PlaybackInfo", "GET", Summary = "Gets live playback media info for an item")]
public class GetPlaybackInfo : IReturn<LiveMediaInfoResult> public class GetPlaybackInfo : IReturn<PlaybackInfoResponse>
{
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; }
[ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public string UserId { get; set; }
}
[Route("/Items/{Id}/PlaybackInfo", "POST", Summary = "Gets live playback media info for an item")]
public class GetPostedPlaybackInfo : PlaybackInfoRequest, IReturn<PlaybackInfoResponse>
{ {
[ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
public string Id { get; set; } public string Id { get; set; }
@ -36,26 +49,55 @@ namespace MediaBrowser.Api.Playback
public class MediaInfoService : BaseApiService public class MediaInfoService : BaseApiService
{ {
private readonly IMediaSourceManager _mediaSourceManager; private readonly IMediaSourceManager _mediaSourceManager;
private readonly IDeviceManager _deviceManager;
private readonly ILibraryManager _libraryManager;
public MediaInfoService(IMediaSourceManager mediaSourceManager) public MediaInfoService(IMediaSourceManager mediaSourceManager, IDeviceManager deviceManager, ILibraryManager libraryManager)
{ {
_mediaSourceManager = mediaSourceManager; _mediaSourceManager = mediaSourceManager;
_deviceManager = deviceManager;
_libraryManager = libraryManager;
}
public async Task<object> Get(GetPlaybackInfo request)
{
var result = await GetPlaybackInfo(request.Id, request.UserId).ConfigureAwait(false);
return ToOptimizedResult(result);
} }
public Task<object> Get(GetPlaybackInfo request) public async Task<object> Get(GetLiveMediaInfo request)
{ {
return GetPlaybackInfo(request.Id, request.UserId); var result = await GetPlaybackInfo(request.Id, request.UserId).ConfigureAwait(false);
return ToOptimizedResult(result);
} }
public Task<object> Get(GetLiveMediaInfo request) public async Task<object> Post(GetPostedPlaybackInfo request)
{ {
return GetPlaybackInfo(request.Id, request.UserId); var info = await GetPlaybackInfo(request.Id, request.UserId).ConfigureAwait(false);
var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
var profile = request.DeviceProfile;
//if (profile == null)
//{
// var caps = _deviceManager.GetCapabilities(authInfo.DeviceId);
// if (caps != null)
// {
// profile = caps.DeviceProfile;
// }
//}
if (profile != null)
{
SetDeviceSpecificData(request.Id, info, profile, authInfo, null);
}
return ToOptimizedResult(info);
} }
private async Task<object> GetPlaybackInfo(string id, string userId) private async Task<PlaybackInfoResponse> GetPlaybackInfo(string id, string userId)
{ {
IEnumerable<MediaSourceInfo> mediaSources; IEnumerable<MediaSourceInfo> mediaSources;
var result = new LiveMediaInfoResult(); var result = new PlaybackInfoResponse();
try try
{ {
@ -68,9 +110,89 @@ namespace MediaBrowser.Api.Playback
} }
result.MediaSources = mediaSources.ToList(); result.MediaSources = mediaSources.ToList();
result.StreamId = Guid.NewGuid().ToString("N");
return ToOptimizedResult(result); if (result.MediaSources.Count == 0)
{
if (!result.ErrorCode.HasValue)
{
result.ErrorCode = PlaybackErrorCode.NoCompatibleStream;
}
}
else
{
result.StreamId = Guid.NewGuid().ToString("N");
}
return result;
}
private void SetDeviceSpecificData(string itemId, PlaybackInfoResponse result, DeviceProfile profile, AuthorizationInfo auth, int? maxBitrate)
{
var streamBuilder = new StreamBuilder();
var item = _libraryManager.GetItemById(itemId);
foreach (var mediaSource in result.MediaSources)
{
var options = new VideoOptions
{
MediaSources = new List<MediaSourceInfo> { mediaSource },
Context = EncodingContext.Streaming,
DeviceId = auth.DeviceId,
ItemId = item.Id.ToString("N"),
Profile = profile,
MaxBitrate = maxBitrate
};
if (mediaSource.SupportsDirectPlay)
{
var supportsDirectStream = mediaSource.SupportsDirectStream;
// Dummy this up to fool StreamBuilder
mediaSource.SupportsDirectStream = true;
// The MediaSource supports direct stream, now test to see if the client supports it
var streamInfo = item is Video ?
streamBuilder.BuildVideoItem(options) :
streamBuilder.BuildAudioItem(options);
if (streamInfo == null || !streamInfo.IsDirectStream)
{
mediaSource.SupportsDirectPlay = false;
}
// Set this back to what it was
mediaSource.SupportsDirectStream = supportsDirectStream;
}
if (mediaSource.SupportsDirectStream)
{
// The MediaSource supports direct stream, now test to see if the client supports it
var streamInfo = item is Video ?
streamBuilder.BuildVideoItem(options) :
streamBuilder.BuildAudioItem(options);
if (streamInfo == null || !streamInfo.IsDirectStream)
{
mediaSource.SupportsDirectStream = false;
}
}
if (mediaSource.SupportsTranscoding)
{
// The MediaSource supports direct stream, now test to see if the client supports it
var streamInfo = item is Video ?
streamBuilder.BuildVideoItem(options) :
streamBuilder.BuildAudioItem(options);
if (streamInfo != null && streamInfo.PlayMethod == PlayMethod.Transcode)
{
mediaSource.TranscodingUrl = streamInfo.ToUrl("-", auth.Token).Substring(1);
mediaSource.TranscodingContainer = streamInfo.Container;
mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol;
}
}
}
} }
} }
} }

@ -62,7 +62,8 @@ namespace MediaBrowser.Controller.Channels
RunTimeTicks = RunTimeTicks, RunTimeTicks = RunTimeTicks,
Name = id, Name = id,
Id = id, Id = id,
ReadAtNativeFramerate = ReadAtNativeFramerate ReadAtNativeFramerate = ReadAtNativeFramerate,
SupportsDirectStream = Protocol == MediaProtocol.File || Protocol == MediaProtocol.Http
}; };
var bitrate = (AudioBitrate ?? 0) + (VideoBitrate ?? 0); var bitrate = (AudioBitrate ?? 0) + (VideoBitrate ?? 0);

@ -501,7 +501,8 @@ namespace MediaBrowser.Controller.Entities
Formats = (i.FormatName ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(), Formats = (i.FormatName ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(),
Timestamp = i.Timestamp, Timestamp = i.Timestamp,
Type = type, Type = type,
PlayableStreamFileNames = i.PlayableStreamFileNames.ToList() PlayableStreamFileNames = i.PlayableStreamFileNames.ToList(),
SupportsDirectStream = i.VideoType == VideoType.VideoFile
}; };
if (i.IsShortcut) if (i.IsShortcut)

@ -800,12 +800,15 @@
<Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs"> <Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs">
<Link>MediaInfo\IBlurayExaminer.cs</Link> <Link>MediaInfo\IBlurayExaminer.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\LiveMediaInfoResult.cs">
<Link>MediaInfo\LiveMediaInfoResult.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs"> <Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs">
<Link>MediaInfo\MediaProtocol.cs</Link> <Link>MediaInfo\MediaProtocol.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\PlaybackInfoRequest.cs">
<Link>MediaInfo\PlaybackInfoRequest.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\PlaybackInfoResponse.cs">
<Link>MediaInfo\PlaybackInfoResponse.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\SubtitleFormat.cs"> <Compile Include="..\MediaBrowser.Model\MediaInfo\SubtitleFormat.cs">
<Link>MediaInfo\SubtitleFormat.cs</Link> <Link>MediaInfo\SubtitleFormat.cs</Link>
</Compile> </Compile>

@ -756,12 +756,15 @@
<Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs"> <Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs">
<Link>MediaInfo\IBlurayExaminer.cs</Link> <Link>MediaInfo\IBlurayExaminer.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\LiveMediaInfoResult.cs">
<Link>MediaInfo\LiveMediaInfoResult.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs"> <Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs">
<Link>MediaInfo\MediaProtocol.cs</Link> <Link>MediaInfo\MediaProtocol.cs</Link>
</Compile> </Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\PlaybackInfoRequest.cs">
<Link>MediaInfo\PlaybackInfoRequest.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\PlaybackInfoResponse.cs">
<Link>MediaInfo\PlaybackInfoResponse.cs</Link>
</Compile>
<Compile Include="..\MediaBrowser.Model\MediaInfo\SubtitleFormat.cs"> <Compile Include="..\MediaBrowser.Model\MediaInfo\SubtitleFormat.cs">
<Link>MediaInfo\SubtitleFormat.cs</Link> <Link>MediaInfo\SubtitleFormat.cs</Link>
</Compile> </Compile>

@ -251,7 +251,7 @@ namespace MediaBrowser.Model.ApiClient
/// <param name="itemId">The item identifier.</param> /// <param name="itemId">The item identifier.</param>
/// <param name="userId">The user identifier.</param> /// <param name="userId">The user identifier.</param>
/// <returns>Task&lt;LiveMediaInfoResult&gt;.</returns> /// <returns>Task&lt;LiveMediaInfoResult&gt;.</returns>
Task<LiveMediaInfoResult> GetPlaybackInfo(string itemId, string userId); Task<PlaybackInfoResponse> GetPlaybackInfo(string itemId, string userId);
/// <summary> /// <summary>
/// Gets the users async. /// Gets the users async.

@ -118,9 +118,7 @@ namespace MediaBrowser.Model.Dlna
return stream; return stream;
} }
PlaybackException error = new PlaybackException(); return null;
error.ErrorCode = PlaybackErrorCode.NoCompatibleStream;
throw error;
} }
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options)
@ -221,7 +219,7 @@ namespace MediaBrowser.Model.Dlna
playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength;
playlistItem.Container = transcodingProfile.Container; playlistItem.Container = transcodingProfile.Container;
playlistItem.AudioCodec = transcodingProfile.AudioCodec; playlistItem.AudioCodec = transcodingProfile.AudioCodec;
playlistItem.Protocol = transcodingProfile.Protocol; playlistItem.SubProtocol = transcodingProfile.Protocol;
List<CodecProfile> audioCodecProfiles = new List<CodecProfile>(); List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
foreach (CodecProfile i in options.Profile.CodecProfiles) foreach (CodecProfile i in options.Profile.CodecProfiles)
@ -374,7 +372,7 @@ namespace MediaBrowser.Model.Dlna
playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo;
playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',')[0]; playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',')[0];
playlistItem.VideoCodec = transcodingProfile.VideoCodec; playlistItem.VideoCodec = transcodingProfile.VideoCodec;
playlistItem.Protocol = transcodingProfile.Protocol; playlistItem.SubProtocol = transcodingProfile.Protocol;
playlistItem.AudioStreamIndex = audioStreamIndex; playlistItem.AudioStreamIndex = audioStreamIndex;
List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>(); List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>();

@ -24,7 +24,7 @@ namespace MediaBrowser.Model.Dlna
public string Container { get; set; } public string Container { get; set; }
public string Protocol { get; set; } public string SubProtocol { get; set; }
public long StartPositionTicks { get; set; } public long StartPositionTicks { get; set; }
@ -69,7 +69,7 @@ namespace MediaBrowser.Model.Dlna
public SubtitleDeliveryMethod SubtitleDeliveryMethod { get; set; } public SubtitleDeliveryMethod SubtitleDeliveryMethod { get; set; }
public string SubtitleFormat { get; set; } public string SubtitleFormat { get; set; }
public LiveMediaInfoResult PlaybackInfo { get; set; } public PlaybackInfoResponse PlaybackInfo { get; set; }
public string MediaSourceId public string MediaSourceId
{ {
@ -115,7 +115,7 @@ namespace MediaBrowser.Model.Dlna
return string.Format("{0}/audio/{1}/stream{2}?{3}", baseUrl, ItemId, extension, dlnaCommand); return string.Format("{0}/audio/{1}/stream{2}?{3}", baseUrl, ItemId, extension, dlnaCommand);
} }
if (StringHelper.EqualsIgnoreCase(Protocol, "hls")) if (StringHelper.EqualsIgnoreCase(SubProtocol, "hls"))
{ {
return string.Format("{0}/videos/{1}/master.m3u8?{2}", baseUrl, ItemId, dlnaCommand); return string.Format("{0}/videos/{1}/master.m3u8?{2}", baseUrl, ItemId, dlnaCommand);
} }
@ -207,7 +207,7 @@ namespace MediaBrowser.Model.Dlna
List<SubtitleStreamInfo> list = new List<SubtitleStreamInfo>(); List<SubtitleStreamInfo> list = new List<SubtitleStreamInfo>();
// HLS will preserve timestamps so we can just grab the full subtitle stream // HLS will preserve timestamps so we can just grab the full subtitle stream
long startPositionTicks = StringHelper.EqualsIgnoreCase(Protocol, "hls") long startPositionTicks = StringHelper.EqualsIgnoreCase(SubProtocol, "hls")
? 0 ? 0
: StartPositionTicks; : StartPositionTicks;

@ -24,6 +24,7 @@ namespace MediaBrowser.Model.Dto
public bool ReadAtNativeFramerate { get; set; } public bool ReadAtNativeFramerate { get; set; }
public bool SupportsTranscoding { get; set; } public bool SupportsTranscoding { get; set; }
public bool SupportsDirectStream { get; set; } public bool SupportsDirectStream { get; set; }
public bool SupportsDirectPlay { get; set; }
public VideoType? VideoType { get; set; } public VideoType? VideoType { get; set; }
@ -39,7 +40,11 @@ namespace MediaBrowser.Model.Dto
public int? Bitrate { get; set; } public int? Bitrate { get; set; }
public TransportStreamTimestamp? Timestamp { get; set; } public TransportStreamTimestamp? Timestamp { get; set; }
public Dictionary<string, string> RequiredHttpHeaders { get; set; } public Dictionary<string, string> RequiredHttpHeaders { get; set; }
public string TranscodingUrl { get; set; }
public string TranscodingSubProtocol { get; set; }
public string TranscodingContainer { get; set; }
public MediaSourceInfo() public MediaSourceInfo()
{ {
@ -49,6 +54,7 @@ namespace MediaBrowser.Model.Dto
PlayableStreamFileNames = new List<string>(); PlayableStreamFileNames = new List<string>();
SupportsTranscoding = true; SupportsTranscoding = true;
SupportsDirectStream = true; SupportsDirectStream = true;
SupportsDirectPlay = true;
} }
public int? DefaultAudioStreamIndex { get; set; } public int? DefaultAudioStreamIndex { get; set; }

@ -140,7 +140,8 @@
<Compile Include="Dto\MetadataEditorInfo.cs" /> <Compile Include="Dto\MetadataEditorInfo.cs" />
<Compile Include="Dto\NameIdPair.cs" /> <Compile Include="Dto\NameIdPair.cs" />
<Compile Include="Dto\NameValuePair.cs" /> <Compile Include="Dto\NameValuePair.cs" />
<Compile Include="MediaInfo\LiveMediaInfoResult.cs" /> <Compile Include="MediaInfo\PlaybackInfoRequest.cs" />
<Compile Include="MediaInfo\PlaybackInfoResponse.cs" />
<Compile Include="Dto\MediaSourceType.cs" /> <Compile Include="Dto\MediaSourceType.cs" />
<Compile Include="Configuration\DynamicDayOfWeek.cs" /> <Compile Include="Configuration\DynamicDayOfWeek.cs" />
<Compile Include="Entities\ExtraType.cs" /> <Compile Include="Entities\ExtraType.cs" />

@ -0,0 +1,9 @@
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Model.MediaInfo
{
public class PlaybackInfoRequest
{
public DeviceProfile DeviceProfile { get; set; }
}
}

@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace MediaBrowser.Model.MediaInfo namespace MediaBrowser.Model.MediaInfo
{ {
public class LiveMediaInfoResult public class PlaybackInfoResponse
{ {
/// <summary> /// <summary>
/// Gets or sets the media sources. /// Gets or sets the media sources.
@ -24,7 +24,7 @@ namespace MediaBrowser.Model.MediaInfo
/// <value>The error code.</value> /// <value>The error code.</value>
public PlaybackErrorCode? ErrorCode { get; set; } public PlaybackErrorCode? ErrorCode { get; set; }
public LiveMediaInfoResult() public PlaybackInfoResponse()
{ {
MediaSources = new List<MediaSourceInfo>(); MediaSources = new List<MediaSourceInfo>();
} }
Loading…
Cancel
Save