Bug 883731. Part 3: Make all calls to ChangeReadyState go through UpdateReadyStateForDtaData. r=cpearce

--HG--
extra : rebase_source : 49e39cedd64bcc52bcda452fb38c2d8f460672a0
This commit is contained in:
Robert O'Callahan 2013-06-19 16:05:52 +12:00
parent 0b524698c6
commit 803c503184
3 changed files with 58 additions and 62 deletions

View File

@ -229,17 +229,11 @@ public:
// Dispatch events that were raised while in the bfcache
nsresult DispatchPendingMediaEvents();
// Called by the decoder when some data has been downloaded or
// buffering/seeking has ended. aNextFrameAvailable is true when
// the data for the next frame is available. This method will
// decide whether to set the ready state to HAVE_CURRENT_DATA,
// HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA.
// Called every time readyState might need to be updated.
// aNextFrame indicates whether the next frame is available. This method will
// choose the correct value for readyState.
virtual void UpdateReadyStateForData(NextFrameStatus aNextFrame) MOZ_FINAL MOZ_OVERRIDE;
// Use this method to change the mReadyState member, so required
// events can be fired.
void ChangeReadyState(nsMediaReadyState aState);
// Return true if we can activate autoplay assuming enough data has arrived.
bool CanActivateAutoplay();
@ -632,6 +626,12 @@ protected:
nsIStreamListener **aListener,
MediaDecoder* aCloneDonor);
/**
* Use this method to change the mReadyState member, so required
* events can be fired. Only UpdateReadyStateForData should call this.
*/
void ChangeReadyState(nsMediaReadyState aState);
/**
* Call this after setting up mLoadingSrc and mDecoder.
*/
@ -1016,9 +1016,15 @@ protected:
// Set to false when completed, or not yet started.
bool mBegun;
// True when the decoder has called MetadataLoaded
bool mMetadataLoaded;
// True when the decoder has loaded enough data to display the
// first frame of the content.
bool mLoadedFirstFrame;
bool mFirstFrameLoaded;
// True when loadeddata has been fired for this resource.
bool mFiredLoadedData;
// Indicates whether current playback is a result of user action
// (ie. calling of the Play method), or automatic playback due to

View File

@ -606,7 +606,10 @@ void HTMLMediaElement::AbortExistingLoads()
}
mError = nullptr;
mLoadedFirstFrame = false;
mMetadataLoaded = false;
mFirstFrameLoaded = false;
mFiredLoadedData = false;
mBegun = false;
mAutoplaying = true;
mIsLoadingFromSourceChildren = false;
mSuspendedAfterFirstFrame = false;
@ -626,7 +629,7 @@ void HTMLMediaElement::AbortExistingLoads()
if (mNetworkState != NETWORK_EMPTY) {
mNetworkState = NETWORK_EMPTY;
NS_ASSERTION(!mDecoder && !mSrcStream, "How did someone setup a new stream/decoder already?");
ChangeReadyState(HAVE_NOTHING);
UpdateReadyStateForData(NEXT_FRAME_UNAVAILABLE);
mPaused = true;
if (fireTimeUpdate) {
@ -778,7 +781,7 @@ void HTMLMediaElement::SelectResource()
// AddRemoveSelfReference, since it must still be held
DispatchAsyncEvent(NS_LITERAL_STRING("loadstart"));
// Delay setting mIsRunningSeletResource until after UpdatePreloadAction
// Delay setting mIsRunningSelectResource until after UpdatePreloadAction
// so that we don't lose our state change by bailing out of the preload
// state update
UpdatePreloadAction();
@ -1887,7 +1890,9 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo)
mCurrentPlayRangeStart(-1.0),
mAllowAudioData(false),
mBegun(false),
mLoadedFirstFrame(false),
mMetadataLoaded(false),
mFirstFrameLoaded(false),
mFiredLoadedData(false),
mAutoplaying(true),
mAutoplayEnabled(true),
mPaused(true),
@ -2722,53 +2727,38 @@ void HTMLMediaElement::MetadataLoaded(int aChannels,
bool aHasVideo,
const MetadataTags* aTags)
{
mMetadataLoaded = true;
mChannels = aChannels;
mRate = aRate;
mHasAudio = aHasAudio;
mHasVideo = aHasVideo;
mTags = aTags;
ChangeReadyState(HAVE_METADATA);
UpdateReadyStateForData(NEXT_FRAME_UNAVAILABLE);
DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
if (mDecoder && mDecoder->IsTransportSeekable() && mDecoder->IsMediaSeekable()) {
ProcessMediaFragmentURI();
mDecoder->SetFragmentEndTime(mFragmentEnd);
}
// If this element had a video track, but consists only of an audio track now,
// delete the VideoFrameContainer. This happens when the src is changed to an
// audio only file.
if (!aHasVideo) {
mVideoFrameContainer = nullptr;
}
}
void HTMLMediaElement::FirstFrameLoaded()
{
mFirstFrameLoaded = true;
ChangeDelayLoadStatus(false);
// The current frame is available, but the *next* frame is not.
UpdateReadyStateForData(NEXT_FRAME_UNAVAILABLE);
NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended");
if (mDecoder && mAllowSuspendAfterFirstFrame && mPaused &&
!HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
mSuspendedAfterFirstFrame = true;
mDecoder->Suspend();
} else if (mLoadedFirstFrame &&
mDownloadSuspendedByCache &&
mDecoder &&
!mDecoder->IsEnded()) {
// We've already loaded the first frame, and the decoder has signalled
// that the download has been suspended by the media cache. So move
// readyState into HAVE_ENOUGH_DATA, in case there's script waiting
// for a "canplaythrough" event; without this forced transition, we will
// never fire the "canplaythrough" event if the media cache is so small
// that the download was suspended before the first frame was loaded.
// Don't force this transition if the decoder is in ended state; the
// readyState should remain at HAVE_CURRENT_DATA in this case.
ChangeReadyState(HAVE_ENOUGH_DATA);
return;
}
}
@ -2859,7 +2849,7 @@ void HTMLMediaElement::PlaybackEnded()
void HTMLMediaElement::SeekStarted()
{
DispatchAsyncEvent(NS_LITERAL_STRING("seeking"));
ChangeReadyState(HAVE_METADATA);
UpdateReadyStateForData(NEXT_FRAME_UNAVAILABLE);
FireTimeUpdate(false);
}
@ -2914,18 +2904,26 @@ void HTMLMediaElement::UpdateReadyStateForData(NextFrameStatus aNextFrame)
{
mLastNextFrameStatus = aNextFrame;
if (mReadyState < HAVE_METADATA) {
// aNextFrame might have a next frame because the decoder can advance
// on its own thread before MetadataLoaded gets
// a chance to run.
// The arrival of more data can't change us out of this readyState.
if (!mMetadataLoaded) {
ChangeReadyState(HAVE_NOTHING);
return;
}
if (mReadyState > HAVE_METADATA &&
mDownloadSuspendedByCache &&
mDecoder &&
!mDecoder->IsEnded()) {
if (!mFirstFrameLoaded || Seeking()) {
ChangeReadyState(HAVE_METADATA);
return;
}
if (mHasVideo) {
VideoFrameContainer* container = GetVideoFrameContainer();
if (container && mMediaSize == nsIntSize(-1,-1)) {
// No frame has been set yet. Don't advance out of HAVE_METADATA.
ChangeReadyState(HAVE_METADATA);
return;
}
}
if (mDownloadSuspendedByCache && mDecoder && !mDecoder->IsEnded()) {
// The decoder has signalled that the download has been suspended by the
// media cache. So move readyState into HAVE_ENOUGH_DATA, in case there's
// script waiting for a "canplaythrough" event; without this forced
@ -2939,14 +2937,6 @@ void HTMLMediaElement::UpdateReadyStateForData(NextFrameStatus aNextFrame)
return;
}
if (mReadyState < HAVE_CURRENT_DATA && mHasVideo) {
VideoFrameContainer* container = GetVideoFrameContainer();
if (container && mMediaSize == nsIntSize(-1,-1)) {
// No frame has been set yet. Don't advance.
return;
}
}
if (aNextFrame != NEXT_FRAME_AVAILABLE) {
ChangeReadyState(HAVE_CURRENT_DATA);
if (!mWaitingFired && aNextFrame == NEXT_FRAME_UNAVAILABLE_BUFFERING) {
@ -2973,11 +2963,11 @@ void HTMLMediaElement::UpdateReadyStateForData(NextFrameStatus aNextFrame)
MediaDecoder::Statistics stats = mDecoder->GetStatistics();
if (stats.mTotalBytes < 0 ? stats.mDownloadRateReliable
: stats.mTotalBytes == stats.mDownloadPosition ||
mDecoder->CanPlayThrough())
{
mDecoder->CanPlayThrough()) {
ChangeReadyState(HAVE_ENOUGH_DATA);
return;
}
ChangeReadyState(HAVE_FUTURE_DATA);
}
@ -3011,12 +3001,10 @@ void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
}
if (oldState < HAVE_CURRENT_DATA &&
mReadyState >= HAVE_CURRENT_DATA &&
!mLoadedFirstFrame)
{
if (oldState < HAVE_CURRENT_DATA && mReadyState >= HAVE_CURRENT_DATA &&
!mFiredLoadedData) {
DispatchAsyncEvent(NS_LITERAL_STRING("loadeddata"));
mLoadedFirstFrame = true;
mFiredLoadedData = true;
}
if (mReadyState == HAVE_CURRENT_DATA) {

View File

@ -740,6 +740,8 @@ void MediaDecoder::MetadataLoaded(int aChannels, int aRate, bool aHasAudio, bool
// our new size.
Invalidate();
mOwner->MetadataLoaded(aChannels, aRate, aHasAudio, aHasVideo, aTags);
// Dispatch an initial progress event to represent the data read so far
mOwner->DispatchAsyncEvent(NS_LITERAL_STRING("progress"));
}
StartProgress();