Add GPL modules

This commit is contained in:
Andrew Rabert
2018-12-27 18:27:57 -05:00
parent 9bac3ac616
commit a86b71899e
648 changed files with 50005 additions and 123 deletions
+87
View File
@@ -0,0 +1,87 @@
using MediaBrowser.Model.Dto;
using System.Collections.Generic;
using System;
namespace MediaBrowser.Model.Dlna
{
/// <summary>
/// Class AudioOptions.
/// </summary>
public class AudioOptions
{
public AudioOptions()
{
Context = EncodingContext.Streaming;
EnableDirectPlay = true;
EnableDirectStream = true;
}
public bool EnableDirectPlay { get; set; }
public bool EnableDirectStream { get; set; }
public bool ForceDirectPlay { get; set; }
public bool ForceDirectStream { get; set; }
public Guid ItemId { get; set; }
public MediaSourceInfo[] MediaSources { get; set; }
public DeviceProfile Profile { get; set; }
/// <summary>
/// Optional. Only needed if a specific AudioStreamIndex or SubtitleStreamIndex are requested.
/// </summary>
public string MediaSourceId { get; set; }
public string DeviceId { get; set; }
/// <summary>
/// Allows an override of supported number of audio channels
/// Example: DeviceProfile supports five channel, but user only has stereo speakers
/// </summary>
public int? MaxAudioChannels { get; set; }
/// <summary>
/// The application's configured quality setting
/// </summary>
public long? MaxBitrate { get; set; }
/// <summary>
/// Gets or sets the context.
/// </summary>
/// <value>The context.</value>
public EncodingContext Context { get; set; }
/// <summary>
/// Gets or sets the audio transcoding bitrate.
/// </summary>
/// <value>The audio transcoding bitrate.</value>
public int? AudioTranscodingBitrate { get; set; }
/// <summary>
/// Gets the maximum bitrate.
/// </summary>
/// <returns>System.Nullable&lt;System.Int32&gt;.</returns>
public long? GetMaxBitrate(bool isAudio)
{
if (MaxBitrate.HasValue)
{
return MaxBitrate;
}
if (Profile != null)
{
if (Context == EncodingContext.Static)
{
if (isAudio && Profile.MaxStaticMusicBitrate.HasValue)
{
return Profile.MaxStaticMusicBitrate;
}
return Profile.MaxStaticBitrate;
}
return Profile.MaxStreamingBitrate;
}
return null;
}
}
}
+68
View File
@@ -0,0 +1,68 @@
using MediaBrowser.Model.Extensions;
using System.Collections.Generic;
using System.Xml.Serialization;
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Model.Dlna
{
public class CodecProfile
{
[XmlAttribute("type")]
public CodecType Type { get; set; }
public ProfileCondition[] Conditions { get; set; }
public ProfileCondition[] ApplyConditions { get; set; }
[XmlAttribute("codec")]
public string Codec { get; set; }
[XmlAttribute("container")]
public string Container { get; set; }
public CodecProfile()
{
Conditions = new ProfileCondition[] {};
ApplyConditions = new ProfileCondition[] { };
}
public string[] GetCodecs()
{
return ContainerProfile.SplitValue(Codec);
}
private bool ContainsContainer(string container)
{
return ContainerProfile.ContainsContainer(Container, container);
}
public bool ContainsAnyCodec(string codec, string container)
{
return ContainsAnyCodec(ContainerProfile.SplitValue(codec), container);
}
public bool ContainsAnyCodec(string[] codec, string container)
{
if (!ContainsContainer(container))
{
return false;
}
var codecs = GetCodecs();
if (codecs.Length == 0)
{
return true;
}
foreach (var val in codec)
{
if (ListHelper.ContainsIgnoreCase(codecs, val))
{
return true;
}
}
return false;
}
}
}
+9
View File
@@ -0,0 +1,9 @@
namespace MediaBrowser.Model.Dlna
{
public enum CodecType
{
Video = 0,
VideoAudio = 1,
Audio = 2
}
}
@@ -0,0 +1,284 @@
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.MediaInfo;
using System;
using System.Collections.Generic;
using System.Globalization;
namespace MediaBrowser.Model.Dlna
{
public class ConditionProcessor
{
public bool IsVideoConditionSatisfied(ProfileCondition condition,
int? width,
int? height,
int? videoBitDepth,
int? videoBitrate,
string videoProfile,
double? videoLevel,
float? videoFramerate,
int? packetLength,
TransportStreamTimestamp? timestamp,
bool? isAnamorphic,
bool? isInterlaced,
int? refFrames,
int? numVideoStreams,
int? numAudioStreams,
string videoCodecTag,
bool? isAvc )
{
switch (condition.Property)
{
case ProfileConditionValue.IsInterlaced:
return IsConditionSatisfied(condition, isInterlaced);
case ProfileConditionValue.IsAnamorphic:
return IsConditionSatisfied(condition, isAnamorphic);
case ProfileConditionValue.IsAvc:
return IsConditionSatisfied(condition, isAvc);
case ProfileConditionValue.VideoFramerate:
return IsConditionSatisfied(condition, videoFramerate);
case ProfileConditionValue.VideoLevel:
return IsConditionSatisfied(condition, videoLevel);
case ProfileConditionValue.VideoProfile:
return IsConditionSatisfied(condition, videoProfile);
case ProfileConditionValue.VideoCodecTag:
return IsConditionSatisfied(condition, videoCodecTag);
case ProfileConditionValue.PacketLength:
return IsConditionSatisfied(condition, packetLength);
case ProfileConditionValue.VideoBitDepth:
return IsConditionSatisfied(condition, videoBitDepth);
case ProfileConditionValue.VideoBitrate:
return IsConditionSatisfied(condition, videoBitrate);
case ProfileConditionValue.Height:
return IsConditionSatisfied(condition, height);
case ProfileConditionValue.Width:
return IsConditionSatisfied(condition, width);
case ProfileConditionValue.RefFrames:
return IsConditionSatisfied(condition, refFrames);
case ProfileConditionValue.NumAudioStreams:
return IsConditionSatisfied(condition, numAudioStreams);
case ProfileConditionValue.NumVideoStreams:
return IsConditionSatisfied(condition, numVideoStreams);
case ProfileConditionValue.VideoTimestamp:
return IsConditionSatisfied(condition, timestamp);
default:
return true;
}
}
public bool IsImageConditionSatisfied(ProfileCondition condition, int? width, int? height)
{
switch (condition.Property)
{
case ProfileConditionValue.Height:
return IsConditionSatisfied(condition, height);
case ProfileConditionValue.Width:
return IsConditionSatisfied(condition, width);
default:
throw new ArgumentException("Unexpected condition on image file: " + condition.Property);
}
}
public bool IsAudioConditionSatisfied(ProfileCondition condition, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
{
switch (condition.Property)
{
case ProfileConditionValue.AudioBitrate:
return IsConditionSatisfied(condition, audioBitrate);
case ProfileConditionValue.AudioChannels:
return IsConditionSatisfied(condition, audioChannels);
case ProfileConditionValue.AudioSampleRate:
return IsConditionSatisfied(condition, audioSampleRate);
case ProfileConditionValue.AudioBitDepth:
return IsConditionSatisfied(condition, audioBitDepth);
default:
throw new ArgumentException("Unexpected condition on audio file: " + condition.Property);
}
}
public bool IsVideoAudioConditionSatisfied(ProfileCondition condition,
int? audioChannels,
int? audioBitrate,
int? audioSampleRate,
int? audioBitDepth,
string audioProfile,
bool? isSecondaryTrack)
{
switch (condition.Property)
{
case ProfileConditionValue.AudioProfile:
return IsConditionSatisfied(condition, audioProfile);
case ProfileConditionValue.AudioBitrate:
return IsConditionSatisfied(condition, audioBitrate);
case ProfileConditionValue.AudioChannels:
return IsConditionSatisfied(condition, audioChannels);
case ProfileConditionValue.IsSecondaryAudio:
return IsConditionSatisfied(condition, isSecondaryTrack);
case ProfileConditionValue.AudioSampleRate:
return IsConditionSatisfied(condition, audioSampleRate);
case ProfileConditionValue.AudioBitDepth:
return IsConditionSatisfied(condition, audioBitDepth);
default:
throw new ArgumentException("Unexpected condition on audio file: " + condition.Property);
}
}
private bool IsConditionSatisfied(ProfileCondition condition, int? currentValue)
{
if (!currentValue.HasValue)
{
// If the value is unknown, it satisfies if not marked as required
return !condition.IsRequired;
}
int expected;
if (int.TryParse(condition.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out expected))
{
switch (condition.Condition)
{
case ProfileConditionType.Equals:
case ProfileConditionType.EqualsAny:
return currentValue.Value.Equals(expected);
case ProfileConditionType.GreaterThanEqual:
return currentValue.Value >= expected;
case ProfileConditionType.LessThanEqual:
return currentValue.Value <= expected;
case ProfileConditionType.NotEquals:
return !currentValue.Value.Equals(expected);
default:
throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition);
}
}
return false;
}
private bool IsConditionSatisfied(ProfileCondition condition, string currentValue)
{
if (string.IsNullOrEmpty(currentValue))
{
// If the value is unknown, it satisfies if not marked as required
return !condition.IsRequired;
}
string expected = condition.Value;
switch (condition.Condition)
{
case ProfileConditionType.EqualsAny:
{
return ListHelper.ContainsIgnoreCase(expected.Split('|'), currentValue);
}
case ProfileConditionType.Equals:
return StringHelper.EqualsIgnoreCase(currentValue, expected);
case ProfileConditionType.NotEquals:
return !StringHelper.EqualsIgnoreCase(currentValue, expected);
default:
throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition);
}
}
private bool IsConditionSatisfied(ProfileCondition condition, bool? currentValue)
{
if (!currentValue.HasValue)
{
// If the value is unknown, it satisfies if not marked as required
return !condition.IsRequired;
}
bool expected;
if (bool.TryParse(condition.Value, out expected))
{
switch (condition.Condition)
{
case ProfileConditionType.Equals:
return currentValue.Value == expected;
case ProfileConditionType.NotEquals:
return currentValue.Value != expected;
default:
throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition);
}
}
return false;
}
private bool IsConditionSatisfied(ProfileCondition condition, float currentValue)
{
if (currentValue <= 0)
{
// If the value is unknown, it satisfies if not marked as required
return !condition.IsRequired;
}
float expected;
if (float.TryParse(condition.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out expected))
{
switch (condition.Condition)
{
case ProfileConditionType.Equals:
return currentValue.Equals(expected);
case ProfileConditionType.GreaterThanEqual:
return currentValue >= expected;
case ProfileConditionType.LessThanEqual:
return currentValue <= expected;
case ProfileConditionType.NotEquals:
return !currentValue.Equals(expected);
default:
throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition);
}
}
return false;
}
private bool IsConditionSatisfied(ProfileCondition condition, double? currentValue)
{
if (!currentValue.HasValue)
{
// If the value is unknown, it satisfies if not marked as required
return !condition.IsRequired;
}
double expected;
if (double.TryParse(condition.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out expected))
{
switch (condition.Condition)
{
case ProfileConditionType.Equals:
return currentValue.Value.Equals(expected);
case ProfileConditionType.GreaterThanEqual:
return currentValue.Value >= expected;
case ProfileConditionType.LessThanEqual:
return currentValue.Value <= expected;
case ProfileConditionType.NotEquals:
return !currentValue.Value.Equals(expected);
default:
throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition);
}
}
return false;
}
private bool IsConditionSatisfied(ProfileCondition condition, TransportStreamTimestamp? timestamp)
{
if (!timestamp.HasValue)
{
// If the value is unknown, it satisfies if not marked as required
return !condition.IsRequired;
}
TransportStreamTimestamp expected = (TransportStreamTimestamp)Enum.Parse(typeof(TransportStreamTimestamp), condition.Value, true);
switch (condition.Condition)
{
case ProfileConditionType.Equals:
return timestamp == expected;
case ProfileConditionType.NotEquals:
return timestamp != expected;
default:
throw new InvalidOperationException("Unexpected ProfileConditionType: " + condition.Condition);
}
}
}
}
+101
View File
@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Model.Dlna
{
public class ContainerProfile
{
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
public ProfileCondition[] Conditions { get; set; }
[XmlAttribute("container")]
public string Container { get; set; }
public ContainerProfile()
{
Conditions = new ProfileCondition[] { };
}
public string[] GetContainers()
{
return SplitValue(Container);
}
private static readonly string[] EmptyStringArray = Array.Empty<string>();
public static string[] SplitValue(string value)
{
if (string.IsNullOrEmpty(value))
{
return EmptyStringArray;
}
return value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
}
public bool ContainsContainer(string container)
{
var containers = GetContainers();
return ContainsContainer(containers, container);
}
public static bool ContainsContainer(string profileContainers, string inputContainer)
{
var isNegativeList = false;
if (profileContainers != null && profileContainers.StartsWith("-"))
{
isNegativeList = true;
profileContainers = profileContainers.Substring(1);
}
return ContainsContainer(SplitValue(profileContainers), isNegativeList, inputContainer);
}
public static bool ContainsContainer(string[] profileContainers, string inputContainer)
{
return ContainsContainer(profileContainers, false, inputContainer);
}
public static bool ContainsContainer(string[] profileContainers, bool isNegativeList, string inputContainer)
{
if (profileContainers.Length == 0)
{
return true;
}
if (isNegativeList)
{
var allInputContainers = SplitValue(inputContainer);
foreach (var container in allInputContainers)
{
if (ListHelper.ContainsIgnoreCase(profileContainers, container))
{
return false;
}
}
return true;
}
else
{
var allInputContainers = SplitValue(inputContainer);
foreach (var container in allInputContainers)
{
if (ListHelper.ContainsIgnoreCase(profileContainers, container))
{
return true;
}
}
return false;
}
}
}
}
@@ -0,0 +1,236 @@
using MediaBrowser.Model.MediaInfo;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Model.Dlna
{
public class ContentFeatureBuilder
{
private readonly DeviceProfile _profile;
public ContentFeatureBuilder(DeviceProfile profile)
{
_profile = profile;
}
public string BuildImageHeader(string container,
int? width,
int? height,
bool isDirectStream,
string orgPn = null)
{
string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetImageOrgOpValue();
// 0 = native, 1 = transcoded
var orgCi = isDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
DlnaFlags flagValue = DlnaFlags.BackgroundTransferMode |
DlnaFlags.InteractiveTransferMode |
DlnaFlags.DlnaV15;
string dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}",
DlnaMaps.FlagsToString(flagValue));
ResponseProfile mediaProfile = _profile.GetImageMediaProfile(container,
width,
height);
if (string.IsNullOrEmpty(orgPn))
{
orgPn = mediaProfile == null ? null : mediaProfile.OrgPn;
}
if (string.IsNullOrEmpty(orgPn))
{
orgPn = GetImageOrgPnValue(container, width, height);
}
string contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn;
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
}
public string BuildAudioHeader(string container,
string audioCodec,
int? audioBitrate,
int? audioSampleRate,
int? audioChannels,
int? audioBitDepth,
bool isDirectStream,
long? runtimeTicks,
TranscodeSeekInfo transcodeSeekInfo)
{
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks > 0, isDirectStream, transcodeSeekInfo);
// 0 = native, 1 = transcoded
string orgCi = isDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
DlnaFlags flagValue = DlnaFlags.StreamingTransferMode |
DlnaFlags.BackgroundTransferMode |
DlnaFlags.InteractiveTransferMode |
DlnaFlags.DlnaV15;
//if (isDirectStream)
//{
// flagValue = flagValue | DlnaFlags.ByteBasedSeek;
//}
//else if (runtimeTicks.HasValue)
//{
// flagValue = flagValue | DlnaFlags.TimeBasedSeek;
//}
string dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}",
DlnaMaps.FlagsToString(flagValue));
ResponseProfile mediaProfile = _profile.GetAudioMediaProfile(container,
audioCodec,
audioChannels,
audioBitrate,
audioSampleRate,
audioBitDepth);
string orgPn = mediaProfile == null ? null : mediaProfile.OrgPn;
if (string.IsNullOrEmpty(orgPn))
{
orgPn = GetAudioOrgPnValue(container, audioBitrate, audioSampleRate, audioChannels);
}
string contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn;
return (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
}
public List<string> BuildVideoHeader(string container,
string videoCodec,
string audioCodec,
int? width,
int? height,
int? bitDepth,
int? videoBitrate,
TransportStreamTimestamp timestamp,
bool isDirectStream,
long? runtimeTicks,
string videoProfile,
double? videoLevel,
float? videoFramerate,
int? packetLength,
TranscodeSeekInfo transcodeSeekInfo,
bool? isAnamorphic,
bool? isInterlaced,
int? refFrames,
int? numVideoStreams,
int? numAudioStreams,
string videoCodecTag,
bool? isAvc)
{
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetOrgOpValue(runtimeTicks > 0, isDirectStream, transcodeSeekInfo);
// 0 = native, 1 = transcoded
string orgCi = isDirectStream ? ";DLNA.ORG_CI=0" : ";DLNA.ORG_CI=1";
DlnaFlags flagValue = DlnaFlags.StreamingTransferMode |
DlnaFlags.BackgroundTransferMode |
DlnaFlags.InteractiveTransferMode |
DlnaFlags.DlnaV15;
//if (isDirectStream)
//{
// flagValue = flagValue | DlnaFlags.ByteBasedSeek;
//}
//else if (runtimeTicks.HasValue)
//{
// flagValue = flagValue | DlnaFlags.TimeBasedSeek;
//}
string dlnaflags = string.Format(";DLNA.ORG_FLAGS={0}",
DlnaMaps.FlagsToString(flagValue));
ResponseProfile mediaProfile = _profile.GetVideoMediaProfile(container,
audioCodec,
videoCodec,
width,
height,
bitDepth,
videoBitrate,
videoProfile,
videoLevel,
videoFramerate,
packetLength,
timestamp,
isAnamorphic,
isInterlaced,
refFrames,
numVideoStreams,
numAudioStreams,
videoCodecTag,
isAvc);
List<string> orgPnValues = new List<string>();
if (mediaProfile != null && !string.IsNullOrEmpty(mediaProfile.OrgPn))
{
orgPnValues.AddRange(mediaProfile.OrgPn.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
}
else
{
foreach (string s in GetVideoOrgPnValue(container, videoCodec, audioCodec, width, height, timestamp))
{
orgPnValues.Add(s);
break;
}
}
List<string> contentFeatureList = new List<string>();
foreach (string orgPn in orgPnValues)
{
string contentFeatures = string.IsNullOrEmpty(orgPn) ? string.Empty : "DLNA.ORG_PN=" + orgPn;
var value = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
contentFeatureList.Add(value);
}
if (orgPnValues.Count == 0)
{
string contentFeatures = string.Empty;
var value = (contentFeatures + orgOp + orgCi + dlnaflags).Trim(';');
contentFeatureList.Add(value);
}
return contentFeatureList;
}
private string GetImageOrgPnValue(string container, int? width, int? height)
{
MediaFormatProfile? format = new MediaFormatProfileResolver()
.ResolveImageFormat(container,
width,
height);
return format.HasValue ? format.Value.ToString() : null;
}
private string GetAudioOrgPnValue(string container, int? audioBitrate, int? audioSampleRate, int? audioChannels)
{
MediaFormatProfile? format = new MediaFormatProfileResolver()
.ResolveAudioFormat(container,
audioBitrate,
audioSampleRate,
audioChannels);
return format.HasValue ? format.Value.ToString() : null;
}
private string[] GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestamp)
{
return new MediaFormatProfileResolver().ResolveVideoFormat(container, videoCodec, audioCodec, width, height, timestamp);
}
}
}
@@ -0,0 +1,61 @@
namespace MediaBrowser.Model.Dlna
{
public class DeviceIdentification
{
/// <summary>
/// Gets or sets the name of the friendly.
/// </summary>
/// <value>The name of the friendly.</value>
public string FriendlyName { get; set; }
/// <summary>
/// Gets or sets the model number.
/// </summary>
/// <value>The model number.</value>
public string ModelNumber { get; set; }
/// <summary>
/// Gets or sets the serial number.
/// </summary>
/// <value>The serial number.</value>
public string SerialNumber { get; set; }
/// <summary>
/// Gets or sets the name of the model.
/// </summary>
/// <value>The name of the model.</value>
public string ModelName { get; set; }
/// <summary>
/// Gets or sets the model description.
/// </summary>
/// <value>The model description.</value>
public string ModelDescription { get; set; }
/// <summary>
/// Gets or sets the device description.
/// </summary>
/// <value>The device description.</value>
public string DeviceDescription { get; set; }
/// <summary>
/// Gets or sets the model URL.
/// </summary>
/// <value>The model URL.</value>
public string ModelUrl { get; set; }
/// <summary>
/// Gets or sets the manufacturer.
/// </summary>
/// <value>The manufacturer.</value>
public string Manufacturer { get; set; }
/// <summary>
/// Gets or sets the manufacturer URL.
/// </summary>
/// <value>The manufacturer URL.</value>
public string ManufacturerUrl { get; set; }
/// <summary>
/// Gets or sets the headers.
/// </summary>
/// <value>The headers.</value>
public HttpHeaderInfo[] Headers { get; set; }
public DeviceIdentification()
{
Headers = new HttpHeaderInfo[] {};
}
}
}
+327
View File
@@ -0,0 +1,327 @@
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.MediaInfo;
using System.Collections.Generic;
using System.Xml.Serialization;
using System;
namespace MediaBrowser.Model.Dlna
{
[XmlRoot("Profile")]
public class DeviceProfile
{
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
public string Name { get; set; }
[XmlIgnore]
public string Id { get; set; }
/// <summary>
/// Gets or sets the identification.
/// </summary>
/// <value>The identification.</value>
public MediaBrowser.Model.Dlna.DeviceIdentification Identification { get; set; }
public string FriendlyName { get; set; }
public string Manufacturer { get; set; }
public string ManufacturerUrl { get; set; }
public string ModelName { get; set; }
public string ModelDescription { get; set; }
public string ModelNumber { get; set; }
public string ModelUrl { get; set; }
public string SerialNumber { get; set; }
public bool EnableAlbumArtInDidl { get; set; }
public bool EnableSingleAlbumArtLimit { get; set; }
public bool EnableSingleSubtitleLimit { get; set; }
public string SupportedMediaTypes { get; set; }
public string UserId { get; set; }
public string AlbumArtPn { get; set; }
public int MaxAlbumArtWidth { get; set; }
public int MaxAlbumArtHeight { get; set; }
public int? MaxIconWidth { get; set; }
public int? MaxIconHeight { get; set; }
public long? MaxStreamingBitrate { get; set; }
public long? MaxStaticBitrate { get; set; }
public int? MusicStreamingTranscodingBitrate { get; set; }
public int? MaxStaticMusicBitrate { get; set; }
/// <summary>
/// Controls the content of the aggregationFlags element in the urn:schemas-sonycom:av namespace.
/// </summary>
public string SonyAggregationFlags { get; set; }
public string ProtocolInfo { get; set; }
public int TimelineOffsetSeconds { get; set; }
public bool RequiresPlainVideoItems { get; set; }
public bool RequiresPlainFolders { get; set; }
public bool EnableMSMediaReceiverRegistrar { get; set; }
public bool IgnoreTranscodeByteRangeRequests { get; set; }
public XmlAttribute[] XmlRootAttributes { get; set; }
/// <summary>
/// Gets or sets the direct play profiles.
/// </summary>
/// <value>The direct play profiles.</value>
public DirectPlayProfile[] DirectPlayProfiles { get; set; }
/// <summary>
/// Gets or sets the transcoding profiles.
/// </summary>
/// <value>The transcoding profiles.</value>
public TranscodingProfile[] TranscodingProfiles { get; set; }
public ContainerProfile[] ContainerProfiles { get; set; }
public CodecProfile[] CodecProfiles { get; set; }
public ResponseProfile[] ResponseProfiles { get; set; }
public SubtitleProfile[] SubtitleProfiles { get; set; }
public DeviceProfile()
{
DirectPlayProfiles = new DirectPlayProfile[] { };
TranscodingProfiles = new TranscodingProfile[] { };
ResponseProfiles = new ResponseProfile[] { };
CodecProfiles = new CodecProfile[] { };
ContainerProfiles = new ContainerProfile[] { };
SubtitleProfiles = Array.Empty<SubtitleProfile>();
XmlRootAttributes = new XmlAttribute[] { };
SupportedMediaTypes = "Audio,Photo,Video";
MaxStreamingBitrate = 8000000;
MaxStaticBitrate = 8000000;
MusicStreamingTranscodingBitrate = 128000;
}
public string[] GetSupportedMediaTypes()
{
return ContainerProfile.SplitValue(SupportedMediaTypes);
}
public TranscodingProfile GetAudioTranscodingProfile(string container, string audioCodec)
{
container = (container ?? string.Empty).TrimStart('.');
foreach (var i in TranscodingProfiles)
{
if (i.Type != MediaBrowser.Model.Dlna.DlnaProfileType.Audio)
{
continue;
}
if (!StringHelper.EqualsIgnoreCase(container, i.Container))
{
continue;
}
if (!ListHelper.ContainsIgnoreCase(i.GetAudioCodecs(), audioCodec ?? string.Empty))
{
continue;
}
return i;
}
return null;
}
public TranscodingProfile GetVideoTranscodingProfile(string container, string audioCodec, string videoCodec)
{
container = (container ?? string.Empty).TrimStart('.');
foreach (var i in TranscodingProfiles)
{
if (i.Type != MediaBrowser.Model.Dlna.DlnaProfileType.Video)
{
continue;
}
if (!StringHelper.EqualsIgnoreCase(container, i.Container))
{
continue;
}
if (!ListHelper.ContainsIgnoreCase(i.GetAudioCodecs(), audioCodec ?? string.Empty))
{
continue;
}
if (!StringHelper.EqualsIgnoreCase(videoCodec, i.VideoCodec ?? string.Empty))
{
continue;
}
return i;
}
return null;
}
public ResponseProfile GetAudioMediaProfile(string container, string audioCodec, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
{
foreach (var i in ResponseProfiles)
{
if (i.Type != DlnaProfileType.Audio)
{
continue;
}
if (!ContainerProfile.ContainsContainer(i.GetContainers(), container))
{
continue;
}
var audioCodecs = i.GetAudioCodecs();
if (audioCodecs.Length > 0 && !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec ?? string.Empty))
{
continue;
}
var conditionProcessor = new ConditionProcessor();
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
{
if (!conditionProcessor.IsAudioConditionSatisfied(GetModelProfileCondition(c), audioChannels, audioBitrate, audioSampleRate, audioBitDepth))
{
anyOff = true;
break;
}
}
if (anyOff)
{
continue;
}
return i;
}
return null;
}
private ProfileCondition GetModelProfileCondition(ProfileCondition c)
{
return new ProfileCondition
{
Condition = c.Condition,
IsRequired = c.IsRequired,
Property = c.Property,
Value = c.Value
};
}
public ResponseProfile GetImageMediaProfile(string container, int? width, int? height)
{
foreach (var i in ResponseProfiles)
{
if (i.Type != DlnaProfileType.Photo)
{
continue;
}
if (!ContainerProfile.ContainsContainer(i.GetContainers(), container))
{
continue;
}
var conditionProcessor = new ConditionProcessor();
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
{
if (!conditionProcessor.IsImageConditionSatisfied(GetModelProfileCondition(c), width, height))
{
anyOff = true;
break;
}
}
if (anyOff)
{
continue;
}
return i;
}
return null;
}
public ResponseProfile GetVideoMediaProfile(string container,
string audioCodec,
string videoCodec,
int? width,
int? height,
int? bitDepth,
int? videoBitrate,
string videoProfile,
double? videoLevel,
float? videoFramerate,
int? packetLength,
TransportStreamTimestamp timestamp,
bool? isAnamorphic,
bool? isInterlaced,
int? refFrames,
int? numVideoStreams,
int? numAudioStreams,
string videoCodecTag,
bool? isAvc)
{
foreach (var i in ResponseProfiles)
{
if (i.Type != DlnaProfileType.Video)
{
continue;
}
if (!ContainerProfile.ContainsContainer(i.GetContainers(), container))
{
continue;
}
var audioCodecs = i.GetAudioCodecs();
if (audioCodecs.Length > 0 && !ListHelper.ContainsIgnoreCase(audioCodecs, audioCodec ?? string.Empty))
{
continue;
}
var videoCodecs = i.GetVideoCodecs();
if (videoCodecs.Length > 0 && !ListHelper.ContainsIgnoreCase(videoCodecs, videoCodec ?? string.Empty))
{
continue;
}
var conditionProcessor = new ConditionProcessor();
var anyOff = false;
foreach (ProfileCondition c in i.Conditions)
{
if (!conditionProcessor.IsVideoConditionSatisfied(GetModelProfileCondition(c), width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isInterlaced, refFrames, numVideoStreams, numAudioStreams, videoCodecTag, isAvc))
{
anyOff = true;
break;
}
}
if (anyOff)
{
continue;
}
return i;
}
return null;
}
}
}
@@ -0,0 +1,24 @@
namespace MediaBrowser.Model.Dlna
{
public class DeviceProfileInfo
{
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>The identifier.</value>
public string Id { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
public string Name { get; set; }
/// <summary>
/// Gets or sets the type.
/// </summary>
/// <value>The type.</value>
public DeviceProfileType Type { get; set; }
}
}
@@ -0,0 +1,8 @@
namespace MediaBrowser.Model.Dlna
{
public enum DeviceProfileType
{
System = 0,
User = 1
}
}
@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
namespace MediaBrowser.Model.Dlna
{
public class DirectPlayProfile
{
[XmlAttribute("container")]
public string Container { get; set; }
[XmlAttribute("audioCodec")]
public string AudioCodec { get; set; }
[XmlAttribute("videoCodec")]
public string VideoCodec { get; set; }
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
public bool SupportsContainer(string container)
{
return ContainerProfile.ContainsContainer(Container, container);
}
public bool SupportsVideoCodec(string codec)
{
return ContainerProfile.ContainsContainer(VideoCodec, codec);
}
public bool SupportsAudioCodec(string codec)
{
return ContainerProfile.ContainsContainer(AudioCodec, codec);
}
}
}
+48
View File
@@ -0,0 +1,48 @@
using System;
namespace MediaBrowser.Model.Dlna
{
[Flags]
public enum DlnaFlags : ulong
{
/*! <i>Background</i> transfer mode.
For use with upload and download transfers to and from the server.
The primary difference between \ref DH_TransferMode_Interactive and
\ref DH_TransferMode_Bulk is that the latter assumes that the user
is not relying on the transfer for immediately rendering the content
and there are no issues with causing a buffer overflow if the
receiver uses TCP flow control to reduce total throughput.
*/
BackgroundTransferMode = 1 << 22,
ByteBasedSeek = 1 << 29,
ConnectionStall = 1 << 21,
DlnaV15 = 1 << 20,
/*! <i>Interactive</i> transfer mode.
For best effort transfer of images and non-real-time transfers.
URIs with image content usually support \ref DH_TransferMode_Bulk too.
The primary difference between \ref DH_TransferMode_Interactive and
\ref DH_TransferMode_Bulk is that the former assumes that the
transfer is intended for immediate rendering.
*/
InteractiveTransferMode = 1 << 23,
PlayContainer = 1 << 28,
RtspPause = 1 << 25,
S0Increase = 1 << 27,
SenderPaced = 1L << 31,
SnIncrease = 1 << 26,
/*! <i>Streaming</i> transfer mode.
The server transmits at a throughput sufficient for real-time playback of
audio or video. URIs with audio or video often support the
\ref DH_TransferMode_Interactive and \ref DH_TransferMode_Bulk transfer modes.
The most well-known exception to this general claim is for live streams.
*/
StreamingTransferMode = 1 << 24,
TimeBasedSeek = 1 << 30
}
}
+56
View File
@@ -0,0 +1,56 @@
namespace MediaBrowser.Model.Dlna
{
public class DlnaMaps
{
private static readonly string DefaultStreaming =
FlagsToString(DlnaFlags.StreamingTransferMode |
DlnaFlags.BackgroundTransferMode |
DlnaFlags.ConnectionStall |
DlnaFlags.ByteBasedSeek |
DlnaFlags.DlnaV15);
private static readonly string DefaultInteractive =
FlagsToString(DlnaFlags.InteractiveTransferMode |
DlnaFlags.BackgroundTransferMode |
DlnaFlags.ConnectionStall |
DlnaFlags.ByteBasedSeek |
DlnaFlags.DlnaV15);
public static string FlagsToString(DlnaFlags flags)
{
return string.Format("{0:X8}{1:D24}", (ulong)flags, 0);
}
public static string GetOrgOpValue(bool hasKnownRuntime, bool isDirectStream, TranscodeSeekInfo profileTranscodeSeekInfo)
{
if (hasKnownRuntime)
{
string orgOp = string.Empty;
// Time-based seeking currently only possible when transcoding
orgOp += isDirectStream ? "0" : "1";
// Byte-based seeking only possible when not transcoding
orgOp += isDirectStream || profileTranscodeSeekInfo == TranscodeSeekInfo.Bytes ? "1" : "0";
return orgOp;
}
// No seeking is available if we don't know the content runtime
return "00";
}
public static string GetImageOrgOpValue()
{
string orgOp = string.Empty;
// Time-based seeking currently only possible when transcoding
orgOp += "0";
// Byte-based seeking only possible when not transcoding
orgOp += "0";
return orgOp;
}
}
}
@@ -0,0 +1,9 @@
namespace MediaBrowser.Model.Dlna
{
public enum DlnaProfileType
{
Audio = 0,
Video = 1,
Photo = 2
}
}
@@ -0,0 +1,8 @@
namespace MediaBrowser.Model.Dlna
{
public enum EncodingContext
{
Streaming = 0,
Static = 1
}
}
@@ -0,0 +1,9 @@
namespace MediaBrowser.Model.Dlna
{
public enum HeaderMatchType
{
Equals = 0,
Regex = 1,
Substring = 2
}
}
+17
View File
@@ -0,0 +1,17 @@
using System.Xml.Serialization;
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Model.Dlna
{
public class HttpHeaderInfo
{
[XmlAttribute("name")]
public string Name { get; set; }
[XmlAttribute("value")]
public string Value { get; set; }
[XmlAttribute("match")]
public HeaderMatchType Match { get; set; }
}
}
@@ -0,0 +1,11 @@
using System;
using MediaBrowser.Model.Events;
namespace MediaBrowser.Model.Dlna
{
public interface IDeviceDiscovery
{
event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscovered;
event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceLeft;
}
}
@@ -0,0 +1,25 @@
namespace MediaBrowser.Model.Dlna
{
public interface ITranscoderSupport
{
bool CanEncodeToAudioCodec(string codec);
bool CanEncodeToSubtitleCodec(string codec);
bool CanExtractSubtitles(string codec);
}
public class FullTranscoderSupport : ITranscoderSupport
{
public bool CanEncodeToAudioCodec(string codec)
{
return true;
}
public bool CanEncodeToSubtitleCodec(string codec)
{
return true;
}
public bool CanExtractSubtitles(string codec)
{
return true;
}
}
}
@@ -0,0 +1,113 @@
namespace MediaBrowser.Model.Dlna
{
public enum MediaFormatProfile
{
MP3,
WMA_BASE,
WMA_FULL,
LPCM16_44_MONO,
LPCM16_44_STEREO,
LPCM16_48_MONO,
LPCM16_48_STEREO,
AAC_ISO,
AAC_ISO_320,
AAC_ADTS,
AAC_ADTS_320,
FLAC,
OGG,
JPEG_SM,
JPEG_MED,
JPEG_LRG,
JPEG_TN,
PNG_LRG,
PNG_TN,
GIF_LRG,
RAW,
MPEG1,
MPEG_PS_PAL,
MPEG_PS_NTSC,
MPEG_TS_SD_EU,
MPEG_TS_SD_EU_ISO,
MPEG_TS_SD_EU_T,
MPEG_TS_SD_NA,
MPEG_TS_SD_NA_ISO,
MPEG_TS_SD_NA_T,
MPEG_TS_SD_KO,
MPEG_TS_SD_KO_ISO,
MPEG_TS_SD_KO_T,
MPEG_TS_JP_T,
AVI,
MATROSKA,
FLV,
DVR_MS,
WTV,
OGV,
AVC_MP4_MP_SD_AAC_MULT5,
AVC_MP4_MP_SD_MPEG1_L3,
AVC_MP4_MP_SD_AC3,
AVC_MP4_MP_HD_720p_AAC,
AVC_MP4_MP_HD_1080i_AAC,
AVC_MP4_HP_HD_AAC,
AVC_TS_MP_HD_AAC_MULT5,
AVC_TS_MP_HD_AAC_MULT5_T,
AVC_TS_MP_HD_AAC_MULT5_ISO,
AVC_TS_MP_HD_MPEG1_L3,
AVC_TS_MP_HD_MPEG1_L3_T,
AVC_TS_MP_HD_MPEG1_L3_ISO,
AVC_TS_MP_HD_AC3,
AVC_TS_MP_HD_AC3_T,
AVC_TS_MP_HD_AC3_ISO,
AVC_TS_HP_HD_MPEG1_L2_T,
AVC_TS_HP_HD_MPEG1_L2_ISO,
AVC_TS_MP_SD_AAC_MULT5,
AVC_TS_MP_SD_AAC_MULT5_T,
AVC_TS_MP_SD_AAC_MULT5_ISO,
AVC_TS_MP_SD_MPEG1_L3,
AVC_TS_MP_SD_MPEG1_L3_T,
AVC_TS_MP_SD_MPEG1_L3_ISO,
AVC_TS_HP_SD_MPEG1_L2_T,
AVC_TS_HP_SD_MPEG1_L2_ISO,
AVC_TS_MP_SD_AC3,
AVC_TS_MP_SD_AC3_T,
AVC_TS_MP_SD_AC3_ISO,
AVC_TS_HD_DTS_T,
AVC_TS_HD_DTS_ISO,
WMVMED_BASE,
WMVMED_FULL,
WMVMED_PRO,
WMVHIGH_FULL,
WMVHIGH_PRO,
VC1_ASF_AP_L1_WMA,
VC1_ASF_AP_L2_WMA,
VC1_ASF_AP_L3_WMA,
VC1_TS_AP_L1_AC3_ISO,
VC1_TS_AP_L2_AC3_ISO,
VC1_TS_HD_DTS_ISO,
VC1_TS_HD_DTS_T,
MPEG4_P2_MP4_ASP_AAC,
MPEG4_P2_MP4_SP_L6_AAC,
MPEG4_P2_MP4_NDSD,
MPEG4_P2_TS_ASP_AAC,
MPEG4_P2_TS_ASP_AAC_T,
MPEG4_P2_TS_ASP_AAC_ISO,
MPEG4_P2_TS_ASP_MPEG1_L3,
MPEG4_P2_TS_ASP_MPEG1_L3_T,
MPEG4_P2_TS_ASP_MPEG1_L3_ISO,
MPEG4_P2_TS_ASP_MPEG2_L2,
MPEG4_P2_TS_ASP_MPEG2_L2_T,
MPEG4_P2_TS_ASP_MPEG2_L2_ISO,
MPEG4_P2_TS_ASP_AC3,
MPEG4_P2_TS_ASP_AC3_T,
MPEG4_P2_TS_ASP_AC3_ISO,
AVC_TS_HD_50_LPCM_T,
AVC_MP4_LPCM,
MPEG4_P2_3GPP_SP_L0B_AAC,
MPEG4_P2_3GPP_SP_L0B_AMR,
AVC_3GPP_BL_QCIF15_AAC,
MPEG4_H263_3GPP_P0_L10_AMR,
MPEG4_H263_MP4_P0_L10_AAC
}
}
@@ -0,0 +1,439 @@
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.MediaInfo;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MediaBrowser.Model.Dlna
{
public class MediaFormatProfileResolver
{
public string[] ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
{
return ResolveVideoFormatInternal(container, videoCodec, audioCodec, width, height, timestampType)
.Select(i => i.ToString())
.ToArray();
}
private MediaFormatProfile[] ResolveVideoFormatInternal(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
{
if (StringHelper.EqualsIgnoreCase(container, "asf"))
{
MediaFormatProfile? val = ResolveVideoASFFormat(videoCodec, audioCodec, width, height);
return val.HasValue ? new MediaFormatProfile[] { val.Value } : new MediaFormatProfile[] { };
}
if (StringHelper.EqualsIgnoreCase(container, "mp4"))
{
MediaFormatProfile? val = ResolveVideoMP4Format(videoCodec, audioCodec, width, height);
return val.HasValue ? new MediaFormatProfile[] { val.Value } : new MediaFormatProfile[] { };
}
if (StringHelper.EqualsIgnoreCase(container, "avi"))
return new MediaFormatProfile[] { MediaFormatProfile.AVI };
if (StringHelper.EqualsIgnoreCase(container, "mkv"))
return new MediaFormatProfile[] { MediaFormatProfile.MATROSKA };
if (StringHelper.EqualsIgnoreCase(container, "mpeg2ps") ||
StringHelper.EqualsIgnoreCase(container, "ts"))
return new MediaFormatProfile[] { MediaFormatProfile.MPEG_PS_NTSC, MediaFormatProfile.MPEG_PS_PAL };
if (StringHelper.EqualsIgnoreCase(container, "mpeg1video"))
return new MediaFormatProfile[] { MediaFormatProfile.MPEG1 };
if (StringHelper.EqualsIgnoreCase(container, "mpeg2ts") ||
StringHelper.EqualsIgnoreCase(container, "mpegts") ||
StringHelper.EqualsIgnoreCase(container, "m2ts"))
{
return ResolveVideoMPEG2TSFormat(videoCodec, audioCodec, width, height, timestampType);
}
if (StringHelper.EqualsIgnoreCase(container, "flv"))
return new MediaFormatProfile[] { MediaFormatProfile.FLV };
if (StringHelper.EqualsIgnoreCase(container, "wtv"))
return new MediaFormatProfile[] { MediaFormatProfile.WTV };
if (StringHelper.EqualsIgnoreCase(container, "3gp"))
{
MediaFormatProfile? val = ResolveVideo3GPFormat(videoCodec, audioCodec);
return val.HasValue ? new MediaFormatProfile[] { val.Value } : new MediaFormatProfile[] { };
}
if (StringHelper.EqualsIgnoreCase(container, "ogv") || StringHelper.EqualsIgnoreCase(container, "ogg"))
return new MediaFormatProfile[] { MediaFormatProfile.OGV };
return new MediaFormatProfile[] { };
}
private MediaFormatProfile[] ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
{
string suffix = "";
switch (timestampType)
{
case TransportStreamTimestamp.None:
suffix = "_ISO";
break;
case TransportStreamTimestamp.Valid:
suffix = "_T";
break;
}
string resolution = "S";
if ((width.HasValue && width.Value > 720) || (height.HasValue && height.Value > 576))
{
resolution = "H";
}
if (StringHelper.EqualsIgnoreCase(videoCodec, "mpeg2video"))
{
List<MediaFormatProfile> list = new List<MediaFormatProfile>();
list.Add(ValueOf("MPEG_TS_SD_NA" + suffix));
list.Add(ValueOf("MPEG_TS_SD_EU" + suffix));
list.Add(ValueOf("MPEG_TS_SD_KO" + suffix));
if ((timestampType == TransportStreamTimestamp.Valid) && StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
{
list.Add(MediaFormatProfile.MPEG_TS_JP_T);
}
return list.ToArray(list.Count);
}
if (StringHelper.EqualsIgnoreCase(videoCodec, "h264"))
{
if (StringHelper.EqualsIgnoreCase(audioCodec, "lpcm"))
return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_50_LPCM_T };
if (StringHelper.EqualsIgnoreCase(audioCodec, "dts"))
{
if (timestampType == TransportStreamTimestamp.None)
{
return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_DTS_ISO };
}
return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_DTS_T };
}
if (StringHelper.EqualsIgnoreCase(audioCodec, "mp2"))
{
if (timestampType == TransportStreamTimestamp.None)
{
return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_HP_{0}D_MPEG1_L2_ISO", resolution)) };
}
return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_HP_{0}D_MPEG1_L2_T", resolution)) };
}
if (StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_AAC_MULT5{1}", resolution, suffix)) };
if (StringHelper.EqualsIgnoreCase(audioCodec, "mp3"))
return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_MPEG1_L3{1}", resolution, suffix)) };
if (string.IsNullOrEmpty(audioCodec) ||
StringHelper.EqualsIgnoreCase(audioCodec, "ac3"))
return new MediaFormatProfile[] { ValueOf(string.Format("AVC_TS_MP_{0}D_AC3{1}", resolution, suffix)) };
}
else if (StringHelper.EqualsIgnoreCase(videoCodec, "vc1"))
{
if (string.IsNullOrEmpty(audioCodec) || StringHelper.EqualsIgnoreCase(audioCodec, "ac3"))
{
if ((width.HasValue && width.Value > 720) || (height.HasValue && height.Value > 576))
{
return new MediaFormatProfile[] { MediaFormatProfile.VC1_TS_AP_L2_AC3_ISO };
}
return new MediaFormatProfile[] { MediaFormatProfile.VC1_TS_AP_L1_AC3_ISO };
}
if (StringHelper.EqualsIgnoreCase(audioCodec, "dts"))
{
suffix = StringHelper.EqualsIgnoreCase(suffix, "_ISO") ? suffix : "_T";
return new MediaFormatProfile[] { ValueOf(string.Format("VC1_TS_HD_DTS{0}", suffix)) };
}
}
else if (StringHelper.EqualsIgnoreCase(videoCodec, "mpeg4") || StringHelper.EqualsIgnoreCase(videoCodec, "msmpeg4"))
{
if (StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_AAC{0}", suffix)) };
if (StringHelper.EqualsIgnoreCase(audioCodec, "mp3"))
return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG1_L3{0}", suffix)) };
if (StringHelper.EqualsIgnoreCase(audioCodec, "mp2"))
return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_MPEG2_L2{0}", suffix)) };
if (StringHelper.EqualsIgnoreCase(audioCodec, "ac3"))
return new MediaFormatProfile[] { ValueOf(string.Format("MPEG4_P2_TS_ASP_AC3{0}", suffix)) };
}
return new MediaFormatProfile[]{};
}
private MediaFormatProfile ValueOf(string value)
{
return (MediaFormatProfile)Enum.Parse(typeof(MediaFormatProfile), value, true);
}
private MediaFormatProfile? ResolveVideoMP4Format(string videoCodec, string audioCodec, int? width, int? height)
{
if (StringHelper.EqualsIgnoreCase(videoCodec, "h264"))
{
if (StringHelper.EqualsIgnoreCase(audioCodec, "lpcm"))
return MediaFormatProfile.AVC_MP4_LPCM;
if (string.IsNullOrEmpty(audioCodec) ||
StringHelper.EqualsIgnoreCase(audioCodec, "ac3"))
{
return MediaFormatProfile.AVC_MP4_MP_SD_AC3;
}
if (StringHelper.EqualsIgnoreCase(audioCodec, "mp3"))
{
return MediaFormatProfile.AVC_MP4_MP_SD_MPEG1_L3;
}
if (width.HasValue && height.HasValue)
{
if ((width.Value <= 720) && (height.Value <= 576))
{
if (StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
return MediaFormatProfile.AVC_MP4_MP_SD_AAC_MULT5;
}
else if ((width.Value <= 1280) && (height.Value <= 720))
{
if (StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
return MediaFormatProfile.AVC_MP4_MP_HD_720p_AAC;
}
else if ((width.Value <= 1920) && (height.Value <= 1080))
{
if (StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
{
return MediaFormatProfile.AVC_MP4_MP_HD_1080i_AAC;
}
}
}
}
else if (StringHelper.EqualsIgnoreCase(videoCodec, "mpeg4") ||
StringHelper.EqualsIgnoreCase(videoCodec, "msmpeg4"))
{
if (width.HasValue && height.HasValue && width.Value <= 720 && height.Value <= 576)
{
if (string.IsNullOrEmpty(audioCodec) || StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
return MediaFormatProfile.MPEG4_P2_MP4_ASP_AAC;
if (StringHelper.EqualsIgnoreCase(audioCodec, "ac3") || StringHelper.EqualsIgnoreCase(audioCodec, "mp3"))
{
return MediaFormatProfile.MPEG4_P2_MP4_NDSD;
}
}
else if (string.IsNullOrEmpty(audioCodec) || StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
{
return MediaFormatProfile.MPEG4_P2_MP4_SP_L6_AAC;
}
}
else if (StringHelper.EqualsIgnoreCase(videoCodec, "h263") && StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
{
return MediaFormatProfile.MPEG4_H263_MP4_P0_L10_AAC;
}
return null;
}
private MediaFormatProfile? ResolveVideo3GPFormat(string videoCodec, string audioCodec)
{
if (StringHelper.EqualsIgnoreCase(videoCodec, "h264"))
{
if (string.IsNullOrEmpty(audioCodec) || StringHelper.EqualsIgnoreCase(audioCodec, "aac"))
return MediaFormatProfile.AVC_3GPP_BL_QCIF15_AAC;
}
else if (StringHelper.EqualsIgnoreCase(videoCodec, "mpeg4") ||
StringHelper.EqualsIgnoreCase(videoCodec, "msmpeg4"))
{
if (string.IsNullOrEmpty(audioCodec) || StringHelper.EqualsIgnoreCase(audioCodec, "wma"))
return MediaFormatProfile.MPEG4_P2_3GPP_SP_L0B_AAC;
if (StringHelper.EqualsIgnoreCase(audioCodec, "amrnb"))
return MediaFormatProfile.MPEG4_P2_3GPP_SP_L0B_AMR;
}
else if (StringHelper.EqualsIgnoreCase(videoCodec, "h263") && StringHelper.EqualsIgnoreCase(audioCodec, "amrnb"))
{
return MediaFormatProfile.MPEG4_H263_3GPP_P0_L10_AMR;
}
return null;
}
private MediaFormatProfile? ResolveVideoASFFormat(string videoCodec, string audioCodec, int? width, int? height)
{
if (StringHelper.EqualsIgnoreCase(videoCodec, "wmv") &&
(string.IsNullOrEmpty(audioCodec) || StringHelper.EqualsIgnoreCase(audioCodec, "wma") || StringHelper.EqualsIgnoreCase(videoCodec, "wmapro")))
{
if (width.HasValue && height.HasValue)
{
if ((width.Value <= 720) && (height.Value <= 576))
{
if (string.IsNullOrEmpty(audioCodec) || StringHelper.EqualsIgnoreCase(audioCodec, "wma"))
{
return MediaFormatProfile.WMVMED_FULL;
}
return MediaFormatProfile.WMVMED_PRO;
}
}
if (string.IsNullOrEmpty(audioCodec) || StringHelper.EqualsIgnoreCase(audioCodec, "wma"))
{
return MediaFormatProfile.WMVHIGH_FULL;
}
return MediaFormatProfile.WMVHIGH_PRO;
}
if (StringHelper.EqualsIgnoreCase(videoCodec, "vc1"))
{
if (width.HasValue && height.HasValue)
{
if ((width.Value <= 720) && (height.Value <= 576))
return MediaFormatProfile.VC1_ASF_AP_L1_WMA;
if ((width.Value <= 1280) && (height.Value <= 720))
return MediaFormatProfile.VC1_ASF_AP_L2_WMA;
if ((width.Value <= 1920) && (height.Value <= 1080))
return MediaFormatProfile.VC1_ASF_AP_L3_WMA;
}
}
else if (StringHelper.EqualsIgnoreCase(videoCodec, "mpeg2video"))
{
return MediaFormatProfile.DVR_MS;
}
return null;
}
public MediaFormatProfile? ResolveAudioFormat(string container, int? bitrate, int? frequency, int? channels)
{
if (StringHelper.EqualsIgnoreCase(container, "asf"))
return ResolveAudioASFFormat(bitrate);
if (StringHelper.EqualsIgnoreCase(container, "mp3"))
return MediaFormatProfile.MP3;
if (StringHelper.EqualsIgnoreCase(container, "lpcm"))
return ResolveAudioLPCMFormat(frequency, channels);
if (StringHelper.EqualsIgnoreCase(container, "mp4") ||
StringHelper.EqualsIgnoreCase(container, "aac"))
return ResolveAudioMP4Format(bitrate);
if (StringHelper.EqualsIgnoreCase(container, "adts"))
return ResolveAudioADTSFormat(bitrate);
if (StringHelper.EqualsIgnoreCase(container, "flac"))
return MediaFormatProfile.FLAC;
if (StringHelper.EqualsIgnoreCase(container, "oga") ||
StringHelper.EqualsIgnoreCase(container, "ogg"))
return MediaFormatProfile.OGG;
return null;
}
private MediaFormatProfile ResolveAudioASFFormat(int? bitrate)
{
if (bitrate.HasValue && bitrate.Value <= 193)
{
return MediaFormatProfile.WMA_BASE;
}
return MediaFormatProfile.WMA_FULL;
}
private MediaFormatProfile? ResolveAudioLPCMFormat(int? frequency, int? channels)
{
if (frequency.HasValue && channels.HasValue)
{
if (frequency.Value == 44100 && channels.Value == 1)
{
return MediaFormatProfile.LPCM16_44_MONO;
}
if (frequency.Value == 44100 && channels.Value == 2)
{
return MediaFormatProfile.LPCM16_44_STEREO;
}
if (frequency.Value == 48000 && channels.Value == 1)
{
return MediaFormatProfile.LPCM16_48_MONO;
}
if (frequency.Value == 48000 && channels.Value == 2)
{
return MediaFormatProfile.LPCM16_48_STEREO;
}
return null;
}
return MediaFormatProfile.LPCM16_48_STEREO;
}
private MediaFormatProfile ResolveAudioMP4Format(int? bitrate)
{
if (bitrate.HasValue && bitrate.Value <= 320)
{
return MediaFormatProfile.AAC_ISO_320;
}
return MediaFormatProfile.AAC_ISO;
}
private MediaFormatProfile ResolveAudioADTSFormat(int? bitrate)
{
if (bitrate.HasValue && bitrate.Value <= 320)
{
return MediaFormatProfile.AAC_ADTS_320;
}
return MediaFormatProfile.AAC_ADTS;
}
public MediaFormatProfile? ResolveImageFormat(string container, int? width, int? height)
{
if (StringHelper.EqualsIgnoreCase(container, "jpeg") ||
StringHelper.EqualsIgnoreCase(container, "jpg"))
return ResolveImageJPGFormat(width, height);
if (StringHelper.EqualsIgnoreCase(container, "png"))
return ResolveImagePNGFormat(width, height);
if (StringHelper.EqualsIgnoreCase(container, "gif"))
return MediaFormatProfile.GIF_LRG;
if (StringHelper.EqualsIgnoreCase(container, "raw"))
return MediaFormatProfile.RAW;
return null;
}
private MediaFormatProfile ResolveImageJPGFormat(int? width, int? height)
{
if (width.HasValue && height.HasValue)
{
if ((width.Value <= 160) && (height.Value <= 160))
return MediaFormatProfile.JPEG_TN;
if ((width.Value <= 640) && (height.Value <= 480))
return MediaFormatProfile.JPEG_SM;
if ((width.Value <= 1024) && (height.Value <= 768))
{
return MediaFormatProfile.JPEG_MED;
}
return MediaFormatProfile.JPEG_LRG;
}
return MediaFormatProfile.JPEG_SM;
}
private MediaFormatProfile ResolveImagePNGFormat(int? width, int? height)
{
if (width.HasValue && height.HasValue)
{
if ((width.Value <= 160) && (height.Value <= 160))
return MediaFormatProfile.PNG_TN;
}
return MediaFormatProfile.PNG_LRG;
}
}
}
@@ -0,0 +1,10 @@
namespace MediaBrowser.Model.Dlna
{
public enum PlaybackErrorCode
{
NotAllowed = 0,
NoCompatibleStream = 1,
RateLimitExceeded = 2
}
}
@@ -0,0 +1,38 @@
using System.Xml.Serialization;
namespace MediaBrowser.Model.Dlna
{
public class ProfileCondition
{
[XmlAttribute("condition")]
public ProfileConditionType Condition { get; set; }
[XmlAttribute("property")]
public ProfileConditionValue Property { get; set; }
[XmlAttribute("value")]
public string Value { get; set; }
[XmlAttribute("isRequired")]
public bool IsRequired { get; set; }
public ProfileCondition()
{
IsRequired = true;
}
public ProfileCondition(ProfileConditionType condition, ProfileConditionValue property, string value)
: this(condition, property, value, false)
{
}
public ProfileCondition(ProfileConditionType condition, ProfileConditionValue property, string value, bool isRequired)
{
Condition = condition;
Property = property;
Value = value;
IsRequired = isRequired;
}
}
}
@@ -0,0 +1,11 @@
namespace MediaBrowser.Model.Dlna
{
public enum ProfileConditionType
{
Equals = 0,
NotEquals = 1,
LessThanEqual = 2,
GreaterThanEqual = 3,
EqualsAny = 4
}
}
@@ -0,0 +1,29 @@
namespace MediaBrowser.Model.Dlna
{
public enum ProfileConditionValue
{
AudioChannels = 0,
AudioBitrate = 1,
AudioProfile = 2,
Width = 3,
Height = 4,
Has64BitOffsets = 5,
PacketLength = 6,
VideoBitDepth = 7,
VideoBitrate = 8,
VideoFramerate = 9,
VideoLevel = 10,
VideoProfile = 11,
VideoTimestamp = 12,
IsAnamorphic = 13,
RefFrames = 14,
NumAudioStreams = 16,
NumVideoStreams = 17,
IsSecondaryAudio = 18,
VideoCodecTag = 19,
IsAvc = 20,
IsInterlaced = 21,
AudioSampleRate = 22,
AudioBitDepth = 23
}
}
@@ -0,0 +1,14 @@
namespace MediaBrowser.Model.Dlna
{
public class ResolutionConfiguration
{
public int MaxWidth { get; set; }
public int MaxBitrate { get; set; }
public ResolutionConfiguration(int maxWidth, int maxBitrate)
{
MaxWidth = maxWidth;
MaxBitrate = maxBitrate;
}
}
}
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using MediaBrowser.Model.Extensions;
namespace MediaBrowser.Model.Dlna
{
public class ResolutionNormalizer
{
private static readonly ResolutionConfiguration[] Configurations =
new []
{
new ResolutionConfiguration(426, 320000),
new ResolutionConfiguration(640, 400000),
new ResolutionConfiguration(720, 950000),
new ResolutionConfiguration(1280, 2500000),
new ResolutionConfiguration(1920, 4000000),
new ResolutionConfiguration(3840, 35000000)
};
public static ResolutionOptions Normalize(int? inputBitrate,
int? unused1,
int? unused2,
int outputBitrate,
string inputCodec,
string outputCodec,
int? maxWidth,
int? maxHeight)
{
// If the bitrate isn't changing, then don't downlscale the resolution
if (inputBitrate.HasValue && outputBitrate >= inputBitrate.Value)
{
if (maxWidth.HasValue || maxHeight.HasValue)
{
return new ResolutionOptions
{
MaxWidth = maxWidth,
MaxHeight = maxHeight
};
}
}
var resolutionConfig = GetResolutionConfiguration(outputBitrate);
if (resolutionConfig != null)
{
var originvalValue = maxWidth;
maxWidth = Math.Min(resolutionConfig.MaxWidth, maxWidth ?? resolutionConfig.MaxWidth);
if (!originvalValue.HasValue || originvalValue.Value != maxWidth.Value)
{
maxHeight = null;
}
}
return new ResolutionOptions
{
MaxWidth = maxWidth,
MaxHeight = maxHeight
};
}
private static ResolutionConfiguration GetResolutionConfiguration(int outputBitrate)
{
ResolutionConfiguration previousOption = null;
foreach (var config in Configurations)
{
if (outputBitrate <= config.MaxBitrate)
{
return previousOption ?? config;
}
previousOption = config;
}
return null;
}
private static double GetVideoBitrateScaleFactor(string codec)
{
if (StringHelper.EqualsIgnoreCase(codec, "h265") ||
StringHelper.EqualsIgnoreCase(codec, "hevc") ||
StringHelper.EqualsIgnoreCase(codec, "vp9"))
{
return .5;
}
return 1;
}
public static int ScaleBitrate(int bitrate, string inputVideoCodec, string outputVideoCodec)
{
var inputScaleFactor = GetVideoBitrateScaleFactor(inputVideoCodec);
var outputScaleFactor = GetVideoBitrateScaleFactor(outputVideoCodec);
var scaleFactor = outputScaleFactor/inputScaleFactor;
var newBitrate = scaleFactor*bitrate;
return Convert.ToInt32(newBitrate);
}
}
}
@@ -0,0 +1,8 @@
namespace MediaBrowser.Model.Dlna
{
public class ResolutionOptions
{
public int? MaxWidth { get; set; }
public int? MaxHeight { get; set; }
}
}
@@ -0,0 +1,49 @@
using System.Collections.Generic;
using System.Xml.Serialization;
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Model.Dlna
{
public class ResponseProfile
{
[XmlAttribute("container")]
public string Container { get; set; }
[XmlAttribute("audioCodec")]
public string AudioCodec { get; set; }
[XmlAttribute("videoCodec")]
public string VideoCodec { get; set; }
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
[XmlAttribute("orgPn")]
public string OrgPn { get; set; }
[XmlAttribute("mimeType")]
public string MimeType { get; set; }
public ProfileCondition[] Conditions { get; set; }
public ResponseProfile()
{
Conditions = new ProfileCondition[] {};
}
public string[] GetContainers()
{
return ContainerProfile.SplitValue(Container);
}
public string[] GetAudioCodecs()
{
return ContainerProfile.SplitValue(AudioCodec);
}
public string[] GetVideoCodecs()
{
return ContainerProfile.SplitValue(VideoCodec);
}
}
}
+75
View File
@@ -0,0 +1,75 @@
using MediaBrowser.Model.Extensions;
using System;
using System.Text.RegularExpressions;
namespace MediaBrowser.Model.Dlna
{
public class SearchCriteria
{
public SearchType SearchType { get; set; }
/// <summary>
/// Splits the specified string.
/// </summary>
/// <param name="str">The string.</param>
/// <param name="term">The term.</param>
/// <param name="limit">The limit.</param>
/// <returns>System.String[].</returns>
private string[] RegexSplit(string str, string term, int limit)
{
return new Regex(term).Split(str, limit);
}
/// <summary>
/// Splits the specified string.
/// </summary>
/// <param name="str">The string.</param>
/// <param name="term">The term.</param>
/// <returns>System.String[].</returns>
private string[] RegexSplit(string str, string term)
{
return Regex.Split(str, term, RegexOptions.IgnoreCase);
}
public SearchCriteria(string search)
{
if (string.IsNullOrEmpty(search))
{
throw new ArgumentNullException("search");
}
SearchType = SearchType.Unknown;
String[] factors = RegexSplit(search, "(and|or)");
foreach (String factor in factors)
{
String[] subFactors = RegexSplit(factor.Trim().Trim('(').Trim(')').Trim(), "\\s", 3);
if (subFactors.Length == 3)
{
if (StringHelper.EqualsIgnoreCase("upnp:class", subFactors[0]) &&
(StringHelper.EqualsIgnoreCase("=", subFactors[1]) || StringHelper.EqualsIgnoreCase("derivedfrom", subFactors[1])))
{
if (StringHelper.EqualsIgnoreCase("\"object.item.imageItem\"", subFactors[2]) || StringHelper.EqualsIgnoreCase("\"object.item.imageItem.photo\"", subFactors[2]))
{
SearchType = SearchType.Image;
}
else if (StringHelper.EqualsIgnoreCase("\"object.item.videoItem\"", subFactors[2]))
{
SearchType = SearchType.Video;
}
else if (StringHelper.EqualsIgnoreCase("\"object.container.playlistContainer\"", subFactors[2]))
{
SearchType = SearchType.Playlist;
}
else if (StringHelper.EqualsIgnoreCase("\"object.container.album.musicAlbum\"", subFactors[2]))
{
SearchType = SearchType.MusicAlbum;
}
}
}
}
}
}
}
+12
View File
@@ -0,0 +1,12 @@
namespace MediaBrowser.Model.Dlna
{
public enum SearchType
{
Unknown = 0,
Audio = 1,
Image = 2,
Video = 3,
Playlist = 4,
MusicAlbum = 5
}
}
+17
View File
@@ -0,0 +1,17 @@
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Model.Dlna
{
public class SortCriteria
{
public SortOrder SortOrder
{
get { return SortOrder.Ascending; }
}
public SortCriteria(string value)
{
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,22 @@
namespace MediaBrowser.Model.Dlna
{
public enum SubtitleDeliveryMethod
{
/// <summary>
/// The encode
/// </summary>
Encode = 0,
/// <summary>
/// The embed
/// </summary>
Embed = 1,
/// <summary>
/// The external
/// </summary>
External = 2,
/// <summary>
/// The HLS
/// </summary>
Hls = 3
}
}
@@ -0,0 +1,46 @@
using MediaBrowser.Model.Extensions;
using System.Collections.Generic;
using System.Xml.Serialization;
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Model.Dlna
{
public class SubtitleProfile
{
[XmlAttribute("format")]
public string Format { get; set; }
[XmlAttribute("method")]
public SubtitleDeliveryMethod Method { get; set; }
[XmlAttribute("didlMode")]
public string DidlMode { get; set; }
[XmlAttribute("language")]
public string Language { get; set; }
[XmlAttribute("container")]
public string Container { get; set; }
public string[] GetLanguages()
{
return ContainerProfile.SplitValue(Language);
}
public bool SupportsLanguage(string subLanguage)
{
if (string.IsNullOrEmpty(Language))
{
return true;
}
if (string.IsNullOrEmpty(subLanguage))
{
subLanguage = "und";
}
var languages = GetLanguages();
return languages.Length == 0 || ListHelper.ContainsIgnoreCase(languages, subLanguage);
}
}
}
@@ -0,0 +1,15 @@
namespace MediaBrowser.Model.Dlna
{
public class SubtitleStreamInfo
{
public string Url { get; set; }
public string Language { get; set; }
public string Name { get; set; }
public bool IsForced { get; set; }
public string Format { get; set; }
public string DisplayTitle { get; set; }
public int Index { get; set; }
public SubtitleDeliveryMethod DeliveryMethod { get; set; }
public bool IsExternalUrl { get; set; }
}
}
@@ -0,0 +1,8 @@
namespace MediaBrowser.Model.Dlna
{
public enum TranscodeSeekInfo
{
Auto = 0,
Bytes = 1
}
}
@@ -0,0 +1,59 @@
using System.Collections.Generic;
using System.Xml.Serialization;
using MediaBrowser.Model.Dlna;
namespace MediaBrowser.Model.Dlna
{
public class TranscodingProfile
{
[XmlAttribute("container")]
public string Container { get; set; }
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
[XmlAttribute("videoCodec")]
public string VideoCodec { get; set; }
[XmlAttribute("audioCodec")]
public string AudioCodec { get; set; }
[XmlAttribute("protocol")]
public string Protocol { get; set; }
[XmlAttribute("estimateContentLength")]
public bool EstimateContentLength { get; set; }
[XmlAttribute("enableMpegtsM2TsMode")]
public bool EnableMpegtsM2TsMode { get; set; }
[XmlAttribute("transcodeSeekInfo")]
public TranscodeSeekInfo TranscodeSeekInfo { get; set; }
[XmlAttribute("copyTimestamps")]
public bool CopyTimestamps { get; set; }
[XmlAttribute("context")]
public EncodingContext Context { get; set; }
[XmlAttribute("enableSubtitlesInManifest")]
public bool EnableSubtitlesInManifest { get; set; }
[XmlAttribute("maxAudioChannels")]
public string MaxAudioChannels { get; set; }
[XmlAttribute("minSegments")]
public int MinSegments { get; set; }
[XmlAttribute("segmentLength")]
public int SegmentLength { get; set; }
[XmlAttribute("breakOnNonKeyFrames")]
public bool BreakOnNonKeyFrames { get; set; }
public string[] GetAudioCodecs()
{
return ContainerProfile.SplitValue(AudioCodec);
}
}
}
+14
View File
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using MediaBrowser.Model.Net;
namespace MediaBrowser.Model.Dlna
{
public class UpnpDeviceInfo
{
public Uri Location { get; set; }
public Dictionary<string, string> Headers { get; set; }
public IpAddressInfo LocalIpAddress { get; set; }
public int LocalPort { get; set; }
}
}
+11
View File
@@ -0,0 +1,11 @@
namespace MediaBrowser.Model.Dlna
{
/// <summary>
/// Class VideoOptions.
/// </summary>
public class VideoOptions : AudioOptions
{
public int? AudioStreamIndex { get; set; }
public int? SubtitleStreamIndex { get; set; }
}
}
+13
View File
@@ -0,0 +1,13 @@
using System.Xml.Serialization;
namespace MediaBrowser.Model.Dlna
{
public class XmlAttribute
{
[XmlAttribute("name")]
public string Name { get; set; }
[XmlAttribute("value")]
public string Value { get; set; }
}
}