mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-16 22:04:36 +00:00
Bug 1144486 - Use state watching machinery for mReadyState updates. r=jww
This commit is contained in:
parent
08da945616
commit
0867953797
@ -636,7 +636,7 @@ void HTMLMediaElement::ShutdownDecoder()
|
||||
RemoveMediaElementFromURITable();
|
||||
NS_ASSERTION(mDecoder, "Must have decoder to shut down");
|
||||
mDecoder->Shutdown();
|
||||
mDecoder = nullptr;
|
||||
SetDecoder(nullptr);
|
||||
}
|
||||
|
||||
void HTMLMediaElement::AbortExistingLoads()
|
||||
@ -700,7 +700,7 @@ void HTMLMediaElement::AbortExistingLoads()
|
||||
mPendingEncryptedInitData.mInitDatas.Clear();
|
||||
#endif // MOZ_EME
|
||||
mSourcePointer = nullptr;
|
||||
mLastNextFrameStatus = NEXT_FRAME_UNINITIALIZED;
|
||||
mNextFrameStatus = NEXT_FRAME_UNINITIALIZED;
|
||||
|
||||
mTags = nullptr;
|
||||
|
||||
@ -941,13 +941,13 @@ void HTMLMediaElement::NotifyMediaStreamTracksAvailable(DOMMediaStream* aStream)
|
||||
|
||||
bool videoHasChanged = IsVideo() && HasVideo() != !VideoTracks()->IsEmpty();
|
||||
|
||||
UpdateReadyStateForData(mLastNextFrameStatus);
|
||||
|
||||
if (videoHasChanged) {
|
||||
// We are a video element and HasVideo() changed so update the screen
|
||||
// wakelock
|
||||
NotifyOwnerDocumentActivityChanged();
|
||||
}
|
||||
|
||||
mReadyStateUpdater->Notify();
|
||||
}
|
||||
|
||||
void HTMLMediaElement::LoadFromSourceChildren()
|
||||
@ -2045,8 +2045,9 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
|
||||
: nsGenericHTMLElement(aNodeInfo),
|
||||
mCurrentLoadID(0),
|
||||
mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY),
|
||||
mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING),
|
||||
mLastNextFrameStatus(NEXT_FRAME_UNINITIALIZED),
|
||||
mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING, "HTMLMediaElement::mReadyState"),
|
||||
mReadyStateUpdater("HTMLMediaElement::mReadyStateUpdater"),
|
||||
mNextFrameStatus(NEXT_FRAME_UNINITIALIZED, "HTMLMediaElement::mNextFrameStatus"),
|
||||
mLoadWaitStatus(NOT_WAITING),
|
||||
mVolume(1.0),
|
||||
mPreloadAction(PRELOAD_UNDEFINED),
|
||||
@ -2087,7 +2088,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
|
||||
mMediaSecurityVerified(false),
|
||||
mCORSMode(CORS_NONE),
|
||||
mIsEncrypted(false),
|
||||
mDownloadSuspendedByCache(false),
|
||||
mDownloadSuspendedByCache(false, "HTMLMediaElement::mDownloadSuspendedByCache"),
|
||||
mAudioChannelFaded(false),
|
||||
mPlayingThroughTheAudioChannel(false),
|
||||
mDisableVideo(false),
|
||||
@ -2100,6 +2101,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
|
||||
if (!gMediaElementEventsLog) {
|
||||
gMediaElementEventsLog = PR_NewLogModule("nsMediaElementEvents");
|
||||
}
|
||||
EnsureStateWatchingLog();
|
||||
#endif
|
||||
|
||||
mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
|
||||
@ -2108,6 +2110,14 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
|
||||
|
||||
RegisterActivityObserver();
|
||||
NotifyOwnerDocumentActivityChanged();
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mReadyStateUpdater->AddWeakCallback(this, &HTMLMediaElement::UpdateReadyStateInternal);
|
||||
mReadyStateUpdater->Watch(mNextFrameStatus);
|
||||
mReadyStateUpdater->Watch(mDownloadSuspendedByCache);
|
||||
// Paradoxically, there is a self-edge whereby UpdateReadyStateInternal refuses
|
||||
// to run until mReadyState reaches at least HAVE_METADATA by some other means.
|
||||
mReadyStateUpdater->Watch(mReadyState);
|
||||
}
|
||||
|
||||
HTMLMediaElement::~HTMLMediaElement()
|
||||
@ -2604,8 +2614,8 @@ HTMLMediaElement::ReportMSETelemetry()
|
||||
ErrorResult ignore;
|
||||
stalled = index != TimeRanges::NoIndex &&
|
||||
(ranges->End(index, ignore) - t) < errorMargin;
|
||||
stalled |= mLastNextFrameStatus == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING &&
|
||||
mReadyState == HTMLMediaElement::HAVE_CURRENT_DATA;
|
||||
stalled |= mNextFrameStatus == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING &&
|
||||
mReadyState == HTMLMediaElement::HAVE_CURRENT_DATA;
|
||||
if (stalled) {
|
||||
state = STALLED;
|
||||
}
|
||||
@ -2751,7 +2761,7 @@ nsresult HTMLMediaElement::InitializeDecoderForChannel(nsIChannel* aChannel,
|
||||
// RtspMediaResource.
|
||||
if (DecoderTraits::DecoderWaitsForOnConnected(mimeType)) {
|
||||
decoder->SetResource(resource);
|
||||
mDecoder = decoder;
|
||||
SetDecoder(decoder);
|
||||
if (aListener) {
|
||||
*aListener = nullptr;
|
||||
}
|
||||
@ -2777,7 +2787,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
||||
mPendingEvents.Clear();
|
||||
// Set mDecoder now so if methods like GetCurrentSrc get called between
|
||||
// here and Load(), they work.
|
||||
mDecoder = aDecoder;
|
||||
SetDecoder(aDecoder);
|
||||
|
||||
// Tell the decoder about its MediaResource now so things like principals are
|
||||
// available immediately.
|
||||
@ -2802,7 +2812,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
||||
|
||||
nsresult rv = aDecoder->Load(aListener, aCloneDonor);
|
||||
if (NS_FAILED(rv)) {
|
||||
mDecoder = nullptr;
|
||||
SetDecoder(nullptr);
|
||||
LOG(PR_LOG_DEBUG, ("%p Failed to load for decoder %p", this, aDecoder));
|
||||
return rv;
|
||||
}
|
||||
@ -3213,7 +3223,7 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
|
||||
if (!aInfo->HasVideo()) {
|
||||
ResetState();
|
||||
} else {
|
||||
UpdateReadyStateForData(mLastNextFrameStatus);
|
||||
mReadyStateUpdater->Notify();
|
||||
}
|
||||
|
||||
if (IsVideo() && aInfo->HasVideo()) {
|
||||
@ -3496,7 +3506,16 @@ bool HTMLMediaElement::IsCORSSameOrigin()
|
||||
|
||||
void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatus aNextFrame)
|
||||
{
|
||||
mLastNextFrameStatus = aNextFrame;
|
||||
mNextFrameStatus = aNextFrame;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::UpdateReadyStateInternal()
|
||||
{
|
||||
if (!mDecoder && !mSrcStream) {
|
||||
// Not initialized - bail out.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDecoder && mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
|
||||
// aNextFrame might have a next frame because the decoder can advance
|
||||
@ -3520,7 +3539,7 @@ void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatu
|
||||
MetadataLoaded(&mediaInfo, nsAutoPtr<const MetadataTags>(nullptr));
|
||||
}
|
||||
|
||||
if (aNextFrame == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING) {
|
||||
if (mNextFrameStatus == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING) {
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
|
||||
return;
|
||||
}
|
||||
@ -3549,9 +3568,9 @@ void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatu
|
||||
return;
|
||||
}
|
||||
|
||||
if (aNextFrame != MediaDecoderOwner::NEXT_FRAME_AVAILABLE) {
|
||||
if (mNextFrameStatus != MediaDecoderOwner::NEXT_FRAME_AVAILABLE) {
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
|
||||
if (!mWaitingFired && aNextFrame == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
|
||||
if (!mWaitingFired && mNextFrameStatus == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
|
||||
FireTimeUpdate(false);
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
|
||||
mWaitingFired = true;
|
||||
@ -3870,7 +3889,7 @@ void HTMLMediaElement::UpdateMediaSize(const nsIntSize& aSize)
|
||||
}
|
||||
|
||||
mMediaInfo.mVideo.mDisplay = aSize;
|
||||
UpdateReadyStateForData(mLastNextFrameStatus);
|
||||
mReadyStateUpdater->Notify();
|
||||
}
|
||||
|
||||
void HTMLMediaElement::UpdateInitialMediaSize(const nsIntSize& aSize)
|
||||
|
@ -23,6 +23,7 @@
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/dom/MediaKeys.h"
|
||||
#endif
|
||||
#include "StateWatching.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
||||
// X.h on Linux #defines CurrentTime as 0L, so we have to #undef it here.
|
||||
@ -647,6 +648,17 @@ protected:
|
||||
class StreamListener;
|
||||
class StreamSizeListener;
|
||||
|
||||
void SetDecoder(MediaDecoder* aDecoder)
|
||||
{
|
||||
if (mDecoder) {
|
||||
mReadyStateUpdater->Unwatch(mDecoder->ReadyStateWatchTarget());
|
||||
}
|
||||
mDecoder = aDecoder;
|
||||
if (mDecoder) {
|
||||
mReadyStateUpdater->Watch(mDecoder->ReadyStateWatchTarget());
|
||||
}
|
||||
}
|
||||
|
||||
virtual void GetItemValueText(DOMString& text) override;
|
||||
virtual void SetItemValueText(const nsAString& text) override;
|
||||
|
||||
@ -1013,6 +1025,9 @@ protected:
|
||||
// MediaElement doesn't yet have one then it will create it.
|
||||
TextTrackManager* GetOrCreateTextTrackManager();
|
||||
|
||||
// Recomputes ready state and fires events as necessary based on current state.
|
||||
void UpdateReadyStateInternal();
|
||||
|
||||
class nsAsyncEventRunner;
|
||||
using nsGenericHTMLElement::DispatchEvent;
|
||||
// For nsAsyncEventRunner.
|
||||
@ -1090,10 +1105,12 @@ protected:
|
||||
// Media loading flags. See:
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#video)
|
||||
nsMediaNetworkState mNetworkState;
|
||||
nsMediaReadyState mReadyState;
|
||||
Watchable<nsMediaReadyState> mReadyState;
|
||||
|
||||
WatcherHolder mReadyStateUpdater;
|
||||
|
||||
// Last value passed from codec or stream source to UpdateReadyStateForData.
|
||||
NextFrameStatus mLastNextFrameStatus;
|
||||
Watchable<NextFrameStatus> mNextFrameStatus;
|
||||
|
||||
enum LoadAlgorithmState {
|
||||
// No load algorithm instance is waiting for a source to be added to the
|
||||
@ -1328,7 +1345,7 @@ protected:
|
||||
#endif // MOZ_EME
|
||||
|
||||
// True if the media's channel's download has been suspended.
|
||||
bool mDownloadSuspendedByCache;
|
||||
Watchable<bool> mDownloadSuspendedByCache;
|
||||
|
||||
// Audio Channel.
|
||||
AudioChannel mAudioChannel;
|
||||
|
@ -585,6 +585,7 @@ bool MediaDecoder::IsInfinite()
|
||||
}
|
||||
|
||||
MediaDecoder::MediaDecoder() :
|
||||
mReadyStateWatchTarget("MediaDecoder::mReadyStateWatchTarget"),
|
||||
mDecoderPosition(0),
|
||||
mPlaybackPosition(0),
|
||||
mCurrentTime(0.0),
|
||||
@ -595,7 +596,7 @@ MediaDecoder::MediaDecoder() :
|
||||
mMediaSeekable(true),
|
||||
mSameOriginMedia(false),
|
||||
mReentrantMonitor("media.decoder"),
|
||||
mPlayState(PLAY_STATE_LOADING),
|
||||
mPlayState(PLAY_STATE_LOADING, "MediaDecoder::mPlayState"),
|
||||
mNextState(PLAY_STATE_PAUSED),
|
||||
mIgnoreProgressData(false),
|
||||
mInfiniteStream(false),
|
||||
@ -622,8 +623,11 @@ MediaDecoder::MediaDecoder() :
|
||||
if (!gMediaDecoderLog) {
|
||||
gMediaDecoderLog = PR_NewLogModule("MediaDecoder");
|
||||
}
|
||||
EnsureStateWatchingLog();
|
||||
#endif
|
||||
mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
|
||||
|
||||
mReadyStateWatchTarget->Watch(mPlayState);
|
||||
}
|
||||
|
||||
bool MediaDecoder::Init(MediaDecoderOwner* aOwner)
|
||||
@ -1140,7 +1144,6 @@ void MediaDecoder::NotifySuspendedStatusChanged()
|
||||
if (mResource && mOwner) {
|
||||
bool suspended = mResource->IsSuspendedByCache();
|
||||
mOwner->NotifySuspendedByCache(suspended);
|
||||
UpdateReadyStateForData();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1704,8 +1707,8 @@ void MediaDecoder::UnpinForSeek()
|
||||
bool MediaDecoder::CanPlayThrough()
|
||||
{
|
||||
Statistics stats = GetStatistics();
|
||||
NS_ENSURE_TRUE(mDecoderStateMachine, false);
|
||||
|
||||
NS_ASSERTION(mDecoderStateMachine, "CanPlayThrough should have state machine!");
|
||||
if (mDecoderStateMachine->IsRealTime() ||
|
||||
(stats.mTotalBytes < 0 && stats.mDownloadRateReliable) ||
|
||||
(stats.mTotalBytes >= 0 && stats.mTotalBytes == stats.mDownloadPosition)) {
|
||||
|
@ -196,6 +196,7 @@ destroying the MediaDecoder object.
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "AbstractMediaDecoder.h"
|
||||
#include "StateWatching.h"
|
||||
#include "necko-config.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/CDMProxy.h"
|
||||
@ -1040,6 +1041,8 @@ public:
|
||||
GetFrameStatistics().NotifyDecodedFrames(aParsed, aDecoded, aDropped);
|
||||
}
|
||||
|
||||
WatchTarget& ReadyStateWatchTarget() { return *mReadyStateWatchTarget; }
|
||||
|
||||
protected:
|
||||
virtual ~MediaDecoder();
|
||||
void SetStateMachineParameters();
|
||||
@ -1055,6 +1058,8 @@ protected:
|
||||
// Return true if the decoder has reached the end of playback
|
||||
bool IsEnded() const;
|
||||
|
||||
WatcherHolder mReadyStateWatchTarget;
|
||||
|
||||
/******
|
||||
* The following members should be accessed with the decoder lock held.
|
||||
******/
|
||||
@ -1137,7 +1142,7 @@ protected:
|
||||
// OR on the main thread.
|
||||
// Any change to the state on the main thread must call NotifyAll on the
|
||||
// monitor so the decode thread can wake up.
|
||||
PlayState mPlayState;
|
||||
Watchable<PlayState> mPlayState;
|
||||
|
||||
// The state to change to after a seek or load operation.
|
||||
// This can only be changed on the main thread while holding the decoder
|
||||
|
Loading…
x
Reference in New Issue
Block a user