diff --git a/content/html/content/public/nsHTMLMediaElement.h b/content/html/content/public/nsHTMLMediaElement.h index 578a2201e553..655ab79921c2 100644 --- a/content/html/content/public/nsHTMLMediaElement.h +++ b/content/html/content/public/nsHTMLMediaElement.h @@ -214,9 +214,6 @@ protected: // Set to false when completed, or not yet started. PRPackedBool mBegun; - // If truen then the video playback has completed. - PRPackedBool mEnded; - // True when the decoder has loaded enough data to display the // first frame of the content. PRPackedBool mLoadedFirstFrame; diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp index decc38a27eec..f2d42d5cf3e1 100644 --- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -112,7 +112,7 @@ NS_IMETHODIMP nsHTMLMediaElement::GetError(nsIDOMHTMLMediaError * *aError) /* readonly attribute boolean ended; */ NS_IMETHODIMP nsHTMLMediaElement::GetEnded(PRBool *aEnded) { - *aEnded = mEnded; + *aEnded = mDecoder ? mDecoder->IsEnded() : PR_FALSE; return NS_OK; } @@ -191,7 +191,6 @@ nsresult nsHTMLMediaElement::LoadWithChannel(nsIChannel *aChannel, NS_ENSURE_SUCCESS(rv, rv); mBegun = PR_TRUE; - mEnded = PR_FALSE; DispatchAsyncProgressEvent(NS_LITERAL_STRING("loadstart")); @@ -343,7 +342,6 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse mMutedVolume(0.0), mMediaSize(-1,-1), mBegun(PR_FALSE), - mEnded(PR_FALSE), mLoadedFirstFrame(PR_FALSE), mAutoplaying(PR_TRUE), mPaused(PR_TRUE), @@ -374,8 +372,7 @@ nsHTMLMediaElement::Play(void) NS_ENSURE_SUCCESS(rv, rv); } - if (mEnded) { - mEnded = PR_FALSE; + if (mDecoder->IsEnded()) { SetCurrentTime(0); } @@ -707,7 +704,6 @@ void nsHTMLMediaElement::FirstFrameLoaded() void nsHTMLMediaElement::ResourceLoaded() { mBegun = PR_FALSE; - mEnded = PR_FALSE; mNetworkState = nsIDOMHTMLMediaElement::LOADED; ChangeReadyState(nsIDOMHTMLMediaElement::CAN_PLAY_THROUGH); @@ -725,8 +721,8 @@ void nsHTMLMediaElement::NetworkError() void nsHTMLMediaElement::PlaybackEnded() { + NS_ASSERTION(mDecoder->IsEnded(), "Decoder fired ended, but not in ended state"); mBegun = PR_FALSE; - mEnded = PR_TRUE; mPaused = PR_TRUE; DispatchSimpleEvent(NS_LITERAL_STRING("ended")); } @@ -871,13 +867,15 @@ PRBool nsHTMLMediaElement::IsActivelyPlaying() const mReadyState == nsIDOMHTMLMediaElement::CAN_PLAY_THROUGH) && !IsPlaybackEnded(); } + PRBool nsHTMLMediaElement::IsPlaybackEnded() const { // TODO: // the current playback position is equal to the effective end of the media resource, // and the currentLoop attribute is equal to playCount-1. // See bug 449157. - return mNetworkState >= nsIDOMHTMLMediaElement::LOADED_METADATA && mEnded; + return mNetworkState >= nsIDOMHTMLMediaElement::LOADED_METADATA && + mDecoder ? mDecoder->IsEnded() : PR_FALSE; } nsIPrincipal* diff --git a/content/media/video/public/nsMediaDecoder.h b/content/media/video/public/nsMediaDecoder.h index 5e8e03412208..f103ad05ef20 100644 --- a/content/media/video/public/nsMediaDecoder.h +++ b/content/media/video/public/nsMediaDecoder.h @@ -134,6 +134,10 @@ class nsMediaDecoder : public nsIObserver // seeking in the media resource. virtual PRBool IsSeeking() const = 0; + // Return PR_TRUE if the decoder has reached the end of playback. + // Call in the main thread only. + virtual PRBool IsEnded() const = 0; + // Return the current number of bytes loaded from the video file. // This is used for progress events. virtual PRUint64 GetBytesLoaded() = 0; diff --git a/content/media/video/public/nsOggDecoder.h b/content/media/video/public/nsOggDecoder.h index 7dc57469b559..bd7dede3c7f6 100644 --- a/content/media/video/public/nsOggDecoder.h +++ b/content/media/video/public/nsOggDecoder.h @@ -339,6 +339,10 @@ class nsOggDecoder : public nsMediaDecoder // seeking in the media resource. virtual PRBool IsSeeking() const; + // Return PR_TRUE if the decoder has reached the end of playback. + // Call on the main thread only. + virtual PRBool IsEnded() const; + // Get the size of the media file in bytes. Called on the main thread only. virtual void SetTotalBytes(PRInt64 aBytes); diff --git a/content/media/video/public/nsWaveDecoder.h b/content/media/video/public/nsWaveDecoder.h index 29ab1fc40309..70b77a5345fc 100644 --- a/content/media/video/public/nsWaveDecoder.h +++ b/content/media/video/public/nsWaveDecoder.h @@ -173,6 +173,9 @@ class nsWaveDecoder : public nsMediaDecoder // Report whether the decoder is currently seeking. virtual PRBool IsSeeking() const; + // Report whether the decoder has reached end of playback. + virtual PRBool IsEnded() const; + // Start downloading the media at the specified URI. The media's metadata // will be parsed and made available as the load progresses. virtual nsresult Load(nsIURI* aURI, nsIChannel* aChannel, nsIStreamListener** aStreamListener); @@ -259,11 +262,12 @@ private: // state machine will validate the offset against the current media. float mTimeOffset; - // Copy of the current time and duration when the state machine was - // disposed. Used to respond to time and duration queries with sensible - // values after playback has ended. + // Copy of the current time, duration, and ended state when the state + // machine was disposed. Used to respond to time and duration queries + // with sensible values after the state machine is destroyed. float mEndedCurrentTime; float mEndedDuration; + PRPackedBool mEnded; // True if we have registered a shutdown observer. PRPackedBool mNotifyOnShutdown; diff --git a/content/media/video/src/nsOggDecoder.cpp b/content/media/video/src/nsOggDecoder.cpp index 1fef7e314550..2fbfa773ddcb 100644 --- a/content/media/video/src/nsOggDecoder.cpp +++ b/content/media/video/src/nsOggDecoder.cpp @@ -1490,7 +1490,12 @@ void nsOggDecoder::NetworkError() PRBool nsOggDecoder::IsSeeking() const { - return mPlayState == PLAY_STATE_SEEKING; + return mPlayState == PLAY_STATE_SEEKING || mNextState == PLAY_STATE_SEEKING; +} + +PRBool nsOggDecoder::IsEnded() const +{ + return mPlayState == PLAY_STATE_ENDED || mPlayState == PLAY_STATE_SHUTDOWN; } void nsOggDecoder::PlaybackEnded() diff --git a/content/media/video/src/nsWaveDecoder.cpp b/content/media/video/src/nsWaveDecoder.cpp index 76390739bc54..149f503dd5cb 100644 --- a/content/media/video/src/nsWaveDecoder.cpp +++ b/content/media/video/src/nsWaveDecoder.cpp @@ -145,6 +145,9 @@ public: // Returns true if the state machine is seeking. Threadsafe. PRBool IsSeeking(); + // Returns true if the state machine has reached the end of playback. Threadsafe. + PRBool IsEnded(); + // Called by the decoder to indicate that the media stream has closed. void StreamEnded(); @@ -428,7 +431,14 @@ PRBool nsWaveStateMachine::IsSeeking() { nsAutoMonitor monitor(mMonitor); - return mState == STATE_SEEKING; + return mState == STATE_SEEKING || mNextState == STATE_SEEKING; +} + +PRBool +nsWaveStateMachine::IsEnded() +{ + nsAutoMonitor monitor(mMonitor); + return mState == STATE_ENDED || mState == STATE_SHUTDOWN; } void @@ -467,7 +477,9 @@ nsWaveStateMachine::Run() newState = STATE_ERROR; } - NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); + if (event) { + NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); + } ChangeState(newState); } } @@ -952,6 +964,7 @@ nsWaveDecoder::nsWaveDecoder() mTimeOffset(0.0), mEndedCurrentTime(0.0), mEndedDuration(std::numeric_limits::quiet_NaN()), + mEnded(PR_FALSE), mNotifyOnShutdown(PR_FALSE), mSeekable(PR_TRUE) { @@ -1075,9 +1088,13 @@ nsWaveDecoder::Stop() } if (mPlaybackThread) { + mPlaybackThread->Shutdown(); + } + + if (mPlaybackStateMachine) { mEndedCurrentTime = mPlaybackStateMachine->GetCurrentTime(); mEndedDuration = mPlaybackStateMachine->GetDuration(); - mPlaybackThread->Shutdown(); + mEnded = mPlaybackStateMachine->IsEnded(); } mPlaybackThread = nsnull; @@ -1193,6 +1210,15 @@ nsWaveDecoder::IsSeeking() const return PR_FALSE; } +PRBool +nsWaveDecoder::IsEnded() const +{ + if (mPlaybackStateMachine) { + return mPlaybackStateMachine->IsEnded(); + } + return mEnded; +} + PRUint64 nsWaveDecoder::GetBytesLoaded() {