Bug 1185972: P1. Remove DECODER_STATE_DECODING_FIRSTFRAME state. r=jwwang

We want to be able to process the steps following decoding of the first frame
independent of a state.
This commit is contained in:
Jean-Yves Avenard 2015-07-22 16:28:14 +10:00
parent 0259a11e37
commit afb92e8070
2 changed files with 49 additions and 40 deletions

View File

@ -217,6 +217,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mDecodeToSeekTarget(false),
mCurrentTimeBeforeSeek(0),
mCorruptFrames(30),
mDecodingFirstFrame(false),
mDisabledHardwareAcceleration(false),
mDecodingFrozenAtStateDecoding(false),
mSentLoadedMetadataEvent(false),
@ -441,7 +442,7 @@ MediaDecoderStateMachine::NeedToDecodeVideo()
HaveEnoughDecodedVideo());
return IsVideoDecoding() &&
((mState == DECODER_STATE_SEEKING && mDecodeToSeekTarget) ||
(mState == DECODER_STATE_DECODING_FIRSTFRAME &&
(IsDecodingFirstFrame() &&
IsVideoDecoding() && VideoQueue().GetSize() == 0) ||
(!mMinimizePreroll && !HaveEnoughDecodedVideo()));
}
@ -451,7 +452,7 @@ MediaDecoderStateMachine::NeedToSkipToNextKeyframe()
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
if (mState == DECODER_STATE_DECODING_FIRSTFRAME) {
if (IsDecodingFirstFrame()) {
return false;
}
MOZ_ASSERT(mState == DECODER_STATE_DECODING ||
@ -508,7 +509,7 @@ MediaDecoderStateMachine::NeedToDecodeAudio()
return IsAudioDecoding() &&
((mState == DECODER_STATE_SEEKING && mDecodeToSeekTarget) ||
(mState == DECODER_STATE_DECODING_FIRSTFRAME &&
(IsDecodingFirstFrame() &&
IsAudioDecoding() && AudioQueue().GetSize() == 0) ||
(!mMinimizePreroll &&
!HaveEnoughDecodedAudio(mAmpleAudioThresholdUsecs * mPlaybackRate) &&
@ -560,12 +561,6 @@ MediaDecoderStateMachine::OnAudioDecoded(AudioData* aAudioSample)
(audio ? audio->mDiscontinuity : 0));
switch (mState) {
case DECODER_STATE_DECODING_FIRSTFRAME: {
Push(audio);
MaybeFinishDecodeFirstFrame();
return;
}
case DECODER_STATE_BUFFERING: {
// If we're buffering, this may be the sample we need to stop buffering.
// Save it and schedule the state machine.
@ -576,6 +571,10 @@ MediaDecoderStateMachine::OnAudioDecoded(AudioData* aAudioSample)
case DECODER_STATE_DECODING: {
Push(audio);
if (IsDecodingFirstFrame()) {
MaybeFinishDecodeFirstFrame();
return;
}
if (mIsAudioPrerolling && DonePrerollingAudio()) {
StopPrerollingAudio();
}
@ -781,13 +780,12 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
StopPrerollingVideo();
}
switch (mState) {
case DECODER_STATE_DECODING_FIRSTFRAME: {
MaybeFinishDecodeFirstFrame();
return;
}
case DECODER_STATE_BUFFERING:
case DECODER_STATE_DECODING: {
if (IsDecodingFirstFrame()) {
MaybeFinishDecodeFirstFrame();
return;
}
CheckIfDecodeComplete();
mDecoder->GetReentrantMonitor().NotifyAll();
// Tell AudioSink to wake up for audio queue is finished.
@ -852,12 +850,6 @@ MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
(video ? video->mDiscontinuity : 0));
switch (mState) {
case DECODER_STATE_DECODING_FIRSTFRAME: {
Push(video);
MaybeFinishDecodeFirstFrame();
return;
}
case DECODER_STATE_BUFFERING: {
// If we're buffering, this may be the sample we need to stop buffering.
// Save it and schedule the state machine.
@ -868,6 +860,10 @@ MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
case DECODER_STATE_DECODING: {
Push(video);
if (IsDecodingFirstFrame()) {
MaybeFinishDecodeFirstFrame();
return;
}
if (mIsVideoPrerolling && DonePrerollingVideo()) {
StopPrerollingVideo();
}
@ -1144,7 +1140,6 @@ static const char* const gMachineStateStr[] = {
"DECODING_METADATA",
"WAIT_FOR_RESOURCES",
"WAIT_FOR_CDM",
"DECODING_FIRSTFRAME",
"DORMANT",
"DECODING",
"SEEKING",
@ -1166,6 +1161,10 @@ void MediaDecoderStateMachine::SetState(State aState)
mState = aState;
if (mState != DECODER_STATE_DECODING) {
mDecodingFirstFrame = false;
}
mIsShutdown = mState == DECODER_STATE_ERROR || mState == DECODER_STATE_SHUTDOWN;
// Clear state-scoped state.
@ -1319,7 +1318,7 @@ void MediaDecoderStateMachine::StartDecoding()
{
MOZ_ASSERT(OnTaskQueue());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mState == DECODER_STATE_DECODING) {
if (mState == DECODER_STATE_DECODING && !mDecodingFirstFrame) {
return;
}
SetState(DECODER_STATE_DECODING);
@ -1353,7 +1352,8 @@ void MediaDecoderStateMachine::NotifyWaitingForResourcesStatusChanged()
ScheduleStateMachine();
} else if (mState == DECODER_STATE_WAIT_FOR_CDM &&
!mReader->IsWaitingOnCDMResource()) {
SetState(DECODER_STATE_DECODING_FIRSTFRAME);
SetState(DECODER_STATE_DECODING);
mDecodingFirstFrame = true;
EnqueueDecodeFirstFrameTask();
}
}
@ -1454,7 +1454,7 @@ MediaDecoderStateMachine::Seek(SeekTarget aTarget)
NS_ASSERTION(mState > DECODER_STATE_DECODING_METADATA,
"We should have got duration already");
if (mState < DECODER_STATE_DECODING) {
if (mState < DECODER_STATE_DECODING || IsDecodingFirstFrame()) {
DECODER_LOG("Seek() Not Enough Data to continue at this stage, queuing seek");
mQueuedSeek.RejectIfExists(__func__);
mQueuedSeek.mTarget = aTarget;
@ -1489,7 +1489,7 @@ MediaDecoderStateMachine::EnqueueDecodeFirstFrameTask()
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
MOZ_ASSERT(mState == DECODER_STATE_DECODING_FIRSTFRAME);
MOZ_ASSERT(IsDecodingFirstFrame());
nsCOMPtr<nsIRunnable> task(
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeFirstFrame));
@ -1504,7 +1504,6 @@ MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
AssertCurrentThreadInMonitor();
if (mState != DECODER_STATE_DECODING &&
mState != DECODER_STATE_DECODING_FIRSTFRAME &&
mState != DECODER_STATE_BUFFERING &&
mState != DECODER_STATE_SEEKING) {
return;
@ -1653,7 +1652,6 @@ MediaDecoderStateMachine::EnsureAudioDecodeTaskQueued()
IsAudioDecoding(), AudioRequestStatus());
if (mState != DECODER_STATE_DECODING &&
mState != DECODER_STATE_DECODING_FIRSTFRAME &&
mState != DECODER_STATE_BUFFERING &&
mState != DECODER_STATE_SEEKING) {
return NS_OK;
@ -1725,7 +1723,6 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued()
IsVideoDecoding(), VideoRequestStatus());
if (mState != DECODER_STATE_DECODING &&
mState != DECODER_STATE_DECODING_FIRSTFRAME &&
mState != DECODER_STATE_BUFFERING &&
mState != DECODER_STATE_SEEKING) {
return NS_OK;
@ -1862,7 +1859,7 @@ bool MediaDecoderStateMachine::HasLowUndecodedData(int64_t aUsecs)
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
NS_ASSERTION(mState > DECODER_STATE_DECODING_FIRSTFRAME,
NS_ASSERTION(mState >= DECODER_STATE_DECODING && !IsDecodingFirstFrame(),
"Must have loaded first frame for mBuffered to be valid");
// If we don't have a duration, mBuffered is probably not going to have
@ -1993,7 +1990,8 @@ MediaDecoderStateMachine::OnMetadataRead(MetadataHolder* aMetadata)
return;
}
SetState(DECODER_STATE_DECODING_FIRSTFRAME);
SetState(DECODER_STATE_DECODING);
mDecodingFirstFrame = true;
EnqueueDecodeFirstFrameTask();
ScheduleStateMachine();
}
@ -2050,7 +2048,7 @@ MediaDecoderStateMachine::CallDecodeFirstFrame()
{
MOZ_ASSERT(OnTaskQueue());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mState != DECODER_STATE_DECODING_FIRSTFRAME) {
if (!IsDecodingFirstFrame()) {
return;
}
if (NS_FAILED(DecodeFirstFrame())) {
@ -2064,7 +2062,7 @@ MediaDecoderStateMachine::DecodeFirstFrame()
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
MOZ_ASSERT(mState == DECODER_STATE_DECODING_FIRSTFRAME);
MOZ_ASSERT(IsDecodingFirstFrame());
DECODER_LOG("DecodeFirstFrame started");
if (IsRealTime()) {
@ -2088,6 +2086,12 @@ MediaDecoderStateMachine::DecodeFirstFrame()
return NS_OK;
}
bool
MediaDecoderStateMachine::IsDecodingFirstFrame()
{
return mState == DECODER_STATE_DECODING && mDecodingFirstFrame;
}
nsresult
MediaDecoderStateMachine::FinishDecodeFirstFrame()
{
@ -2137,11 +2141,13 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
mPendingSeek.Steal(mQueuedSeek);
SetState(DECODER_STATE_SEEKING);
ScheduleStateMachine();
} else if (mState == DECODER_STATE_DECODING_FIRSTFRAME) {
} else if (IsDecodingFirstFrame()) {
// StartDecoding() will also check if decode is completed.
StartDecoding();
}
mDecodingFirstFrame = false;
return NS_OK;
}
@ -2338,12 +2344,11 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
return NS_OK;
}
case DECODER_STATE_DECODING_FIRSTFRAME: {
// DECODER_STATE_DECODING_FIRSTFRAME will be started by OnMetadataRead.
return NS_OK;
}
case DECODER_STATE_DECODING: {
if (IsDecodingFirstFrame()) {
// DECODER_STATE_DECODING will be started by OnMetadataRead.
return NS_OK;
}
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying())
{
// We're playing, but the element/decoder is in paused state. Stop
@ -2890,7 +2895,7 @@ void MediaDecoderStateMachine::UpdateNextFrameStatus()
MediaDecoderOwner::NextFrameStatus status;
const char* statusString;
if (mState <= DECODER_STATE_DECODING_FIRSTFRAME) {
if (mState <= DECODER_STATE_WAIT_FOR_CDM || IsDecodingFirstFrame()) {
status = MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
statusString = "NEXT_FRAME_UNAVAILABLE";
} else if (IsBuffering()) {

View File

@ -138,7 +138,6 @@ public:
DECODER_STATE_DECODING_METADATA,
DECODER_STATE_WAIT_FOR_RESOURCES,
DECODER_STATE_WAIT_FOR_CDM,
DECODER_STATE_DECODING_FIRSTFRAME,
DECODER_STATE_DORMANT,
DECODER_STATE_DECODING,
DECODER_STATE_SEEKING,
@ -407,6 +406,7 @@ protected:
MediaQueue<AudioData>& AudioQueue() { return mAudioQueue; }
MediaQueue<VideoData>& VideoQueue() { return mVideoQueue; }
bool IsDecodingFirstFrame();
nsresult FinishDecodeFirstFrame();
// True if our buffers of decoded audio are not full, and we should
@ -1262,6 +1262,10 @@ private:
mozilla::RollingMean<uint32_t, uint32_t> mCorruptFrames;
// True if we need to call FinishDecodeFirstFrame() upon frame decoding
// successeeding.
bool mDecodingFirstFrame;
bool mDisabledHardwareAcceleration;
// mDecodingFrozenAtStateDecoding: turn on/off at