Bug 1420608. P1 - don't switch off blank decoder when seeking begins.
When looping videos in a background tab, SeekingState::Enter() will switch off
blank decoder and then DecodingState::Enter() will switch it on again. It is a
waste of CPU cycles when the tab never goes to the foreground. The overhread is
even more significant when looping short files.
We should resume video decoding only when necessary that is we check in
DecodingState::Enter() to see if mVideoDecodeSuspended matches mVideoDecodeMode.
MozReview-Commit-ID: 54vq7mEjWQf
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -828,25 +828,16 @@ public:
explicit SeekingState(Master* aPtr) : StateObject(aPtr) { }
RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob&& aSeekJob,
EventVisibility aVisibility)
{
mSeekJob = Move(aSeekJob);
mVisibility = aVisibility;
- // Always switch off the blank decoder otherwise we might become visible
- // in the middle of seeking and won't have a valid video frame to show
- // when seek is done.
- if (mMaster->mVideoDecodeSuspended) {
- mMaster->mVideoDecodeSuspended = false;
- mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::ExitVideoSuspend);
- Reader()->SetVideoBlankDecode(false);
- }
-
// Suppressed visibility comes from two cases: (1) leaving dormant state,
// and (2) resuming suspended video decoder. We want both cases to be
// transparent to the user. So we only notify the change when the seek
// request is from the user.
if (mVisibility == EventVisibility::Observable) {
// Don't stop playback for a video-only seek since we want to keep playing
// audio and we don't need to stop playback while leaving dormant for the
// playback should has been stopped.
@@ -879,18 +870,17 @@ public:
void HandleVideoSuspendTimeout() override
{
// Do nothing since we want a valid video frame to show when seek is done.
}
void HandleResumeVideoDecoding(const TimeUnit&) override
{
- // We set mVideoDecodeSuspended to false in Enter().
- MOZ_ASSERT(false, "Shouldn't have suspended video decoding.");
+ // Do nothing. We will resume video decoding in the decoding state.
}
protected:
SeekJob mSeekJob;
EventVisibility mVisibility;
virtual void DoSeek() = 0;
// Transition to the next state (defined by the subclass) when seek is completed.
@@ -2111,16 +2101,20 @@ ReportRecoveryTelemetry(const TimeStamp&
}
void
MediaDecoderStateMachine::
StateObject::HandleResumeVideoDecoding(const TimeUnit& aTarget)
{
MOZ_ASSERT(mMaster->mVideoDecodeSuspended);
+ mMaster->mVideoDecodeSuspended = false;
+ mMaster->mOnPlaybackEvent.Notify(MediaPlaybackEvent::ExitVideoSuspend);
+ Reader()->SetVideoBlankDecode(false);
+
// Start counting recovery time from right now.
TimeStamp start = TimeStamp::Now();
// Local reference to mInfo, so that it will be copied in the lambda below.
auto& info = Info();
bool hw = Reader()->VideoIsHardwareAccelerated();
// Start video-only seek to the current time.
@@ -2273,16 +2267,22 @@ DecodingFirstFrameState::MaybeFinishDeco
}
void
MediaDecoderStateMachine::
DecodingState::Enter()
{
MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
+ if (mMaster->mVideoDecodeSuspended &&
+ mMaster->mVideoDecodeMode == VideoDecodeMode::Normal) {
+ StateObject::HandleResumeVideoDecoding(mMaster->GetMediaTime());
+ return;
+ }
+
if (mMaster->mVideoDecodeMode == VideoDecodeMode::Suspend &&
!mMaster->mVideoDecodeSuspendTimer.IsScheduled() &&
!mMaster->mVideoDecodeSuspended) {
// If the VideoDecodeMode is Suspend and the timer is not schedule, it means
// the timer has timed out and we should suspend video decoding now if
// necessary.
HandleVideoSuspendTimeout();
}