/// <summary> /// Creates a clone instance of this StreamInfo object. /// </summary> /// <returns>A copy of the StreamInfo object.</returns> public StreamInfo Clone() { StreamInfo clone = new StreamInfo(this.StreamType); clone.ParentClip = this.ParentClip; foreach (QualityLevel qualityLevel in this.QualityLevels) { clone.QualityLevels.Add(qualityLevel.Clone()); } foreach (Chunk chunk in this.Chunks) { clone.Chunks.Add(chunk); } foreach (KeyValuePair<string, string> attributeValuePair in this.Attributes) { clone.AddAttribute(attributeValuePair.Key, attributeValuePair.Value); } return clone; }
/// <summary> /// Parses the manifest stream. /// </summary> /// <param name="manifestStream">The manifest stream being parsed.</param> private void ParseManifest(Stream manifestStream) { using (XmlReader reader = XmlReader.Create(manifestStream)) { if (reader.Read() && reader.IsStartElement(ManifestSmoothStreamingMediaElement)) { int majorVersion = reader.GetValueAsInt(ManifestMajorVersionAttribute).GetValueOrDefault(); int minorVersion = reader.GetValueAsInt(ManifestMinorVersionAttribute).GetValueOrDefault(); bool isLive = reader.GetValueAsBool(ManifestIsLiveAttribute).GetValueOrDefault(); int lookAheadFragmentCount = 0; int dvrWindowLength = 0; if (isLive) { lookAheadFragmentCount = reader.GetValueAsInt(ManifestLookAheadFragmentCountAttribute).GetValueOrDefault(); dvrWindowLength = reader.GetValueAsInt(ManifestDvrWindowLengthAttribute).GetValueOrDefault(); } ulong Timescale = reader.GetValueAsULong(TimeScaleAttribute).GetValueOrDefault(TicksPerSecond); ulong manifestDuration = reader.GetValueAsULong(ManifestDurationAttribute).GetValueOrDefault(); Guid protectionGuid = Guid.Empty; string protectionData = string.Empty; List<StreamInfo> streams = new List<StreamInfo>(); while (reader.Read()) { if (reader.Name == ManifestProtectionElement && reader.NodeType == XmlNodeType.Element) { reader.Read(); if (reader.Name == ManifestProtectionHeaderElement && reader.NodeType == XmlNodeType.Element) { protectionGuid = new Guid(reader.GetValue(ManifestProtectionSystemIDElement)); protectionData = reader.ReadElementContentAsString(); } } if (reader.Name == ManifestStreamIndexElement && reader.NodeType == XmlNodeType.Element) { string type = reader.GetValue(ManifestStreamIndexTypeAttribute); StreamInfo streamInfo = new StreamInfo(type); AddAttributes(reader, streamInfo); while (reader.Read()) { if (reader.Name == ManifestStreamIndexElement && reader.NodeType == XmlNodeType.EndElement) { break; } if ((reader.Name == "QualityLevel") && (reader.NodeType == XmlNodeType.Element)) { QualityLevel qualityLevel = new QualityLevel(); AddAttributes(reader, qualityLevel); AddCustomAttributes(reader, qualityLevel); streamInfo.QualityLevels.Add(qualityLevel); } if ((reader.Name == "c") && (reader.NodeType == XmlNodeType.Element)) { int? chunkId = reader.GetValueAsInt("n"); UInt64? time = reader.GetValueAsUInt64("t"); ulong? duration = reader.GetValueAsULong("d"); ulong? repetitions = reader.GetValueAsULong("r"); for (ulong i = 0; i < (repetitions.HasValue ? repetitions.Value : 1); i++) { Chunk chunk = new Chunk(chunkId, i == 0 ? time : null, duration); if (((!reader.IsEmptyElement && reader.Read()) && (reader.IsStartElement("f") && reader.Read())) && (reader.NodeType == XmlNodeType.Text)) { chunk.Value = reader.Value; } streamInfo.Chunks.Add(chunk); } } } streams.Add(streamInfo); } } streams.ToArray(); if (!isLive) { this.ManifestInfo = new ManifestInfo(majorVersion, minorVersion, manifestDuration, streams, protectionGuid, protectionData,Timescale); } else { this.ManifestInfo = new ManifestInfo(majorVersion, minorVersion, manifestDuration, isLive, lookAheadFragmentCount, dvrWindowLength, streams, protectionGuid, protectionData,Timescale); } } } }
/// <summary> /// Adds attributes to the stream info. /// </summary> /// <param name="reader">The xml reader.</param> /// <param name="streamInfo">The stream info.</param> private static void AddAttributes(XmlReader reader, StreamInfo streamInfo) { if (reader.HasAttributes && reader.MoveToFirstAttribute()) { do { streamInfo.AddAttribute(reader.Name, reader.Value); } while (reader.MoveToNextAttribute()); reader.MoveToFirstAttribute(); } }
/// <summary> /// InitializeChunks /// Initialize the chunks parameter based on the information in the manifest. /// </summary> /// <param name="stream"></param> /// <param name="selected"></param> /// <returns>true if success</returns> bool InitializeChunks(StreamInfo stream, QualityLevel selected) { ulong Bitrate = 0; string UrlTemplate = string.Empty; if ((selected != null)&&(stream!= null)) { selected.TryGetAttributeValueAsUlong("Bitrate", out Bitrate); if (Bitrate > 0) { if (stream.TryGetAttributeValueAsString("Url", out UrlTemplate)) { UrlTemplate = UrlTemplate.Replace("{bitrate}", Bitrate.ToString()); UrlTemplate = UrlTemplate.Replace("{start time}", "{start_time}"); UrlTemplate = UrlTemplate.Replace("{CustomAttributes}", "timeScale=10000000"); bool bAudio = false; bool bVideo = false; if (stream.StreamType.ToLower() == "audio") { ulong index = 0; if (SelectAudioTrackIndex < 0) { selected.TryGetAttributeValueAsUlong("Index", out index); SelectedAudioTrackIndex = (int)index; } else SelectedAudioTrackIndex = SelectAudioTrackIndex; bAudio = true; } if (stream.StreamType.ToLower() == "video") { ulong index = 0; if (SelectVideoTrackIndex < 0) { selected.TryGetAttributeValueAsUlong("Index", out index); SelectedVideoTrackIndex = (int)index; } else SelectedVideoTrackIndex = SelectVideoTrackIndex; bVideo = true; } if ((bAudio) || (bVideo)) { UInt64 time = 0; ulong duration = 0; foreach (var chunk in stream.Chunks) { if (chunk.Duration != null) duration = (ulong)chunk.Duration; else duration = 0; if (chunk.Time != null) time = (UInt64)chunk.Time; ChunkCache cc = new ChunkCache(time, duration); time += (ulong)duration; if (cc != null) { if (bAudio) this.AudioChunkList.Add(cc); if (bVideo) this.VideoChunkList.Add(cc); } } if (bAudio) { this.AudioBitrate = Bitrate; this.AudioChunks = (ulong)this.AudioChunkList.Count; this.AudioTemplateUrl = UrlTemplate; this.AudioTemplateUrlType = GetType(UrlTemplate); } if (bVideo) { this.VideoBitrate = Bitrate; this.VideoChunks = (ulong)this.VideoChunkList.Count; this.VideoTemplateUrl = UrlTemplate; this.VideoTemplateUrlType = GetType(UrlTemplate); } } return true; }; } } return false; }