Bug 1230004. Part 1 - cache data in MDSM so it won't need to ask MediaDecoder. r=cpearce.
authorJW Wang <jwwang@mozilla.com>
Thu, 03 Dec 2015 15:59:30 +0800
changeset 309731 5836cdd7d259f76089885f1f56c4edb84ba01186
parent 309730 835de4b7bcb2b9016ef425db25878929c28a9448
child 309732 c0be6f556504a7c03ccce3226587c393d1b8cde2
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1230004
milestone45.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 1230004. Part 1 - cache data in MDSM so it won't need to ask MediaDecoder. r=cpearce.
dom/media/FrameStatistics.h
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaDecoderStateMachine.h
--- a/dom/media/FrameStatistics.h
+++ b/dom/media/FrameStatistics.h
@@ -8,16 +8,18 @@
 #define FrameStatistics_h_
 
 namespace mozilla {
 
 // Frame decoding/painting related performance counters.
 // Threadsafe.
 class FrameStatistics {
 public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FrameStatistics);
+
   FrameStatistics() :
       mReentrantMonitor("FrameStats"),
       mParsedFrames(0),
       mDecodedFrames(0),
       mPresentedFrames(0),
       mDroppedFrames(0),
       mCorruptFrames(0) {}
 
@@ -75,16 +77,17 @@ public:
   }
 
   void NotifyCorruptFrame() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     ++mCorruptFrames;
   }
 
 private:
+  ~FrameStatistics() {}
 
   // ReentrantMonitor to protect access of playback statistics.
   ReentrantMonitor mReentrantMonitor;
 
   // Number of frames parsed and demuxed from media.
   // Access protected by mReentrantMonitor.
   uint32_t mParsedFrames;
 
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -497,16 +497,17 @@ MediaDecoder::MediaDecoder(MediaDecoderO
   , mDuration(std::numeric_limits<double>::quiet_NaN())
   , mResourceCallback(new ResourceCallback())
 #ifdef MOZ_EME
   , mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__))
 #endif
   , mIgnoreProgressData(false)
   , mInfiniteStream(false)
   , mOwner(aOwner)
+  , mFrameStats(new FrameStatistics())
   , mVideoFrameContainer(aOwner->GetVideoFrameContainer())
   , mPlaybackStatistics(new MediaChannelStatistics())
   , mPinnedForSeek(false)
   , mShuttingDown(false)
   , mPausedForPlaybackRateNull(false)
   , mMinimizePreroll(false)
   , mMediaTracksConstructed(false)
   , mFiredMetadataLoaded(false)
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -695,17 +695,17 @@ private:
 
   // Return statistics. This is used for progress events and other things.
   // This can be called from any thread. It's only a snapshot of the
   // current state, since other threads might be changing the state
   // at any time.
   MediaStatistics GetStatistics();
 
   // Return the frame decode/paint related statistics.
-  FrameStatistics& GetFrameStatistics() { return mFrameStats; }
+  FrameStatistics& GetFrameStatistics() { return *mFrameStats; }
 
   // Increments the parsed and decoded frame counters by the passed in counts.
   // Can be called on any thread.
   virtual void NotifyDecodedFrames(uint32_t aParsed, uint32_t aDecoded,
                                    uint32_t aDropped) override
   {
     GetFrameStatistics().NotifyDecodedFrames(aParsed, aDecoded, aDropped);
   }
@@ -861,17 +861,17 @@ protected:
   void OnMetadataUpdate(TimedMetadata&& aMetadata);
 
   // This should only ever be accessed from the main thread.
   // It is set in Init and cleared in Shutdown when the element goes away.
   // The decoder does not add a reference the element.
   MediaDecoderOwner* const mOwner;
 
   // Counters related to decode and presentation of frames.
-  FrameStatistics mFrameStats;
+  const RefPtr<FrameStatistics> mFrameStats;
 
   const RefPtr<VideoFrameContainer> mVideoFrameContainer;
 
   // Data needed to estimate playback data rate. The timeline used for
   // this estimate is "decode time" (where the "current time" is the
   // time of the last decoded video frame).
   RefPtr<MediaChannelStatistics> mPlaybackStatistics;
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -57,29 +57,29 @@ using namespace mozilla::media;
 #define NS_DispatchToMainThread(...) CompileError_UseAbstractThreadDispatchInstead
 
 // avoid redefined macro in unified build
 #undef LOG
 #undef DECODER_LOG
 #undef VERBOSE_LOG
 
 #define LOG(m, l, x, ...) \
-  MOZ_LOG(m, l, ("Decoder=%p " x, mDecoder.get(), ##__VA_ARGS__))
+  MOZ_LOG(m, l, ("Decoder=%p " x, mDecoderID, ##__VA_ARGS__))
 #define DECODER_LOG(x, ...) \
   LOG(gMediaDecoderLog, LogLevel::Debug, x, ##__VA_ARGS__)
 #define VERBOSE_LOG(x, ...) \
   LOG(gMediaDecoderLog, LogLevel::Verbose, x, ##__VA_ARGS__)
 #define SAMPLE_LOG(x, ...) \
   LOG(gMediaSampleLog, LogLevel::Debug, x, ##__VA_ARGS__)
 
 // Somehow MSVC doesn't correctly delete the comma before ##__VA_ARGS__
 // when __VA_ARGS__ expands to nothing. This is a workaround for it.
 #define DECODER_WARN_HELPER(a, b) NS_WARNING b
 #define DECODER_WARN(x, ...) \
-  DECODER_WARN_HELPER(0, (nsPrintfCString("Decoder=%p " x, mDecoder.get(), ##__VA_ARGS__).get()))
+  DECODER_WARN_HELPER(0, (nsPrintfCString("Decoder=%p " x, mDecoderID, ##__VA_ARGS__).get()))
 
 // Certain constants get stored as member variables and then adjusted by various
 // scale factors on a per-decoder basis. We want to make sure to avoid using these
 // constants directly, so we put them in a namespace.
 namespace detail {
 
 // If audio queue has less than this many usecs of decoded audio, we won't risk
 // trying to decode the video, we'll skip decoding video up to the next
@@ -195,16 +195,20 @@ static void InitVideoQueuePrefs() {
       "media.video-queue.send-to-compositor-size", VIDEO_QUEUE_SEND_TO_COMPOSITOR_SIZE);
   }
 }
 
 MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
                                                    MediaDecoderReader* aReader,
                                                    bool aRealTime) :
   mDecoder(aDecoder),
+  mDecoderID(aDecoder),
+  mFrameStats(&aDecoder->GetFrameStatistics()),
+  mVideoFrameContainer(aDecoder->GetVideoFrameContainer()),
+  mAudioChannel(aDecoder->GetAudioChannel()),
   mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
                            /* aSupportsTailDispatch = */ true)),
   mWatchManager(this, mTaskQueue),
   mRealTime(aRealTime),
   mDispatchedStateMachine(false),
   mDelayedScheduler(mTaskQueue),
   mState(DECODER_STATE_DECODING_NONE, "MediaDecoderStateMachine::mState"),
   mCurrentFrameID(0),
@@ -275,17 +279,18 @@ MediaDecoderStateMachine::MediaDecoderSt
                    "MediaDecoderStateMachine::mCurrentPosition (Canonical)"),
   mPlaybackOffset(mTaskQueue, 0,
                   "MediaDecoderStateMachine::mPlaybackOffset (Canonical)")
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
   // Dispatch initialization that needs to happen on that task queue.
-  nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::InitializationTask);
+  nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethodWithArg<RefPtr<MediaDecoder>>(
+    this, &MediaDecoderStateMachine::InitializationTask, aDecoder);
   mTaskQueue->Dispatch(r.forget());
 
   InitVideoQueuePrefs();
 
   mBufferingWait = IsRealTime() ? 0 : 15;
   mLowDataThresholdUsecs = IsRealTime() ? 0 : detail::LOW_DATA_THRESHOLD_USECS;
 
 #ifdef XP_WIN
@@ -302,17 +307,17 @@ MediaDecoderStateMachine::MediaDecoderSt
   mVideoQueueListener = VideoQueue().PopEvent().Connect(
     mTaskQueue, this, &MediaDecoderStateMachine::OnVideoPopped);
 
   mMetadataManager.Connect(mReader->TimedMetadataEvent(), OwnerThread());
 
   mMediaSink = CreateMediaSink(mAudioCaptured);
 
 #ifdef MOZ_EME
-  mCDMProxyPromise.Begin(mDecoder->RequestCDMProxy()->Then(
+  mCDMProxyPromise.Begin(aDecoder->RequestCDMProxy()->Then(
     OwnerThread(), __func__, this,
     &MediaDecoderStateMachine::OnCDMProxyReady,
     &MediaDecoderStateMachine::OnCDMProxyNotReady));
 #endif
 }
 
 MediaDecoderStateMachine::~MediaDecoderStateMachine()
 {
@@ -322,35 +327,35 @@ MediaDecoderStateMachine::~MediaDecoderS
   mReader = nullptr;
 
 #ifdef XP_WIN
   timeEndPeriod(1);
 #endif
 }
 
 void
-MediaDecoderStateMachine::InitializationTask()
+MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // Connect mirrors.
   mBuffered.Connect(mReader->CanonicalBuffered());
-  mEstimatedDuration.Connect(mDecoder->CanonicalEstimatedDuration());
-  mExplicitDuration.Connect(mDecoder->CanonicalExplicitDuration());
-  mPlayState.Connect(mDecoder->CanonicalPlayState());
-  mNextPlayState.Connect(mDecoder->CanonicalNextPlayState());
-  mLogicallySeeking.Connect(mDecoder->CanonicalLogicallySeeking());
-  mVolume.Connect(mDecoder->CanonicalVolume());
-  mLogicalPlaybackRate.Connect(mDecoder->CanonicalPlaybackRate());
-  mPreservesPitch.Connect(mDecoder->CanonicalPreservesPitch());
-  mSameOriginMedia.Connect(mDecoder->CanonicalSameOriginMedia());
-  mPlaybackBytesPerSecond.Connect(mDecoder->CanonicalPlaybackBytesPerSecond());
-  mPlaybackRateReliable.Connect(mDecoder->CanonicalPlaybackRateReliable());
-  mDecoderPosition.Connect(mDecoder->CanonicalDecoderPosition());
-  mMediaSeekable.Connect(mDecoder->CanonicalMediaSeekable());
+  mEstimatedDuration.Connect(aDecoder->CanonicalEstimatedDuration());
+  mExplicitDuration.Connect(aDecoder->CanonicalExplicitDuration());
+  mPlayState.Connect(aDecoder->CanonicalPlayState());
+  mNextPlayState.Connect(aDecoder->CanonicalNextPlayState());
+  mLogicallySeeking.Connect(aDecoder->CanonicalLogicallySeeking());
+  mVolume.Connect(aDecoder->CanonicalVolume());
+  mLogicalPlaybackRate.Connect(aDecoder->CanonicalPlaybackRate());
+  mPreservesPitch.Connect(aDecoder->CanonicalPreservesPitch());
+  mSameOriginMedia.Connect(aDecoder->CanonicalSameOriginMedia());
+  mPlaybackBytesPerSecond.Connect(aDecoder->CanonicalPlaybackBytesPerSecond());
+  mPlaybackRateReliable.Connect(aDecoder->CanonicalPlaybackRateReliable());
+  mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition());
+  mMediaSeekable.Connect(aDecoder->CanonicalMediaSeekable());
 
   // Initialize watchers.
   mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated);
   mWatchManager.Watch(mState, &MediaDecoderStateMachine::UpdateNextFrameStatus);
   mWatchManager.Watch(mAudioCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
   mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
   mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged);
   mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
@@ -370,34 +375,34 @@ MediaDecoderStateMachine::Initialization
 media::MediaSink*
 MediaDecoderStateMachine::CreateAudioSink()
 {
   RefPtr<MediaDecoderStateMachine> self = this;
   auto audioSinkCreator = [self] () {
     MOZ_ASSERT(self->OnTaskQueue());
     return new DecodedAudioDataSink(
       self->mAudioQueue, self->GetMediaTime(),
-      self->mInfo.mAudio, self->mDecoder->GetAudioChannel());
+      self->mInfo.mAudio, self->mAudioChannel);
   };
   return new AudioSinkWrapper(mTaskQueue, audioSinkCreator);
 }
 
 already_AddRefed<media::MediaSink>
 MediaDecoderStateMachine::CreateMediaSink(bool aAudioCaptured)
 {
   // TODO: We can't really create a new DecodedStream until OutputStreamManager
   //       is extracted. It is tricky that the implementation of DecodedStream
   //       happens to allow reuse after shutdown without creating a new one.
   RefPtr<media::MediaSink> audioSink = aAudioCaptured ?
     mStreamSink : CreateAudioSink();
 
   RefPtr<media::MediaSink> mediaSink =
     new VideoSink(mTaskQueue, audioSink, mVideoQueue,
-                  mDecoder->GetVideoFrameContainer(), mRealTime,
-                  mDecoder->GetFrameStatistics(),
+                  mVideoFrameContainer, mRealTime,
+                  *mFrameStats,
                   sVideoQueueSendToCompositorSize);
   return mediaSink.forget();
 }
 
 bool MediaDecoderStateMachine::HasFutureAudio()
 {
   MOZ_ASSERT(OnTaskQueue());
   NS_ASSERTION(HasAudio(), "Should only call HasFutureAudio() when we have audio");
@@ -2464,17 +2469,17 @@ MediaDecoderStateMachine::Reset()
 
 void
 MediaDecoderStateMachine::CheckFrameValidity(VideoData* aData)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // Update corrupt-frames statistics
   if (aData->mImage && !aData->mImage->IsValid()) {
-    FrameStatistics& frameStats = mDecoder->GetFrameStatistics();
+    FrameStatistics& frameStats = *mFrameStats;
     frameStats.NotifyCorruptFrame();
     // If more than 10% of the last 30 frames have been corrupted, then try disabling
     // hardware acceleration. We use 10 as the corrupt value because RollingMean<>
     // only supports integer types.
     mCorruptFrames.insert(10);
     if (mReader->VideoIsHardwareAccelerated() &&
         frameStats.GetPresentedFrames() > 60 &&
         mCorruptFrames.mean() >= 2 /* 20% */) {
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -271,17 +271,17 @@ public:
 private:
   // Functions used by assertions to ensure we're calling things
   // on the appropriate threads.
   bool OnTaskQueue() const;
 
   // Initialization that needs to happen on the task queue. This is the first
   // task that gets run on the task queue, and is dispatched from the MDSM
   // constructor immediately after the task queue is created.
-  void InitializationTask();
+  void InitializationTask(MediaDecoder* aDecoder);
 
   void SetDormant(bool aDormant);
 
   void SetAudioCaptured(bool aCaptured);
 
   RefPtr<MediaDecoder::SeekPromise> Seek(SeekTarget aTarget);
 
   void Shutdown();
@@ -671,16 +671,20 @@ private:
   // alive once media element has started the decoder shutdown process, and has
   // dropped its reference to the decoder. This enables the state machine to
   // keep using the decoder's monitor until the state machine has finished
   // shutting down, without fear of the monitor being destroyed. After
   // shutting down, the state machine will then release this reference,
   // causing the decoder to be destroyed. This is accessed on the decode,
   // state machine, audio and main threads.
   RefPtr<MediaDecoder> mDecoder;
+  void* const mDecoderID;
+  const RefPtr<FrameStatistics> mFrameStats;
+  const RefPtr<VideoFrameContainer> mVideoFrameContainer;
+  const dom::AudioChannel mAudioChannel;
 
   // Task queue for running the state machine.
   RefPtr<TaskQueue> mTaskQueue;
 
   // State-watching manager.
   WatchManager<MediaDecoderStateMachine> mWatchManager;
 
   // True is we are decoding a realtime stream, like a camera stream.