Bug 1272919: Blank video frames when suspending decoding. r?jwwang draft
authorDan Glastonbury <dglastonbury@mozilla.com>
Mon, 23 May 2016 14:18:48 +1000
changeset 370103 dd6f7866cb4aa451e110bc3a5a201d0d704aa329
parent 367997 f3f2fa1d7eed5a8262f6401ef18ff8117a3ce43e
child 370570 d59d44f895b9c538b98fda44fe906f44c7232081
push id18986
push userbmo:dglastonbury@mozilla.com
push dateTue, 24 May 2016 06:03:46 +0000
reviewersjwwang
bugs1272919
milestone49.0a1
Bug 1272919: Blank video frames when suspending decoding. r?jwwang Blank out the video frame when suspending video decoding, so a black frame is seen when resuming and not the frame previous to being suspended. MozReview-Commit-ID: GBkoaql8FmV
dom/media/MediaDecoderStateMachine.cpp
dom/media/MediaQueue.h
dom/media/mediasink/MediaSink.h
dom/media/mediasink/VideoSink.cpp
dom/media/mediasink/VideoSink.h
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1338,22 +1338,31 @@ void MediaDecoderStateMachine::Visibilit
   if (!sSuspendBackgroundVideos) {
     return;
   }
 
   if (!HasVideo()) {
     return;
   }
 
-  // If not transitioning to visible and not playing then there's
-  // nothing to do.
-  if (!mIsVisible || mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
+  // If not playing then there's nothing to do.
+  if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
     return;
   }
 
+  // If suspending, flush the video container of frames. When restarting from
+  // suspended decoding, a blank frame will be displayed until recovery seek
+  // completes.
+  if (!mIsVisible) {
+    mMediaSink->DrainVideo();
+    return;
+  }
+
+  // Resuming from suspended decoding
+
   // If an existing seek is in flight don't bother creating a new one to catch
   // up.
   if (mSeekTask || mQueuedSeek.Exists()) {
     return;
   }
 
   // Start video-only seek to the current time...
   InitiateVideoDecodeRecoverySeek();
--- a/dom/media/MediaQueue.h
+++ b/dom/media/MediaQueue.h
@@ -70,21 +70,27 @@ public:
     return static_cast<T*>(nsDeque::Peek());
   }
 
   inline RefPtr<T> PeekFront() const {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return static_cast<T*>(nsDeque::PeekFront());
   }
 
-  void Reset() {
+  // Remove all items from the queue with out firing "pop event" notifications.
+  void Drain() {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     while (GetSize() > 0) {
       RefPtr<T> x = dont_AddRef(static_cast<T*>(nsDeque::PopFront()));
     }
+  }
+
+  void Reset() {
+    ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+    Drain();
     mEndOfStream = false;
   }
 
   bool AtEndOfStream() const {
     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     return GetSize() == 0 && mEndOfStream;
   }
 
--- a/dom/media/mediasink/MediaSink.h
+++ b/dom/media/mediasink/MediaSink.h
@@ -114,16 +114,20 @@ public:
   // Can be called in any state.
   virtual bool IsPlaying() const = 0;
 
   // Called on the state machine thread to shut down the sink. All resources
   // allocated by this sink should be released.
   // Must be called after playback stopped.
   virtual void Shutdown() {}
 
+  // Called by the state machine thread to drain the sink of all video frames.
+  // Do nothing if this sink has no video track. Can be called in any state.
+  virtual void DrainVideo() {}
+
 protected:
   virtual ~MediaSink() {}
 };
 
 } // namespace media
 } // namespace mozilla
 
 #endif //MediaSink_h_
--- a/dom/media/mediasink/VideoSink.cpp
+++ b/dom/media/mediasink/VideoSink.cpp
@@ -232,16 +232,24 @@ VideoSink::Shutdown()
   AssertOwnerThread();
   MOZ_ASSERT(!mAudioSink->IsStarted(), "must be called after playback stops.");
   VSINK_LOG("[%s]", __func__);
 
   mAudioSink->Shutdown();
 }
 
 void
+VideoSink::DrainVideo()
+{
+  AssertOwnerThread();
+  mVideoQueue.Drain();
+  mContainer->ClearCurrentFrame();
+}
+
+void
 VideoSink::OnVideoQueuePushed(RefPtr<MediaData>&& aSample)
 {
   AssertOwnerThread();
   // Listen to push event, VideoSink should try rendering ASAP if first frame
   // arrives but update scheduler is not triggered yet.
   VideoData* v = aSample->As<VideoData>();
   if (!v->mSentToCompositor) {
     // Since we push rendered frames back to the queue, we will receive
--- a/dom/media/mediasink/VideoSink.h
+++ b/dom/media/mediasink/VideoSink.h
@@ -63,16 +63,18 @@ public:
   void Stop() override;
 
   bool IsStarted() const override;
 
   bool IsPlaying() const override;
 
   void Shutdown() override;
 
+  void DrainVideo() override;
+
 private:
   virtual ~VideoSink();
 
   // VideoQueue listener related.
   void OnVideoQueuePushed(RefPtr<MediaData>&& aSample);
   void OnVideoQueueFinished();
   void ConnectListener();
   void DisconnectListener();