protected ulong ReadBoxSize(BoxBinaryReader reader) { ulong size = 0; size = reader.ReadUInt32(); if (size == 1) { reader.BaseStream.Seek(4, SeekOrigin.Current); // Skip over the box type size = reader.ReadUInt64(); } return size; }
/// <summary> /// Reads the header boxes for the video, which includes /// ftyp, pdin, bloc, moov, and the optional mdat. /// </summary> /// <param name="callback"></param> private async Task ReadMovieHeaderBoxes() { var moov = await this.GetBox(BoxType.Moov); this.Boxes.Add(moov); // See if we have an mdat next and grab it if we do var stream = await WebRequestor.GetStreamRangeAsync(this.fileUri, this.fileOffset, this.fileOffset + 8); using (var reader = new BoxBinaryReader(stream)) { if (reader.PeekNextBoxType() == BoxType.Mdat) { var mdat = await this.GetNextBox(); this.Boxes.Add(mdat); } } }
private static Stream HackFragment(Stream stream) { long offset = 0; long versionBitOffset = 0; BoxBinaryReader reader = new BoxBinaryReader(stream); Box box = null; do { box = reader.ReadNextBox(); if (box != null) { if (box.Type == BoxType.Moof) { offset = box.Offset; var traf = box.InnerBoxes.FirstOrDefault(b => b.Type == BoxType.Traf) as TrackFragmentBox; if (traf != null) { var trun = traf.InnerBoxes.First(b => b.Type == BoxType.Trun) as TrackFragmentRunFullBox; if (trun != null && trun.Version != 0) { versionBitOffset = trun.Offset + 8; } } break; } } } while (box != null); if (offset == 0 && versionBitOffset == 0) { return stream; } else { stream.Seek(offset, SeekOrigin.Begin); var buffer = new byte[stream.Length - offset]; stream.Read(buffer, 0, buffer.Length); if (versionBitOffset != 0) { versionBitOffset -= offset; buffer[versionBitOffset] = 0; } return new MemoryStream(buffer); } }
/// <summary> /// Opens a local (offline) file and initializes the CFF data that can be used for /// manifest generation. /// </summary> /// <param name="path">The file URI of the resource to be opened. i.e. ms-appx:////Big_Buck_Bunny.uvu </param> public override async Task Parse(Uri path) { if (StorageFile == null) { StorageFile = await Windows.Storage.StorageFile.GetFileFromApplicationUriAsync(path); } using (var fileStream = await StorageFile.OpenStreamForReadAsync()) { var reader = new BoxBinaryReader(fileStream); Box box = null; do { box = reader.ReadNextBox(); if (box != null) { this.Boxes.Add(box); if (box.Type == BoxType.Moov) { // There may be an mdat after the moov, if so parse it if (reader.PeekNextBoxType() == BoxType.Mdat) { box = reader.ReadNextBox(); this.Boxes.Add(box); } // After parsing the moov and optional mdat after it, skip to the mfra // this will jump past the moof and mdats which we don't need to process reader.GotoMovieFragmentRandomAccess(); } } } while (box != null); } this.InitializeTrackRegistry(); }
private static async Task<IList<Box>> GetBoxesAsync(Uri uri, WebRequestor.Range range) { using (var stream = await WebRequestor.GetStreamRangeAsync(uri, range)) { using (var reader = new BoxBinaryReader(stream)) { return reader.GetAllBoxes(); } } }
private static Stream TrimToBox(Stream stream, BoxType boxType) { long offset = 0; BoxBinaryReader reader = new BoxBinaryReader(stream); Box box = null; do { box = reader.ReadNextBox(); if (box != null && box.Type == boxType) { offset = box.Offset; break; } } while (box != null); if (offset == 0) { return stream; } else { stream.Seek(offset, SeekOrigin.Begin); var buffer = new byte[stream.Length - offset]; stream.Read(buffer, 0, buffer.Length); return new MemoryStream(buffer); } }
/// <summary> /// Gets a fragment of track data from the file that is being streamed locally. /// </summary> /// <param name="trackType">The type of track being requested (video, audio, text)</param> /// <param name="bitrate">The bitrate of the track that should be returned.</param> /// <param name="timeOffset">The time offset of the fragment of data being requested.</param> /// <param name="language">The ISO language code of the track if there is one.</param> /// <param name="callback">The callback that will be invoked when the fragment has been retrieved. /// The callback will have the stream to the data.</param> /// <remarks>The fragment that will be returned will be a moof and mdat pair of boxes from the file.</remarks> public override async Task<WebRequestorResponse> GetTrackFragmentStream(ManifestTrackType trackType, uint bitrate, ulong timeOffset, string language) { if (language == string.Empty) language = null; var track = this.ManifestTracks .Where(t => t.Type == trackType && t.Bitrate == bitrate && t.Language == language) .SingleOrDefault(); if (track != null) { var entry = track.Fragments.TrackFragmentRandomAccessEntries.FirstOrDefault(e => e.Time == timeOffset); if (entry != null) { ulong moofSize = 0; ulong mdatSize = 0; long moofOffset = 0; using (var fileStream = await StorageFile.OpenStreamForReadAsync()) { var reader = new BoxBinaryReader(fileStream); moofOffset = (long)entry.MoofOffset; reader.BaseStream.Seek(moofOffset, SeekOrigin.Begin); moofSize = this.ReadBoxSize(reader); // Run to the end of the moof to get to its mdat box reader.BaseStream.Seek(moofOffset + (long)moofSize, SeekOrigin.Begin); mdatSize = this.ReadBoxSize(reader); // And back to the beginning of the moof so we can read both boxes into the stream reader.BaseStream.Seek(moofOffset, SeekOrigin.Begin); var size = moofSize + mdatSize; var fragment = reader.ReadBytes((int)size); var stream = new MemoryStream(fragment); return new WebRequestorResponse(stream, System.Net.HttpStatusCode.OK, null, string.Empty); } } } throw new WebRequestorFailure(System.Net.HttpStatusCode.NotFound, null); }
/// <summary> /// This method of building the mfra will make web requests in order to download the data /// from the online source. /// </summary> /// <param name="callback">The action that should be notified when the process is complete.</param> private async Task ReadMovieFragmentRandomAccess() { #if !RANGESUFFIXSUPPORTED // not all backend services support range suffixes. For example, Azure Blobs. Here is a way around this but it requires an extra request to get the length and therefore does not perform as well. var fileSize = await WebRequestor.GetFileSizeAsync(this.fileUri); #endif // grab the mfra offset #if RANGESUFFIXSUPPORTED var offsetStream = await WebRequestor.GetStreamRangeAsync(this.fileUri, -4); #else var offsetStream = await WebRequestor.GetStreamRangeNoSuffixAsync(this.fileUri, -4, fileSize); #endif uint mfraOffset = 0; using (var reader = new BoxBinaryReader(offsetStream)) { mfraOffset = reader.ReadUInt32(); } // grab the mfra data #if RANGESUFFIXSUPPORTED var mfraStream = await WebRequestor.GetStreamRangeAsync(this.fileUri, -mfraOffset); #else var mfraStream = await WebRequestor.GetStreamRangeNoSuffixAsync(this.fileUri, -mfraOffset, fileSize); #endif // Write the bytes to our TOC file using (var reader = new BoxBinaryReader(mfraStream)) { reader.GotoPosition(0); Box box = null; do { box = reader.ReadNextBox(); if (box != null) { this.Boxes.Add(box); } } while (box != null); } }
private async Task<ulong> GetBoxSize(long position) { var stream = await WebRequestor.GetStreamRangeAsync(this.fileUri, position, position + 16); using (var reader = new BoxBinaryReader(stream)) { var size = this.ReadBoxSize(reader); return size; } }
private async Task<Box> GetBox(BoxType boxType) { // get the box size var size = await this.GetBoxSize(this.fileOffset); // gets the box var stream = await WebRequestor.GetStreamRangeAsync(this.fileUri, this.fileOffset, this.fileOffset + (long)size); Box box = null; using (var boxReader = new BoxBinaryReader(stream)) { box = boxReader.ReadNextBox(); this.fileOffset += (long)size; } if (box.Type == boxType) { return box; } else { return await this.GetBox(boxType); } }
private async Task<Box> GetNextBox() { var size = await this.GetBoxSize(this.fileOffset); var boxStream = await WebRequestor.GetStreamRangeAsync(this.fileUri, this.fileOffset, this.fileOffset + (long)size); Box box = null; using (var boxReader = new BoxBinaryReader(boxStream)) { box = boxReader.ReadNextBox(); this.fileOffset += (long)size; } return box; }