From 4f96a3066ce737268b14f0643b7744765ecf162a Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Wed, 21 Jan 2015 20:01:12 -0800 Subject: [PATCH] Bug 1122228 - Use document's status change to trigger MediaDecoderStateMachine's dormant status change r=cpearce --- dom/html/HTMLMediaElement.cpp | 46 ++++++++++++++++++++--------------- dom/html/HTMLMediaElement.h | 6 ++++- dom/media/MediaDecoder.cpp | 28 ++++++++++++++++++--- dom/media/MediaDecoder.h | 8 ++++-- dom/media/MediaDecoderOwner.h | 6 +++++ 5 files changed, 68 insertions(+), 26 deletions(-) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index b2192518105f..372f17d151de 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -2524,15 +2524,13 @@ nsresult HTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParen // It's value may have changed, so update it. UpdatePreloadAction(); } + mElementInTreeState = ELEMENT_INTREE; + if (mDecoder) { // When the MediaElement is binding to tree, the dormant status is // aligned to document's hidden status. - nsIDocument* ownerDoc = OwnerDoc(); - if (ownerDoc) { - mDecoder->SetDormantIfNecessary(ownerDoc->Hidden()); - } + mDecoder->NotifyOwnerActivityChanged(); } - mElementInTreeState = ELEMENT_INTREE; return rv; } @@ -2543,12 +2541,14 @@ void HTMLMediaElement::UnbindFromTree(bool aDeep, if (!mPaused && mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY) Pause(); - if (mDecoder) { - mDecoder->SetDormantIfNecessary(true); - } mElementInTreeState = ELEMENT_NOT_INTREE_HAD_INTREE; nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); + + if (mDecoder) { + MOZ_ASSERT(IsHidden()); + mDecoder->NotifyOwnerActivityChanged(); + } } /* static */ @@ -3519,6 +3519,21 @@ void HTMLMediaElement::CheckAutoplayDataReady() } } +bool HTMLMediaElement::IsActive() +{ + nsIDocument* ownerDoc = OwnerDoc(); + return ownerDoc && ownerDoc->IsActive() && ownerDoc->IsVisible(); +} + +bool HTMLMediaElement::IsHidden() +{ + if (mElementInTreeState == ELEMENT_NOT_INTREE_HAD_INTREE) { + return true; + } + nsIDocument* ownerDoc = OwnerDoc(); + return !ownerDoc || ownerDoc->Hidden(); +} + VideoFrameContainer* HTMLMediaElement::GetVideoFrameContainer() { if (mVideoFrameContainer) @@ -3698,15 +3713,7 @@ void HTMLMediaElement::NotifyOwnerDocumentActivityChanged() if (mDecoder) { mDecoder->SetElementVisibility(!ownerDoc->Hidden()); - - if (mElementInTreeState == ELEMENT_NOT_INTREE_HAD_INTREE) { - mDecoder->SetDormantIfNecessary(true); - } else if (mElementInTreeState == ELEMENT_NOT_INTREE || - mElementInTreeState == ELEMENT_INTREE) { - // The MediaElement had never been binded to tree, or in the tree now, - // align to document. - mDecoder->SetDormantIfNecessary(ownerDoc->Hidden()); - } + mDecoder->NotifyOwnerActivityChanged(); } // SetVisibilityState will update mMuted with MUTED_BY_AUDIO_CHANNEL via the @@ -3716,10 +3723,9 @@ void HTMLMediaElement::NotifyOwnerDocumentActivityChanged() AutoNoJSAPI nojsapi; mAudioChannelAgent->SetVisibilityState(!ownerDoc->Hidden()); } - bool suspendEvents = !ownerDoc->IsActive() || !ownerDoc->IsVisible(); - bool pauseElement = suspendEvents || (mMuted & MUTED_BY_AUDIO_CHANNEL); + bool pauseElement = !IsActive() || (mMuted & MUTED_BY_AUDIO_CHANNEL); - SuspendOrResumeElement(pauseElement, suspendEvents); + SuspendOrResumeElement(pauseElement, !IsActive()); AddRemoveSelfReference(); } diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index 3f2e52c2e92f..477bbc1f14ca 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -211,6 +211,10 @@ public: // suspended the channel. virtual void NotifySuspendedByCache(bool aIsSuspended) MOZ_FINAL MOZ_OVERRIDE; + virtual bool IsActive() MOZ_FINAL MOZ_OVERRIDE; + + virtual bool IsHidden() MOZ_FINAL MOZ_OVERRIDE; + // Called by the media decoder and the video frame to get the // ImageContainer containing the video data. virtual VideoFrameContainer* GetVideoFrameContainer() MOZ_FINAL MOZ_OVERRIDE; @@ -374,7 +378,7 @@ public: // Called by the media decoder object, on the main thread, // when the connection between Rtsp server and client gets lost. - void ResetConnectionState() MOZ_FINAL MOZ_OVERRIDE; + virtual void ResetConnectionState() MOZ_FINAL MOZ_OVERRIDE; // XPCOM GetPreload() is OK void SetPreload(const nsAString& aValue, ErrorResult& aRv) diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 10c7a5b2c708..8fba87581f23 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -118,7 +118,7 @@ NS_IMPL_ISUPPORTS(MediaMemoryTracker, nsIMemoryReporter) NS_IMPL_ISUPPORTS(MediaDecoder, nsIObserver) -void MediaDecoder::SetDormantIfNecessary(bool aDormant) +void MediaDecoder::NotifyOwnerActivityChanged() { MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); @@ -129,7 +129,28 @@ void MediaDecoder::SetDormantIfNecessary(bool aDormant) return; } - if(aDormant) { + if (!mOwner) { + NS_WARNING("MediaDecoder without a decoder owner, can't update dormant"); + return; + } + + bool prevDormant = mIsDormant; + mIsDormant = false; + if (!mOwner->IsActive() && mOwner->GetVideoFrameContainer()) { + mIsDormant = true; + } +#ifdef MOZ_WIDGET_GONK + if (mOwner->IsHidden() && mOwner->GetVideoFrameContainer()) { + mIsDormant = true; + } +#endif + + if (prevDormant == mIsDormant) { + // No update to dormant state + return; + } + + if (mIsDormant) { // enter dormant state mDecoderStateMachine->SetDormant(true); @@ -450,7 +471,8 @@ MediaDecoder::MediaDecoder() : mShuttingDown(false), mPausedForPlaybackRateNull(false), mMinimizePreroll(false), - mMediaTracksConstructed(false) + mMediaTracksConstructed(false), + mIsDormant(false) { MOZ_COUNT_CTOR(MediaDecoder); MOZ_ASSERT(NS_IsMainThread()); diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index d07e12e5d3a0..92dc83ce1c50 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -360,11 +360,12 @@ public: // called. virtual nsresult Play(); - // Set/Unset dormant state if necessary. + // Notify activity of the decoder owner is changed. + // Based on the activity, dormant state is updated. // Dormant state is a state to free all scarce media resources // (like hw video codec), did not decoding and stay dormant. // It is used to share scarece media resources in system. - virtual void SetDormantIfNecessary(bool aDormant); + virtual void NotifyOwnerActivityChanged(); // Pause video playback. virtual void Pause(); @@ -1215,6 +1216,9 @@ protected: // Stores media info, including info of audio tracks and video tracks, should // only be accessed from main thread. nsAutoPtr mInfo; + + // True if MediaDecoder is in dormant state. + bool mIsDormant; }; } // namespace mozilla diff --git a/dom/media/MediaDecoderOwner.h b/dom/media/MediaDecoderOwner.h index 815cd1ce52b9..23f7e9634440 100644 --- a/dom/media/MediaDecoderOwner.h +++ b/dom/media/MediaDecoderOwner.h @@ -120,6 +120,12 @@ public: // HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA. virtual void UpdateReadyStateForData(NextFrameStatus aNextFrame) = 0; + // Check if the decoder owner is active. + virtual bool IsActive() = 0; + + // Check if the decoder owner is hidden. + virtual bool IsHidden() = 0; + // Called by the media decoder and the video frame to get the // ImageContainer containing the video data. virtual VideoFrameContainer* GetVideoFrameContainer() = 0;