Bug 1122228 - Use document's status change to trigger MediaDecoderStateMachine's dormant status change r=cpearce

This commit is contained in:
Sotaro Ikeda 2015-01-21 20:01:12 -08:00
parent a9545c0e64
commit 4f96a3066c
5 changed files with 68 additions and 26 deletions

View File

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

View File

@ -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)

View File

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

View File

@ -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<MediaInfo> mInfo;
// True if MediaDecoder is in dormant state.
bool mIsDormant;
};
} // namespace mozilla

View File

@ -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;