Bug 1171629 - Use fallible array to store MP4 samples index. r=kentuckyfriedtakahe, a=lizzard
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 09 Jun 2015 19:08:28 +1000
changeset 275053 0dcce98d251cecc04050c023c6aea6270346598f
parent 275052 0317bce5dabdd71398a176980153e400b611c5d6
child 275054 cb88dde640aa1b55d9ed030c6a8674c611745386
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskentuckyfriedtakahe, lizzard
bugs1171629
milestone40.0a2
Bug 1171629 - Use fallible array to store MP4 samples index. r=kentuckyfriedtakahe, a=lizzard
media/libstagefright/binding/Index.cpp
media/libstagefright/binding/MP4Metadata.cpp
media/libstagefright/binding/MoofParser.cpp
media/libstagefright/binding/include/mp4_demuxer/Index.h
media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
media/libstagefright/binding/mp4_demuxer.cpp
--- a/media/libstagefright/binding/Index.cpp
+++ b/media/libstagefright/binding/Index.cpp
@@ -232,25 +232,29 @@ Index::Index(const nsTArray<Indice>& aIn
              bool aIsAudio,
              Monitor* aMonitor)
   : mSource(aSource)
   , mMonitor(aMonitor)
 {
   if (aIndex.IsEmpty()) {
     mMoofParser = new MoofParser(aSource, aTrackId, aIsAudio, aMonitor);
   } else {
+    if (!mIndex.SetCapacity(aIndex.Length())) {
+      // OOM.
+      return;
+    }
     for (size_t i = 0; i < aIndex.Length(); i++) {
       const Indice& indice = aIndex[i];
       Sample sample;
       sample.mByteRange = MediaByteRange(indice.start_offset,
                                          indice.end_offset);
       sample.mCompositionRange = Interval<Microseconds>(indice.start_composition,
                                                         indice.end_composition);
       sample.mSync = indice.sync;
-      mIndex.AppendElement(sample);
+      MOZ_ALWAYS_TRUE(mIndex.AppendElement(sample));
     }
   }
 }
 
 Index::~Index() {}
 
 void
 Index::UpdateMoofIndex(const nsTArray<MediaByteRange>& aByteRanges)
@@ -260,17 +264,17 @@ Index::UpdateMoofIndex(const nsTArray<Me
   }
 
   mMoofParser->RebuildFragmentedIndex(aByteRanges);
 }
 
 Microseconds
 Index::GetEndCompositionIfBuffered(const nsTArray<MediaByteRange>& aByteRanges)
 {
-  nsTArray<Sample>* index;
+  FallibleTArray<Sample>* index;
   if (mMoofParser) {
     if (!mMoofParser->ReachedEnd() || mMoofParser->Moofs().IsEmpty()) {
       return 0;
     }
     index = &mMoofParser->Moofs().LastElement().mIndex;
   } else {
     index = &mIndex;
   }
@@ -293,17 +297,17 @@ Index::GetEndCompositionIfBuffered(const
 void
 Index::ConvertByteRangesToTimeRanges(
   const nsTArray<MediaByteRange>& aByteRanges,
   nsTArray<Interval<Microseconds>>* aTimeRanges)
 {
   RangeFinder rangeFinder(aByteRanges);
   nsTArray<Interval<Microseconds>> timeRanges;
 
-  nsTArray<nsTArray<Sample>*> indexes;
+  nsTArray<FallibleTArray<Sample>*> indexes;
   if (mMoofParser) {
     // We take the index out of the moof parser and move it into a local
     // variable so we don't get concurrency issues. It gets freed when we
     // exit this function.
     for (int i = 0; i < mMoofParser->Moofs().Length(); i++) {
       Moof& moof = mMoofParser->Moofs()[i];
 
       // We need the entire moof in order to play anything
@@ -316,17 +320,17 @@ Index::ConvertByteRangesToTimeRanges(
       }
     }
   } else {
     indexes.AppendElement(&mIndex);
   }
 
   bool hasSync = false;
   for (size_t i = 0; i < indexes.Length(); i++) {
-    nsTArray<Sample>* index = indexes[i];
+    FallibleTArray<Sample>* index = indexes[i];
     for (size_t j = 0; j < index->Length(); j++) {
       const Sample& sample = (*index)[j];
       if (!rangeFinder.Contains(sample.mByteRange)) {
         // We process the index in decode order so we clear hasSync when we hit
         // a range that isn't buffered.
         hasSync = false;
         continue;
       }
--- a/media/libstagefright/binding/MP4Metadata.cpp
+++ b/media/libstagefright/binding/MP4Metadata.cpp
@@ -61,30 +61,34 @@ public:
   virtual uint32_t flags() { return kWantsPrefetching | kIsHTTPBasedSource; }
 
   virtual status_t reconnectAtOffset(off64_t offset) { return NO_ERROR; }
 
 private:
   nsRefPtr<Stream> mSource;
 };
 
-static inline void
-ConvertIndex(nsTArray<Index::Indice>& aDest,
+static inline bool
+ConvertIndex(FallibleTArray<Index::Indice>& aDest,
              const stagefright::Vector<stagefright::MediaSource::Indice>& aIndex)
 {
+  if (!aDest.SetCapacity(aIndex.size())) {
+    return false;
+  }
   for (size_t i = 0; i < aIndex.size(); i++) {
     Index::Indice indice;
     const stagefright::MediaSource::Indice& s_indice = aIndex[i];
     indice.start_offset = s_indice.start_offset;
     indice.end_offset = s_indice.end_offset;
     indice.start_composition = s_indice.start_composition;
     indice.end_composition = s_indice.end_composition;
     indice.sync = s_indice.sync;
-    aDest.AppendElement(indice);
+    MOZ_ALWAYS_TRUE(aDest.AppendElement(indice));
   }
+  return true;
 }
 
 MP4Metadata::MP4Metadata(Stream* aSource)
   : mPrivate(new StageFrightPrivate)
   , mSource(aSource)
 {
   mPrivate->mMetadataExtractor =
     new MPEG4Extractor(new DataSourceAdapter(mSource));
@@ -228,32 +232,32 @@ MP4Metadata::UpdateCrypto(const MetaData
   // isn't set consistently in the MPEG4Extractor.
   if (!aMetaData->findData(kKeyPssh, &type, &data, &size)) {
     return;
   }
   mCrypto.Update(reinterpret_cast<const uint8_t*>(data), size);
 }
 
 bool
-MP4Metadata::ReadTrackIndex(nsTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID)
+MP4Metadata::ReadTrackIndex(FallibleTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID)
 {
   size_t numTracks = mPrivate->mMetadataExtractor->countTracks();
   int32_t trackNumber = GetTrackNumber(aTrackID);
   if (trackNumber < 0) {
     return false;
   }
   sp<MediaSource> track = mPrivate->mMetadataExtractor->getTrack(trackNumber);
   if (!track.get() || track->start() != OK) {
     return false;
   }
-  ConvertIndex(aDest, track->exportIndex());
+  bool rv = ConvertIndex(aDest, track->exportIndex());
 
   track->stop();
 
-  return true;
+  return rv;
 }
 
 int32_t
 MP4Metadata::GetTrackNumber(mozilla::TrackID aTrackID)
 {
   size_t numTracks = mPrivate->mMetadataExtractor->countTracks();
   for (size_t i = 0; i < numTracks; i++) {
     sp<MetaData> metaData = mPrivate->mMetadataExtractor->getTrackMetaData(i);
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -442,16 +442,22 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, 
     return false;
   }
 
   uint64_t offset = aTfhd.mBaseDataOffset + (flags & 1 ? reader->ReadU32() : 0);
   bool hasFirstSampleFlags = flags & 4;
   uint32_t firstSampleFlags = hasFirstSampleFlags ? reader->ReadU32() : 0;
   uint64_t decodeTime = *aDecodeTime;
   nsTArray<Interval<Microseconds>> timeRanges;
+
+  if (!mIndex.SetCapacity(sampleCount)) {
+    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() : hasFirstSampleFlags && i == 0
                                             ? firstSampleFlags
@@ -470,17 +476,17 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, 
       aMdhd.ToMicroseconds((int64_t)decodeTime + ctsOffset - aEdts.mMediaStart),
       aMdhd.ToMicroseconds((int64_t)decodeTime + ctsOffset + sampleDuration - aEdts.mMediaStart));
     decodeTime += sampleDuration;
 
     // Sometimes audio streams don't properly mark their samples as keyframes,
     // because every audio sample is a keyframe.
     sample.mSync = !(sampleFlags & 0x1010000) || aIsAudio;
 
-    mIndex.AppendElement(sample);
+    MOZ_ALWAYS_TRUE(mIndex.AppendElement(sample));
 
     mMdatRange = mMdatRange.Extents(sample.mByteRange);
   }
   mMaxRoundingError += aMdhd.ToMicroseconds(sampleCount);
 
   nsTArray<Sample*> ctsOrder;
   for (int i = 0; i < mIndex.Length(); i++) {
     ctsOrder.AppendElement(&mIndex[i]);
--- a/media/libstagefright/binding/include/mp4_demuxer/Index.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Index.h
@@ -69,15 +69,15 @@ public:
   bool IsFragmented() { return mMoofParser; }
 
   friend class SampleIterator;
 
 private:
   ~Index();
 
   Stream* mSource;
-  nsTArray<Sample> mIndex;
+  FallibleTArray<Sample> mIndex;
   nsAutoPtr<MoofParser> mMoofParser;
   mozilla::Monitor* mMonitor;
 };
 }
 
 #endif
--- a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
@@ -34,17 +34,17 @@ public:
                                                       size_t aTrackNumber) const;
   bool CanSeek() const;
 
   const CryptoFile& Crypto() const
   {
     return mCrypto;
   }
 
-  bool ReadTrackIndex(nsTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID);
+  bool ReadTrackIndex(FallibleTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID);
 
 private:
   int32_t GetTrackNumber(mozilla::TrackID aTrackID);
   void UpdateCrypto(const stagefright::MetaData* aMetaData);
   nsAutoPtr<StageFrightPrivate> mPrivate;
   CryptoFile mCrypto;
   nsRefPtr<Stream> mSource;
 };
--- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
@@ -170,17 +170,17 @@ class Moof : public Atom
 public:
   Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, bool aIsAudio);
   bool GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges);
   void FixRounding(const Moof& aMoof);
 
   mozilla::MediaByteRange mRange;
   mozilla::MediaByteRange mMdatRange;
   Interval<Microseconds> mTimeRange;
-  nsTArray<Sample> mIndex;
+  FallibleTArray<Sample> mIndex;
 
   nsTArray<Saiz> mSaizs;
   nsTArray<Saio> mSaios;
 
 private:
   void ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts, Sinf& aSinf, bool aIsAudio);
   // aDecodeTime is updated to the end of the parsed TRUN on return.
   bool ParseTrun(Box& aBox, Tfhd& aTfhd, Mdhd& aMdhd, Edts& aEdts, uint64_t* aDecodeTime, bool aIsAudio);
--- a/media/libstagefright/binding/mp4_demuxer.cpp
+++ b/media/libstagefright/binding/mp4_demuxer.cpp
@@ -40,34 +40,34 @@ MP4Demuxer::Init()
   if (!mMetadata->GetNumberTracks(mozilla::TrackInfo::kAudioTrack) &&
       !mMetadata->GetNumberTracks(mozilla::TrackInfo::kVideoTrack)) {
     return false;
   }
 
   auto audioInfo = mMetadata->GetTrackInfo(mozilla::TrackInfo::kAudioTrack, 0);
   if (audioInfo) {
     mAudioConfig = mozilla::Move(audioInfo);
-    nsTArray<Index::Indice> indices;
+    FallibleTArray<Index::Indice> indices;
     if (!mMetadata->ReadTrackIndex(indices, mAudioConfig->mTrackId)) {
       return false;
     }
     nsRefPtr<Index> index =
       new Index(indices,
                 mSource,
                 mAudioConfig->mTrackId,
                 /* aIsAudio = */ true,
                 mMonitor);
     mIndexes.AppendElement(index);
     mAudioIterator = mozilla::MakeUnique<SampleIterator>(index);
   }
 
   auto videoInfo = mMetadata->GetTrackInfo(mozilla::TrackInfo::kVideoTrack, 0);
   if (videoInfo) {
     mVideoConfig = mozilla::Move(videoInfo);
-    nsTArray<Index::Indice> indices;
+    FallibleTArray<Index::Indice> indices;
     if (!mMetadata->ReadTrackIndex(indices, mVideoConfig->mTrackId)) {
       return false;
     }
 
     nsRefPtr<Index> index =
       new Index(indices,
                 mSource,
                 mVideoConfig->mTrackId,