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
--- 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();