Bug 1387798 - refactory MoofParser so it gets error when reading malformat video. r?kinetik draft
authorAlfredo.Yang <ayang@mozilla.com>
Fri, 18 Aug 2017 15:11:37 +0800
changeset 649701 05aecd83211c67d2348e8f15cb2ba308fe00474d
parent 646265 b95b1638db48fc3d450b95b98da6bcd2f9326d2f
child 727146 f5422c9ba26382d8916e26d6c27d2ad41fc1061a
push id75106
push userbmo:ayang@mozilla.com
push dateMon, 21 Aug 2017 06:35:52 +0000
reviewerskinetik
bugs1387798
milestone57.0a1
Bug 1387798 - refactory MoofParser so it gets error when reading malformat video. r?kinetik MozReview-Commit-ID: CCL1KTb3VLG
media/libstagefright/binding/MoofParser.cpp
media/libstagefright/binding/SinfParser.cpp
media/libstagefright/binding/include/mp4_demuxer/Box.h
media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -590,24 +590,30 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, 
     return false;
   }
 
   BoxReader reader(aBox);
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Moof, "Incomplete Box (missing flags)");
     return false;
   }
-  uint32_t flags = reader->ReadU32();
+  uint32_t flags;
+  if (!reader->ReadU32(flags)) {
+    return false;
+  }
   uint8_t version = flags >> 24;
 
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Moof, "Incomplete Box (missing sampleCount)");
     return false;
   }
-  uint32_t sampleCount = reader->ReadU32();
+  uint32_t sampleCount;
+  if (!reader->ReadU32(sampleCount)) {
+    return false;
+  }
   if (sampleCount == 0) {
     return true;
   }
 
   size_t need =
     ((flags & 1) ? sizeof(uint32_t) : 0) +
     ((flags & 4) ? sizeof(uint32_t) : 0);
   uint16_t flag[] = { 0x100, 0x200, 0x400, 0x800, 0 };
@@ -617,38 +623,63 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, 
     }
   }
   if (reader->Remaining() < need) {
     LOG(Moof, "Incomplete Box (have:%zu need:%zu)",
         reader->Remaining(), need);
     return false;
   }
 
-  uint64_t offset = aTfhd.mBaseDataOffset + (flags & 1 ? reader->ReadU32() : 0);
-  uint32_t firstSampleFlags =
-    flags & 4 ? reader->ReadU32() : aTfhd.mDefaultSampleFlags;
+  uint64_t offset = aTfhd.mBaseDataOffset;
+  if (flags & 1) {
+    uint32_t baseOffset;
+    if (!reader->ReadU32(baseOffset)) {
+      return false;
+    }
+    offset += baseOffset;
+  }
+  uint32_t firstSampleFlags = aTfhd.mDefaultSampleFlags;
+  if (flags & 4) {
+    if (!reader->ReadU32(firstSampleFlags)) {
+      return false;
+    }
+  }
+
   uint64_t decodeTime = *aDecodeTime;
   nsTArray<Interval<Microseconds>> timeRanges;
 
   if (!mIndex.SetCapacity(sampleCount, fallible)) {
     LOG(Moof, "Out of Memory");
     return false;
   }
 
   for (size_t i = 0; i < sampleCount; i++) {
-    uint32_t sampleDuration =
-      flags & 0x100 ? reader->ReadU32() : aTfhd.mDefaultSampleDuration;
-    uint32_t sampleSize =
-      flags & 0x200 ? reader->ReadU32() : aTfhd.mDefaultSampleSize;
-    uint32_t sampleFlags =
-      flags & 0x400 ? reader->ReadU32()
-                    : i ? aTfhd.mDefaultSampleFlags : firstSampleFlags;
+    uint32_t sampleDuration = aTfhd.mDefaultSampleDuration;
+    if (flags & 0x100) {
+      if (!reader->ReadU32(sampleDuration)) {
+        return false;
+      }
+    }
+    uint32_t sampleSize = aTfhd.mDefaultSampleSize;
+    if (flags & 0x200) {
+      if (!reader->ReadU32(sampleSize)) {
+        return false;
+      }
+    }
+    uint32_t sampleFlags = i ? aTfhd.mDefaultSampleFlags : firstSampleFlags;
+    if (flags & 0x400) {
+      if (!reader->ReadU32(sampleFlags)) {
+        return false;
+      }
+    }
     int32_t ctsOffset = 0;
     if (flags & 0x800) {
-      ctsOffset = reader->Read32();
+      if (!reader->Read32(ctsOffset)) {
+        return false;
+      }
     }
 
     Sample sample;
     sample.mByteRange = MediaByteRange(offset, offset + sampleSize);
     offset += sampleSize;
 
     sample.mDecodeTime =
       aMdhd.ToMicroseconds((int64_t)decodeTime - aEdts.mMediaStart) + aMvhd.ToMicroseconds(aEdts.mEmptyOffset);
@@ -675,71 +706,96 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, 
 
 Tkhd::Tkhd(Box& aBox)
 {
   BoxReader reader(aBox);
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Tkhd, "Incomplete Box (missing flags)");
     return;
   }
-  uint32_t flags = reader->ReadU32();
+  uint32_t flags;
+  if (!reader->ReadU32(flags)) {
+    return;
+  }
   uint8_t version = flags >> 24;
   size_t need =
     3*(version ? sizeof(int64_t) : sizeof(int32_t)) + 2*sizeof(int32_t);
   if (reader->Remaining() < need) {
     LOG(Tkhd, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
   if (version == 0) {
-    mCreationTime = reader->ReadU32();
-    mModificationTime = reader->ReadU32();
-    mTrackId = reader->ReadU32();
-    uint32_t reserved = reader->ReadU32();
+    uint32_t createTime, modificationTime, trackId, reserved, duration;
+    if (!reader->ReadU32(createTime) ||
+        !reader->ReadU32(modificationTime) ||
+        !reader->ReadU32(trackId) ||
+        !reader->ReadU32(reserved) ||
+        !reader->ReadU32(duration)) {
+      return;
+    }
     NS_ASSERTION(!reserved, "reserved should be 0");
-    mDuration = reader->ReadU32();
+    mCreationTime = createTime;
+    mModificationTime = modificationTime;
+    mTrackId = trackId;
+    mDuration = duration;
   } else if (version == 1) {
-    mCreationTime = reader->ReadU64();
-    mModificationTime = reader->ReadU64();
-    mTrackId = reader->ReadU32();
-    uint32_t reserved = reader->ReadU32();
+    uint32_t trackId, reserved;
+    if (!reader->ReadU64(mCreationTime) ||
+        !reader->ReadU64(mModificationTime) ||
+        !reader->ReadU32(trackId) ||
+        !reader->ReadU32(reserved) ||
+        !reader->ReadU64(mDuration)) {
+      return;
+    }
     NS_ASSERTION(!reserved, "reserved should be 0");
-    mDuration = reader->ReadU64();
+    mTrackId = trackId;
   }
   // We don't care about whatever else may be in the box.
   mValid = true;
 }
 
 Mvhd::Mvhd(Box& aBox)
 {
   BoxReader reader(aBox);
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Mdhd, "Incomplete Box (missing flags)");
     return;
   }
-  uint32_t flags = reader->ReadU32();
+  uint32_t flags;
+  if (!reader->ReadU32(flags)) {
+    return;
+  }
   uint8_t version = flags >> 24;
   size_t need =
-    3*(version ? sizeof(int64_t) : sizeof(int32_t)) + sizeof(uint32_t);
+    3 * (version ? sizeof(int64_t) : sizeof(int32_t)) + sizeof(uint32_t);
   if (reader->Remaining() < need) {
     LOG(Mvhd, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
 
   if (version == 0) {
-    mCreationTime = reader->ReadU32();
-    mModificationTime = reader->ReadU32();
-    mTimescale = reader->ReadU32();
-    mDuration = reader->ReadU32();
+    uint32_t createTime, modificationTime, duration;
+    if (!reader->ReadU32(createTime) ||
+        !reader->ReadU32(modificationTime) ||
+        !reader->ReadU32(mTimescale) ||
+        !reader->ReadU32(duration)) {
+      return;
+    }
+    mCreationTime = createTime;
+    mModificationTime = modificationTime;
+    mDuration = duration;
   } else if (version == 1) {
-    mCreationTime = reader->ReadU64();
-    mModificationTime = reader->ReadU64();
-    mTimescale = reader->ReadU32();
-    mDuration = reader->ReadU64();
+    if (!reader->ReadU64(mCreationTime) ||
+        !reader->ReadU64(mModificationTime) ||
+        !reader->ReadU32(mTimescale) ||
+        !reader->ReadU64(mDuration)) {
+      return;
+    }
   } else {
     return;
   }
   // We don't care about whatever else may be in the box.
   if (mTimescale) {
     mValid = true;
   }
 }
@@ -747,93 +803,120 @@ Mvhd::Mvhd(Box& aBox)
 Mdhd::Mdhd(Box& aBox)
   : Mvhd(aBox)
 {
 }
 
 Trex::Trex(Box& aBox)
 {
   BoxReader reader(aBox);
-  if (reader->Remaining() < 6*sizeof(uint32_t)) {
+  if (reader->Remaining() < 6 * sizeof(uint32_t)) {
     LOG(Trex, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
         (uint64_t)reader->Remaining(), (uint64_t)6*sizeof(uint32_t));
     return;
   }
-  mFlags = reader->ReadU32();
-  mTrackId = reader->ReadU32();
-  mDefaultSampleDescriptionIndex = reader->ReadU32();
-  mDefaultSampleDuration = reader->ReadU32();
-  mDefaultSampleSize = reader->ReadU32();
-  mDefaultSampleFlags = reader->ReadU32();
+  if (!reader->ReadU32(mFlags) ||
+      !reader->ReadU32(mTrackId) ||
+      !reader->ReadU32(mDefaultSampleDescriptionIndex) ||
+      !reader->ReadU32(mDefaultSampleDuration) ||
+      !reader->ReadU32(mDefaultSampleSize) ||
+      !reader->ReadU32(mDefaultSampleFlags)) {
+    return;
+  }
   mValid = true;
 }
 
 Tfhd::Tfhd(Box& aBox, Trex& aTrex)
   : Trex(aTrex)
 {
   MOZ_ASSERT(aBox.IsType("tfhd"));
   MOZ_ASSERT(aBox.Parent()->IsType("traf"));
   MOZ_ASSERT(aBox.Parent()->Parent()->IsType("moof"));
 
   BoxReader reader(aBox);
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Tfhd, "Incomplete Box (missing flags)");
     return;
   }
-  mFlags = reader->ReadU32();
+  if (!reader->ReadU32(mFlags)) {
+    return;
+  }
   size_t need = sizeof(uint32_t) /* trackid */;
   uint8_t flag[] = { 1, 2, 8, 0x10, 0x20, 0 };
   uint8_t flagSize[] = { sizeof(uint64_t), sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t) };
   for (size_t i = 0; flag[i]; i++) {
     if (mFlags & flag[i]) {
       need += flagSize[i];
     }
   }
   if (reader->Remaining() < need) {
     LOG(Tfhd, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
-  mTrackId = reader->ReadU32();
-  mBaseDataOffset =
-    mFlags & 1 ? reader->ReadU64() : aBox.Parent()->Parent()->Offset();
+  if (!reader->ReadU32(mTrackId)) {
+    return;
+  }
+  mBaseDataOffset = aBox.Parent()->Parent()->Offset();
+  if (mFlags & 1) {
+    if (!reader->ReadU64(mBaseDataOffset)) {
+      return;
+    }
+  }
   if (mFlags & 2) {
-    mDefaultSampleDescriptionIndex = reader->ReadU32();
+    if (!reader->ReadU32(mDefaultSampleDescriptionIndex)) {
+      return;
+    }
   }
   if (mFlags & 8) {
-    mDefaultSampleDuration = reader->ReadU32();
+    if (!reader->ReadU32(mDefaultSampleDuration)) {
+      return;
+    }
   }
   if (mFlags & 0x10) {
-    mDefaultSampleSize = reader->ReadU32();
+    if (!reader->ReadU32(mDefaultSampleSize)) {
+      return;
+    }
   }
   if (mFlags & 0x20) {
-    mDefaultSampleFlags = reader->ReadU32();
+    if (!reader->ReadU32(mDefaultSampleFlags)) {
+      return;
+    }
   }
   mValid = true;
 }
 
 Tfdt::Tfdt(Box& aBox)
 {
   BoxReader reader(aBox);
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Tfdt, "Incomplete Box (missing flags)");
     return;
   }
-  uint32_t flags = reader->ReadU32();
+  uint32_t flags;
+  if (!reader->ReadU32(flags)) {
+    return;
+  }
   uint8_t version = flags >> 24;
   size_t need = version ? sizeof(uint64_t) : sizeof(uint32_t) ;
   if (reader->Remaining() < need) {
     LOG(Tfdt, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
   if (version == 0) {
-    mBaseMediaDecodeTime = reader->ReadU32();
+    uint32_t baseDecodeTime;
+    if (!reader->ReadU32(baseDecodeTime)) {
+      return;
+    }
+    mBaseMediaDecodeTime = baseDecodeTime;
   } else if (version == 1) {
-    mBaseMediaDecodeTime = reader->ReadU64();
+    if (!reader->ReadU64(mBaseMediaDecodeTime)) {
+      return;
+    }
   }
   mValid = true;
 }
 
 Edts::Edts(Box& aBox)
   : mMediaStart(0)
   , mEmptyOffset(0)
 {
@@ -842,76 +925,106 @@ Edts::Edts(Box& aBox)
     return;
   }
 
   BoxReader reader(child);
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Edts, "Incomplete Box (missing flags)");
     return;
   }
-  uint32_t flags = reader->ReadU32();
+  uint32_t flags;
+  if (!reader->ReadU32(flags)) {
+    return;
+  }
   uint8_t version = flags >> 24;
   size_t need =
     sizeof(uint32_t) + 2*(version ? sizeof(int64_t) : sizeof(uint32_t));
   if (reader->Remaining() < need) {
     LOG(Edts, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
   bool emptyEntry = false;
-  uint32_t entryCount = reader->ReadU32();
+  uint32_t entryCount;
+  if (!reader->ReadU32(entryCount)) {
+    return;
+  }
   for (uint32_t i = 0; i < entryCount; i++) {
     uint64_t segment_duration;
     int64_t media_time;
     if (version == 1) {
-      segment_duration = reader->ReadU64();
-      media_time = reader->Read64();
+      if (!reader->ReadU64(segment_duration) ||
+          !reader->Read64(media_time)) {
+        return;
+      }
     } else {
-      segment_duration = reader->ReadU32();
-      media_time = reader->Read32();
+      uint32_t duration;
+      int32_t time;
+      if (!reader->ReadU32(duration) ||
+          !reader->Read32(time)) {
+        return;
+      }
+      segment_duration = duration;
+      media_time = time;
     }
     if (media_time == -1 && i) {
       LOG(Edts, "Multiple empty edit, not handled");
     } else if (media_time == -1) {
       mEmptyOffset = segment_duration;
       emptyEntry = true;
     } else if (i > 1 || (i > 0 && !emptyEntry)) {
       LOG(Edts, "More than one edit entry, not handled. A/V sync will be wrong");
       break;
     } else {
       mMediaStart = media_time;
     }
-    reader->ReadU32(); // media_rate_integer and media_rate_fraction
+
+    // media_rate_integer and media_rate_fraction
+    if (!reader->Skip(4)) {
+      return;
+    }
   }
+  mValid = true;
 }
 
 Saiz::Saiz(Box& aBox, AtomType aDefaultType)
   : mAuxInfoType(aDefaultType)
   , mAuxInfoTypeParameter(0)
 {
   BoxReader reader(aBox);
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Saiz, "Incomplete Box (missing flags)");
     return;
   }
-  uint32_t flags = reader->ReadU32();
+  uint32_t flags;
+  if (!reader->ReadU32(flags)) {
+    return;
+  }
   uint8_t version = flags >> 24;
   size_t need =
     ((flags & 1) ? 2*sizeof(uint32_t) : 0) + sizeof(uint8_t) + sizeof(uint32_t);
   if (reader->Remaining() < need) {
     LOG(Saiz, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
   if (flags & 1) {
-    mAuxInfoType = reader->ReadU32();
-    mAuxInfoTypeParameter = reader->ReadU32();
+    uint32_t auxType;
+    if (!reader->ReadU32(auxType) ||
+        !reader->ReadU32(mAuxInfoTypeParameter)) {
+      return;
+    }
+    mAuxInfoType = auxType;
   }
-  uint8_t defaultSampleInfoSize = reader->ReadU8();
-  uint32_t count = reader->ReadU32();
+  uint8_t defaultSampleInfoSize;
+  uint32_t count;
+  if (!reader->ReadU8(defaultSampleInfoSize) ||
+      !reader->ReadU32(count)) {
+    return;
+  }
   if (defaultSampleInfoSize) {
     if (!mSampleInfoSize.SetLength(count, fallible)) {
       LOG(Saiz, "OOM");
       return;
     }
     memset(mSampleInfoSize.Elements(), defaultSampleInfoSize, mSampleInfoSize.Length());
   } else {
     if (!reader->ReadArray(mSampleInfoSize, count)) {
@@ -926,145 +1039,193 @@ Saio::Saio(Box& aBox, AtomType aDefaultT
   : mAuxInfoType(aDefaultType)
   , mAuxInfoTypeParameter(0)
 {
   BoxReader reader(aBox);
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Saio, "Incomplete Box (missing flags)");
     return;
   }
-  uint32_t flags = reader->ReadU32();
+  uint32_t flags;
+  if (!reader->ReadU32(flags)) {
+    return;
+  }
   uint8_t version = flags >> 24;
-  size_t need = ((flags & 1) ? (2*sizeof(uint32_t)) : 0) + sizeof(uint32_t);
+  size_t need = ((flags & 1) ? (2 * sizeof(uint32_t)) : 0) + sizeof(uint32_t);
   if (reader->Remaining() < need) {
     LOG(Saio, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
   if (flags & 1) {
-    mAuxInfoType = reader->ReadU32();
-    mAuxInfoTypeParameter = reader->ReadU32();
+    uint32_t auxType;
+    if (!reader->ReadU32(auxType) ||
+        !reader->ReadU32(mAuxInfoTypeParameter)) {
+      return;
+    }
+    mAuxInfoType = auxType;
   }
-  size_t count = reader->ReadU32();
+  uint32_t count;
+  if (!reader->ReadU32(count)) {
+    return;
+  }
   need = (version ? sizeof(uint64_t) : sizeof(uint32_t)) * count;
   if (reader->Remaining() < need) {
     LOG(Saio, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
   if (!mOffsets.SetCapacity(count, fallible)) {
     LOG(Saiz, "OOM");
     return;
   }
   if (version == 0) {
+    uint32_t offset;
     for (size_t i = 0; i < count; i++) {
-      MOZ_ALWAYS_TRUE(mOffsets.AppendElement(reader->ReadU32(), fallible));
+      if (!reader->ReadU32(offset)) {
+        return;
+      }
+      MOZ_ALWAYS_TRUE(mOffsets.AppendElement(offset, fallible));
     }
   } else {
+    uint64_t offset;
     for (size_t i = 0; i < count; i++) {
-      MOZ_ALWAYS_TRUE(mOffsets.AppendElement(reader->ReadU64(), fallible));
+      if (!reader->ReadU64(offset)) {
+        return;
+      }
+      MOZ_ALWAYS_TRUE(mOffsets.AppendElement(offset, fallible));
     }
   }
   mValid = true;
 }
 
 Sbgp::Sbgp(Box& aBox)
 {
   BoxReader reader(aBox);
 
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Sbgp, "Incomplete Box (missing flags)");
     return;
   }
 
-  uint32_t flags = reader->ReadU32();
+  uint32_t flags;
+  if (!reader->ReadU32(flags)) {
+    return;
+  }
   const uint8_t version = flags >> 24;
   flags = flags & 0xffffff;
 
   // Make sure we have enough bytes to read as far as the count.
   uint32_t need = (version == 1 ? sizeof(uint32_t) : 0) + sizeof(uint32_t) * 2;
   if (reader->Remaining() < need) {
     LOG(Sbgp, "Incomplete Box (have:%" PRIu64 ", need:%" PRIu64 ")",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
 
-  mGroupingType = reader->ReadU32();
+  uint32_t groupType;
+  if (!reader->ReadU32(groupType)) {
+    return;
+  }
+  mGroupingType = groupType;
 
   if (version == 1) {
-    mGroupingTypeParam = reader->Read32();
+    if (reader->ReadU32(mGroupingTypeParam)) {
+      false;
+    }
   }
 
-  uint32_t count = reader->ReadU32();
+  uint32_t count;
+  if (!reader->ReadU32(count)) {
+    return;
+  }
 
   // Make sure we can read all the entries.
   need = sizeof(uint32_t) * 2 * count;
   if (reader->Remaining() < need) {
     LOG(Sbgp, "Incomplete Box (have:%" PRIu64 ", need:%" PRIu64 "). Failed to read entries",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
 
   for (uint32_t i = 0; i < count; i++) {
-    uint32_t sampleCount = reader->ReadU32();
-    uint32_t groupDescriptionIndex = reader->ReadU32();
-
+    uint32_t sampleCount;
+    uint32_t groupDescriptionIndex;
+    if (!reader->ReadU32(sampleCount) ||
+        !reader->ReadU32(groupDescriptionIndex)) {
+      return;
+    }
     SampleToGroupEntry entry(sampleCount, groupDescriptionIndex);
     mEntries.AppendElement(entry);
   }
 
   mValid = true;
 }
 
 Sgpd::Sgpd(Box& aBox)
 {
   BoxReader reader(aBox);
 
   if (!reader->CanReadType<uint32_t>()) {
     LOG(Sgpd, "Incomplete Box (missing flags)");
     return;
   }
 
-  uint32_t flags = reader->ReadU32();
+  uint32_t flags;
+  if (!reader->ReadU32(flags)) {
+    return;
+  }
   const uint8_t version = flags >> 24;
   flags = flags & 0xffffff;
 
   uint32_t need = ((flags & 1) ? sizeof(uint32_t) : 0) + sizeof(uint32_t) * 2;
   if (reader->Remaining() < need) {
     LOG(Sgpd, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 ")",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
 
-  mGroupingType = reader->ReadU32();
+  uint32_t groupType;
+  if (!reader->ReadU32(groupType)) {
+    return;
+  }
+  mGroupingType = groupType;
 
   const uint32_t entrySize = sizeof(uint32_t) + kKeyIdSize;
   uint32_t defaultLength = 0;
 
   if (version == 1) {
-    defaultLength = reader->ReadU32();
+    if (!reader->ReadU32(defaultLength)) {
+      return;
+    }
     if (defaultLength < entrySize && defaultLength != 0) {
       return;
     }
   }
 
-  uint32_t count = reader->ReadU32();
+  uint32_t count;
+  if (!reader->ReadU32(count)) {
+    return;
+  }
 
   // Make sure we have sufficient remaining bytes to read the entries.
   need =
     count * (sizeof(uint32_t) * (version == 1 && defaultLength == 0 ? 2 : 1) +
              kKeyIdSize * sizeof(uint8_t));
   if (reader->Remaining() < need) {
     LOG(Sgpd, "Incomplete Box (have:%" PRIu64 " need:%" PRIu64 "). Failed to read entries",
         (uint64_t)reader->Remaining(), (uint64_t)need);
     return;
   }
   for (uint32_t i = 0; i < count; ++i) {
     if (version == 1 && defaultLength == 0) {
-      uint32_t descriptionLength = reader->ReadU32();
+      uint32_t descriptionLength;
+      if (!reader->ReadU32(descriptionLength)) {
+        return;
+      }
       if (descriptionLength < entrySize) {
         return;
       }
     }
 
     CencSampleEncryptionInfoEntry entry;
     bool valid = entry.Init(reader);
     if (!valid) {
@@ -1074,26 +1235,36 @@ Sgpd::Sgpd(Box& aBox)
   }
 
   mValid = true;
 }
 
 bool CencSampleEncryptionInfoEntry::Init(BoxReader& aReader)
 {
   // Skip a reserved byte.
-  aReader->ReadU8();
+  uint8_t skip;
+  if (!aReader->ReadU8(skip)) {
+    return false;
+  }
 
-  uint8_t possiblePatternInfo = aReader->ReadU8();
-  uint8_t flag = aReader->ReadU8();
-
-  mIVSize = aReader->ReadU8();
+  uint8_t possiblePatternInfo;
+  uint8_t flag;
+  if (!aReader->ReadU8(possiblePatternInfo) ||
+      !aReader->ReadU8(flag) ||
+      !aReader->ReadU8(mIVSize)) {
+    return false;
+  }
 
   // Read the key id.
+  uint8_t key;
   for (uint32_t i = 0; i < kKeyIdSize; ++i) {
-    mKeyId.AppendElement(aReader->ReadU8());
+    if (!aReader->ReadU8(key)) {
+      return false;
+    }
+    mKeyId.AppendElement(key);
   }
 
   mIsEncrypted = flag != 0;
 
   if (mIsEncrypted) {
     if (mIVSize != 8 && mIVSize != 16) {
       return false;
     }
--- a/media/libstagefright/binding/SinfParser.cpp
+++ b/media/libstagefright/binding/SinfParser.cpp
@@ -33,19 +33,23 @@ SinfParser::SinfParser(Box& aBox)
 void
 SinfParser::ParseSchm(Box& aBox)
 {
   BoxReader reader(aBox);
 
   if (reader->Remaining() < 8) {
     return;
   }
-
-  mozilla::Unused << reader->ReadU32(); // flags -- ignore
-  mSinf.mDefaultEncryptionType = reader->ReadU32();
+  uint32_t type;
+  if (!reader->Skip(4) ||
+      !reader->ReadU32(type)) {
+    NS_WARNING("Failed to parse schm data");
+    return;
+  }
+  mSinf.mDefaultEncryptionType = type;
 }
 
 void
 SinfParser::ParseSchi(Box& aBox)
 {
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("tenc")) {
       ParseTenc(box);
@@ -57,16 +61,21 @@ 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);
+  uint32_t isEncrypted;
+  const uint8_t* key;
+  if (!reader->Skip(4) ||  // flags -- ignore
+      !reader->ReadU24(isEncrypted) ||
+      !reader->ReadU8(mSinf.mDefaultIVSize) ||
+      !reader->Read(16, &key)) {
+    NS_WARNING("Failed to parse tenc data");
+    return;
+  }
+  memcpy(mSinf.mDefaultKeyID, key, 16);
 }
 
 }
--- a/media/libstagefright/binding/include/mp4_demuxer/Box.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Box.h
@@ -70,17 +70,17 @@ private:
 class MOZ_RAII BoxReader
 {
 public:
   explicit BoxReader(Box& aBox)
     : mBuffer(aBox.Read())
     , mReader(mBuffer.Elements(), mBuffer.Length())
   {
   }
-  ByteReader* operator->() { return &mReader; }
+  DataReader* operator->() { return &mReader; }
 
 private:
   nsTArray<uint8_t> mBuffer;
-  ByteReader mReader;
+  DataReader mReader;
 };
 }
 
 #endif
--- a/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
@@ -7,16 +7,230 @@
 
 #include "mozilla/EndianUtils.h"
 #include "mozilla/Vector.h"
 #include "nsTArray.h"
 #include "MediaData.h"
 
 namespace mp4_demuxer {
 
+class MOZ_RAII DataReader
+{
+public:
+  DataReader() : mPtr(nullptr), mRemaining(0) {}
+  explicit DataReader(const mozilla::Vector<uint8_t>& aData)
+    : mPtr(aData.begin()), mRemaining(aData.length()), mLength(aData.length())
+  {
+  }
+  DataReader(const uint8_t* aData, size_t aSize)
+    : mPtr(aData), mRemaining(aSize), mLength(aSize)
+  {
+  }
+  template<size_t S>
+  explicit DataReader(const AutoTArray<uint8_t, S>& aData)
+    : mPtr(aData.Elements()), mRemaining(aData.Length()), mLength(aData.Length())
+  {
+  }
+  explicit DataReader(const nsTArray<uint8_t>& aData)
+    : mPtr(aData.Elements()), mRemaining(aData.Length()), mLength(aData.Length())
+  {
+  }
+  explicit DataReader(const mozilla::MediaByteBuffer* aData)
+    : mPtr(aData->Elements()), mRemaining(aData->Length()), mLength(aData->Length())
+  {
+  }
+
+  void SetData(const nsTArray<uint8_t>& aData)
+  {
+    MOZ_ASSERT(!mPtr && !mRemaining);
+    mPtr = aData.Elements();
+    mRemaining = aData.Length();
+    mLength = mRemaining;
+  }
+
+  ~DataReader()
+  {
+  }
+
+  size_t Offset() const
+  {
+    return mLength - mRemaining;
+  }
+
+  size_t Remaining() const { return mRemaining; }
+
+  bool CanRead8() const { return mRemaining >= 1; }
+
+  bool ReadU8(uint8_t& aU8)
+  {
+    const uint8_t* ptr;
+    if (!Read(1, &ptr)) {
+      NS_WARNING("Failed to read data");
+      return false;
+    }
+    aU8 = *ptr;
+    return true;
+  }
+
+  bool CanRead16() { return mRemaining >= 2; }
+
+  bool ReadU16(uint16_t& u16)
+  {
+    const uint8_t* ptr;
+    if (!Read(2, &ptr)) {
+      NS_WARNING("Failed to read data");
+      return false;
+    }
+    u16 = mozilla::BigEndian::readUint16(ptr);
+    return true;
+  }
+
+  bool CanRead32() { return mRemaining >= 4; }
+
+  bool ReadU32(uint32_t& u32)
+  {
+    const uint8_t* ptr;
+    if (!Read(4, &ptr)) {
+      NS_WARNING("Failed to read data");
+      return false;
+    }
+    u32 = mozilla::BigEndian::readUint32(ptr);
+    return true;
+  }
+
+  bool Read32(int32_t& i32)
+  {
+    const uint8_t* ptr;
+    if (!Read(4, &ptr)) {
+      NS_WARNING("Failed to read data");
+      return 0;
+    }
+    i32 = mozilla::BigEndian::readInt32(ptr);
+    return true;
+  }
+
+  bool ReadU64(uint64_t& u64)
+  {
+    const uint8_t* ptr;
+    if (!Read(8, &ptr)) {
+      NS_WARNING("Failed to read data");
+      return false;
+    }
+    u64 = mozilla::BigEndian::readUint64(ptr);
+    return true;
+  }
+
+  bool Read64(int64_t& i64)
+  {
+    const uint8_t* ptr;
+    if (!Read(8, &ptr)) {
+      NS_WARNING("Failed to read data");
+      return false;
+    }
+    i64 = mozilla::BigEndian::readInt64(ptr);
+    return true;
+  }
+
+  bool ReadU24(uint32_t& u32)
+  {
+    const uint8_t* ptr;
+    if (!Read(3, &ptr)) {
+      NS_WARNING("Failed to read data");
+      return false;
+    }
+    u32 = ptr[0] << 16 | ptr[1] << 8 | ptr[2];
+    return true;
+  }
+
+  bool Skip(size_t aCount)
+  {
+    const uint8_t* ptr;
+    if (!Read(aCount, &ptr)) {
+      NS_WARNING("Failed to skip data");
+      return false;
+    }
+    return true;
+  }
+
+  bool Read(size_t aCount, const uint8_t** aPtr)
+  {
+    if (aCount > mRemaining) {
+      mRemaining = 0;
+      return false;
+    }
+    mRemaining -= aCount;
+
+    *aPtr = mPtr;
+    mPtr += aCount;
+
+    return true;
+  }
+
+  uint32_t Align() const
+  {
+    return 4 - ((intptr_t)mPtr & 3);
+  }
+
+  template <typename T> bool CanReadType() const { return mRemaining >= sizeof(T); }
+
+  template <typename T> T ReadType()
+  {
+    const uint8_t* ptr;
+    if (!Read(sizeof(T), &ptr)) {
+      NS_WARNING("ReadType failed");
+      return 0;
+    }
+    return *reinterpret_cast<const T*>(ptr);
+  }
+
+  template <typename T>
+  MOZ_MUST_USE bool ReadArray(nsTArray<T>& aDest, size_t aLength)
+  {
+    const uint8_t* ptr;
+    if (!Read(aLength * sizeof(T), &ptr)) {
+      NS_WARNING("ReadArray failed");
+      return false;
+    }
+
+    aDest.Clear();
+    aDest.AppendElements(reinterpret_cast<const T*>(ptr), aLength);
+    return true;
+  }
+
+  template <typename T>
+  MOZ_MUST_USE bool ReadArray(FallibleTArray<T>& aDest, size_t aLength)
+  {
+    const uint8_t* ptr;
+    if (!Read(aLength * sizeof(T), &ptr)) {
+      NS_WARNING("ReadArray failed");
+      return false;
+    }
+
+    aDest.Clear();
+    if (!aDest.SetCapacity(aLength, mozilla::fallible)) {
+      return false;
+    }
+    MOZ_ALWAYS_TRUE(aDest.AppendElements(reinterpret_cast<const T*>(ptr),
+                                         aLength,
+                                         mozilla::fallible));
+    return true;
+  }
+
+private:
+  const uint8_t* mPtr;
+  size_t mRemaining;
+  size_t mLength;
+};
+
+
+/*
+ * Do NOT use this anymore, it will deprecate soon due to lack the returning
+ * errr.
+ * Please use DataReader instead.
+ */
 class MOZ_RAII ByteReader
 {
 public:
   ByteReader() : mPtr(nullptr), mRemaining(0) {}
   explicit ByteReader(const mozilla::Vector<uint8_t>& aData)
     : mPtr(aData.begin()), mRemaining(aData.length()), mLength(aData.length())
   {
   }