зеркало из https://github.com/mozilla/pjs.git
Bug 476811. Fire 'waiting' event when the decoder starts buffering. r=doublec
--HG-- extra : rebase_source : 1ac5d728e4f3f3e83de61d0806b20f328cdf380c
This commit is contained in:
Родитель
bf033eb12c
Коммит
520f7cff94
|
@ -134,7 +134,16 @@ public:
|
|||
// 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.
|
||||
void UpdateReadyStateForData(PRBool aNextFrameAvailable);
|
||||
enum NextFrameStatus {
|
||||
// The next frame of audio/video is available
|
||||
NEXT_FRAME_AVAILABLE,
|
||||
// The next frame of audio/video is unavailable because the decoder
|
||||
// is paused while it buffers up data
|
||||
NEXT_FRAME_UNAVAILABLE_BUFFERING,
|
||||
// The next frame of audio/video is unavailable for some other reasons
|
||||
NEXT_FRAME_UNAVAILABLE
|
||||
};
|
||||
void UpdateReadyStateForData(NextFrameStatus aNextFrame);
|
||||
|
||||
// Use this method to change the mReadyState member, so required
|
||||
// events can be fired.
|
||||
|
@ -272,4 +281,8 @@ protected:
|
|||
// to ensure that the playstate doesn't change when the user goes Forward/Back
|
||||
// from the bfcache.
|
||||
PRPackedBool mPausedBeforeFreeze;
|
||||
|
||||
// PR_TRUE if we've reported a "waiting" event since the last
|
||||
// readyState change to HAVE_CURRENT_DATA.
|
||||
PRPackedBool mWaitingFired;
|
||||
};
|
||||
|
|
|
@ -506,7 +506,8 @@ nsHTMLMediaElement::nsHTMLMediaElement(nsINodeInfo *aNodeInfo, PRBool aFromParse
|
|||
mPaused(PR_TRUE),
|
||||
mMuted(PR_FALSE),
|
||||
mIsDoneAddingChildren(!aFromParser),
|
||||
mPlayingBeforeSeek(PR_FALSE)
|
||||
mPlayingBeforeSeek(PR_FALSE),
|
||||
mWaitingFired(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1018,16 +1019,21 @@ PRBool nsHTMLMediaElement::ShouldCheckAllowOrigin()
|
|||
// or other conditions are worse than expected
|
||||
static const PRInt32 gDownloadSizeSafetyMargin = 1000000;
|
||||
|
||||
void nsHTMLMediaElement::UpdateReadyStateForData(PRBool aNextFrameAvailable)
|
||||
void nsHTMLMediaElement::UpdateReadyStateForData(NextFrameStatus aNextFrame)
|
||||
{
|
||||
if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
|
||||
NS_ASSERTION(!aNextFrameAvailable, "How can we have a frame but no metadata?");
|
||||
NS_ASSERTION(aNextFrame != NEXT_FRAME_AVAILABLE,
|
||||
"How can we have a frame but no metadata?");
|
||||
// The arrival of more data can't change us out of this state.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aNextFrameAvailable && !mDecoder->IsEnded()) {
|
||||
if (aNextFrame != NEXT_FRAME_AVAILABLE && !mDecoder->IsEnded()) {
|
||||
ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
|
||||
if (!mWaitingFired && aNextFrame == NEXT_FRAME_UNAVAILABLE_BUFFERING) {
|
||||
DispatchAsyncSimpleEvent(NS_LITERAL_STRING("waiting"));
|
||||
mWaitingFired = PR_TRUE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1085,6 +1091,7 @@ void nsHTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
|
|||
case nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA:
|
||||
if (oldState != mReadyState) {
|
||||
LOG(PR_LOG_DEBUG, ("Ready state changed to HAVE_CURRENT_DATA"));
|
||||
mWaitingFired = PR_FALSE;
|
||||
}
|
||||
if (oldState <= nsIDOMHTMLMediaElement::HAVE_METADATA &&
|
||||
!mLoadedFirstFrame) {
|
||||
|
|
|
@ -422,10 +422,6 @@ protected:
|
|||
// Call on the main thread only.
|
||||
void PlaybackEnded();
|
||||
|
||||
// Buffering of data has stopped. Inform the element on the main
|
||||
// thread.
|
||||
void BufferingStopped();
|
||||
|
||||
// Seeking has stopped. Inform the element on the main
|
||||
// thread.
|
||||
void SeekingStopped();
|
||||
|
@ -439,16 +435,16 @@ protected:
|
|||
// This must be called on the main thread only.
|
||||
void PlaybackPositionChanged();
|
||||
|
||||
// Calls mElement->UpdateReadyStateForData, telling it whether we have
|
||||
// data for the next frame and if we're buffering. Main thread only.
|
||||
void UpdateReadyStateForData();
|
||||
|
||||
private:
|
||||
// Register/Unregister with Shutdown Observer.
|
||||
// Call on main thread only.
|
||||
void RegisterShutdownObserver();
|
||||
void UnregisterShutdownObserver();
|
||||
|
||||
// Calls mElement->UpdateReadyStateForData, telling it whether we have
|
||||
// data for the next frame.
|
||||
void UpdateReadyStateForData();
|
||||
|
||||
/******
|
||||
* The following members should be accessed with the decoder lock held.
|
||||
******/
|
||||
|
|
|
@ -221,13 +221,10 @@ class nsWaveDecoder : public nsMediaDecoder
|
|||
// main thread only.
|
||||
virtual void Resume();
|
||||
|
||||
private:
|
||||
// Change the element's ready state as necessary
|
||||
// Change the element's ready state as necessary. Main thread only.
|
||||
void UpdateReadyStateForData();
|
||||
|
||||
// Notifies the element that buffering has stopped.
|
||||
void BufferingStopped();
|
||||
|
||||
private:
|
||||
// Notifies the element that seeking has started.
|
||||
void SeekingStarted();
|
||||
|
||||
|
|
|
@ -308,7 +308,15 @@ public:
|
|||
// Must be called with the decode monitor held. Can be called by main
|
||||
// thread.
|
||||
PRBool HaveNextFrameData() const {
|
||||
return !mDecodedFrames.IsEmpty();
|
||||
return !mDecodedFrames.IsEmpty() &&
|
||||
(mState == DECODER_STATE_DECODING ||
|
||||
mState == DECODER_STATE_COMPLETED);
|
||||
}
|
||||
|
||||
// Must be called with the decode monitor held. Can be called by main
|
||||
// thread.
|
||||
PRBool IsBuffering() const {
|
||||
return mState == nsOggDecodeStateMachine::DECODER_STATE_BUFFERING;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -993,6 +1001,19 @@ nsresult nsOggDecodeStateMachine::Run()
|
|||
StopPlayback();
|
||||
}
|
||||
|
||||
// We need to tell the element that buffering has started.
|
||||
// We can't just directly send an asynchronous runnable that
|
||||
// eventually fires the "waiting" event. The problem is that
|
||||
// there might be pending main-thread events, such as "data
|
||||
// received" notifications, that mean we're not actually still
|
||||
// buffering by the time this runnable executes. So instead
|
||||
// we just trigger UpdateReadyStateForData; when it runs, it
|
||||
// will check the current state and decide whether to tell
|
||||
// the element we're buffering or not.
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, UpdateReadyStateForData);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
|
||||
mBufferingStart = PR_IntervalNow();
|
||||
double playbackRate = mDecoder->GetStatistics().mPlaybackRate;
|
||||
mBufferingBytes = BUFFERING_RATE(playbackRate) * BUFFERING_WAIT;
|
||||
|
@ -1096,7 +1117,7 @@ nsresult nsOggDecodeStateMachine::Run()
|
|||
|
||||
if (mState != DECODER_STATE_BUFFERING) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, BufferingStopped);
|
||||
NS_NEW_RUNNABLE_METHOD(nsOggDecoder, mDecoder, UpdateReadyStateForData);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
if (mDecoder->GetState() == nsOggDecoder::PLAY_STATE_PLAYING) {
|
||||
if (!mPlaying) {
|
||||
|
@ -1769,17 +1790,18 @@ void nsOggDecoder::UpdateReadyStateForData()
|
|||
if (!mElement || mShuttingDown || !mDecodeStateMachine)
|
||||
return;
|
||||
|
||||
PRBool haveNextFrame;
|
||||
nsHTMLMediaElement::NextFrameStatus frameStatus;
|
||||
{
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
haveNextFrame = mDecodeStateMachine->HaveNextFrameData();
|
||||
if (mDecodeStateMachine->HaveNextFrameData()) {
|
||||
frameStatus = nsHTMLMediaElement::NEXT_FRAME_AVAILABLE;
|
||||
} else if (mDecodeStateMachine->IsBuffering()) {
|
||||
frameStatus = nsHTMLMediaElement::NEXT_FRAME_UNAVAILABLE_BUFFERING;
|
||||
} else {
|
||||
frameStatus = nsHTMLMediaElement::NEXT_FRAME_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
mElement->UpdateReadyStateForData(haveNextFrame);
|
||||
}
|
||||
|
||||
void nsOggDecoder::BufferingStopped()
|
||||
{
|
||||
UpdateReadyStateForData();
|
||||
mElement->UpdateReadyStateForData(frameStatus);
|
||||
}
|
||||
|
||||
void nsOggDecoder::SeekingStopped()
|
||||
|
|
|
@ -174,8 +174,8 @@ public:
|
|||
// Called on any thread
|
||||
void NotifyBytesConsumed(PRInt64 aBytes);
|
||||
|
||||
// Called by the main thread
|
||||
PRBool HasPendingData();
|
||||
// Called by the main thread only
|
||||
nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus();
|
||||
|
||||
private:
|
||||
// Change the current state and wake the playback thread if it is waiting
|
||||
|
@ -492,11 +492,15 @@ nsWaveStateMachine::StreamEnded(PRBool aAtEnd)
|
|||
}
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsWaveStateMachine::HasPendingData()
|
||||
nsHTMLMediaElement::NextFrameStatus
|
||||
nsWaveStateMachine::GetNextFrameStatus()
|
||||
{
|
||||
nsAutoMonitor monitor(mMonitor);
|
||||
return mPlaybackPosition < mDownloadPosition;
|
||||
if (mPlaybackPosition < mDownloadPosition)
|
||||
return nsHTMLMediaElement::NEXT_FRAME_AVAILABLE;
|
||||
if (mState == STATE_BUFFERING)
|
||||
return nsHTMLMediaElement::NEXT_FRAME_UNAVAILABLE_BUFFERING;
|
||||
return nsHTMLMediaElement::NEXT_FRAME_UNAVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -549,7 +553,7 @@ nsWaveStateMachine::Run()
|
|||
} else {
|
||||
ChangeState(mNextState);
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, BufferingStopped);
|
||||
NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, UpdateReadyStateForData);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
|
@ -568,6 +572,11 @@ nsWaveStateMachine::Run()
|
|||
// Buffer until mBufferingWait milliseconds of data is available.
|
||||
mBufferingBytes = TimeToBytes(float(mBufferingWait) / 1000.0);
|
||||
mBufferingStart = PR_IntervalNow();
|
||||
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, UpdateReadyStateForData);
|
||||
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
|
||||
|
||||
ChangeState(STATE_BUFFERING);
|
||||
} else {
|
||||
// Media stream has ended and there is less data available than a
|
||||
|
@ -1489,15 +1498,13 @@ nsWaveDecoder::UpdateReadyStateForData()
|
|||
if (!mElement || mShuttingDown || !mPlaybackStateMachine)
|
||||
return;
|
||||
|
||||
PRBool haveDataToPlay =
|
||||
mPlaybackStateMachine->HasPendingData() && mMetadataLoadedReported;
|
||||
mElement->UpdateReadyStateForData(haveDataToPlay);
|
||||
}
|
||||
|
||||
void
|
||||
nsWaveDecoder::BufferingStopped()
|
||||
{
|
||||
UpdateReadyStateForData();
|
||||
nsHTMLMediaElement::NextFrameStatus frameStatus =
|
||||
mPlaybackStateMachine->GetNextFrameStatus();
|
||||
if (frameStatus == nsHTMLMediaElement::NEXT_FRAME_AVAILABLE &&
|
||||
!mMetadataLoadedReported) {
|
||||
frameStatus = nsHTMLMediaElement::NEXT_FRAME_UNAVAILABLE;
|
||||
}
|
||||
mElement->UpdateReadyStateForData(frameStatus);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Загрузка…
Ссылка в новой задаче