Bug 1295921 - P1: Track decoder tainting. r?jwwang
Some uses of media elements should 'taint' the element so that the video
doesn't participate in video decode suspending.
Add the infrastructure to track the taint status on MediaDecoder and
mirror the status to MediaDecoderStateMachine.
MozReview-Commit-ID: 1nrNqg0KavT
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -410,16 +410,17 @@ MediaDecoder::MediaDecoder(MediaDecoderO
, INIT_CANONICAL(mNextState, PLAY_STATE_PAUSED)
, INIT_CANONICAL(mLogicallySeeking, false)
, INIT_CANONICAL(mSameOriginMedia, false)
, INIT_CANONICAL(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE)
, INIT_CANONICAL(mPlaybackBytesPerSecond, 0.0)
, INIT_CANONICAL(mPlaybackRateReliable, true)
, INIT_CANONICAL(mDecoderPosition, 0)
, INIT_CANONICAL(mIsVisible, !aOwner->IsHidden())
+ , INIT_CANONICAL(mHasSuspendTaint, false)
, mTelemetryReported(false)
{
MOZ_ASSERT(NS_IsMainThread());
MediaMemoryTracker::AddMediaDecoder(this);
mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
mResourceCallback->Connect(this);
@@ -1261,16 +1262,30 @@ void
MediaDecoder::SetForcedHidden(bool aForcedHidden)
{
MOZ_ASSERT(NS_IsMainThread());
mForcedHidden = aForcedHidden;
SetElementVisibility(mElementVisible);
}
void
+MediaDecoder::SetSuspendTaint(bool aTainted)
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ mHasSuspendTaint = aTainted;
+}
+
+bool
+MediaDecoder::HasSuspendTaint() const
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ return mHasSuspendTaint;
+}
+
+void
MediaDecoder::UpdateEstimatedMediaDuration(int64_t aDuration)
{
MOZ_ASSERT(NS_IsMainThread());
if (mPlayState <= PLAY_STATE_LOADING) {
return;
}
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -353,16 +353,22 @@ private:
// Called from HTMLMediaElement when owner document activity changes
virtual void SetElementVisibility(bool aIsVisible);
// Force override the visible state to hidden.
// Called from HTMLMediaElement when testing of video decode suspend from mochitests.
void SetForcedHidden(bool aForcedHidden);
+ // Mark the decoder as tainted, meaning video decode suspend is disabled.
+ void SetSuspendTaint(bool aTaint);
+
+ // Returns true if the decoder can't participate in video decode suspending.
+ bool HasSuspendTaint() const;
+
/******
* The following methods must only be called on the main
* thread.
******/
// Change to a new play state. This updates the mState variable and
// notifies any thread blocking on this object's monitor of the
// change. Call on the main thread only.
@@ -761,16 +767,20 @@ protected:
// is up to consuming the stream. This is not adjusted during decoder
// seek operations, but it's updated at the end when we start playing
// back again.
Canonical<int64_t> mDecoderPosition;
// True if the decoder is visible.
Canonical<bool> mIsVisible;
+ // True if the decoder has a suspend taint - meaning video decode suspend is
+ // disabled.
+ Canonical<bool> mHasSuspendTaint;
+
public:
AbstractCanonical<media::NullableTimeUnit>* CanonicalDurationOrNull() override;
AbstractCanonical<double>* CanonicalVolume() {
return &mVolume;
}
AbstractCanonical<bool>* CanonicalPreservesPitch() {
return &mPreservesPitch;
}
@@ -802,16 +812,19 @@ public:
return &mPlaybackRateReliable;
}
AbstractCanonical<int64_t>* CanonicalDecoderPosition() {
return &mDecoderPosition;
}
AbstractCanonical<bool>* CanonicalIsVisible() {
return &mIsVisible;
}
+ AbstractCanonical<bool>* CanonicalHasSuspendTaint() {
+ return &mHasSuspendTaint;
+ }
private:
// Notify owner when the audible state changed
void NotifyAudibleStateChanged();
/* Functions called by ResourceCallback */
// A media stream is assumed to be infinite if the metadata doesn't
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -603,21 +603,29 @@ public:
{
MaybeStopPrerolling();
// MediaSink is changed. Schedule Step() to check if we can start playback.
mMaster->ScheduleStateMachine();
}
void HandleVideoSuspendTimeout() override
{
- if (mMaster->HasVideo()) {
- mMaster->mVideoDecodeSuspended = true;
- mMaster->mOnPlaybackEvent.Notify(MediaEventType::EnterVideoSuspend);
- Reader()->SetVideoBlankDecode(true);
+ // No video, so nothing to suspend.
+ if (!mMaster->HasVideo()) {
+ return;
}
+
+ // The decoder is tainted, so nothing to suspend.
+ if (mMaster->mHasSuspendTaint) {
+ return;
+ }
+
+ mMaster->mVideoDecodeSuspended = true;
+ mMaster->mOnPlaybackEvent.Notify(MediaEventType::EnterVideoSuspend);
+ Reader()->SetVideoBlankDecode(true);
}
void HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) override
{
if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
// Schedule Step() to check if we can start playback.
mMaster->ScheduleStateMachine();
}
@@ -1477,21 +1485,29 @@ public:
mMaster->Push(aVideo);
mMaster->ScheduleStateMachine();
}
void HandleEndOfStream() override;
void HandleVideoSuspendTimeout() override
{
- if (mMaster->HasVideo()) {
- mMaster->mVideoDecodeSuspended = true;
- mMaster->mOnPlaybackEvent.Notify(MediaEventType::EnterVideoSuspend);
- Reader()->SetVideoBlankDecode(true);
+ // No video, so nothing to suspend.
+ if (!mMaster->HasVideo()) {
+ return;
}
+
+ // The decoder is tainted, so nothing to suspend.
+ if (mMaster->mHasSuspendTaint) {
+ return;
+ }
+
+ mMaster->mVideoDecodeSuspended = true;
+ mMaster->mOnPlaybackEvent.Notify(MediaEventType::EnterVideoSuspend);
+ Reader()->SetVideoBlankDecode(true);
}
private:
TimeStamp mBufferingStart;
// The maximum number of second we spend buffering when we are short on
// unbuffered data.
const uint32_t mBufferingWait = 15;
@@ -2154,16 +2170,17 @@ ShutdownState::Enter()
master->mVolume.DisconnectIfConnected();
master->mPreservesPitch.DisconnectIfConnected();
master->mSameOriginMedia.DisconnectIfConnected();
master->mMediaPrincipalHandle.DisconnectIfConnected();
master->mPlaybackBytesPerSecond.DisconnectIfConnected();
master->mPlaybackRateReliable.DisconnectIfConnected();
master->mDecoderPosition.DisconnectIfConnected();
master->mIsVisible.DisconnectIfConnected();
+ master->mHasSuspendTaint.DisconnectIfConnected();
master->mDuration.DisconnectAll();
master->mIsShutdown.DisconnectAll();
master->mNextFrameStatus.DisconnectAll();
master->mCurrentPosition.DisconnectAll();
master->mPlaybackOffset.DisconnectAll();
master->mIsAudioDataAudible.DisconnectAll();
@@ -2220,16 +2237,17 @@ MediaDecoderStateMachine::MediaDecoderSt
INIT_MIRROR(mVolume, 1.0),
INIT_MIRROR(mPreservesPitch, true),
INIT_MIRROR(mSameOriginMedia, false),
INIT_MIRROR(mMediaPrincipalHandle, PRINCIPAL_HANDLE_NONE),
INIT_MIRROR(mPlaybackBytesPerSecond, 0.0),
INIT_MIRROR(mPlaybackRateReliable, true),
INIT_MIRROR(mDecoderPosition, 0),
INIT_MIRROR(mIsVisible, true),
+ INIT_MIRROR(mHasSuspendTaint, false),
INIT_CANONICAL(mDuration, NullableTimeUnit()),
INIT_CANONICAL(mIsShutdown, false),
INIT_CANONICAL(mNextFrameStatus, MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE),
INIT_CANONICAL(mCurrentPosition, 0),
INIT_CANONICAL(mPlaybackOffset, 0),
INIT_CANONICAL(mIsAudioDataAudible, false)
{
MOZ_COUNT_CTOR(MediaDecoderStateMachine);
@@ -2286,16 +2304,17 @@ MediaDecoderStateMachine::Initialization
mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
mWatchManager.Watch(mEstimatedDuration, &MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mExplicitDuration, &MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mObservedDuration, &MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
if (MediaPrefs::MDSMSuspendBackgroundVideoEnabled()) {
mIsVisible.Connect(aDecoder->CanonicalIsVisible());
+ mHasSuspendTaint.Connect(aDecoder->CanonicalHasSuspendTaint());
mWatchManager.Watch(mIsVisible, &MediaDecoderStateMachine::VisibilityChanged);
}
// Configure MediaDecoderReaderWrapper.
SetMediaDecoderReaderWrapperCallback();
}
void
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -788,16 +788,19 @@ private:
Mirror<bool> mPlaybackRateReliable;
// Current decoding position in the stream.
Mirror<int64_t> mDecoderPosition;
// IsVisible, mirrored from the media decoder.
Mirror<bool> mIsVisible;
+ // HasSuspendTaint, mirrored from the media decoder.
+ Mirror<bool> mHasSuspendTaint;
+
// Duration of the media. This is guaranteed to be non-null after we finish
// decoding the first frame.
Canonical<media::NullableTimeUnit> mDuration;
// Whether we're currently in or transitioning to shutdown state.
Canonical<bool> mIsShutdown;
// The status of our next frame. Mirrored on the main thread and used to