apply codec profile conditions

This commit is contained in:
Luke Pulverenti 2014-03-24 13:54:45 -04:00
parent 501dedb13c
commit a94a98dc6c
15 changed files with 270 additions and 82 deletions

View file

@ -211,12 +211,7 @@ namespace MediaBrowser.Api
private void UpdateItem(BaseItemDto request, BaseItem item)
{
item.Name = request.Name;
// Only set the forced value if they changed it, or there's already one
if (!string.Equals(item.SortName, request.SortName) || !string.IsNullOrEmpty(item.ForcedSortName))
{
item.ForcedSortName = request.SortName;
}
item.ForcedSortName = request.ForcedSortName;
var hasBudget = item as IHasBudget;
if (hasBudget != null)

View file

@ -1168,18 +1168,23 @@ namespace MediaBrowser.Api.Playback
protected double? GetFramerateParam(StreamState state)
{
if (state.VideoRequest != null && state.VideoRequest.Framerate.HasValue)
if (state.VideoRequest != null)
{
return state.VideoRequest.Framerate.Value;
}
if (state.VideoStream != null)
{
var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate;
if (contentRate.HasValue && contentRate.Value > 23.976)
if (state.VideoRequest.Framerate.HasValue)
{
return 23.976;
return state.VideoRequest.Framerate.Value;
}
var maxrate = state.VideoRequest.MaxFramerate ?? 23.976;
if (state.VideoStream != null)
{
var contentRate = state.VideoStream.AverageFrameRate ?? state.VideoStream.RealFrameRate;
if (contentRate.HasValue && contentRate.Value > maxrate)
{
return maxrate;
}
}
}
@ -1265,17 +1270,38 @@ namespace MediaBrowser.Api.Playback
{
if (videoRequest != null)
{
request.StartTimeTicks = long.Parse(val, UsCulture);
videoRequest.MaxWidth = int.Parse(val, UsCulture);
}
}
else if (i == 12)
{
if (videoRequest != null)
{
videoRequest.Profile = val;
videoRequest.MaxHeight = int.Parse(val, UsCulture);
}
}
else if (i == 13)
{
if (videoRequest != null)
{
videoRequest.Framerate = int.Parse(val, UsCulture);
}
}
else if (i == 14)
{
if (videoRequest != null)
{
request.StartTimeTicks = long.Parse(val, UsCulture);
}
}
else if (i == 15)
{
if (videoRequest != null)
{
videoRequest.Profile = val;
}
}
else if (i == 16)
{
if (videoRequest != null)
{

View file

@ -145,6 +145,9 @@ namespace MediaBrowser.Api.Playback
[ApiMember(Name = "Framerate", Description = "Optional. A specific video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", IsRequired = false, DataType = "double", ParameterType = "query", Verb = "GET")]
public double? Framerate { get; set; }
[ApiMember(Name = "MaxFramerate", Description = "Optional. A specific maximum video framerate to encode to, e.g. 23.976. Generally this should be omitted unless the device has specific requirements.", IsRequired = false, DataType = "double", ParameterType = "query", Verb = "GET")]
public double? MaxFramerate { get; set; }
/// <summary>
/// Gets or sets the profile.
/// </summary>

View file

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Controller.Dlna
@ -18,6 +19,13 @@ namespace MediaBrowser.Controller.Dlna
{
return (Codec ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList();
}
public bool ContainsCodec(string codec)
{
var codecs = GetCodecs();
return codecs.Count == 0 || codecs.Contains(codec, StringComparer.OrdinalIgnoreCase);
}
}
public enum CodecType

View file

@ -32,9 +32,7 @@ namespace MediaBrowser.Controller.Dlna
public enum TranscodingSettingType
{
VideoLevel = 0,
VideoProfile = 1,
MaxAudioChannels = 2
VideoProfile = 0
}
public enum TranscodeSeekInfo

View file

@ -34,7 +34,20 @@ namespace MediaBrowser.Dlna.PlayTo
public int? SubtitleStreamIndex { get; set; }
public string DeviceProfileName { get; set; }
public int? MaxAudioChannels { get; set; }
public int? AudioBitrate { get; set; }
public int? VideoBitrate { get; set; }
public int? VideoLevel { get; set; }
public int? MaxWidth { get; set; }
public int? MaxHeight { get; set; }
public int? MaxFramerate { get; set; }
public PlaylistItem()
{
TranscodingSettings = new List<TranscodingSetting>();

View file

@ -24,13 +24,16 @@ namespace MediaBrowser.Dlna.PlayTo
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
if (profile.CodecProfiles.Where(i => i.Type == CodecType.AudioCodec)
.All(i => IsCodecProfileSupported(i, item.Path, null, audioStream)))
{
var directPlay = profile.DirectPlayProfiles
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, audioStream));
var directPlay = profile.DirectPlayProfiles
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, audioStream));
if (directPlay != null)
if (directPlay != null)
{
var audioCodec = audioStream == null ? null : audioStream.Codec;
// Make sure audio codec profiles are satisfied
if (!string.IsNullOrEmpty(audioCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.AudioCodec && i.ContainsCodec(audioCodec))
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, null, audioStream)))
{
playlistItem.Transcode = false;
playlistItem.Container = Path.GetExtension(item.Path);
@ -48,8 +51,15 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
playlistItem.AudioCodec = transcodingProfile.AudioCodec;
var audioTranscodingConditions = profile.CodecProfiles
.Where(i => i.Type == CodecType.AudioCodec && i.ContainsCodec(transcodingProfile.AudioCodec))
.Take(1)
.SelectMany(i => i.Conditions);
ApplyTranscodingConditions(playlistItem, audioTranscodingConditions);
}
return playlistItem;
}
@ -81,7 +91,7 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.TranscodingSettings = transcodingProfile.Settings.ToList();
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
}
return playlistItem;
}
@ -96,18 +106,28 @@ namespace MediaBrowser.Dlna.PlayTo
var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
if (profile.CodecProfiles.Where(i => i.Type == CodecType.VideoCodec || i.Type == CodecType.VideoAudioCodec)
.All(i => IsCodecProfileSupported(i, item.Path, videoStream, audioStream)))
var directPlay = profile.DirectPlayProfiles
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, videoStream, audioStream));
if (directPlay != null)
{
var directPlay = profile.DirectPlayProfiles
.FirstOrDefault(i => i.Type == playlistItem.MediaType && IsSupported(i, item, videoStream, audioStream));
var videoCodec = videoStream == null ? null : videoStream.Codec;
if (directPlay != null)
// Make sure video codec profiles are satisfied
if (!string.IsNullOrEmpty(videoCodec) && profile.CodecProfiles.Where(i => i.Type == CodecType.VideoCodec && i.ContainsCodec(videoCodec))
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream)))
{
playlistItem.Transcode = false;
playlistItem.Container = Path.GetExtension(item.Path);
var audioCodec = audioStream == null ? null : audioStream.Codec;
return playlistItem;
// Make sure audio codec profiles are satisfied
if (string.IsNullOrEmpty(audioCodec) || profile.CodecProfiles.Where(i => i.Type == CodecType.VideoAudioCodec && i.ContainsCodec(audioCodec))
.All(i => AreConditionsSatisfied(i.Conditions, item.Path, videoStream, audioStream)))
{
playlistItem.Transcode = false;
playlistItem.Container = Path.GetExtension(item.Path);
return playlistItem;
}
}
}
@ -121,11 +141,113 @@ namespace MediaBrowser.Dlna.PlayTo
playlistItem.Container = "." + transcodingProfile.Container.TrimStart('.');
playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',').FirstOrDefault();
playlistItem.VideoCodec = transcodingProfile.VideoCodec;
var videoTranscodingConditions = profile.CodecProfiles
.Where(i => i.Type == CodecType.VideoCodec && i.ContainsCodec(transcodingProfile.VideoCodec))
.Take(1)
.SelectMany(i => i.Conditions);
ApplyTranscodingConditions(playlistItem, videoTranscodingConditions);
var audioTranscodingConditions = profile.CodecProfiles
.Where(i => i.Type == CodecType.VideoAudioCodec && i.ContainsCodec(transcodingProfile.AudioCodec))
.Take(1)
.SelectMany(i => i.Conditions);
ApplyTranscodingConditions(playlistItem, audioTranscodingConditions);
}
return playlistItem;
}
private void ApplyTranscodingConditions(PlaylistItem item, IEnumerable<ProfileCondition> conditions)
{
foreach (var condition in conditions.Where(i => !string.IsNullOrEmpty(i.Value)))
{
var value = condition.Value;
switch (condition.Property)
{
case ProfileConditionValue.AudioBitrate:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.AudioBitrate = num;
}
break;
}
case ProfileConditionValue.AudioChannels:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxAudioChannels = num;
}
break;
}
case ProfileConditionValue.Filesize:
case ProfileConditionValue.AudioProfile:
case ProfileConditionValue.Has64BitOffsets:
case ProfileConditionValue.VideoBitDepth:
case ProfileConditionValue.VideoPacketLength:
case ProfileConditionValue.VideoProfile:
case ProfileConditionValue.VideoTimestamp:
{
// Not supported yet
break;
}
case ProfileConditionValue.Height:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxHeight = num;
}
break;
}
case ProfileConditionValue.VideoBitrate:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.VideoBitrate = num;
}
break;
}
case ProfileConditionValue.VideoFramerate:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxFramerate = num;
}
break;
}
case ProfileConditionValue.VideoLevel:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.VideoLevel = num;
}
break;
}
case ProfileConditionValue.Width:
{
var num = 0;
if (int.TryParse(value, NumberStyles.Any, _usCulture, out num))
{
item.MaxWidth = num;
}
break;
}
default:
throw new ArgumentException("Unrecognized ProfileConditionValue");
}
}
}
private bool IsSupported(DirectPlayProfile profile, Photo item)
{
var mediaPath = item.Path;
@ -142,7 +264,7 @@ namespace MediaBrowser.Dlna.PlayTo
return true;
}
private bool IsSupported(DirectPlayProfile profile, Audio item, MediaStream audioStream)
{
var mediaPath = item.Path;
@ -222,22 +344,9 @@ namespace MediaBrowser.Dlna.PlayTo
return true;
}
private bool IsCodecProfileSupported(CodecProfile profile, string mediaPath, MediaStream videoStream, MediaStream audioStream)
private bool AreConditionsSatisfied(IEnumerable<ProfileCondition> conditions, string mediaPath, MediaStream videoStream, MediaStream audioStream)
{
var codecs = profile.GetCodecs();
var stream = profile.Type == CodecType.VideoCodec ? videoStream : audioStream;
var existingCodec = (stream == null ? null : stream.Codec) ?? string.Empty;
if (codecs.Count == 0 || codecs.Contains(existingCodec, StringComparer.OrdinalIgnoreCase))
{
// Check additional conditions
if (!profile.Conditions.Any(i => IsConditionSatisfied(i, mediaPath, videoStream, audioStream)))
{
return false;
}
}
return true;
return conditions.All(i => IsConditionSatisfied(i, mediaPath, videoStream, audioStream));
}
/// <summary>

View file

@ -18,7 +18,7 @@ namespace MediaBrowser.Dlna.PlayTo
/// <returns>System.String.</returns>
internal static string GetAudioUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
{
var dlnaCommand = BuildDlnaUrl(item.DeviceProfileName, item.MediaSourceId, deviceProperties.UUID, !item.Transcode, null, item.AudioCodec, item.AudioStreamIndex, item.SubtitleStreamIndex, null, 128000, item.StartPositionTicks, item.TranscodingSettings);
var dlnaCommand = BuildDlnaUrl(deviceProperties, item);
return string.Format("{0}/audio/{1}/stream{2}?{3}", serverAddress, item.ItemId, "." + item.Container.TrimStart('.'), dlnaCommand);
}
@ -33,7 +33,7 @@ namespace MediaBrowser.Dlna.PlayTo
/// <returns>The url to send to the device</returns>
internal static string GetVideoUrl(DeviceInfo deviceProperties, PlaylistItem item, List<MediaStream> streams, string serverAddress)
{
var dlnaCommand = BuildDlnaUrl(item.DeviceProfileName, item.MediaSourceId, deviceProperties.UUID, !item.Transcode, item.VideoCodec, item.AudioCodec, item.AudioStreamIndex, item.SubtitleStreamIndex, 1500000, 128000, item.StartPositionTicks, item.TranscodingSettings);
var dlnaCommand = BuildDlnaUrl(deviceProperties, item);
return string.Format("{0}/Videos/{1}/stream{2}?{3}", serverAddress, item.ItemId, item.Container, dlnaCommand);
}
@ -41,30 +41,33 @@ namespace MediaBrowser.Dlna.PlayTo
/// <summary>
/// Builds the dlna URL.
/// </summary>
private static string BuildDlnaUrl(string deviceProfileName, string mediaSourceId, string deviceID, bool isStatic, string videoCodec, string audioCodec, int? audiostreamIndex, int? subtitleIndex, int? videoBitrate, int? audioBitrate, long? startPositionTicks, List<TranscodingSetting> settings)
private static string BuildDlnaUrl(DeviceInfo deviceProperties, PlaylistItem item)
{
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 profile = item.TranscodingSettings.Where(i => i.Name == TranscodingSettingType.VideoProfile)
.Select(i => i.Value)
.FirstOrDefault();
var usCulture = new CultureInfo("en-US");
var list = new List<string>
{
deviceProfileName ?? string.Empty,
deviceID ?? string.Empty,
mediaSourceId ?? string.Empty,
isStatic.ToString().ToLower(),
videoCodec ?? string.Empty,
audioCodec ?? string.Empty,
audiostreamIndex.HasValue ? audiostreamIndex.Value.ToString(usCulture) : string.Empty,
subtitleIndex.HasValue ? subtitleIndex.Value.ToString(usCulture) : string.Empty,
videoBitrate.HasValue ? videoBitrate.Value.ToString(usCulture) : string.Empty,
audioBitrate.HasValue ? audioBitrate.Value.ToString(usCulture) : string.Empty,
maxAudioChannels ?? string.Empty,
startPositionTicks.HasValue ? startPositionTicks.Value.ToString(usCulture) : string.Empty,
item.DeviceProfileName ?? string.Empty,
deviceProperties.UUID ?? string.Empty,
item.MediaSourceId ?? string.Empty,
(!item.Transcode).ToString().ToLower(),
item.VideoCodec ?? string.Empty,
item.AudioCodec ?? string.Empty,
item.AudioStreamIndex.HasValue ? item.AudioStreamIndex.Value.ToString(usCulture) : string.Empty,
item.SubtitleStreamIndex.HasValue ? item.SubtitleStreamIndex.Value.ToString(usCulture) : string.Empty,
item.VideoBitrate.HasValue ? item.VideoBitrate.Value.ToString(usCulture) : string.Empty,
item.AudioBitrate.HasValue ? item.AudioBitrate.Value.ToString(usCulture) : string.Empty,
item.MaxAudioChannels.HasValue ? item.MaxAudioChannels.Value.ToString(usCulture) : string.Empty,
item.MaxFramerate.HasValue ? item.MaxFramerate.Value.ToString(usCulture) : string.Empty,
item.MaxWidth.HasValue ? item.MaxWidth.Value.ToString(usCulture) : string.Empty,
item.MaxHeight.HasValue ? item.MaxHeight.Value.ToString(usCulture) : string.Empty,
item.StartPositionTicks.ToString(usCulture),
profile ?? string.Empty,
videoLevel ?? string.Empty
item.VideoLevel.HasValue ? item.VideoLevel.Value.ToString(usCulture) : string.Empty
};
return string.Format("Params={0}", string.Join(";", list.ToArray()));

View file

@ -34,7 +34,6 @@ namespace MediaBrowser.Dlna.Profiles
Settings = new []
{
new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"},
new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
}
}
@ -54,6 +53,24 @@ namespace MediaBrowser.Dlna.Profiles
Type = DlnaProfileType.Video
}
};
CodecProfiles = new[]
{
new CodecProfile
{
Type = CodecType.VideoCodec,
Conditions = new []
{
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "3",
IsRequired = false
}
}
}
};
}
}
}

View file

@ -6,10 +6,12 @@ namespace MediaBrowser.Dlna.Profiles
{
public SonyPs3Profile()
{
Name = "Sony Bravia (2010)";
Name = "Sony PlayStation 3";
Identification = new DeviceIdentification
{
FriendlyName = "PLAYSTATION 3",
Headers = new[]
{
new HttpHeaderInfo

View file

@ -44,7 +44,6 @@ namespace MediaBrowser.Dlna.Profiles
Settings = new []
{
new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"},
new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
}
},

View file

@ -49,8 +49,6 @@ namespace MediaBrowser.Dlna.Profiles
Settings = new []
{
new TranscodingSetting {Name = TranscodingSettingType.MaxAudioChannels, Value = "6"},
new TranscodingSetting {Name = TranscodingSettingType.VideoLevel, Value = "3"},
new TranscodingSetting {Name = TranscodingSettingType.VideoProfile, Value = "baseline"}
}
},
@ -229,6 +227,13 @@ namespace MediaBrowser.Dlna.Profiles
Property = ProfileConditionValue.VideoBitrate,
Value = "10240000",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "3",
IsRequired = false
}
}
},
@ -264,6 +269,13 @@ namespace MediaBrowser.Dlna.Profiles
Property = ProfileConditionValue.VideoBitrate,
Value = "15360000",
IsRequired = false
},
new ProfileCondition
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.VideoLevel,
Value = "3",
IsRequired = false
}
}
},
@ -294,7 +306,7 @@ namespace MediaBrowser.Dlna.Profiles
{
Condition = ProfileConditionType.LessThanEqual,
Property = ProfileConditionValue.AudioChannels,
Value = "6",
Value = "2",
IsRequired = false
},
new ProfileCondition

View file

@ -69,6 +69,7 @@ namespace MediaBrowser.Model.Dto
/// </summary>
/// <value>The name of the sort.</value>
public string SortName { get; set; }
public string ForcedSortName { get; set; }
/// <summary>
/// Gets or sets the video3 D format.

View file

@ -107,7 +107,8 @@ namespace MediaBrowser.Providers.Manager
// Next run metadata providers
if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None)
{
var providers = GetProviders(item, refreshResult.DateLastMetadataRefresh.HasValue, refreshOptions).ToList();
var providers = GetProviders(item, refreshResult.DateLastMetadataRefresh.HasValue, refreshOptions)
.ToList();
if (providers.Count > 0 || !refreshResult.DateLastMetadataRefresh.HasValue)
{

View file

@ -741,6 +741,7 @@ namespace MediaBrowser.Server.Implementations.Dto
{
dto.LockedFields = item.LockedFields;
dto.LockData = item.IsLocked;
dto.ForcedSortName = item.ForcedSortName;
}
var hasBudget = item as IHasBudget;