mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-08 04:18:06 +02:00
support more profile features
This commit is contained in:
parent
0ffb2e2efa
commit
f3e992b82b
10 changed files with 188 additions and 272 deletions
|
@ -117,10 +117,9 @@ namespace MediaBrowser.Api.Movies
|
||||||
|
|
||||||
public object Get(GetMovieRecommendations request)
|
public object Get(GetMovieRecommendations request)
|
||||||
{
|
{
|
||||||
var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null;
|
var user = _userManager.GetUserById(request.UserId.Value);
|
||||||
|
|
||||||
var folder = user.RootFolder;
|
var movies = user.RootFolder.GetRecursiveChildren(user).OfType<Movie>().ToList();
|
||||||
var movies = folder.RecursiveChildren.OfType<Movie>().ToList();
|
|
||||||
|
|
||||||
var result = GetRecommendationCategories(user, movies, request.CategoryLimit, request.ItemLimit, request.GetItemFields().ToList());
|
var result = GetRecommendationCategories(user, movies, request.CategoryLimit, request.ItemLimit, request.GetItemFields().ToList());
|
||||||
|
|
||||||
|
|
|
@ -745,6 +745,16 @@ namespace MediaBrowser.Api.Playback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.MaxAudioChannels.HasValue)
|
||||||
|
{
|
||||||
|
if (audioStream != null && audioStream.Channels.HasValue)
|
||||||
|
{
|
||||||
|
return Math.Min(request.MaxAudioChannels.Value, audioStream.Channels.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return request.MaxAudioChannels.Value;
|
||||||
|
}
|
||||||
|
|
||||||
return request.AudioChannels;
|
return request.AudioChannels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1205,73 +1215,73 @@ namespace MediaBrowser.Api.Playback
|
||||||
}
|
}
|
||||||
else if (i == 1)
|
else if (i == 1)
|
||||||
{
|
{
|
||||||
request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
|
request.MediaSourceId = val;
|
||||||
}
|
}
|
||||||
else if (i == 2)
|
else if (i == 2)
|
||||||
|
{
|
||||||
|
request.Static = string.Equals("true", val, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
else if (i == 3)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
videoRequest.VideoCodec = (VideoCodecs)Enum.Parse(typeof(VideoCodecs), val, true);
|
videoRequest.VideoCodec = (VideoCodecs)Enum.Parse(typeof(VideoCodecs), val, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 3)
|
else if (i == 4)
|
||||||
{
|
{
|
||||||
request.AudioCodec = (AudioCodecs)Enum.Parse(typeof(AudioCodecs), val, true);
|
request.AudioCodec = (AudioCodecs)Enum.Parse(typeof(AudioCodecs), val, true);
|
||||||
}
|
}
|
||||||
else if (i == 4)
|
else if (i == 5)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
videoRequest.AudioStreamIndex = int.Parse(val, UsCulture);
|
videoRequest.AudioStreamIndex = int.Parse(val, UsCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 5)
|
else if (i == 6)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture);
|
videoRequest.SubtitleStreamIndex = int.Parse(val, UsCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 6)
|
else if (i == 7)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
videoRequest.VideoBitRate = int.Parse(val, UsCulture);
|
videoRequest.VideoBitRate = int.Parse(val, UsCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 7)
|
else if (i == 8)
|
||||||
{
|
{
|
||||||
request.AudioBitRate = int.Parse(val, UsCulture);
|
request.AudioBitRate = int.Parse(val, UsCulture);
|
||||||
}
|
}
|
||||||
else if (i == 8)
|
|
||||||
{
|
|
||||||
request.AudioChannels = int.Parse(val, UsCulture);
|
|
||||||
}
|
|
||||||
else if (i == 9)
|
else if (i == 9)
|
||||||
|
{
|
||||||
|
request.MaxAudioChannels = int.Parse(val, UsCulture);
|
||||||
|
}
|
||||||
|
else if (i == 10)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
request.StartTimeTicks = long.Parse(val, UsCulture);
|
request.StartTimeTicks = long.Parse(val, UsCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 10)
|
else if (i == 11)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
videoRequest.Profile = val;
|
videoRequest.Profile = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 11)
|
else if (i == 12)
|
||||||
{
|
{
|
||||||
if (videoRequest != null)
|
if (videoRequest != null)
|
||||||
{
|
{
|
||||||
videoRequest.Level = val;
|
videoRequest.Level = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (i == 12)
|
|
||||||
{
|
|
||||||
request.ForcedMimeType = val;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,9 @@ namespace MediaBrowser.Api.Playback
|
||||||
[ApiMember(Name = "AudioChannels", Description = "Optional. Specify a specific number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
[ApiMember(Name = "AudioChannels", Description = "Optional. Specify a specific number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
public int? AudioChannels { get; set; }
|
public int? AudioChannels { get; set; }
|
||||||
|
|
||||||
|
[ApiMember(Name = "MaxAudioChannels", Description = "Optional. Specify a maximum number of audio channels to encode to, e.g. 2", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||||
|
public int? MaxAudioChannels { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the audio sample rate.
|
/// Gets or sets the audio sample rate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -69,8 +72,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
public bool ThrowDebugError { get; set; }
|
public bool ThrowDebugError { get; set; }
|
||||||
|
|
||||||
public string Params { get; set; }
|
public string Params { get; set; }
|
||||||
|
|
||||||
public string ForcedMimeType { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VideoStreamRequest : StreamRequest
|
public class VideoStreamRequest : StreamRequest
|
||||||
|
|
|
@ -79,16 +79,6 @@ namespace MediaBrowser.Api.Playback
|
||||||
|
|
||||||
public string GetMimeType(string outputPath)
|
public string GetMimeType(string outputPath)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(Request.ForcedMimeType))
|
|
||||||
{
|
|
||||||
if (VideoRequest == null)
|
|
||||||
{
|
|
||||||
return "audio/" + Request.ForcedMimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "video/" + Request.ForcedMimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MimeTypes.GetMimeType(outputPath);
|
return MimeTypes.GetMimeType(outputPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,9 @@ namespace MediaBrowser.Controller.Dlna
|
||||||
|
|
||||||
public enum TranscodingSettingType
|
public enum TranscodingSettingType
|
||||||
{
|
{
|
||||||
Profile = 0,
|
VideoLevel = 0,
|
||||||
MaxAudioChannels = 1
|
VideoProfile = 1,
|
||||||
|
MaxAudioChannels = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TranscodeSeekInfo
|
public enum TranscodeSeekInfo
|
||||||
|
|
|
@ -274,11 +274,9 @@ namespace MediaBrowser.Dlna
|
||||||
|
|
||||||
Settings = new List<TranscodingSetting>
|
Settings = new List<TranscodingSetting>
|
||||||
{
|
{
|
||||||
new TranscodingSetting
|
new TranscodingSetting { Name = TranscodingSettingType.MaxAudioChannels, Value = "6" },
|
||||||
{
|
new TranscodingSetting{ Name = TranscodingSettingType.VideoLevel, Value = "3"},
|
||||||
Name = TranscodingSettingType.MaxAudioChannels,
|
new TranscodingSetting{ Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
|
||||||
Value = "6"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new TranscodingProfile
|
new TranscodingProfile
|
||||||
|
@ -791,7 +789,13 @@ namespace MediaBrowser.Dlna
|
||||||
Container = "ts",
|
Container = "ts",
|
||||||
Type = DlnaProfileType.Video,
|
Type = DlnaProfileType.Video,
|
||||||
VideoCodec = "h264",
|
VideoCodec = "h264",
|
||||||
AudioCodec = "aac"
|
AudioCodec = "aac",
|
||||||
|
|
||||||
|
Settings = new List<TranscodingSetting>
|
||||||
|
{
|
||||||
|
new TranscodingSetting{ Name = TranscodingSettingType.VideoLevel, Value = "3"},
|
||||||
|
new TranscodingSetting{ Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
new TranscodingProfile
|
new TranscodingProfile
|
||||||
{
|
{
|
||||||
|
@ -1010,12 +1014,20 @@ namespace MediaBrowser.Dlna
|
||||||
new TranscodingProfile
|
new TranscodingProfile
|
||||||
{
|
{
|
||||||
Container = "mp3",
|
Container = "mp3",
|
||||||
|
AudioCodec = "mp3",
|
||||||
Type = DlnaProfileType.Audio
|
Type = DlnaProfileType.Audio
|
||||||
},
|
},
|
||||||
new TranscodingProfile
|
new TranscodingProfile
|
||||||
{
|
{
|
||||||
Container = "ts",
|
Container = "ts",
|
||||||
Type = DlnaProfileType.Video
|
Type = DlnaProfileType.Video,
|
||||||
|
AudioCodec = "aac",
|
||||||
|
VideoCodec = "h264",
|
||||||
|
Settings = new List<TranscodingSetting>
|
||||||
|
{
|
||||||
|
new TranscodingSetting{ Name = TranscodingSettingType.VideoLevel, Value = "3"},
|
||||||
|
new TranscodingSetting{ Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -270,7 +270,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
playlistItem.StartPositionTicks = newItem.StartPositionTicks;
|
playlistItem.StartPositionTicks = newItem.StartPositionTicks;
|
||||||
playlistItem.StreamUrl = newItem.StreamUrl;
|
playlistItem.StreamUrl = newItem.StreamUrl;
|
||||||
playlistItem.Didl = newItem.Didl;
|
playlistItem.Didl = newItem.Didl;
|
||||||
return _device.SetAvTransport(playlistItem.StreamUrl, playlistItem.DlnaHeaders, playlistItem.Didl);
|
return _device.SetAvTransport(playlistItem.StreamUrl, GetDlnaHeaders(playlistItem), playlistItem.Didl);
|
||||||
|
|
||||||
}
|
}
|
||||||
return _device.Seek(TimeSpan.FromTicks(command.SeekPositionTicks ?? 0));
|
return _device.Seek(TimeSpan.FromTicks(command.SeekPositionTicks ?? 0));
|
||||||
|
@ -391,16 +391,20 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
private PlaylistItem CreatePlaylistItem(BaseItem item, long startPostionTicks, string serverAddress)
|
private PlaylistItem CreatePlaylistItem(BaseItem item, long startPostionTicks, string serverAddress)
|
||||||
{
|
{
|
||||||
var streams = _itemRepository.GetMediaStreams(new MediaStreamQuery { ItemId = item.Id }).ToList();
|
var streams = _itemRepository.GetMediaStreams(new MediaStreamQuery
|
||||||
|
{
|
||||||
|
ItemId = item.Id
|
||||||
|
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
var deviceInfo = _device.Properties;
|
var deviceInfo = _device.Properties;
|
||||||
|
|
||||||
var playlistItem = GetPlaylistItem(item, _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()));
|
var playlistItem = GetPlaylistItem(item, streams, _dlnaManager.GetProfile(deviceInfo.ToDeviceIdentification()));
|
||||||
playlistItem.StartPositionTicks = startPostionTicks;
|
playlistItem.StartPositionTicks = startPostionTicks;
|
||||||
|
|
||||||
if (playlistItem.MediaType == DlnaProfileType.Audio)
|
if (playlistItem.MediaType == DlnaProfileType.Audio)
|
||||||
{
|
{
|
||||||
playlistItem.StreamUrl = StreamHelper.GetAudioUrl(playlistItem, serverAddress);
|
playlistItem.StreamUrl = StreamHelper.GetAudioUrl(deviceInfo, playlistItem, streams, serverAddress);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -410,32 +414,92 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams);
|
var didl = DidlBuilder.Build(item, _session.UserId.ToString(), serverAddress, playlistItem.StreamUrl, streams);
|
||||||
playlistItem.Didl = didl;
|
playlistItem.Didl = didl;
|
||||||
|
|
||||||
var header = StreamHelper.GetDlnaHeaders(playlistItem);
|
|
||||||
playlistItem.DlnaHeaders = header;
|
|
||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlaylistItem GetPlaylistItem(BaseItem item, DeviceProfile profile)
|
private string GetDlnaHeaders(PlaylistItem item)
|
||||||
|
{
|
||||||
|
var orgOp = item.Transcode ? ";DLNA.ORG_OP=00" : ";DLNA.ORG_OP=01";
|
||||||
|
|
||||||
|
var orgCi = item.Transcode ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
|
||||||
|
|
||||||
|
const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
|
||||||
|
|
||||||
|
string contentFeatures;
|
||||||
|
|
||||||
|
var container = item.Container.TrimStart('.');
|
||||||
|
|
||||||
|
if (string.Equals(container, "mp3", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
contentFeatures = "DLNA.ORG_PN=MP3";
|
||||||
|
}
|
||||||
|
else if (string.Equals(container, "wma", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
contentFeatures = "DLNA.ORG_PN=WMABASE";
|
||||||
|
}
|
||||||
|
else if (string.Equals(container, "wmw", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
contentFeatures = "DLNA.ORG_PN=WMVMED_BASE";
|
||||||
|
}
|
||||||
|
else if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
contentFeatures = "DLNA.ORG_PN=WMVMED_BASE";
|
||||||
|
}
|
||||||
|
else if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
contentFeatures = "DLNA.ORG_PN=AVI";
|
||||||
|
}
|
||||||
|
else if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
contentFeatures = "DLNA.ORG_PN=MATROSKA";
|
||||||
|
}
|
||||||
|
else if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC";
|
||||||
|
}
|
||||||
|
else if (string.Equals(container, "mpeg", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
||||||
|
}
|
||||||
|
else if (string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
||||||
|
}
|
||||||
|
else if (item.MediaType == DlnaProfileType.Video)
|
||||||
|
{
|
||||||
|
// Default to AVI for video
|
||||||
|
contentFeatures = "DLNA.ORG_PN=AVI";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Default to MP3 for audio
|
||||||
|
contentFeatures = "DLNA.ORG_PN=MP3";
|
||||||
|
}
|
||||||
|
|
||||||
|
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlaylistItem GetPlaylistItem(BaseItem item, List<MediaStream> mediaStreams, DeviceProfile profile)
|
||||||
{
|
{
|
||||||
var video = item as Video;
|
var video = item as Video;
|
||||||
|
|
||||||
if (video != null)
|
if (video != null)
|
||||||
{
|
{
|
||||||
return new PlaylistItemFactory(_itemRepository).Create(video, profile);
|
return new PlaylistItemFactory().Create(video, mediaStreams, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
var audio = item as Audio;
|
var audio = item as Audio;
|
||||||
|
|
||||||
if (audio != null)
|
if (audio != null)
|
||||||
{
|
{
|
||||||
return new PlaylistItemFactory(_itemRepository).Create(audio, profile);
|
return new PlaylistItemFactory().Create(audio, mediaStreams, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
var photo = item as Photo;
|
var photo = item as Photo;
|
||||||
|
|
||||||
if (photo != null)
|
if (photo != null)
|
||||||
{
|
{
|
||||||
return new PlaylistItemFactory(_itemRepository).Create(photo, profile);
|
return new PlaylistItemFactory().Create(photo, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ArgumentException("Unrecognized item type.");
|
throw new ArgumentException("Unrecognized item type.");
|
||||||
|
@ -482,11 +546,18 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
await _device.SetStop();
|
await _device.SetStop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTrack.PlayState = 1;
|
nextTrack.PlayState = 1;
|
||||||
_logger.Debug("{0} - SetAvTransport Uri: {1} DlnaHeaders: {2}", _device.Properties.Name, nextTrack.StreamUrl, nextTrack.DlnaHeaders);
|
|
||||||
await _device.SetAvTransport(nextTrack.StreamUrl, nextTrack.DlnaHeaders, nextTrack.Didl);
|
var dlnaheaders = GetDlnaHeaders(nextTrack);
|
||||||
|
|
||||||
|
_logger.Debug("{0} - SetAvTransport Uri: {1} DlnaHeaders: {2}", _device.Properties.Name, nextTrack.StreamUrl, dlnaheaders);
|
||||||
|
|
||||||
|
await _device.SetAvTransport(nextTrack.StreamUrl, dlnaheaders, nextTrack.Didl);
|
||||||
|
|
||||||
if (nextTrack.StartPositionTicks > 0 && !nextTrack.Transcode)
|
if (nextTrack.StartPositionTicks > 0 && !nextTrack.Transcode)
|
||||||
await _device.Seek(TimeSpan.FromTicks(nextTrack.StartPositionTicks));
|
await _device.Seek(TimeSpan.FromTicks(nextTrack.StartPositionTicks));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,7 +579,7 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
return Task.FromResult(false);
|
return Task.FromResult(false);
|
||||||
|
|
||||||
prevTrack.PlayState = 1;
|
prevTrack.PlayState = 1;
|
||||||
return _device.SetAvTransport(prevTrack.StreamUrl, prevTrack.DlnaHeaders, prevTrack.Didl);
|
return _device.SetAvTransport(prevTrack.StreamUrl, GetDlnaHeaders(prevTrack), prevTrack.Didl);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace MediaBrowser.Dlna.PlayTo
|
namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
|
@ -14,16 +15,27 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
|
|
||||||
public string Container { get; set; }
|
public string Container { get; set; }
|
||||||
|
|
||||||
public string MimeType { get; set; }
|
|
||||||
|
|
||||||
public int PlayState { get; set; }
|
public int PlayState { get; set; }
|
||||||
|
|
||||||
public string StreamUrl { get; set; }
|
public string StreamUrl { get; set; }
|
||||||
|
|
||||||
public string DlnaHeaders { get; set; }
|
|
||||||
|
|
||||||
public string Didl { get; set; }
|
public string Didl { get; set; }
|
||||||
|
|
||||||
public long StartPositionTicks { get; set; }
|
public long StartPositionTicks { get; set; }
|
||||||
|
|
||||||
|
public string VideoCodec { get; set; }
|
||||||
|
|
||||||
|
public string AudioCodec { get; set; }
|
||||||
|
|
||||||
|
public List<TranscodingSetting> TranscodingSettings { get; set; }
|
||||||
|
|
||||||
|
public int? AudioStreamIndex { get; set; }
|
||||||
|
|
||||||
|
public int? SubtitleStreamIndex { get; set; }
|
||||||
|
|
||||||
|
public PlaylistItem()
|
||||||
|
{
|
||||||
|
TranscodingSettings = new List<TranscodingSetting>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
using MediaBrowser.Controller.Dlna;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Persistence;
|
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -12,15 +12,9 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
public class PlaylistItemFactory
|
public class PlaylistItemFactory
|
||||||
{
|
{
|
||||||
private readonly IItemRepository _itemRepo;
|
|
||||||
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
public PlaylistItemFactory(IItemRepository itemRepo)
|
public PlaylistItem Create(Audio item, List<MediaStream> mediaStreams, DeviceProfile profile)
|
||||||
{
|
|
||||||
_itemRepo = itemRepo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlaylistItem Create(Audio item, DeviceProfile profile)
|
|
||||||
{
|
{
|
||||||
var playlistItem = new PlaylistItem
|
var playlistItem = new PlaylistItem
|
||||||
{
|
{
|
||||||
|
@ -28,12 +22,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
MediaType = DlnaProfileType.Audio
|
MediaType = DlnaProfileType.Audio
|
||||||
};
|
};
|
||||||
|
|
||||||
var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
|
|
||||||
{
|
|
||||||
ItemId = item.Id,
|
|
||||||
Type = MediaStreamType.Audio
|
|
||||||
});
|
|
||||||
|
|
||||||
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
|
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
|
||||||
|
|
||||||
if (profile.CodecProfiles.Where(i => i.Type == CodecType.AudioCodec)
|
if (profile.CodecProfiles.Where(i => i.Type == CodecType.AudioCodec)
|
||||||
|
@ -57,12 +45,10 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
if (transcodingProfile != null)
|
if (transcodingProfile != null)
|
||||||
{
|
{
|
||||||
playlistItem.Transcode = true;
|
playlistItem.Transcode = true;
|
||||||
|
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
|
||||||
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachMediaProfile(playlistItem, profile);
|
|
||||||
|
|
||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,16 +77,14 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
if (transcodingProfile != null)
|
if (transcodingProfile != null)
|
||||||
{
|
{
|
||||||
playlistItem.Transcode = true;
|
playlistItem.Transcode = true;
|
||||||
|
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
|
||||||
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachMediaProfile(playlistItem, profile);
|
|
||||||
|
|
||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlaylistItem Create(Video item, DeviceProfile profile)
|
public PlaylistItem Create(Video item, List<MediaStream> mediaStreams, DeviceProfile profile)
|
||||||
{
|
{
|
||||||
var playlistItem = new PlaylistItem
|
var playlistItem = new PlaylistItem
|
||||||
{
|
{
|
||||||
|
@ -108,12 +92,6 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
MediaType = DlnaProfileType.Video
|
MediaType = DlnaProfileType.Video
|
||||||
};
|
};
|
||||||
|
|
||||||
var mediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery
|
|
||||||
{
|
|
||||||
ItemId = item.Id
|
|
||||||
|
|
||||||
}).ToList();
|
|
||||||
|
|
||||||
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
|
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
|
||||||
var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
|
var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
|
||||||
|
|
||||||
|
@ -138,43 +116,13 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
if (transcodingProfile != null)
|
if (transcodingProfile != null)
|
||||||
{
|
{
|
||||||
playlistItem.Transcode = true;
|
playlistItem.Transcode = true;
|
||||||
|
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
|
||||||
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachMediaProfile(playlistItem, profile);
|
|
||||||
|
|
||||||
return playlistItem;
|
return playlistItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AttachMediaProfile(PlaylistItem item, DeviceProfile profile)
|
|
||||||
{
|
|
||||||
var mediaProfile = GetMediaProfile(item, profile);
|
|
||||||
|
|
||||||
if (mediaProfile != null)
|
|
||||||
{
|
|
||||||
item.MimeType = (mediaProfile.MimeType ?? string.Empty).Split('/').LastOrDefault();
|
|
||||||
|
|
||||||
// TODO: Org_pn?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private MediaProfile GetMediaProfile(PlaylistItem item, DeviceProfile profile)
|
|
||||||
{
|
|
||||||
return profile.MediaProfiles.FirstOrDefault(i =>
|
|
||||||
{
|
|
||||||
if (i.Type == item.MediaType)
|
|
||||||
{
|
|
||||||
if (string.Equals(item.Container.TrimStart('.'), i.Container.TrimStart('.'), StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
// TODO: Enforce codecs
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsSupported(DirectPlayProfile profile, Photo item)
|
private bool IsSupported(DirectPlayProfile profile, Photo item)
|
||||||
{
|
{
|
||||||
var mediaPath = item.Path;
|
var mediaPath = item.Path;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Controller.Dlna;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -9,91 +8,21 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
{
|
{
|
||||||
class StreamHelper
|
class StreamHelper
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Gets the dlna headers.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
internal static string GetDlnaHeaders(PlaylistItem item)
|
|
||||||
{
|
|
||||||
var orgOp = item.Transcode ? ";DLNA.ORG_OP=00" : ";DLNA.ORG_OP=01";
|
|
||||||
|
|
||||||
var orgCi = item.Transcode ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
|
|
||||||
|
|
||||||
const string dlnaflags = ";DLNA.ORG_FLAGS=01500000000000000000000000000000";
|
|
||||||
|
|
||||||
var contentFeatures = string.Empty;
|
|
||||||
|
|
||||||
if (string.Equals(item.Container, "mp3", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=MP3";
|
|
||||||
}
|
|
||||||
else if (string.Equals(item.Container, "wma", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=WMABASE";
|
|
||||||
}
|
|
||||||
else if (string.Equals(item.Container, "wmw", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=WMVMED_BASE";
|
|
||||||
}
|
|
||||||
else if (string.Equals(item.Container, "asf", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=WMVMED_BASE";
|
|
||||||
}
|
|
||||||
else if (string.Equals(item.Container, "avi", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=AVI";
|
|
||||||
}
|
|
||||||
else if (string.Equals(item.Container, "mkv", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=MATROSKA";
|
|
||||||
}
|
|
||||||
else if (string.Equals(item.Container, "mp4", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=AVC_MP4_MP_HD_720p_AAC";
|
|
||||||
}
|
|
||||||
else if (string.Equals(item.Container, "mpeg", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
|
||||||
}
|
|
||||||
else if (string.Equals(item.Container, "ts", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
contentFeatures = "DLNA.ORG_PN=MPEG_PS_PAL";
|
|
||||||
}
|
|
||||||
else if (item.MediaType == Controller.Dlna.DlnaProfileType.Video)
|
|
||||||
{
|
|
||||||
//Default to AVI for video
|
|
||||||
contentFeatures = "DLNA.ORG_PN=AVI";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Default to MP3 for audio
|
|
||||||
contentFeatures = "DLNA.ORG_PN=MP3";
|
|
||||||
}
|
|
||||||
|
|
||||||
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Audio
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the audio URL.
|
/// Gets the audio URL.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="deviceProperties">The device properties.</param>
|
||||||
/// <param name="item">The item.</param>
|
/// <param name="item">The item.</param>
|
||||||
|
/// <param name="streams">The streams.</param>
|
||||||
/// <param name="serverAddress">The server address.</param>
|
/// <param name="serverAddress">The server address.</param>
|
||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
internal static string GetAudioUrl(PlaylistItem item, string serverAddress)
|
internal static string GetAudioUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
|
||||||
{
|
{
|
||||||
if (!item.Transcode)
|
var dlnaCommand = BuildDlnaUrl(item.MediaSourceId, deviceProperties.UUID, !item.Transcode, null, item.AudioCodec, item.AudioStreamIndex, item.SubtitleStreamIndex, null, 128000, item.StartPositionTicks, item.TranscodingSettings);
|
||||||
return string.Format("{0}/audio/{1}/stream{2}?Static=True", serverAddress, item.ItemId, item.Container);
|
|
||||||
|
|
||||||
return string.Format("{0}/audio/{1}/stream.mp3?AudioCodec=Mp3", serverAddress, item.ItemId);
|
return string.Format("{0}/audio/{1}/stream{2}?{3}", serverAddress, item.ItemId, "." + item.Container.TrimStart('.'), dlnaCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Video
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the video URL.
|
/// Gets the video URL.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -104,97 +33,40 @@ namespace MediaBrowser.Dlna.PlayTo
|
||||||
/// <returns>The url to send to the device</returns>
|
/// <returns>The url to send to the device</returns>
|
||||||
internal static string GetVideoUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
|
internal static string GetVideoUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
|
||||||
{
|
{
|
||||||
string dlnaCommand = string.Empty;
|
var dlnaCommand = BuildDlnaUrl(item.MediaSourceId, deviceProperties.UUID, !item.Transcode, item.VideoCodec, item.AudioCodec, item.AudioStreamIndex, item.SubtitleStreamIndex, 1500000, 128000, item.StartPositionTicks, item.TranscodingSettings);
|
||||||
if (!item.Transcode)
|
|
||||||
{
|
|
||||||
dlnaCommand = BuildDlnaUrl(deviceProperties.UUID, !item.Transcode, null, null, null, null, null, null, null, null, null, null, item.MimeType);
|
|
||||||
return string.Format("{0}/Videos/{1}/stream{2}?{3}", serverAddress, item.ItemId, item.Container, dlnaCommand);
|
return string.Format("{0}/Videos/{1}/stream{2}?{3}", serverAddress, item.ItemId, item.Container, dlnaCommand);
|
||||||
}
|
}
|
||||||
var videostream = streams.Where(m => m.Type == MediaStreamType.Video).OrderBy(m => m.IsDefault).FirstOrDefault();
|
|
||||||
var audiostream = streams.Where(m => m.Type == MediaStreamType.Audio).OrderBy(m => m.IsDefault).FirstOrDefault();
|
|
||||||
|
|
||||||
var videoCodec = GetVideoCodec(videostream);
|
|
||||||
var audioCodec = GetAudioCodec(audiostream);
|
|
||||||
int? videoBitrate = null;
|
|
||||||
int? audioBitrate = null;
|
|
||||||
int? audioChannels = null;
|
|
||||||
|
|
||||||
if (videoCodec != VideoCodecs.Copy)
|
|
||||||
videoBitrate = 2000000;
|
|
||||||
|
|
||||||
if (audioCodec != AudioCodecs.Copy)
|
|
||||||
{
|
|
||||||
audioBitrate = 128000;
|
|
||||||
audioChannels = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
dlnaCommand = BuildDlnaUrl(deviceProperties.UUID, !item.Transcode, videoCodec, audioCodec, null, null, videoBitrate, audioChannels, audioBitrate, item.StartPositionTicks, "baseline", "3", item.MimeType);
|
|
||||||
return string.Format("{0}/Videos/{1}/stream{2}?{3}", serverAddress, item.ItemId, item.Container, dlnaCommand);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the video codec.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="videoStream">The video stream.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static VideoCodecs GetVideoCodec(MediaStream videoStream)
|
|
||||||
{
|
|
||||||
switch (videoStream.Codec.ToLower())
|
|
||||||
{
|
|
||||||
case "h264":
|
|
||||||
case "mpeg4":
|
|
||||||
return VideoCodecs.Copy;
|
|
||||||
|
|
||||||
}
|
|
||||||
return VideoCodecs.H264;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the audio codec.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="audioStream">The audio stream.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static AudioCodecs GetAudioCodec(MediaStream audioStream)
|
|
||||||
{
|
|
||||||
if (audioStream != null)
|
|
||||||
{
|
|
||||||
switch (audioStream.Codec.ToLower())
|
|
||||||
{
|
|
||||||
case "aac":
|
|
||||||
case "mp3":
|
|
||||||
case "wma":
|
|
||||||
return AudioCodecs.Copy;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return AudioCodecs.Aac;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Builds the dlna URL.
|
/// Builds the dlna URL.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static string BuildDlnaUrl(string deviceID, bool isStatic, VideoCodecs? videoCodec, AudioCodecs? audioCodec, int? subtitleIndex, int? audiostreamIndex, int? videoBitrate, int? audiochannels, int? audioBitrate, long? startPositionTicks, string profile, string videoLevel, string mimeType)
|
private static string BuildDlnaUrl(string mediaSourceId, string deviceID, bool isStatic, string videoCodec, string audioCodec, int? audiostreamIndex, int? subtitleIndex, int? videoBitrate, int? audioBitrate, long? startPositionTicks, List<TranscodingSetting> settings)
|
||||||
{
|
{
|
||||||
|
var profile = settings.Where(i => i.Name == TranscodingSettingType.VideoProfile).Select(i => i.Value).FirstOrDefault();
|
||||||
|
var videoLevel = settings.Where(i => i.Name == TranscodingSettingType.VideoLevel).Select(i => i.Value).FirstOrDefault();
|
||||||
|
var maxAudioChannels = settings.Where(i => i.Name == TranscodingSettingType.MaxAudioChannels).Select(i => i.Value).FirstOrDefault();
|
||||||
|
|
||||||
var usCulture = new CultureInfo("en-US");
|
var usCulture = new CultureInfo("en-US");
|
||||||
|
|
||||||
var dlnaparam = string.Format("Params={0};", deviceID);
|
var list = new List<string>
|
||||||
dlnaparam += isStatic ? "true;" : "false;";
|
{
|
||||||
dlnaparam += videoCodec.HasValue ? videoCodec.Value + ";" : ";";
|
deviceID ?? string.Empty,
|
||||||
dlnaparam += audioCodec.HasValue ? audioCodec.Value + ";" : ";";
|
mediaSourceId ?? string.Empty,
|
||||||
dlnaparam += audiostreamIndex.HasValue ? audiostreamIndex.Value.ToString(usCulture) + ";" : ";";
|
isStatic.ToString().ToLower(),
|
||||||
dlnaparam += subtitleIndex.HasValue ? subtitleIndex.Value.ToString(usCulture) + ";" : ";";
|
videoCodec ?? string.Empty,
|
||||||
dlnaparam += videoBitrate.HasValue ? videoBitrate.Value.ToString(usCulture) + ";" : ";";
|
audioCodec ?? string.Empty,
|
||||||
dlnaparam += audioBitrate.HasValue ? audioBitrate.Value.ToString(usCulture) + ";" : ";";
|
audiostreamIndex.HasValue ? audiostreamIndex.Value.ToString(usCulture) : string.Empty,
|
||||||
dlnaparam += audiochannels.HasValue ? audiochannels.Value.ToString(usCulture) + ";" : ";";
|
subtitleIndex.HasValue ? subtitleIndex.Value.ToString(usCulture) : string.Empty,
|
||||||
dlnaparam += startPositionTicks.HasValue ? startPositionTicks.Value.ToString(usCulture) + ";" : ";";
|
videoBitrate.HasValue ? videoBitrate.Value.ToString(usCulture) : string.Empty,
|
||||||
dlnaparam += profile + ";";
|
audioBitrate.HasValue ? audioBitrate.Value.ToString(usCulture) : string.Empty,
|
||||||
dlnaparam += videoLevel + ";";
|
maxAudioChannels ?? string.Empty,
|
||||||
dlnaparam += mimeType + ";";
|
startPositionTicks.HasValue ? startPositionTicks.Value.ToString(usCulture) : string.Empty,
|
||||||
|
profile ?? string.Empty,
|
||||||
return dlnaparam;
|
videoLevel ?? string.Empty
|
||||||
}
|
};
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
|
return string.Format("Params={0}", string.Join(";", list.ToArray()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue