public static IEnumerable<SmoothStreamingMediaStreamIndex> GenerateClientManifestStreamIndexs(IEnumerable<ManifestTrack> ManifestTracks, Box moov) { foreach (var track in ManifestTracks) { yield return GenerateClientManifestStreamIndex(track, moov); } }
public static SmoothStreamingMediaProtection GetProtectionHeader(Box moov) { //create protection data if it exists var protectionBox = moov.InnerBoxes.SingleOrDefault(b => b.Type == BoxType.Pssh) as ProtectionSystemSpecificHeaderFullBox; if (protectionBox != null) { return new SmoothStreamingMediaProtection() { ProtectionHeader = new SmoothStreamingMediaProtectionProtectionHeader() { SystemID = protectionBox.SystemId.ToString().ToUpper(), Value = Convert.ToBase64String(protectionBox.Data) } }; } return null; }
public static SmoothStreamingMediaStreamIndex GenerateClientManifestStreamIndex(ManifestTrack track, Box moov) { var streamIndex = new SmoothStreamingMediaStreamIndex(); streamIndex.Type = track.Type.ToString().ToLower(); var qualityLevel = new SmoothStreamingMediaStreamIndexQualityLevel(); streamIndex.QualityLevel.Add(qualityLevel); streamIndex.TimeScale = track.TimeScale; var mdhd = moov.InnerBoxes.Single(box => box.Type == BoxType.Trak && (box.InnerBoxes.Single(tkhd => tkhd.Type == BoxType.Tkhd) as TrackHeaderFullBox).TrackId == track.Id) .InnerBoxes.Single(box => box.Type == BoxType.Mdia) .InnerBoxes.Single(box => box.Type == BoxType.Mdhd) as MediaHeaderFullBox; streamIndex.Language = mdhd.Language; switch (track.Type) { case ManifestTrackType.Video: //populate track streamIndex.MaxHeight = track.Height; streamIndex.MaxWidth = track.Width; streamIndex.DisplayWidth = track.DisplayWidth; streamIndex.DisplayHeight = track.DisplayHeight; //populate quality level qualityLevel.Index = 0; qualityLevel.Bitrate = track.Bitrate; qualityLevel.FourCC = track.FourCodecCode; qualityLevel.MaxHeight = track.Height; qualityLevel.MaxWidth = track.Width; qualityLevel.CodecPrivateData = track.CodecPrivateData; break; case ManifestTrackType.Audio: streamIndex.FourCC = track.FourCodecCode; streamIndex.Index = 0; //populate quality level qualityLevel.Bitrate = track.Bitrate; qualityLevel.SamplingRate = track.SampleRate; qualityLevel.Channels = track.ChannelCount; qualityLevel.BitsPerSample = track.SampleSize; qualityLevel.PacketSize = track.PacketSize; qualityLevel.AudioTag = track.AudioTag; qualityLevel.CodecPrivateData = track.CodecPrivateData; qualityLevel.FourCC = track.FourCodecCode; break; case ManifestTrackType.Text: int i = 0; i++; break; } if (track.Fragments != null) { streamIndex.c.AddRange(GenerateClientManifestChunks(track, moov)); streamIndex.Chunks = (uint)streamIndex.c.Count; } return streamIndex; }
private static IEnumerable<SmoothStreamingMediaStreamIndexC> GenerateClientManifestChunks(ManifestTrack track, Box moov) { // Pull entries that point to different moof boxes, duplicate boxes offsets cause playback issues. var entries = track.Fragments.TrackFragmentRandomAccessEntries .GroupBy(entry => entry.MoofOffset) .Select(entry => entry.First()) .ToList(); ulong entriesDuration = 0; //create chunks for (int i = 0; i < entries.Count; i++) { var c = new SmoothStreamingMediaStreamIndexC(); c.n = i; if (i != entries.Count - 1) { // The duration is the difference between this entry and the next's time c.d = entries.ElementAt(i + 1).Time - entries.ElementAt(i).Time; entriesDuration += c.d; } else { var mvhd = moov.InnerBoxes.SingleOrDefault(b => b.Type == BoxType.Mvhd) as MovieHeaderFullBox; // Final duration is what we have left, the track duration is in the timescale of the presentation, // so we have to convert to the timescale of the actual media in the track c.d = ConvertTimeToTimescale(track.Duration, mvhd.TimeScale, track.TimeScale) - entriesDuration; } yield return c; } }