Bug 822952 - Dispatch events from UpdateReadyState only when the state has changed. r=roc
authorMatthew Gregan <kinetik@flim.org>
Wed, 19 Dec 2012 17:48:32 +1300
changeset 116578 5f697a87ec466d96daffc0b515147e5adf91ccfa
parent 116577 52b5ac5877670aab08ef027055e8c4ff115b6e5b
child 116579 9c5effe633f0de18246b787fb43aedddfc302714
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs822952
milestone20.0a1
Bug 822952 - Dispatch events from UpdateReadyState only when the state has changed. r=roc
content/media/MediaDecoderOwner.h
content/media/MediaDecoderStateMachine.cpp
content/media/MediaDecoderStateMachine.h
--- a/content/media/MediaDecoderOwner.h
+++ b/content/media/MediaDecoderOwner.h
@@ -121,17 +121,19 @@ public:
   // The status of the next frame which might be available from the decoder
   enum NextFrameStatus {
     // The next frame of audio/video is available
     NEXT_FRAME_AVAILABLE,
     // The next frame of audio/video is unavailable because the decoder
     // is paused while it buffers up data
     NEXT_FRAME_UNAVAILABLE_BUFFERING,
     // The next frame of audio/video is unavailable for some other reasons
-    NEXT_FRAME_UNAVAILABLE
+    NEXT_FRAME_UNAVAILABLE,
+    // Sentinel value
+    NEXT_FRAME_UNINITIALIZED
   };
 
   // Called by the decoder when some data has been downloaded or
   // buffering/seeking has ended. aNextFrameAvailable is true when
   // the data for the next frame is available. This method will
   // decide whether to set the ready state to HAVE_CURRENT_DATA,
   // HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA.
   virtual void UpdateReadyStateForData(NextFrameStatus aNextFrame) = 0;
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -381,17 +381,18 @@ MediaDecoderStateMachine::MediaDecoderSt
   mIsRunning(false),
   mRunAgain(false),
   mDispatchedRunEvent(false),
   mDecodeThreadWaiting(false),
   mRealTime(aRealTime),
   mDidThrottleAudioDecoding(false),
   mDidThrottleVideoDecoding(false),
   mRequestedNewDecodeThread(false),
-  mEventManager(aDecoder)
+  mEventManager(aDecoder),
+  mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED)
 {
   MOZ_COUNT_CTOR(MediaDecoderStateMachine);
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
 
   StateMachineTracker::Instance().EnsureGlobalStateMachine();
 
   // only enable realtime mode when "media.realtime_decoder.enabled" is true.
   if (Preferences::GetBool("media.realtime_decoder.enabled", false) == false)
@@ -550,21 +551,21 @@ void MediaDecoderStateMachine::SendStrea
   nsRefPtr<SharedBuffer> buffer = aAudio->mAudioBuffer;
   aOutput->AppendFrames(buffer.forget(), aAudio->mFrames, int32_t(offset), aAudio->mFrames,
                         AUDIO_OUTPUT_FORMAT);
   LOG(PR_LOG_DEBUG, ("%p Decoder writing %d frames of data to MediaStream for AudioData at %lld",
                      mDecoder.get(), aAudio->mFrames - int32_t(offset), aAudio->mTime));
   aStream->mAudioFramesWritten += aAudio->mFrames - int32_t(offset);
 }
 
-static void WriteVideoToMediaStream(mozilla::layers::Image* aImage,
+static void WriteVideoToMediaStream(layers::Image* aImage,
                                     int64_t aDuration, const gfxIntSize& aIntrinsicSize,
                                     VideoSegment* aOutput)
 {
-  nsRefPtr<mozilla::layers::Image> image = aImage;
+  nsRefPtr<layers::Image> image = aImage;
   aOutput->AppendFrame(image.forget(), aDuration, aIntrinsicSize);
 }
 
 static const TrackID TRACK_AUDIO = 1;
 static const TrackID TRACK_VIDEO = 2;
 static const TrackRate RATE_VIDEO = USECS_PER_S;
 
 void MediaDecoderStateMachine::SendStreamData()
@@ -2464,18 +2465,24 @@ VideoData* MediaDecoderStateMachine::Fin
   mAudioStartTime = mStartTime;
   LOG(PR_LOG_DEBUG, ("%p Media start time is %lld", mDecoder.get(), mStartTime));
   return v;
 }
 
 void MediaDecoderStateMachine::UpdateReadyState() {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
 
+  MediaDecoderOwner::NextFrameStatus nextFrameStatus = GetNextFrameStatus();
+  if (nextFrameStatus == mLastFrameStatus) {
+    return;
+  }
+  mLastFrameStatus = nextFrameStatus;
+
   nsCOMPtr<nsIRunnable> event;
-  switch (GetNextFrameStatus()) {
+  switch (nextFrameStatus) {
     case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING:
       event = NS_NewRunnableMethod(mDecoder, &MediaDecoder::NextFrameUnavailableBuffering);
       break;
     case MediaDecoderOwner::NEXT_FRAME_AVAILABLE:
       event = NS_NewRunnableMethod(mDecoder, &MediaDecoder::NextFrameAvailable);
       break;
     case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE:
       event = NS_NewRunnableMethod(mDecoder, &MediaDecoder::NextFrameUnavailable);
@@ -2609,20 +2616,16 @@ void MediaDecoderStateMachine::TimeoutEx
     // can just run it from here.
     CallRunStateMachine();
   }
   // Otherwise, an event has already been dispatched to run the state machine
   // as soon as possible. Nothing else needed to do, the state machine is
   // going to run anyway.
 }
 
-nsresult MediaDecoderStateMachine::ScheduleStateMachine() {
-  return ScheduleStateMachine(0);
-}
-
 void MediaDecoderStateMachine::ScheduleStateMachineWithLockAndWakeDecoder() {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   mon.NotifyAll();
   ScheduleStateMachine(0);
 }
 
 nsresult MediaDecoderStateMachine::ScheduleStateMachine(int64_t aUsecs) {
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
--- a/content/media/MediaDecoderStateMachine.h
+++ b/content/media/MediaDecoderStateMachine.h
@@ -275,30 +275,24 @@ public:
 
   // Sets the current frame buffer length for the MozAudioAvailable event.
   // Accessed on the main and state machine threads.
   void SetFrameBufferLength(uint32_t aLength);
 
   // Returns the shared state machine thread.
   static nsIThread* GetStateMachineThread();
 
-  // Schedules the shared state machine thread to run the state machine.
-  // If the state machine thread is the currently running the state machine,
-  // we wait until that has completely finished before running the state
-  // machine again.
-  nsresult ScheduleStateMachine();
-
   // Calls ScheduleStateMachine() after taking the decoder lock. Also
   // notifies the decoder thread in case it's waiting on the decoder lock.
   void ScheduleStateMachineWithLockAndWakeDecoder();
 
   // Schedules the shared state machine thread to run the state machine
   // in aUsecs microseconds from now, if it's not already scheduled to run
   // earlier, in which case the request is discarded.
-  nsresult ScheduleStateMachine(int64_t aUsecs);
+  nsresult ScheduleStateMachine(int64_t aUsecs = 0);
 
   // Creates and starts a new decode thread. Don't call this directly,
   // request a new decode thread by calling
   // StateMachineTracker::RequestCreateDecodeThread().
   // The decoder monitor must not be held. Called on the state machine thread.
   nsresult StartDecodeThread();
 
   // Timer function to implement ScheduleStateMachine(aUsecs).
@@ -792,12 +786,14 @@ private:
   // and takes care of synchronizing access to its internal queue.
   AudioAvailableEventManager mEventManager;
 
   // Stores presentation info required for playback. The decoder monitor
   // must be held when accessing this.
   VideoInfo mInfo;
 
   mozilla::MediaMetadataManager mMetadataManager;
+
+  MediaDecoderOwner::NextFrameStatus mLastFrameStatus;
 };
 
 } // namespace mozilla;
 #endif