Parcourir la source

use server to build initial stream url's

Luke Pulverenti il y a 10 ans
Parent
commit
348b8c4414

+ 134 - 12
MediaBrowser.Api/Playback/MediaInfoService.cs

@@ -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.Model.Dlna;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Session;
 using ServiceStack;
 using System;
 using System.Collections.Generic;
@@ -13,7 +16,7 @@ using System.Threading.Tasks;
 namespace MediaBrowser.Api.Playback
 {
     [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")]
         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")]
-    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")]
         public string Id { get; set; }
@@ -36,26 +49,55 @@ namespace MediaBrowser.Api.Playback
     public class MediaInfoService : BaseApiService
     {
         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;
+            _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;
-            var result = new LiveMediaInfoResult();
+            var result = new PlaybackInfoResponse();
 
             try
             {
@@ -68,9 +110,89 @@ namespace MediaBrowser.Api.Playback
             }
 
             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;
+                    }
+                }
+            }
         }
     }
 }

+ 2 - 1
MediaBrowser.Controller/Channels/ChannelMediaInfo.cs

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

+ 2 - 1
MediaBrowser.Controller/Entities/Video.cs

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

+ 6 - 3
MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj

@@ -800,12 +800,15 @@
     <Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs">
       <Link>MediaInfo\IBlurayExaminer.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\MediaInfo\LiveMediaInfoResult.cs">
-      <Link>MediaInfo\LiveMediaInfoResult.cs</Link>
-    </Compile>
     <Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs">
       <Link>MediaInfo\MediaProtocol.cs</Link>
     </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">
       <Link>MediaInfo\SubtitleFormat.cs</Link>
     </Compile>

+ 6 - 3
MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj

@@ -756,12 +756,15 @@
     <Compile Include="..\MediaBrowser.Model\MediaInfo\IBlurayExaminer.cs">
       <Link>MediaInfo\IBlurayExaminer.cs</Link>
     </Compile>
-    <Compile Include="..\MediaBrowser.Model\MediaInfo\LiveMediaInfoResult.cs">
-      <Link>MediaInfo\LiveMediaInfoResult.cs</Link>
-    </Compile>
     <Compile Include="..\MediaBrowser.Model\MediaInfo\MediaProtocol.cs">
       <Link>MediaInfo\MediaProtocol.cs</Link>
     </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">
       <Link>MediaInfo\SubtitleFormat.cs</Link>
     </Compile>

+ 1 - 1
MediaBrowser.Model/ApiClient/IApiClient.cs

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

+ 3 - 5
MediaBrowser.Model/Dlna/StreamBuilder.cs

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

+ 4 - 4
MediaBrowser.Model/Dlna/StreamInfo.cs

@@ -24,7 +24,7 @@ namespace MediaBrowser.Model.Dlna
 
         public string Container { get; set; }
 
-        public string Protocol { get; set; }
+        public string SubProtocol { get; set; }
 
         public long StartPositionTicks { get; set; }
 
@@ -69,7 +69,7 @@ namespace MediaBrowser.Model.Dlna
         public SubtitleDeliveryMethod SubtitleDeliveryMethod { get; set; }
         public string SubtitleFormat { get; set; }
 
-        public LiveMediaInfoResult PlaybackInfo { get; set; }
+        public PlaybackInfoResponse PlaybackInfo { get; set; }
 
         public string MediaSourceId
         {
@@ -115,7 +115,7 @@ namespace MediaBrowser.Model.Dlna
                 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);
             }
@@ -207,7 +207,7 @@ namespace MediaBrowser.Model.Dlna
             List<SubtitleStreamInfo> list = new List<SubtitleStreamInfo>();
 
             // 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
                 : StartPositionTicks;
 

+ 7 - 1
MediaBrowser.Model/Dto/MediaSourceInfo.cs

@@ -24,6 +24,7 @@ namespace MediaBrowser.Model.Dto
         public bool ReadAtNativeFramerate { get; set; }
         public bool SupportsTranscoding { get; set; }
         public bool SupportsDirectStream { get; set; }
+        public bool SupportsDirectPlay { get; set; }
 
         public VideoType? VideoType { get; set; }
 
@@ -39,7 +40,11 @@ namespace MediaBrowser.Model.Dto
         public int? Bitrate { 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()
         {
@@ -49,6 +54,7 @@ namespace MediaBrowser.Model.Dto
             PlayableStreamFileNames = new List<string>();
             SupportsTranscoding = true;
             SupportsDirectStream = true;
+            SupportsDirectPlay = true;
         }
 
         public int? DefaultAudioStreamIndex { get; set; }

+ 2 - 1
MediaBrowser.Model/MediaBrowser.Model.csproj

@@ -140,7 +140,8 @@
     <Compile Include="Dto\MetadataEditorInfo.cs" />
     <Compile Include="Dto\NameIdPair.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="Configuration\DynamicDayOfWeek.cs" />
     <Compile Include="Entities\ExtraType.cs" />

+ 9 - 0
MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs

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

+ 2 - 2
MediaBrowser.Model/MediaInfo/LiveMediaInfoResult.cs → MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs

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