public DeviceProfile() { DirectPlayProfiles = new DirectPlayProfile[] { }; TranscodingProfiles = new TranscodingProfile[] { }; ResponseProfiles = new ResponseProfile[] { }; CodecProfiles = new CodecProfile[] { }; ContainerProfiles = new ContainerProfile[] { }; SupportedMediaTypes = "Audio,Photo,Video"; }
public DeviceProfile() { DirectPlayProfiles = new DirectPlayProfile[] { }; TranscodingProfiles = new TranscodingProfile[] { }; ResponseProfiles = new ResponseProfile[] { }; CodecProfiles = new CodecProfile[] { }; ContainerProfiles = new ContainerProfile[] { }; XmlRootAttributes = new XmlAttribute[] { }; SupportedMediaTypes = "Audio,Photo,Video"; }
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; }
private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options) { StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Video, MediaSource = item, RunTimeTicks = item.RunTimeTicks, Context = options.Context, DeviceProfile = options.Profile }; playlistItem.SubtitleStreamIndex = options.SubtitleStreamIndex ?? GetDefaultSubtitleStreamIndex(item, options.Profile.SubtitleProfiles); MediaStream subtitleStream = playlistItem.SubtitleStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Subtitle, playlistItem.SubtitleStreamIndex.Value) : null; MediaStream audioStream = item.GetDefaultAudioStream(options.AudioStreamIndex ?? item.DefaultAudioStreamIndex); int? audioStreamIndex = null; if (audioStream != null) { audioStreamIndex = audioStream.Index; } MediaStream videoStream = item.VideoStream; // TODO: This doesn't accout for situation of device being able to handle media bitrate, but wifi connection not fast enough bool isEligibleForDirectPlay = IsEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options), subtitleStream, options, PlayMethod.DirectPlay); bool isEligibleForDirectStream = IsEligibleForDirectPlay(item, options.GetMaxBitrate(), subtitleStream, options, PlayMethod.DirectStream); _logger.Info("Profile: {0}, Path: {1}, isEligibleForDirectPlay: {2}, isEligibleForDirectStream: {3}", options.Profile.Name ?? "Unknown Profile", item.Path ?? "Unknown path", isEligibleForDirectPlay, isEligibleForDirectStream); if (isEligibleForDirectPlay || isEligibleForDirectStream) { // See if it can be direct played PlayMethod?directPlay = GetVideoDirectPlayProfile(options.Profile, item, videoStream, audioStream, isEligibleForDirectPlay, isEligibleForDirectStream); if (directPlay != null) { playlistItem.PlayMethod = directPlay.Value; playlistItem.Container = item.Container; if (subtitleStream != null) { SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile.SubtitleProfiles, directPlay.Value); playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method; playlistItem.SubtitleFormat = subtitleProfile.Format; } return(playlistItem); } } // Can't direct play, find the transcoding profile TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { if (i.Type == playlistItem.MediaType && i.Context == options.Context) { transcodingProfile = i; break; } } if (transcodingProfile != null) { if (!item.SupportsTranscoding) { return(null); } if (subtitleStream != null) { SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile.SubtitleProfiles, PlayMethod.Transcode); playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method; playlistItem.SubtitleFormat = subtitleProfile.Format; } playlistItem.PlayMethod = PlayMethod.Transcode; playlistItem.Container = transcodingProfile.Container; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(','); playlistItem.VideoCodec = transcodingProfile.VideoCodec; playlistItem.CopyTimestamps = transcodingProfile.CopyTimestamps; playlistItem.ForceLiveStream = transcodingProfile.ForceLiveStream; if (!string.IsNullOrEmpty(transcodingProfile.MaxAudioChannels)) { int transcodingMaxAudioChannels; if (IntHelper.TryParseCultureInvariant(transcodingProfile.MaxAudioChannels, out transcodingMaxAudioChannels)) { playlistItem.TranscodingMaxAudioChannels = transcodingMaxAudioChannels; } } playlistItem.SubProtocol = transcodingProfile.Protocol; playlistItem.AudioStreamIndex = audioStreamIndex; List <ProfileCondition> videoTranscodingConditions = new List <ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec, transcodingProfile.Container)) { foreach (ProfileCondition c in i.Conditions) { videoTranscodingConditions.Add(c); } break; } } ApplyTranscodingConditions(playlistItem, videoTranscodingConditions); List <ProfileCondition> audioTranscodingConditions = new List <ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.VideoAudio && i.ContainsCodec(playlistItem.TargetAudioCodec, transcodingProfile.Container)) { foreach (ProfileCondition c in i.Conditions) { audioTranscodingConditions.Add(c); } break; } } ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { int currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } int audioBitrate = GetAudioBitrate(options.GetMaxBitrate(), playlistItem.TargetAudioChannels, playlistItem.TargetAudioCodec, audioStream); playlistItem.AudioBitrate = Math.Min(playlistItem.AudioBitrate ?? audioBitrate, audioBitrate); int?maxBitrateSetting = options.GetMaxBitrate(); // Honor max rate if (maxBitrateSetting.HasValue) { int videoBitrate = maxBitrateSetting.Value; if (playlistItem.AudioBitrate.HasValue) { videoBitrate -= playlistItem.AudioBitrate.Value; } // Make sure the video bitrate is lower than bitrate settings but at least 64k int currentValue = playlistItem.VideoBitrate ?? videoBitrate; playlistItem.VideoBitrate = Math.Max(Math.Min(videoBitrate, currentValue), 64000); } } return(playlistItem); }
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) { StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Audio, MediaSource = item, RunTimeTicks = item.RunTimeTicks, Context = options.Context, DeviceProfile = options.Profile }; MediaStream audioStream = item.GetDefaultAudioStream(null); List <PlayMethod> directPlayMethods = GetAudioDirectPlayMethods(item, audioStream, options); if (directPlayMethods.Count > 0) { string audioCodec = audioStream == null ? null : audioStream.Codec; // Make sure audio codec profiles are satisfied if (!string.IsNullOrEmpty(audioCodec)) { ConditionProcessor conditionProcessor = new ConditionProcessor(); List <ProfileCondition> conditions = new List <ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec, item.Container)) { foreach (ProfileCondition c in i.Conditions) { conditions.Add(c); } } } int?audioChannels = audioStream.Channels; int?audioBitrate = audioStream.BitRate; bool all = true; foreach (ProfileCondition c in conditions) { if (!conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate)) { LogConditionFailure(options.Profile, "AudioCodecProfile", c, item); all = false; break; } } if (all) { if (item.Protocol == MediaProtocol.File && directPlayMethods.Contains(PlayMethod.DirectPlay) && _localPlayer.CanAccessFile(item.Path)) { playlistItem.PlayMethod = PlayMethod.DirectPlay; } else if (item.Protocol == MediaProtocol.Http && directPlayMethods.Contains(PlayMethod.DirectPlay) && _localPlayer.CanAccessUrl(item.Path, item.RequiredHttpHeaders.Count > 0)) { playlistItem.PlayMethod = PlayMethod.DirectPlay; } else if (directPlayMethods.Contains(PlayMethod.DirectStream)) { playlistItem.PlayMethod = PlayMethod.DirectStream; } playlistItem.Container = item.Container; return(playlistItem); } } } TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { if (i.Type == playlistItem.MediaType && i.Context == options.Context) { if (_transcoderSupport.CanEncodeToAudioCodec(i.AudioCodec ?? i.Container)) { transcodingProfile = i; break; } } } if (transcodingProfile != null) { if (!item.SupportsTranscoding) { return(null); } playlistItem.PlayMethod = PlayMethod.Transcode; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.Container = transcodingProfile.Container; if (string.IsNullOrEmpty(transcodingProfile.AudioCodec)) { playlistItem.AudioCodecs = new string[] { }; } else { playlistItem.AudioCodecs = transcodingProfile.AudioCodec.Split(','); } playlistItem.SubProtocol = transcodingProfile.Protocol; List <CodecProfile> audioCodecProfiles = new List <CodecProfile>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container)) { audioCodecProfiles.Add(i); } if (audioCodecProfiles.Count >= 1) { break; } } List <ProfileCondition> audioTranscodingConditions = new List <ProfileCondition>(); foreach (CodecProfile i in audioCodecProfiles) { foreach (ProfileCondition c in i.Conditions) { audioTranscodingConditions.Add(c); } } ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { int currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } int configuredBitrate = options.AudioTranscodingBitrate ?? (options.Context == EncodingContext.Static ? options.Profile.MusicSyncBitrate : options.Profile.MusicStreamingTranscodingBitrate) ?? 128000; playlistItem.AudioBitrate = Math.Min(configuredBitrate, playlistItem.AudioBitrate ?? configuredBitrate); } return(playlistItem); }
private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options) { StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Video, MediaSource = item, RunTimeTicks = item.RunTimeTicks, Context = options.Context, DeviceProfile = options.Profile }; int?audioStreamIndex = options.AudioStreamIndex ?? item.DefaultAudioStreamIndex; playlistItem.SubtitleStreamIndex = options.SubtitleStreamIndex ?? item.DefaultSubtitleStreamIndex; MediaStream audioStream = audioStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Audio, audioStreamIndex.Value) : null; MediaStream subtitleStream = playlistItem.SubtitleStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Subtitle, playlistItem.SubtitleStreamIndex.Value) : null; MediaStream videoStream = item.VideoStream; int?maxBitrateSetting = options.GetMaxBitrate(); if (IsEligibleForDirectPlay(item, maxBitrateSetting, subtitleStream, options)) { // See if it can be direct played var directPlay = GetVideoDirectPlayProfile(options, options.Profile, item, videoStream, audioStream); if (directPlay != null) { playlistItem.PlayMethod = directPlay.Value; playlistItem.Container = item.Container; if (subtitleStream != null) { SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile, options.Context); playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method; playlistItem.SubtitleFormat = subtitleProfile.Format; } return(playlistItem); } } // Can't direct play, find the transcoding profile TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { if (i.Type == playlistItem.MediaType && i.Context == options.Context) { transcodingProfile = i; break; } } if (transcodingProfile != null) { if (!item.SupportsTranscoding) { return(null); } if (subtitleStream != null) { SubtitleProfile subtitleProfile = GetSubtitleProfile(subtitleStream, options.Profile, options.Context); playlistItem.SubtitleDeliveryMethod = subtitleProfile.Method; playlistItem.SubtitleFormat = subtitleProfile.Format; } playlistItem.PlayMethod = PlayMethod.Transcode; playlistItem.Container = transcodingProfile.Container; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',')[0]; playlistItem.VideoCodec = transcodingProfile.VideoCodec; playlistItem.Protocol = transcodingProfile.Protocol; playlistItem.AudioStreamIndex = audioStreamIndex; List <ProfileCondition> videoTranscodingConditions = new List <ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec)) { foreach (ProfileCondition c in i.Conditions) { videoTranscodingConditions.Add(c); } break; } } ApplyTranscodingConditions(playlistItem, videoTranscodingConditions); List <ProfileCondition> audioTranscodingConditions = new List <ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec)) { foreach (ProfileCondition c in i.Conditions) { audioTranscodingConditions.Add(c); } break; } } ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { int currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } if (!playlistItem.AudioBitrate.HasValue) { playlistItem.AudioBitrate = GetAudioBitrate(playlistItem.TargetAudioChannels, playlistItem.TargetAudioCodec); } // Honor max rate if (maxBitrateSetting.HasValue) { int videoBitrate = maxBitrateSetting.Value; if (playlistItem.AudioBitrate.HasValue) { videoBitrate -= playlistItem.AudioBitrate.Value; } int currentValue = playlistItem.VideoBitrate ?? videoBitrate; playlistItem.VideoBitrate = Math.Min(videoBitrate, currentValue); } } return(playlistItem); }
private StreamInfo BuildAudioItem(MediaSourceInfo item, AudioOptions options) { StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Audio, MediaSource = item, RunTimeTicks = item.RunTimeTicks, Context = options.Context }; int?maxBitrateSetting = options.GetMaxBitrate(); MediaStream audioStream = item.DefaultAudioStream; // Honor the max bitrate setting if (IsAudioEligibleForDirectPlay(item, maxBitrateSetting)) { DirectPlayProfile directPlay = null; foreach (DirectPlayProfile i in options.Profile.DirectPlayProfiles) { if (i.Type == playlistItem.MediaType && IsAudioDirectPlaySupported(i, item, audioStream)) { directPlay = i; break; } } if (directPlay != null) { string audioCodec = audioStream == null ? null : audioStream.Codec; // Make sure audio codec profiles are satisfied if (!string.IsNullOrEmpty(audioCodec)) { ConditionProcessor conditionProcessor = new ConditionProcessor(); List <ProfileCondition> conditions = new List <ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec)) { foreach (ProfileCondition c in i.Conditions) { conditions.Add(c); } } } int?audioChannels = audioStream.Channels; int?audioBitrate = audioStream.BitRate; bool all = true; foreach (ProfileCondition c in conditions) { if (!conditionProcessor.IsAudioConditionSatisfied(c, audioChannels, audioBitrate)) { all = false; break; } } if (all) { playlistItem.PlayMethod = PlayMethod.DirectStream; playlistItem.Container = item.Container; return(playlistItem); } } } } TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { if (i.Type == playlistItem.MediaType && i.Context == options.Context) { transcodingProfile = i; break; } } if (transcodingProfile != null) { playlistItem.PlayMethod = PlayMethod.Transcode; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.Container = transcodingProfile.Container; playlistItem.AudioCodec = transcodingProfile.AudioCodec; playlistItem.Protocol = transcodingProfile.Protocol; List <CodecProfile> audioCodecProfiles = new List <CodecProfile>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec)) { audioCodecProfiles.Add(i); } if (audioCodecProfiles.Count >= 1) { break; } } List <ProfileCondition> audioTranscodingConditions = new List <ProfileCondition>(); foreach (CodecProfile i in audioCodecProfiles) { foreach (ProfileCondition c in i.Conditions) { audioTranscodingConditions.Add(c); } } ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { int currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } int configuredBitrate = options.AudioTranscodingBitrate ?? (options.Context == EncodingContext.Static ? options.Profile.MusicSyncBitrate : options.Profile.MusicStreamingTranscodingBitrate) ?? 128000; playlistItem.AudioBitrate = Math.Min(configuredBitrate, playlistItem.AudioBitrate ?? configuredBitrate); } return(playlistItem); }
public DeviceProfile() { DirectPlayProfiles = new DirectPlayProfile[] { }; TranscodingProfiles = new TranscodingProfile[] { }; ResponseProfiles = new ResponseProfile[] { }; CodecProfiles = new CodecProfile[] { }; ContainerProfiles = new ContainerProfile[] { }; SubtitleProfiles = new SubtitleProfile[] { }; XmlRootAttributes = new XmlAttribute[] { }; SupportedMediaTypes = "Audio,Photo,Video"; MaxStreamingBitrate = 8000000; MaxStaticBitrate = 8000000; MusicStreamingTranscodingBitrate = 128000; }
private bool IsSupported(DeviceProfile profile, TranscodingProfile transcodingProfile, Video item) { // Placeholder for future conditions return true; }
private StreamInfo BuildVideoItem(MediaSourceInfo item, VideoOptions options) { StreamInfo playlistItem = new StreamInfo { ItemId = options.ItemId, MediaType = DlnaProfileType.Video, MediaSource = item, RunTimeTicks = item.RunTimeTicks }; MediaStream audioStream = item.DefaultAudioStream; MediaStream videoStream = item.VideoStream; int?maxBitrateSetting = options.MaxBitrate ?? options.Profile.MaxBitrate; if (IsEligibleForDirectPlay(item, options, maxBitrateSetting)) { // See if it can be direct played DirectPlayProfile directPlay = GetVideoDirectPlayProfile(options.Profile, item, videoStream, audioStream); if (directPlay != null) { playlistItem.IsDirectStream = true; playlistItem.Container = item.Container; return(playlistItem); } } // Can't direct play, find the transcoding profile TranscodingProfile transcodingProfile = null; foreach (TranscodingProfile i in options.Profile.TranscodingProfiles) { if (i.Type == playlistItem.MediaType) { transcodingProfile = i; break; } } if (transcodingProfile != null) { playlistItem.IsDirectStream = false; playlistItem.Container = transcodingProfile.Container; playlistItem.EstimateContentLength = transcodingProfile.EstimateContentLength; playlistItem.TranscodeSeekInfo = transcodingProfile.TranscodeSeekInfo; playlistItem.AudioCodec = transcodingProfile.AudioCodec.Split(',')[0]; playlistItem.VideoCodec = transcodingProfile.VideoCodec; playlistItem.Protocol = transcodingProfile.Protocol; playlistItem.AudioStreamIndex = options.AudioStreamIndex ?? item.DefaultAudioStreamIndex; playlistItem.SubtitleStreamIndex = options.SubtitleStreamIndex ?? item.DefaultSubtitleStreamIndex; List <ProfileCondition> videoTranscodingConditions = new List <ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec)) { videoTranscodingConditions.AddRange(i.Conditions); break; } } ApplyTranscodingConditions(playlistItem, videoTranscodingConditions); List <ProfileCondition> audioTranscodingConditions = new List <ProfileCondition>(); foreach (CodecProfile i in options.Profile.CodecProfiles) { if (i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec)) { audioTranscodingConditions.AddRange(i.Conditions); break; } } ApplyTranscodingConditions(playlistItem, audioTranscodingConditions); // Honor requested max channels if (options.MaxAudioChannels.HasValue) { int currentValue = playlistItem.MaxAudioChannels ?? options.MaxAudioChannels.Value; playlistItem.MaxAudioChannels = Math.Min(options.MaxAudioChannels.Value, currentValue); } // Honor requested max bitrate if (options.MaxAudioTranscodingBitrate.HasValue) { int currentValue = playlistItem.AudioBitrate ?? options.MaxAudioTranscodingBitrate.Value; playlistItem.AudioBitrate = Math.Min(options.MaxAudioTranscodingBitrate.Value, currentValue); } // Honor max rate if (maxBitrateSetting.HasValue) { int videoBitrate = maxBitrateSetting.Value; if (playlistItem.AudioBitrate.HasValue) { videoBitrate -= playlistItem.AudioBitrate.Value; } int currentValue = playlistItem.VideoBitrate ?? videoBitrate; playlistItem.VideoBitrate = Math.Min(videoBitrate, currentValue); } } return(playlistItem); }
public DeviceProfile() { DirectPlayProfiles = new DirectPlayProfile[] { }; TranscodingProfiles = new TranscodingProfile[] { }; ResponseProfiles = new ResponseProfile[] { }; CodecProfiles = new CodecProfile[] { }; ContainerProfiles = new ContainerProfile[] { }; SoftSubtitleProfiles = new SubtitleProfile[] { }; ExternalSubtitleProfiles = new SubtitleProfile[] { }; XmlRootAttributes = new XmlAttribute[] { }; SupportedMediaTypes = "Audio,Photo,Video"; }