Bug 1336271 - use MediaByteRangeSet to keep metadata stream in case of invalid 'ftyp' box. r?jya draft
authorAlfredo Yang <ayang@mozilla.com>
Wed, 03 May 2017 16:55:00 +0800
changeset 574547 59ff4728c7908d7e909be47293e81c77a6251cde
parent 572730 0b255199db9d6a6f189b89b7906f99155bde3726
child 627633 d85d87dd73172ec28c30eb9825a02df689e1068c
push id57747
push userayang@mozilla.com
push dateTue, 09 May 2017 01:39:08 +0000
reviewersjya
bugs1336271
milestone55.0a1
Bug 1336271 - use MediaByteRangeSet to keep metadata stream in case of invalid 'ftyp' box. r?jya MozReview-Commit-ID: JruswJ3EpEb
media/libstagefright/binding/MoofParser.cpp
media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -142,84 +142,85 @@ MoofParser::BlockingReadNextMoof()
       byteRanges.Clear();
       byteRanges += MediaByteRange(mOffset, box.Range().mEnd);
       return RebuildFragmentedIndex(context);
     }
   }
   return false;
 }
 
-void
-MoofParser::ScanForMetadata(mozilla::MediaByteRange& aFtyp,
-                            mozilla::MediaByteRange& aMoov)
+bool
+MoofParser::ScanForMetadata(mozilla::MediaByteRangeSet& aRanges)
 {
+  // TODO:
+  //   aRanges should include the box from beginning of streaming
+  //   ('ftyp' in most cases) due to stagefright limitation. mInitRange
+  //   includes 'moov' only. Once rust parser is enabled, aRanges can be
+  //   removed and use mInitRange.
+
   int64_t length = std::numeric_limits<int64_t>::max();
   mSource->Length(&length);
   MediaByteRangeSet byteRanges;
   byteRanges += MediaByteRange(0, length);
   RefPtr<mp4_demuxer::BlockingStream> stream = new BlockingStream(mSource);
 
   BoxContext context(stream, byteRanges);
   for (Box box(&context, mOffset); box.IsAvailable(); box = box.Next()) {
-    if (box.IsType("ftyp")) {
-      aFtyp = box.Range();
+    CheckedInt<MediaByteBuffer::size_type> boxLength = box.Range().Length();
+    if (!boxLength.isValid() || !boxLength.value()) {
       continue;
     }
+
+    if (box.IsType("ftyp")) {
+      aRanges += box.Range();
+    }
+
     if (box.IsType("moov")) {
-      aMoov = box.Range();
-      break;
+      aRanges += box.Range();
+      mInitRange = box.Range();
+      return true;
     }
   }
-  mInitRange = aFtyp.Span(aMoov);
+  return false;
 }
 
 bool
 MoofParser::HasMetadata()
 {
-  MediaByteRange ftyp;
-  MediaByteRange moov;
-  ScanForMetadata(ftyp, moov);
-  return !!ftyp.Length() && !!moov.Length();
+  MediaByteRangeSet ranges;
+  return ScanForMetadata(ranges);
 }
 
 already_AddRefed<mozilla::MediaByteBuffer>
 MoofParser::Metadata()
 {
-  MediaByteRange ftyp;
-  MediaByteRange moov;
-  ScanForMetadata(ftyp, moov);
-  CheckedInt<MediaByteBuffer::size_type> ftypLength = ftyp.Length();
-  CheckedInt<MediaByteBuffer::size_type> moovLength = moov.Length();
-  if (!ftypLength.isValid() || !moovLength.isValid()
-      || !ftypLength.value() || !moovLength.value()) {
-    // No ftyp or moov, or they cannot be used as array size.
-    return nullptr;
-  }
-  CheckedInt<MediaByteBuffer::size_type> totalLength = ftypLength + moovLength;
-  if (!totalLength.isValid()) {
-    // Addition overflow, or sum cannot be used as array size.
-    return nullptr;
-  }
-  RefPtr<MediaByteBuffer> metadata = new MediaByteBuffer();
-  if (!metadata->SetLength(totalLength.value(), fallible)) {
-    // OOM
+  MediaByteRangeSet ranges;
+  if (!ScanForMetadata(ranges)) {
     return nullptr;
   }
 
+  RefPtr<MediaByteBuffer> metadata = new MediaByteBuffer();
   RefPtr<mp4_demuxer::BlockingStream> stream = new BlockingStream(mSource);
-  size_t read;
-  bool rv =
-    stream->ReadAt(ftyp.mStart, metadata->Elements(), ftypLength.value(), &read);
-  if (!rv || read != ftypLength.value()) {
-    return nullptr;
-  }
-  rv =
-    stream->ReadAt(moov.mStart, metadata->Elements() + ftypLength.value(), moovLength.value(), &read);
-  if (!rv || read != moovLength.value()) {
-    return nullptr;
+  for (const auto& range: ranges) {
+    RefPtr<MediaByteBuffer> buffer = new MediaByteBuffer();
+    if (!buffer->SetLength(range.Length(), fallible)) {
+      // OOM
+      return nullptr;
+    }
+
+    size_t read;
+    bool rv =
+      stream->ReadAt(range.mStart, buffer->Elements(), range.Length(), &read);
+    if (!rv || read != range.Length()) {
+      return nullptr;
+    }
+    if (!metadata->AppendElements(*buffer, fallible)) {
+      // OOM
+      return nullptr;
+    }
   }
   return metadata.forget();
 }
 
 Interval<Microseconds>
 MoofParser::GetCompositionRange(const MediaByteRangeSet& aByteRanges)
 {
   Interval<Microseconds> compositionRange;
--- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
@@ -294,18 +294,17 @@ public:
   Edts mEdts;
   Sinf mSinf;
 
   nsTArray<CencSampleEncryptionInfoEntry> mTrackSampleEncryptionInfoEntries;
   nsTArray<SampleToGroupEntry> mTrackSampleToGroupEntries;
 
   nsTArray<Moof>& Moofs() { return mMoofs; }
 private:
-  void ScanForMetadata(mozilla::MediaByteRange& aFtyp,
-                       mozilla::MediaByteRange& aMoov);
+  bool ScanForMetadata(mozilla::MediaByteRangeSet& aRanges);
   nsTArray<Moof> mMoofs;
   nsTArray<MediaByteRange> mMediaRanges;
   bool mIsAudio;
   uint64_t mLastDecodeTime;
 };
 }
 
 #endif