Bug 1118597 - Parse sinf boxes in MoofParser - r=jya a=lmandel
☠☠ backed out by 77d5e3a30435 ☠ ☠
authorEdwin Flores <edwin@mozilla.com>
Mon, 19 Jan 2015 21:39:00 +1300
changeset 249850 e9584e7c65b275ab15a676b5bdd2818f129acd92
parent 249849 5f012ce3f3eafd3cc9c8ce734fab518e5b81542f
child 249851 eea43cfc67c72b5cc054de2637d8b44a17f89984
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya, lmandel
bugs1118597
milestone37.0a2
Bug 1118597 - Parse sinf boxes in MoofParser - r=jya a=lmandel
media/libstagefright/binding/Box.cpp
media/libstagefright/binding/Index.cpp
media/libstagefright/binding/MoofParser.cpp
media/libstagefright/binding/SinfParser.cpp
media/libstagefright/binding/include/mp4_demuxer/Atom.h
media/libstagefright/binding/include/mp4_demuxer/AtomType.h
media/libstagefright/binding/include/mp4_demuxer/Box.h
media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
media/libstagefright/binding/include/mp4_demuxer/SinfParser.h
media/libstagefright/moz.build
--- a/media/libstagefright/binding/Box.cpp
+++ b/media/libstagefright/binding/Box.cpp
@@ -7,16 +7,39 @@
 #include "mp4_demuxer/Box.h"
 #include "mp4_demuxer/mp4_demuxer.h"
 #include "mozilla/Endian.h"
 
 using namespace mozilla;
 
 namespace mp4_demuxer {
 
+// Returns the offset from the start of the body of a box of type |aType|
+// to the start of its first child.
+static uint32_t
+BoxOffset(AtomType aType)
+{
+  const uint32_t FULLBOX_OFFSET = 4;
+
+  if (aType == AtomType("mp4a") || aType == AtomType("enca")) {
+    // AudioSampleEntry; ISO 14496-12, section 8.16
+    return 28;
+  } else if (aType == AtomType("mp4v") || aType == AtomType("encv")) {
+    // VideoSampleEntry; ISO 14496-12, section 8.16
+    return 78;
+  } else if (aType == AtomType("stsd")) {
+    // SampleDescriptionBox; ISO 14496-12, section 8.16
+    // This is a FullBox, and contains a |count| member before its child
+    // boxes.
+    return FULLBOX_OFFSET + 4;
+  }
+
+  return 0;
+}
+
 Box::Box(BoxContext* aContext, uint64_t aOffset, const Box* aParent)
   : mContext(aContext), mParent(aParent)
 {
   uint8_t header[8];
   MediaByteRange headerRange(aOffset, aOffset + sizeof(header));
   if (mParent && !mParent->mRange.Contains(headerRange)) {
     return;
   }
@@ -48,29 +71,31 @@ Box::Box(BoxContext* aContext, uint64_t 
     if ((mParent && !mParent->mRange.Contains(bigLengthRange)) ||
         !byteRange->Contains(bigLengthRange) ||
         !mContext->mSource->CachedReadAt(aOffset, bigLength,
                                          sizeof(bigLength), &bytes) ||
         bytes != sizeof(bigLength)) {
       return;
     }
     size = BigEndian::readUint64(bigLength);
-    mChildOffset = bigLengthRange.mEnd;
+    mBodyOffset = bigLengthRange.mEnd;
   } else {
-    mChildOffset = headerRange.mEnd;
+    mBodyOffset = headerRange.mEnd;
   }
 
+  mType = BigEndian::readUint32(&header[4]);
+  mChildOffset = mBodyOffset + BoxOffset(mType);
+
   MediaByteRange boxRange(aOffset, aOffset + size);
   if (mChildOffset > boxRange.mEnd ||
       (mParent && !mParent->mRange.Contains(boxRange)) ||
       !byteRange->Contains(boxRange)) {
     return;
   }
   mRange = boxRange;
-  mType = BigEndian::readUint32(&header[4]);
 }
 
 Box::Box()
   : mContext(nullptr)
 {}
 
 Box
 Box::Next() const
--- a/media/libstagefright/binding/Index.cpp
+++ b/media/libstagefright/binding/Index.cpp
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mp4_demuxer/ByteReader.h"
 #include "mp4_demuxer/Index.h"
 #include "mp4_demuxer/Interval.h"
 #include "mp4_demuxer/MoofParser.h"
+#include "mp4_demuxer/SinfParser.h"
 #include "media/stagefright/MediaSource.h"
 #include "MediaResource.h"
 
 #include <algorithm>
 #include <limits>
 
 using namespace stagefright;
 using namespace mozilla;
@@ -103,34 +104,50 @@ MP4Sample* SampleIterator::GetNext()
 
   size_t bytesRead;
   if (!mIndex->mSource->ReadAt(sample->byte_offset, sample->data, sample->size,
                                &bytesRead) || bytesRead != sample->size) {
     return nullptr;
   }
 
   if (!s->mCencRange.IsNull()) {
+    MoofParser* parser = mIndex->mMoofParser.get();
+
+    if (!parser || !parser->mSinf.IsValid()) {
+      return nullptr;
+    }
+
+    uint8_t ivSize = parser->mSinf.mDefaultIVSize;
+
     // The size comes from an 8 bit field
     nsAutoTArray<uint8_t, 256> cenc;
     cenc.SetLength(s->mCencRange.Length());
-    if (!mIndex->mSource->ReadAt(s->mCencRange.mStart, &cenc[0], cenc.Length(),
+    if (!mIndex->mSource->ReadAt(s->mCencRange.mStart, cenc.Elements(), cenc.Length(),
                                  &bytesRead) || bytesRead != cenc.Length()) {
       return nullptr;
     }
     ByteReader reader(cenc);
     sample->crypto.valid = true;
-    reader.ReadArray(sample->crypto.iv, 16);
-    if (reader.Remaining()) {
+    sample->crypto.iv_size = ivSize;
+
+    if (!reader.ReadArray(sample->crypto.iv, ivSize)) {
+      return nullptr;
+    }
+
+    if (reader.CanRead16()) {
       uint16_t count = reader.ReadU16();
+
+      if (reader.Remaining() < count * 6) {
+        return nullptr;
+      }
+
       for (size_t i = 0; i < count; i++) {
         sample->crypto.plain_sizes.AppendElement(reader.ReadU16());
         sample->crypto.encrypted_sizes.AppendElement(reader.ReadU32());
       }
-      reader.ReadArray(sample->crypto.iv, 16);
-      sample->crypto.iv_size = 16;
     }
   }
 
   Next();
 
   return sample.forget();
 }
 
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mp4_demuxer/MoofParser.h"
 #include "mp4_demuxer/Box.h"
+#include "mp4_demuxer/SinfParser.h"
 #include <limits>
 
 namespace mp4_demuxer
 {
 
 using namespace stagefright;
 using namespace mozilla;
 
@@ -23,17 +24,17 @@ MoofParser::RebuildFragmentedIndex(
 void
 MoofParser::RebuildFragmentedIndex(BoxContext& aContext)
 {
   for (Box box(&aContext, mOffset); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("moov")) {
       mInitRange = MediaByteRange(0, box.Range().mEnd);
       ParseMoov(box);
     } else if (box.IsType("moof")) {
-      Moof moof(box, mTrex, mMdhd, mEdts, mTimestampOffset);
+      Moof moof(box, mTrex, mMdhd, mEdts, mSinf, mTimestampOffset);
 
       if (!mMoofs.IsEmpty()) {
         // Stitch time ranges together in the case of a (hopefully small) time
         // range gap between moofs.
         mMoofs.LastElement().FixRounding(moof);
       }
 
       mMoofs.AppendElement(moof);
@@ -142,16 +143,18 @@ MoofParser::ParseTrak(Box& aBox)
 }
 
 void
 MoofParser::ParseMdia(Box& aBox, Tkhd& aTkhd)
 {
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("mdhd")) {
       mMdhd = Mdhd(box);
+    } else if (box.IsType("minf")) {
+      ParseMinf(box);
     }
   }
 }
 
 void
 MoofParser::ParseMvex(Box& aBox)
 {
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
@@ -159,22 +162,69 @@ MoofParser::ParseMvex(Box& aBox)
       Trex trex = Trex(box);
       if (!mTrex.mTrackId || trex.mTrackId == mTrex.mTrackId) {
         mTrex = trex;
       }
     }
   }
 }
 
-Moof::Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts, Microseconds aTimestampOffset) :
+void
+MoofParser::ParseMinf(Box& aBox)
+{
+  for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
+    if (box.IsType("stbl")) {
+      ParseStbl(box);
+    }
+  }
+}
+
+void
+MoofParser::ParseStbl(Box& aBox)
+{
+  for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
+    if (box.IsType("stsd")) {
+      ParseStsd(box);
+    }
+  }
+}
+
+void
+MoofParser::ParseStsd(Box& aBox)
+{
+  for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
+    if (box.IsType("encv") || box.IsType("enca")) {
+      ParseEncrypted(box);
+    }
+  }
+}
+
+void
+MoofParser::ParseEncrypted(Box& aBox)
+{
+  for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
+    // Some MP4 files have been found to have multiple sinf boxes in the same
+    // enc* box. This does not match spec anyway, so just choose the first
+    // one that parses properly.
+    if (box.IsType("sinf")) {
+      mSinf = Sinf(box);
+
+      if (mSinf.IsValid()) {
+        break;
+      }
+    }
+  }
+}
+
+Moof::Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, Microseconds aTimestampOffset) :
     mRange(aBox.Range()), mTimestampOffset(aTimestampOffset), mMaxRoundingError(0)
 {
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("traf")) {
-      ParseTraf(box, aTrex, aMdhd, aEdts);
+      ParseTraf(box, aTrex, aMdhd, aEdts, aSinf);
     }
   }
   ProcessCenc();
 }
 
 bool
 Moof::GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges)
 {
@@ -235,32 +285,32 @@ Moof::ProcessCenc()
   }
   for (int i = 0; i < cencRanges.Length(); i++) {
     mIndex[i].mCencRange = cencRanges[i];
   }
   return true;
 }
 
 void
-Moof::ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts)
+Moof::ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf)
 {
   Tfhd tfhd(aTrex);
   Tfdt tfdt;
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("tfhd")) {
       tfhd = Tfhd(box, aTrex);
     } else if (!aTrex.mTrackId || tfhd.mTrackId == aTrex.mTrackId) {
       if (box.IsType("tfdt")) {
         tfdt = Tfdt(box);
       } else if (box.IsType("trun")) {
         ParseTrun(box, tfhd, tfdt, aMdhd, aEdts);
       } else if (box.IsType("saiz")) {
-        mSaizs.AppendElement(Saiz(box));
+        mSaizs.AppendElement(Saiz(box, aSinf.mDefaultEncryptionType));
       } else if (box.IsType("saio")) {
-        mSaios.AppendElement(Saio(box));
+        mSaios.AppendElement(Saio(box, aSinf.mDefaultEncryptionType));
       }
     }
   }
 }
 
 void
 Moof::FixRounding(const Moof& aMoof) {
   Microseconds gap = aMoof.mTimeRange.start - mTimeRange.end;
@@ -552,17 +602,19 @@ Edts::Edts(Box& aBox)
   } else {
     segment_duration = reader->ReadU32();
     mMediaStart = reader->Read32();
   }
   NS_ASSERTION(segment_duration == 0, "Can't handle edits with fixed durations");
   reader->DiscardRemaining();
 }
 
-Saiz::Saiz(Box& aBox) : mAuxInfoType("sinf"), mAuxInfoTypeParameter(0)
+Saiz::Saiz(Box& aBox, AtomType aDefaultType)
+  : mAuxInfoType(aDefaultType)
+  , mAuxInfoTypeParameter(0)
 {
   BoxReader reader(aBox);
   if (!reader->CanReadType<uint32_t>()) {
     return;
   }
   uint32_t flags = reader->ReadU32();
   uint8_t version = flags >> 24;
   size_t need =
@@ -583,17 +635,19 @@ Saiz::Saiz(Box& aBox) : mAuxInfoType("si
   } else {
     if (!reader->ReadArray(mSampleInfoSize, count)) {
       return;
     }
   }
   mValid = true;
 }
 
-Saio::Saio(Box& aBox) : mAuxInfoType("sinf"), mAuxInfoTypeParameter(0)
+Saio::Saio(Box& aBox, AtomType aDefaultType)
+  : mAuxInfoType(aDefaultType)
+  , mAuxInfoTypeParameter(0)
 {
   BoxReader reader(aBox);
   if (!reader->CanReadType<uint32_t>()) {
     return;
   }
   uint32_t flags = reader->ReadU32();
   uint8_t version = flags >> 24;
   size_t need = ((flags & 1) ? (2*sizeof(uint32_t)) : 0) + sizeof(uint32_t);
new file mode 100644
--- /dev/null
+++ b/media/libstagefright/binding/SinfParser.cpp
@@ -0,0 +1,74 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/unused.h"
+#include "mp4_demuxer/SinfParser.h"
+#include "mp4_demuxer/AtomType.h"
+#include "mp4_demuxer/Box.h"
+
+namespace mp4_demuxer {
+
+Sinf::Sinf(Box& aBox)
+  : mDefaultIVSize(0)
+  , mDefaultEncryptionType()
+{
+  SinfParser parser(aBox);
+  if (parser.GetSinf().IsValid()) {
+    *this = parser.GetSinf();
+  }
+}
+
+SinfParser::SinfParser(Box& aBox)
+{
+  for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
+    if (box.IsType("schm")) {
+      ParseSchm(box);
+    } else if (box.IsType("schi")) {
+      ParseSchi(box);
+    }
+  }
+}
+
+void
+SinfParser::ParseSchm(Box& aBox)
+{
+  BoxReader reader(aBox);
+
+  if (reader->Remaining() < 8) {
+    return;
+  }
+
+  mozilla::unused << reader->ReadU32(); // flags -- ignore
+  mSinf.mDefaultEncryptionType = reader->ReadU32();
+
+  reader->DiscardRemaining();
+}
+
+void
+SinfParser::ParseSchi(Box& aBox)
+{
+  for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
+    if (box.IsType("tenc")) {
+      ParseTenc(box);
+    }
+  }
+}
+
+void
+SinfParser::ParseTenc(Box& aBox)
+{
+  BoxReader reader(aBox);
+
+  if (reader->Remaining() < 24) {
+    return;
+  }
+
+  mozilla::unused << reader->ReadU32(); // flags -- ignore
+
+  uint32_t isEncrypted = reader->ReadU24();
+  mSinf.mDefaultIVSize = reader->ReadU8();
+  memcpy(mSinf.mDefaultKeyID, reader->Read(16), 16);
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/media/libstagefright/binding/include/mp4_demuxer/Atom.h
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef ATOM_H_
+#define ATOM_H_
+
+namespace mp4_demuxer {
+
+class Atom
+{
+public:
+  Atom()
+    : mValid(false)
+  {
+  }
+  virtual bool IsValid()
+  {
+    return mValid;
+  }
+protected:
+  bool mValid;
+};
+
+}
+
+#endif // ATOM_H_
--- a/media/libstagefright/binding/include/mp4_demuxer/AtomType.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/AtomType.h
@@ -16,15 +16,16 @@ namespace mp4_demuxer {
 
 class AtomType
 {
 public:
   AtomType() : mType(0) { }
   MOZ_IMPLICIT AtomType(uint32_t aType) : mType(aType) { }
   MOZ_IMPLICIT AtomType(const char* aType) : mType(BigEndian::readUint32(aType)) { }
   bool operator==(const AtomType& aType) const { return mType == aType.mType; }
+  bool operator!() const { return !mType; }
 
 private:
   uint32_t mType;
 };
 }
 
 #endif
--- a/media/libstagefright/binding/include/mp4_demuxer/Box.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Box.h
@@ -49,16 +49,17 @@ public:
   Box Next() const;
   Box FirstChild() const;
   void Read(nsTArray<uint8_t>* aDest);
 
 private:
   bool Contains(MediaByteRange aRange) const;
   BoxContext* mContext;
   mozilla::MediaByteRange mRange;
+  uint64_t mBodyOffset;
   uint64_t mChildOffset;
   AtomType mType;
   const Box* mParent;
 };
 
 class BoxReader
 {
 public:
--- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
@@ -1,41 +1,28 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOOF_PARSER_H_
 #define MOOF_PARSER_H_
 
+#include "mp4_demuxer/Atom.h"
 #include "mp4_demuxer/AtomType.h"
 #include "mp4_demuxer/mp4_demuxer.h"
+#include "mp4_demuxer/SinfParser.h"
 #include "MediaResource.h"
 
 namespace mp4_demuxer {
 
 class Stream;
 class Box;
 class BoxContext;
 class Moof;
 
-class Atom
-{
-public:
-  Atom()
-    : mValid(false)
-  {
-  }
-  virtual bool IsValid()
-  {
-    return mValid;
-  }
-protected:
-  bool mValid;
-};
-
 class Tkhd : public Atom
 {
 public:
   Tkhd()
     : mCreationTime(0)
     , mModificationTime(0)
     , mTrackId(0)
     , mDuration(0)
@@ -145,27 +132,27 @@ struct Sample
   Microseconds mDecodeTime;
   Interval<Microseconds> mCompositionRange;
   bool mSync;
 };
 
 class Saiz : public Atom
 {
 public:
-  explicit Saiz(Box& aBox);
+  Saiz(Box& aBox, AtomType aDefaultType);
 
   AtomType mAuxInfoType;
   uint32_t mAuxInfoTypeParameter;
   nsTArray<uint8_t> mSampleInfoSize;
 };
 
 class Saio : public Atom
 {
 public:
-  explicit Saio(Box& aBox);
+  Saio(Box& aBox, AtomType aDefaultType);
 
   AtomType mAuxInfoType;
   uint32_t mAuxInfoTypeParameter;
   nsTArray<uint64_t> mOffsets;
 };
 
 class AuxInfo {
 public:
@@ -176,30 +163,30 @@ private:
   int64_t mMoofOffset;
   Saiz& mSaiz;
   Saio& mSaio;
 };
 
 class Moof : public Atom
 {
 public:
-  Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts, Microseconds aTimestampOffset);
+  Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, Microseconds aTimestampOffset);
   bool GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges);
   void FixRounding(const Moof& aMoof);
 
   mozilla::MediaByteRange mRange;
   mozilla::MediaByteRange mMdatRange;
   Interval<Microseconds> mTimeRange;
   nsTArray<Sample> mIndex;
 
   nsTArray<Saiz> mSaizs;
   nsTArray<Saio> mSaios;
 
 private:
-  void ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts);
+  void ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf);
   void ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd, Edts& aEdts);
   void ParseSaiz(Box& aBox);
   void ParseSaio(Box& aBox);
   bool ProcessCenc();
   Microseconds mTimestampOffset;
   uint64_t mMaxRoundingError;
 };
 
@@ -220,27 +207,34 @@ public:
   Interval<Microseconds> GetCompositionRange(
     const nsTArray<mozilla::MediaByteRange>& aByteRanges);
   bool ReachedEnd();
   void ParseMoov(Box& aBox);
   void ParseTrak(Box& aBox);
   void ParseMdia(Box& aBox, Tkhd& aTkhd);
   void ParseMvex(Box& aBox);
 
+  void ParseMinf(Box& aBox);
+  void ParseStbl(Box& aBox);
+  void ParseStsd(Box& aBox);
+  void ParseEncrypted(Box& aBox);
+  void ParseSinf(Box& aBox);
+
   bool BlockingReadNextMoof();
 
   mozilla::MediaByteRange mInitRange;
   nsRefPtr<Stream> mSource;
   uint64_t mOffset;
   Microseconds mTimestampOffset;
   nsTArray<uint64_t> mMoofOffsets;
   Mdhd mMdhd;
   Trex mTrex;
   Tfdt mTfdt;
   Edts mEdts;
+  Sinf mSinf;
   Monitor* mMonitor;
   nsTArray<Moof>& Moofs() { mMonitor->AssertCurrentThreadOwns(); return mMoofs; }
 private:
   nsTArray<Moof> mMoofs;
 };
 }
 
 #endif
new file mode 100644
--- /dev/null
+++ b/media/libstagefright/binding/include/mp4_demuxer/SinfParser.h
@@ -0,0 +1,51 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+#ifndef SINF_PARSER_H_
+#define SINF_PARSER_H_
+
+#include "mp4_demuxer/Atom.h"
+#include "mp4_demuxer/AtomType.h"
+
+namespace mp4_demuxer {
+
+class Box;
+
+class Sinf : public Atom
+{
+public:
+  Sinf()
+    : mDefaultIVSize(0)
+    , mDefaultEncryptionType()
+  {}
+  explicit Sinf(Box& aBox);
+
+  virtual bool IsValid() MOZ_OVERRIDE
+  {
+    return !!mDefaultIVSize && !!mDefaultEncryptionType;
+  }
+
+  uint8_t mDefaultIVSize;
+  AtomType mDefaultEncryptionType;
+  uint8_t mDefaultKeyID[16];
+};
+
+class SinfParser
+{
+public:
+  explicit SinfParser(Box& aBox);
+
+  Sinf& GetSinf() { return mSinf; }
+private:
+  void ParseSchm(Box& aBox);
+  void ParseSchi(Box& aBox);
+  void ParseTenc(Box& aBox);
+
+  Sinf mSinf;
+};
+
+}
+
+#endif // SINF_PARSER_H_
--- a/media/libstagefright/moz.build
+++ b/media/libstagefright/moz.build
@@ -45,25 +45,27 @@ if CONFIG['OS_TARGET'] != 'Android':
         'system/core/libcutils/strdup16to8.c',
         'system/core/liblog/logd_write.c',
         'system/core/liblog/logprint.c',
     ]
 
 EXPORTS.mp4_demuxer += [
     'binding/include/mp4_demuxer/Adts.h',
     'binding/include/mp4_demuxer/AnnexB.h',
+    'binding/include/mp4_demuxer/Atom.h',
     'binding/include/mp4_demuxer/AtomType.h',
     'binding/include/mp4_demuxer/BufferStream.h',
     'binding/include/mp4_demuxer/ByteReader.h',
     'binding/include/mp4_demuxer/ByteWriter.h',
     'binding/include/mp4_demuxer/DecoderData.h',
     'binding/include/mp4_demuxer/H264.h',
     'binding/include/mp4_demuxer/Interval.h',
     'binding/include/mp4_demuxer/MoofParser.h',
     'binding/include/mp4_demuxer/mp4_demuxer.h',
+    'binding/include/mp4_demuxer/SinfParser.h',
 ]
 
 SOURCES += [
     'frameworks/av/media/libstagefright/foundation/hexdump.cpp',
     'frameworks/av/media/libstagefright/MetaData.cpp',
     'system/core/libutils/RefBase.cpp',
     'system/core/libutils/String16.cpp',
     'system/core/libutils/String8.cpp',
@@ -75,16 +77,17 @@ UNIFIED_SOURCES += [
     'binding/AnnexB.cpp',
     'binding/Box.cpp',
     'binding/BufferStream.cpp',
     'binding/DecoderData.cpp',
     'binding/H264.cpp',
     'binding/Index.cpp',
     'binding/MoofParser.cpp',
     'binding/mp4_demuxer.cpp',
+    'binding/SinfParser.cpp',
     'frameworks/av/media/libstagefright/DataSource.cpp',
     'frameworks/av/media/libstagefright/ESDS.cpp',
     'frameworks/av/media/libstagefright/foundation/AAtomizer.cpp',
     'frameworks/av/media/libstagefright/foundation/ABitReader.cpp',
     'frameworks/av/media/libstagefright/foundation/ABuffer.cpp',
     'frameworks/av/media/libstagefright/foundation/AString.cpp',
     'frameworks/av/media/libstagefright/id3/ID3.cpp',
     'frameworks/av/media/libstagefright/MediaBuffer.cpp',