using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using MatrixIO.IO.Bmff; namespace MatrixIO.IO.Bmff { public class BmffReader : ISuperBox, IEnumerable<Box> { private readonly Stream _baseStream; public Stream BaseStream { get { return _baseStream; } } private IList<Box> _rootBoxes; public IList<Box> RootBoxes { get { #pragma warning disable 612,618 if (_rootBoxes == null) return _rootBoxes = Portability.CreateList<Box>(GetBoxes()); #pragma warning restore 612,618 return _rootBoxes; } } public bool RandomAccess { get { return _baseStream.CanSeek; } } #region Navigation private readonly Stack<Box> _boxStack = new Stack<Box>(); public int Depth { get { return _boxStack.Count; } } public Box CurrentBox { get { return _boxStack.Peek(); } } public bool HasChildren { get { if (CurrentBox is ISuperBox) return true; else return false; } } #endregion public BmffReader(Stream stream) { if (stream.CanSeek && stream.Position!=0) stream.Seek(0, SeekOrigin.Begin); _baseStream = stream; } [Obsolete("Use the BaseMedia class instead.")] public void Scan() { GetBoxes(); } /// <summary> /// Traverses the tree of Boxes in file order (depth-first) /// </summary> /// <returns>IEnumerable collection of Box types in file order.</returns> [Obsolete("Use the BaseMedia class instead.")] public IEnumerable<Box> GetBoxes() { Box box = null; do { box = Box.FromStream(_baseStream); if (box != null) yield return box; } while (box != null); } /// <summary> /// Seeks to the beginning of the file and reads the "ftyp" Box. /// </summary> /// <returns>FileTypeBox</returns> [Obsolete] public Boxes.FileTypeBox GetFileTypeBox() { if (_baseStream.CanSeek && _baseStream.Position!=0) _baseStream.Seek(0, SeekOrigin.Begin); // TODO: Support files where "ftyp" is not the first FourCC like JPEG2000. return Box.FromStream<Boxes.FileTypeBox>(_baseStream); } /// <summary> /// Seek to the end of the file and returns the "mfro" Box for a Microsoft Smooth Streaming PIFF format file that gives /// you the chunk offsets within the file. /// </summary> /// <returns>MovieFragmentRandomAccessBox</returns> // TODO: Move to a new MatrixIO.IO.Piff.??? class public Boxes.MovieFragmentRandomAccessBox GetMovieFragmentRandomAccessBox() { _baseStream.Seek(-24, SeekOrigin.End); byte[] mfrobuf = _baseStream.ReadBytes(24); uint mfraOffset; if (BitConverter.ToUInt32(mfrobuf, 12).NetworkToHostOrder() == 0x6d66726f || BitConverter.ToUInt32(mfrobuf, 4).NetworkToHostOrder() == 0x6d66726f) // 'mfro' { mfraOffset = BitConverter.ToUInt32(mfrobuf, 20).NetworkToHostOrder(); } else return null; _baseStream.Seek(-mfraOffset, SeekOrigin.End); return new Boxes.MovieFragmentRandomAccessBox(_baseStream); } [Obsolete("Use the BaseMedia class instead.")] IList<Box> ISuperBox.Children { get { return RootBoxes; } } [Obsolete("Use the BaseMedia class instead.")] IEnumerator<Box> IEnumerable<Box>.GetEnumerator() { return RootBoxes.GetEnumerator(); } [Obsolete("Use the BaseMedia class instead.")] System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return RootBoxes.GetEnumerator(); } } }