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;
        }