Bug 1114383 - Assert that access to mMoofs goes through a monitor. r=k17e
authorBobby Holley <bobbyholley@gmail.com>
Sun, 21 Dec 2014 22:04:36 -0800
changeset 220812 1c7ac8ef924d3e33a855ee1d2151c0b10b744e70
parent 220811 810bbcb9bf7e63d46782d10d0b74ec2b10b57ca2
child 220813 73a8a6927bdecc164059b5e7b428a7e16defabfc
push id53198
push userbobbyholley@gmail.com
push dateMon, 22 Dec 2014 06:04:49 +0000
treeherdermozilla-inbound@73a8a6927bde [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersk17e
bugs1114383
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1114383 - Assert that access to mMoofs goes through a monitor. r=k17e
dom/media/fmp4/MP4Reader.cpp
dom/media/gtest/TestMP4Demuxer.cpp
dom/media/mediasource/ContainerParser.cpp
media/libstagefright/binding/Index.cpp
media/libstagefright/binding/include/mp4_demuxer/Index.h
media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h
media/libstagefright/binding/mp4_demuxer.cpp
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -152,17 +152,17 @@ MP4Reader::InitLayersBackendType()
 
 static bool sIsEMEEnabled = false;
 
 nsresult
 MP4Reader::Init(MediaDecoderReader* aCloneDonor)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
   PlatformDecoderModule::Init();
-  mDemuxer = new MP4Demuxer(new MP4Stream(mDecoder->GetResource()));
+  mDemuxer = new MP4Demuxer(new MP4Stream(mDecoder->GetResource()), &mIndexMonitor);
 
   InitLayersBackendType();
 
   mAudio.mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
   NS_ENSURE_TRUE(mAudio.mTaskQueue, NS_ERROR_FAILURE);
 
   mVideo.mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
   NS_ENSURE_TRUE(mVideo.mTaskQueue, NS_ERROR_FAILURE);
--- a/dom/media/gtest/TestMP4Demuxer.cpp
+++ b/dom/media/gtest/TestMP4Demuxer.cpp
@@ -13,34 +13,37 @@ using namespace mozilla;
 using namespace mp4_demuxer;
 
 class MP4DemuxerBinding
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MP4DemuxerBinding);
 
   nsRefPtr<MockMediaResource> resource;
+  Monitor mMonitor;
   nsAutoPtr<MP4Demuxer> demuxer;
 
   explicit MP4DemuxerBinding(const char* aFileName = "dash_dashinit.mp4")
     : resource(new MockMediaResource(aFileName))
-    , demuxer(new MP4Demuxer(new MP4Stream(resource)))
+    , mMonitor("TestMP4Demuxer monitor")
+    , demuxer(new MP4Demuxer(new MP4Stream(resource), &mMonitor))
   {
     EXPECT_EQ(NS_OK, resource->Open(nullptr));
   }
 
 private:
   virtual ~MP4DemuxerBinding()
   {
   }
 };
 
 TEST(MP4Demuxer, Seek)
 {
   nsRefPtr<MP4DemuxerBinding> b = new MP4DemuxerBinding();
+  MonitorAutoLock mon(b->mMonitor);
   MP4Demuxer* d = b->demuxer;
 
   EXPECT_TRUE(d->Init());
 
   nsTArray<nsAutoPtr<MP4Sample>> samples;
   MP4Sample* sample;
   while (!!(sample = d->DemuxVideoSample())) {
     samples.AppendElement(sample);
@@ -82,16 +85,17 @@ ToCryptoString(CryptoSample& aCrypto)
     res.Append("no crypto");
   }
   return res;
 }
 
 TEST(MP4Demuxer, CENC)
 {
   nsRefPtr<MP4DemuxerBinding> b = new MP4DemuxerBinding("short-cenc.mp4");
+  MonitorAutoLock mon(b->mMonitor);
   MP4Demuxer* d = b->demuxer;
 
   EXPECT_TRUE(d->Init());
 
   const char* video[] = {
     "1 16 7e571d017e571d017e571d017e571d01 00000000000000000000000000000000 5,686 5,388",
     "1 16 7e571d017e571d017e571d017e571d01 00000000000000000000000000000044 5,717",
     "1 16 7e571d017e571d017e571d017e571d01 00000000000000000000000000000071 5,613",
@@ -142,16 +146,17 @@ TEST(MP4Demuxer, CENC)
     EXPECT_STREQ(audio[i++], text.get());
   }
   EXPECT_EQ(ArrayLength(audio), i);
 }
 
 TEST(MP4Demuxer, CENCFrag)
 {
   nsRefPtr<MP4DemuxerBinding> b = new MP4DemuxerBinding("gizmo-frag.mp4");
+  MonitorAutoLock mon(b->mMonitor);
   MP4Demuxer* d = b->demuxer;
 
   EXPECT_TRUE(d->Init());
 
   const char* video[] = {
     "1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000000 5,684 5,16980",
     "1 16 7e571d037e571d037e571d037e571d03 00000000000000000000000000000450 5,1826",
     "1 16 7e571d037e571d037e571d037e571d03 000000000000000000000000000004c3 5,1215",
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -198,17 +198,17 @@ public:
 private:
   WebMBufferedParser mParser;
   nsTArray<WebMTimeDataOffset> mOverlappedMapping;
   int64_t mOffset;
 };
 
 class MP4ContainerParser : public ContainerParser {
 public:
-  MP4ContainerParser() {}
+  MP4ContainerParser() :mMonitor("MP4ContainerParser Index Monitor") {}
 
   bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
   {
     ContainerParser::IsInitSegmentPresent(aData, aLength);
     // Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4
     // file is the 'ftyp' atom followed by a file type. We just check for a
     // vaguely valid 'ftyp' atom.
 
@@ -239,20 +239,22 @@ public:
 
     return aData[4] == 'm' && aData[5] == 'o' && aData[6] == 'o' &&
            aData[7] == 'f';
   }
 
   bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
                                   int64_t& aStart, int64_t& aEnd)
   {
+    MonitorAutoLock mon(mMonitor); // We're not actually racing against anything,
+                                   // but mParser requires us to hold a monitor.
     bool initSegment = IsInitSegmentPresent(aData, aLength);
     if (initSegment) {
       mStream = new mp4_demuxer::BufferStream();
-      mParser = new mp4_demuxer::MoofParser(mStream, 0);
+      mParser = new mp4_demuxer::MoofParser(mStream, 0, &mMonitor);
     } else if (!mStream || !mParser) {
       return false;
     }
 
     mStream->AppendBytes(aData, aLength);
     nsTArray<MediaByteRange> byteRanges;
     byteRanges.AppendElement(mStream->GetByteRange());
     mParser->RebuildFragmentedIndex(byteRanges);
@@ -286,16 +288,17 @@ public:
   int64_t GetRoundingError()
   {
     return 1000;
   }
 
 private:
   nsRefPtr<mp4_demuxer::BufferStream> mStream;
   nsAutoPtr<mp4_demuxer::MoofParser> mParser;
+  Monitor mMonitor;
 };
 
 /*static*/ ContainerParser*
 ContainerParser::CreateForMIMEType(const nsACString& aType)
 {
   if (aType.LowerCaseEqualsLiteral("video/webm") || aType.LowerCaseEqualsLiteral("audio/webm")) {
     return new WebMContainerParser();
   }
--- a/media/libstagefright/binding/Index.cpp
+++ b/media/libstagefright/binding/Index.cpp
@@ -135,17 +135,17 @@ MP4Sample* SampleIterator::GetNext()
 }
 
 Sample* SampleIterator::Get()
 {
   if (!mIndex->mMoofParser) {
     return nullptr;
   }
 
-  nsTArray<Moof>& moofs = mIndex->mMoofParser->mMoofs;
+  nsTArray<Moof>& moofs = mIndex->mMoofParser->Moofs();
   while (true) {
     if (mCurrentMoof == moofs.Length()) {
       if (!mIndex->mMoofParser->BlockingReadNextMoof()) {
         return nullptr;
       }
       MOZ_ASSERT(mCurrentMoof < moofs.Length());
     }
     if (mCurrentSample < moofs[mCurrentMoof].mIndex.Length()) {
@@ -182,21 +182,22 @@ void SampleIterator::Seek(Microseconds a
     }
     Next();
   }
   mCurrentMoof = syncMoof;
   mCurrentSample = syncSample;
 }
 
 Index::Index(const stagefright::Vector<MediaSource::Indice>& aIndex,
-             Stream* aSource, uint32_t aTrackId)
+             Stream* aSource, uint32_t aTrackId, Monitor* aMonitor)
   : mSource(aSource)
+  , mMonitor(aMonitor)
 {
   if (aIndex.isEmpty()) {
-    mMoofParser = new MoofParser(aSource, aTrackId);
+    mMoofParser = new MoofParser(aSource, aTrackId, aMonitor);
   } else {
     for (size_t i = 0; i < aIndex.size(); i++) {
       const MediaSource::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);
@@ -218,20 +219,20 @@ Index::UpdateMoofIndex(const nsTArray<Me
   mMoofParser->RebuildFragmentedIndex(aByteRanges);
 }
 
 Microseconds
 Index::GetEndCompositionIfBuffered(const nsTArray<MediaByteRange>& aByteRanges)
 {
   nsTArray<Sample>* index;
   if (mMoofParser) {
-    if (!mMoofParser->ReachedEnd() || mMoofParser->mMoofs.IsEmpty()) {
+    if (!mMoofParser->ReachedEnd() || mMoofParser->Moofs().IsEmpty()) {
       return 0;
     }
-    index = &mMoofParser->mMoofs.LastElement().mIndex;
+    index = &mMoofParser->Moofs().LastElement().mIndex;
   } else {
     index = &mIndex;
   }
 
   Microseconds lastComposition = 0;
   RangeFinder rangeFinder(aByteRanges);
   for (size_t i = index->Length(); i--;) {
     const Sample& sample = (*index)[i];
@@ -254,18 +255,18 @@ Index::ConvertByteRangesToTimeRanges(
   RangeFinder rangeFinder(aByteRanges);
   nsTArray<Interval<Microseconds>> timeRanges;
 
   nsTArray<nsTArray<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->mMoofs.Length(); i++) {
-      Moof& moof = mMoofParser->mMoofs[i];
+    for (int i = 0; i < mMoofParser->Moofs().Length(); i++) {
+      Moof& moof = mMoofParser->Moofs()[i];
 
       // We need the entire moof in order to play anything
       if (rangeFinder.Contains(moof.mRange)) {
         if (rangeFinder.Contains(moof.mMdatRange)) {
           Interval<Microseconds>::SemiNormalAppend(timeRanges, moof.mTimeRange);
         } else {
           indexes.AppendElement(&moof.mIndex);
         }
@@ -303,18 +304,18 @@ Index::ConvertByteRangesToTimeRanges(
 
 uint64_t
 Index::GetEvictionOffset(Microseconds aTime)
 {
   uint64_t offset = std::numeric_limits<uint64_t>::max();
   if (mMoofParser) {
     // We need to keep the whole moof if we're keeping any of it because the
     // parser doesn't keep parsed moofs.
-    for (int i = 0; i < mMoofParser->mMoofs.Length(); i++) {
-      Moof& moof = mMoofParser->mMoofs[i];
+    for (int i = 0; i < mMoofParser->Moofs().Length(); i++) {
+      Moof& moof = mMoofParser->Moofs()[i];
 
       if (moof.mTimeRange.Length() && moof.mTimeRange.end > aTime) {
         offset = std::min(offset, uint64_t(std::min(moof.mRange.mStart,
                                                     moof.mMdatRange.mStart)));
       }
     }
   } else {
     // We've already parsed and stored the moov so we don't need to keep it.
--- a/media/libstagefright/binding/include/mp4_demuxer/Index.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Index.h
@@ -32,17 +32,17 @@ private:
 };
 
 class Index
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Index)
 
   Index(const stagefright::Vector<stagefright::MediaSource::Indice>& aIndex,
-        Stream* aSource, uint32_t aTrackId);
+        Stream* aSource, uint32_t aTrackId, Monitor* aMonitor);
 
   void UpdateMoofIndex(const nsTArray<mozilla::MediaByteRange>& aByteRanges);
   Microseconds GetEndCompositionIfBuffered(
     const nsTArray<mozilla::MediaByteRange>& aByteRanges);
   void ConvertByteRangesToTimeRanges(
     const nsTArray<mozilla::MediaByteRange>& aByteRanges,
     nsTArray<Interval<Microseconds>>* aTimeRanges);
   uint64_t GetEvictionOffset(Microseconds aTime);
@@ -51,12 +51,13 @@ public:
   friend class SampleIterator;
 
 private:
   ~Index();
 
   Stream* mSource;
   nsTArray<Sample> mIndex;
   nsAutoPtr<MoofParser> mMoofParser;
+  Monitor* mMonitor;
 };
 }
 
 #endif
--- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
@@ -170,18 +170,18 @@ private:
   void ParseSaio(Box& aBox);
   bool ProcessCenc();
   uint64_t mMaxRoundingError;
 };
 
 class MoofParser
 {
 public:
-  MoofParser(Stream* aSource, uint32_t aTrackId)
-    : mSource(aSource), mOffset(0), mTrex(aTrackId)
+  MoofParser(Stream* aSource, uint32_t aTrackId, Monitor* aMonitor)
+    : mSource(aSource), mOffset(0), mTrex(aTrackId), mMonitor(aMonitor)
   {
     // Setting the mTrex.mTrackId to 0 is a nasty work around for calculating
     // the composition range for MSE. We need an array of tracks.
   }
   void RebuildFragmentedIndex(
     const nsTArray<mozilla::MediaByteRange>& aByteRanges);
   void RebuildFragmentedIndex(BoxContext& aContext);
   Interval<Microseconds> GetCompositionRange(
@@ -197,13 +197,16 @@ public:
   mozilla::MediaByteRange mInitRange;
   nsRefPtr<Stream> mSource;
   uint64_t mOffset;
   nsTArray<uint64_t> mMoofOffsets;
   Mdhd mMdhd;
   Trex mTrex;
   Tfdt mTfdt;
   Edts mEdts;
+  Monitor* mMonitor;
+  nsTArray<Moof>& Moofs() { mMonitor->AssertCurrentThreadOwns(); return mMoofs; }
+private:
   nsTArray<Moof> mMoofs;
 };
 }
 
 #endif
--- a/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h
@@ -5,22 +5,24 @@
 #ifndef MP4_DEMUXER_H_
 #define MP4_DEMUXER_H_
 
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 #include "mp4_demuxer/DecoderData.h"
 #include "mp4_demuxer/Interval.h"
 #include "nsISupportsImpl.h"
+#include "mozilla/Monitor.h"
 
 namespace mozilla { class MediaByteRange; }
 
 namespace mp4_demuxer
 {
 
+using mozilla::Monitor;
 struct StageFrightPrivate;
 typedef int64_t Microseconds;
 
 class Stream
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Stream);
 
@@ -36,17 +38,17 @@ protected:
   virtual ~Stream() {}
 };
 
 enum TrackType { kVideo = 1, kAudio };
 
 class MP4Demuxer
 {
 public:
-  explicit MP4Demuxer(Stream* aSource);
+  explicit MP4Demuxer(Stream* aSource, Monitor* aMonitor);
   ~MP4Demuxer();
 
   bool Init();
   Microseconds Duration();
   bool CanSeek();
 
   bool HasValidAudio();
   bool HasValidVideo();
@@ -75,13 +77,14 @@ private:
   AudioDecoderConfig mAudioConfig;
   VideoDecoderConfig mVideoConfig;
   CryptoFile mCrypto;
 
   nsAutoPtr<StageFrightPrivate> mPrivate;
   nsRefPtr<Stream> mSource;
   nsTArray<mozilla::MediaByteRange> mCachedByteRanges;
   nsTArray<Interval<Microseconds>> mCachedTimeRanges;
+  Monitor* mMonitor;
 };
 
 } // namespace mozilla
 
 #endif // MP4_DEMUXER_H_
--- a/media/libstagefright/binding/mp4_demuxer.cpp
+++ b/media/libstagefright/binding/mp4_demuxer.cpp
@@ -68,18 +68,18 @@ public:
   virtual uint32_t flags() { return kWantsPrefetching | kIsHTTPBasedSource; }
 
   virtual status_t reconnectAtOffset(off64_t offset) { return NO_ERROR; }
 
 private:
   nsRefPtr<Stream> mSource;
 };
 
-MP4Demuxer::MP4Demuxer(Stream* source)
-  : mPrivate(new StageFrightPrivate()), mSource(source)
+MP4Demuxer::MP4Demuxer(Stream* source, Monitor* aMonitor)
+  : mPrivate(new StageFrightPrivate()), mSource(source), mMonitor(aMonitor)
 {
   mPrivate->mExtractor = new MPEG4Extractor(new DataSourceAdapter(source));
 }
 
 MP4Demuxer::~MP4Demuxer()
 {
   if (mPrivate->mAudio.get()) {
     mPrivate->mAudio->stop();
@@ -104,30 +104,30 @@ MP4Demuxer::Init()
     if (!mPrivate->mAudio.get() && !strncmp(mimeType, "audio/", 6)) {
       sp<MediaSource> track = e->getTrack(i);
       if (track->start() != OK) {
         return false;
       }
       mPrivate->mAudio = track;
       mAudioConfig.Update(metaData, mimeType);
       nsRefPtr<Index> index = new Index(mPrivate->mAudio->exportIndex(),
-                                        mSource, mAudioConfig.mTrackId);
+                                        mSource, mAudioConfig.mTrackId, mMonitor);
       mPrivate->mIndexes.AppendElement(index);
       if (index->IsFragmented()) {
         mPrivate->mAudioIterator = new SampleIterator(index);
       }
     } else if (!mPrivate->mVideo.get() && !strncmp(mimeType, "video/", 6)) {
       sp<MediaSource> track = e->getTrack(i);
       if (track->start() != OK) {
         return false;
       }
       mPrivate->mVideo = track;
       mVideoConfig.Update(metaData, mimeType);
       nsRefPtr<Index> index = new Index(mPrivate->mVideo->exportIndex(),
-                                        mSource, mVideoConfig.mTrackId);
+                                        mSource, mVideoConfig.mTrackId, mMonitor);
       mPrivate->mIndexes.AppendElement(index);
       if (index->IsFragmented()) {
         mPrivate->mVideoIterator = new SampleIterator(index);
       }
     }
   }
   sp<MetaData> metaData = e->getMetaData();
   mCrypto.Update(metaData);