Bug 1166836: Part1. Cache main thread buffered time range. r=cpearce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 25 May 2015 15:09:16 +1000
changeset 245448 6d38104707a18e395d4cd12a2ead1107b839031c
parent 245447 a0dcad6b9a4a7ec4cf26f71234c2365bcf6ca6be
child 245449 91df4391d32177465f006d44b39635eefcd4ef5f
push id28806
push userphilringnalda@gmail.com
push dateTue, 26 May 2015 02:10:16 +0000
treeherdermozilla-central@4362d9251296 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1166836
milestone41.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 1166836: Part1. Cache main thread buffered time range. r=cpearce GetBuffered() can be particularly slow under some circumstances.
dom/media/MediaFormatReader.cpp
dom/media/MediaFormatReader.h
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -64,16 +64,17 @@ MediaFormatReader::MediaFormatReader(Abs
   , mDemuxer(aDemuxer)
   , mAudio(this, MediaData::AUDIO_DATA, Preferences::GetUint("media.audio-decode-ahead", 2))
   , mVideo(this, MediaData::VIDEO_DATA, Preferences::GetUint("media.video-decode-ahead", 2))
   , mLastReportedNumDecodedFrames(0)
   , mLayersBackendType(layers::LayersBackend::LAYERS_NONE)
   , mInitDone(false)
   , mSeekable(false)
   , mIsEncrypted(false)
+  , mCachedTimeRangesStale(true)
 #if defined(READER_DORMANT_HEURISTIC)
   , mDormantEnabled(Preferences::GetBool("media.decoder.heuristic.dormant.enabled", false))
 #endif
 {
   MOZ_ASSERT(aDemuxer);
   MOZ_COUNT_CTOR(MediaFormatReader);
 }
 
@@ -1246,24 +1247,53 @@ MediaFormatReader::GetEvictionOffset(dou
 }
 
 media::TimeIntervals
 MediaFormatReader::GetBuffered()
 {
   media::TimeIntervals videoti;
   media::TimeIntervals audioti;
 
+  if (!mInitDone) {
+    return media::TimeIntervals();
+  }
   if (NS_IsMainThread()) {
+    if (!mCachedTimeRangesStale) {
+      return mCachedTimeRanges;
+    }
+    MOZ_ASSERT(mMainThreadDemuxer);
+    if (!mDataRange.IsEmpty()) {
+      mMainThreadDemuxer->NotifyDataArrived(mDataRange.Length(), mDataRange.mStart);
+    }
     if (mVideoTrackDemuxer) {
       videoti = mVideoTrackDemuxer->GetBuffered();
     }
     if (mAudioTrackDemuxer) {
       audioti = mAudioTrackDemuxer->GetBuffered();
     }
+    if (HasAudio() && HasVideo()) {
+      mCachedTimeRanges = Intersection(Move(videoti), Move(audioti));
+    } else if (HasAudio()) {
+      mCachedTimeRanges = Move(audioti);
+    } else if (HasVideo()) {
+      mCachedTimeRanges = Move(videoti);
+    }
+    mDataRange = ByteInterval();
+    mCachedTimeRangesStale = false;
+    return mCachedTimeRanges;
   } else {
+    if (OnTaskQueue()) {
+      // Ensure we have up to date buffered time range.
+      if (HasVideo()) {
+        UpdateReceivedNewData(TrackType::kVideoTrack);
+      }
+      if (HasAudio()) {
+        UpdateReceivedNewData(TrackType::kAudioTrack);
+      }
+    }
     if (HasVideo()) {
       MonitorAutoLock lock(mVideo.mMonitor);
       videoti = mVideo.mTimeRanges;
     }
     if (HasAudio()) {
       MonitorAutoLock lock(mAudio.mMonitor);
       audioti = mAudio.mTimeRanges;
     }
@@ -1349,37 +1379,44 @@ MediaFormatReader::NotifyDemuxer(uint32_
   }
 }
 
 void
 MediaFormatReader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  MOZ_ASSERT(aBuffer || aLength);
+  if (mDataRange.IsEmpty()) {
+    mDataRange = ByteInterval(aOffset, aOffset + aLength);
+  } else {
+    mDataRange = mDataRange.Span(ByteInterval(aOffset, aOffset + aLength));
+  }
+  mCachedTimeRangesStale = true;
+
   if (!mInitDone) {
     return;
   }
 
-  MOZ_ASSERT(mMainThreadDemuxer);
-  MOZ_ASSERT(aBuffer || aLength);
-  mMainThreadDemuxer->NotifyDataArrived(aLength, aOffset);
-
   // Queue a task to notify our main demuxer.
   RefPtr<nsIRunnable> task =
     NS_NewRunnableMethodWithArgs<int32_t, uint64_t>(
       this, &MediaFormatReader::NotifyDemuxer,
       aLength, aOffset);
   GetTaskQueue()->Dispatch(task.forget());
 }
 
 void
 MediaFormatReader::NotifyDataRemoved()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  mDataRange = ByteInterval();
+  mCachedTimeRangesStale = true;
+
   if (!mInitDone) {
     return;
   }
 
   MOZ_ASSERT(mMainThreadDemuxer);
   mMainThreadDemuxer->NotifyDataRemoved();
 
   // Queue a task to notify our main demuxer.
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -21,16 +21,17 @@ namespace mozilla {
 #define READER_DORMANT_HEURISTIC
 #else
 #undef READER_DORMANT_HEURISTIC
 #endif
 
 class MediaFormatReader final : public MediaDecoderReader
 {
   typedef TrackInfo::TrackType TrackType;
+  typedef media::Interval<int64_t> ByteInterval;
 
 public:
   explicit MediaFormatReader(AbstractMediaDecoder* aDecoder,
                               MediaDataDemuxer* aDemuxer);
 
   virtual ~MediaFormatReader();
 
   virtual nsresult Init(MediaDecoderReader* aCloneDonor) override;
@@ -99,16 +100,19 @@ public:
 
   virtual bool IsWaitForDataSupported() override { return true; }
   virtual nsRefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) override;
 
   virtual bool IsWaitingOnCDMResource() override;
 
 private:
   bool InitDemuxer();
+  // Notify the demuxer that new data has been received.
+  // The next queued task calling GetBuffered() is guaranteed to have up to date
+  // buffered ranges.
   void NotifyDemuxer(uint32_t aLength, int64_t aOffset);
   void ReturnOutput(MediaData* aData, TrackType aTrack);
 
   bool EnsureDecodersSetup();
 
   // Enqueues a task to call Update(aTrack) on the decoder task queue.
   // Lock for corresponding track must be held.
   void ScheduleUpdate(TrackType aTrack);
@@ -300,17 +304,16 @@ private:
       mPromise.Reject(aReason, aMethodName);
     }
   };
 
   DecoderDataWithPromise<AudioDataPromise> mAudio;
   DecoderDataWithPromise<VideoDataPromise> mVideo;
 
   // Returns true when the decoder for this track needs input.
-  // aDecoder.mMonitor must be locked.
   bool NeedInput(DecoderData& aDecoder);
 
   DecoderData& GetDecoderData(TrackType aTrack);
 
   // Demuxer objects.
   void OnDemuxerInitDone(nsresult);
   void OnDemuxerInitFailed(DemuxerFailureReason aFailure);
   MediaPromiseConsumerHolder<MediaDataDemuxer::InitPromise> mDemuxerInitRequest;
@@ -385,19 +388,24 @@ private:
 
 #ifdef MOZ_EME
   nsRefPtr<CDMProxy> mCDMProxy;
 #endif
 
   nsRefPtr<SharedDecoderManager> mSharedDecoderManager;
 
   // Main thread objects
+  // Those are only used to calculate our buffered range on the main thread.
+  // The cached buffered range is calculated one when required.
   nsRefPtr<MediaDataDemuxer> mMainThreadDemuxer;
   nsRefPtr<MediaTrackDemuxer> mAudioTrackDemuxer;
   nsRefPtr<MediaTrackDemuxer> mVideoTrackDemuxer;
+  ByteInterval mDataRange;
+  media::TimeIntervals mCachedTimeRanges;
+  bool mCachedTimeRangesStale;
 
 #if defined(READER_DORMANT_HEURISTIC)
   const bool mDormantEnabled;
 #endif
 };
 
 } // namespace mozilla