--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -189,17 +189,18 @@ public:
virtual void Exit() {}; // Exit action.
virtual void Step() {} // Perform a 'cycle' of this state object.
virtual State GetState() const = 0;
// Event handlers for various events.
virtual void HandleCDMProxyReady() {}
virtual void HandleAudioDecoded(MediaData* aAudio) {}
virtual void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) {}
- virtual void HandleNotDecoded(MediaData::Type aType, const MediaResult& aError);
+ virtual void HandleAudioNotDecoded(const MediaResult& aError);
+ virtual void HandleVideoNotDecoded(const MediaResult& aError);
virtual void HandleAudioWaited(MediaData::Type aType);
virtual void HandleVideoWaited(MediaData::Type aType);
virtual void HandleNotWaited(const WaitForDataRejectValue& aRejection);
virtual void HandleEndOfStream() {}
virtual void HandleWaitingForData() {}
virtual void HandleAudioCaptured() {}
virtual RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget);
@@ -795,25 +796,21 @@ public:
virtual void Exit() override = 0;
State GetState() const override
{
return DECODER_STATE_SEEKING;
}
void HandleAudioDecoded(MediaData* aAudio) override = 0;
-
void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override = 0;
-
- void HandleNotDecoded(MediaData::Type aType, const MediaResult& aError) override = 0;
-
+ void HandleAudioNotDecoded(const MediaResult& aError) override = 0;
+ void HandleVideoNotDecoded(const MediaResult& aError) override = 0;
void HandleAudioWaited(MediaData::Type aType) override = 0;
-
void HandleVideoWaited(MediaData::Type aType) override = 0;
-
void HandleNotWaited(const WaitForDataRejectValue& aRejection) override = 0;
void HandleVideoSuspendTimeout() override
{
// Do nothing since we want a valid video frame to show when seek is done.
}
void HandleResumeVideoDecoding() override
@@ -915,61 +912,18 @@ public:
if (!mDoneVideoSeeking) {
RequestVideoData();
return;
}
MaybeFinishSeek();
}
- void HandleNotDecoded(MediaData::Type aType, const MediaResult& aError) override
- {
- MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking, "Seek shouldn't be finished");
-
- // Ignore pending requests from video-only seek.
- if (aType == MediaData::AUDIO_DATA && mSeekJob.mTarget->IsVideoOnly()) {
- return;
- }
-
- // If the decoder is waiting for data, we tell it to call us back when the
- // data arrives.
- if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
- mMaster->WaitForData(aType);
- return;
- }
-
- if (aError == NS_ERROR_DOM_MEDIA_CANCELED) {
- if (aType == MediaData::AUDIO_DATA) {
- RequestAudioData();
- } else {
- RequestVideoData();
- }
- return;
- }
-
- if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
- if (aType == MediaData::AUDIO_DATA) {
- AudioQueue().Finish();
- mDoneAudioSeeking = true;
- } else {
- if (mFirstVideoFrameAfterSeek) {
- // Hit the end of stream. Move mFirstVideoFrameAfterSeek into
- // mSeekedVideoData so we have something to display after seeking.
- mMaster->PushVideo(mFirstVideoFrameAfterSeek);
- }
- VideoQueue().Finish();
- mDoneVideoSeeking = true;
- }
- MaybeFinishSeek();
- return;
- }
-
- // This is a decode error, delegate to the generic error path.
- mMaster->DecodeError(aError);
- }
+ void HandleAudioNotDecoded(const MediaResult& aError) override;
+ void HandleVideoNotDecoded(const MediaResult& aError) override;
void HandleAudioWaited(MediaData::Type aType) override
{
MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking, "Seek shouldn't be finished");
// Ignore pending requests from video-only seek.
if (mSeekJob.mTarget->IsVideoOnly()) {
return;
@@ -1371,58 +1325,18 @@ private:
if (aVideo->mTime > mCurrentTime) {
mMaster->PushVideo(aVideo);
FinishSeek();
} else {
RequestVideoData();
}
}
- void HandleNotDecoded(MediaData::Type aType, const MediaResult& aError) override
- {
- MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
- MOZ_ASSERT(NeedMoreVideo());
-
- switch (aType) {
- case MediaData::AUDIO_DATA:
- {
- // We don't care about audio decode errors in this state which will be
- // handled by other states after seeking.
- break;
- }
- case MediaData::VIDEO_DATA:
- {
- if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
- VideoQueue().Finish();
- FinishSeek();
- break;
- }
-
- // Video seek not finished.
- switch (aError.Code()) {
- case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
- mMaster->WaitForData(MediaData::VIDEO_DATA);
- break;
- case NS_ERROR_DOM_MEDIA_CANCELED:
- RequestVideoData();
- break;
- case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
- MOZ_ASSERT(false, "Shouldn't want more data for ended video.");
- break;
- default:
- // Raise an error since we can't finish video seek anyway.
- mMaster->DecodeError(aError);
- break;
- }
- break;
- }
- default:
- MOZ_ASSERT_UNREACHABLE("We cannot handle RAW_DATA or NULL_DATA here.");
- }
- }
+ void HandleAudioNotDecoded(const MediaResult& aError) override;
+ void HandleVideoNotDecoded(const MediaResult& aError) override;
void HandleAudioWaited(MediaData::Type aType) override
{
// We don't care about audio in this state.
}
void HandleVideoWaited(MediaData::Type aType) override
{
@@ -1703,20 +1617,18 @@ public:
MOZ_DIAGNOSTIC_ASSERT(false, "Shouldn't escape the SHUTDOWN state.");
}
State GetState() const override
{
return DECODER_STATE_SHUTDOWN;
}
- void HandleNotDecoded(MediaData::Type aType, const MediaResult& aError) override
- {
- return;
- }
+ void HandleAudioNotDecoded(const MediaResult& aError) override {}
+ void HandleVideoNotDecoded(const MediaResult& aError) override {}
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
{
MOZ_DIAGNOSTIC_ASSERT(false, "Can't seek in shutdown state.");
return MediaDecoder::SeekPromise::CreateAndReject(true, __func__);
}
RefPtr<ShutdownPromise> HandleShutdown() override
@@ -1733,57 +1645,16 @@ public:
void HandleResumeVideoDecoding() override
{
MOZ_DIAGNOSTIC_ASSERT(false, "Already shutting down.");
}
};
void
MediaDecoderStateMachine::
-StateObject::HandleNotDecoded(MediaData::Type aType, const MediaResult& aError)
-{
- bool isAudio = aType == MediaData::AUDIO_DATA;
- MOZ_ASSERT_IF(!isAudio, aType == MediaData::VIDEO_DATA);
-
- // If the decoder is waiting for data, we tell it to call us back when the
- // data arrives.
- if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
- mMaster->WaitForData(aType);
- HandleWaitingForData();
- return;
- }
-
- if (aError == NS_ERROR_DOM_MEDIA_CANCELED) {
- if (isAudio) {
- mMaster->EnsureAudioDecodeTaskQueued();
- } else {
- mMaster->EnsureVideoDecodeTaskQueued();
- }
- return;
- }
-
- // If this is a decode error, delegate to the generic error path.
- if (aError != NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
- mMaster->DecodeError(aError);
- return;
- }
-
- // This is an EOS. Finish off the queue, and then handle things based on our
- // state.
- if (isAudio) {
- AudioQueue().Finish();
- } else {
- VideoQueue().Finish();
- }
-
- HandleEndOfStream();
-}
-
-void
-MediaDecoderStateMachine::
StateObject::HandleAudioWaited(MediaData::Type aType)
{
mMaster->EnsureAudioDecodeTaskQueued();
}
void
MediaDecoderStateMachine::
StateObject::HandleVideoWaited(MediaData::Type aType)
@@ -1793,16 +1664,58 @@ StateObject::HandleVideoWaited(MediaData
void
MediaDecoderStateMachine::
StateObject::HandleNotWaited(const WaitForDataRejectValue& aRejection)
{
}
+void
+MediaDecoderStateMachine::
+StateObject::HandleAudioNotDecoded(const MediaResult& aError)
+{
+ switch (aError.Code()) {
+ case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+ mMaster->WaitForData(MediaData::AUDIO_DATA);
+ HandleWaitingForData();
+ break;
+ case NS_ERROR_DOM_MEDIA_CANCELED:
+ mMaster->EnsureAudioDecodeTaskQueued();
+ break;
+ case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+ AudioQueue().Finish();
+ HandleEndOfStream();
+ break;
+ default:
+ mMaster->DecodeError(aError);
+ }
+}
+
+void
+MediaDecoderStateMachine::
+StateObject::HandleVideoNotDecoded(const MediaResult& aError)
+{
+ switch (aError.Code()) {
+ case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+ mMaster->WaitForData(MediaData::VIDEO_DATA);
+ HandleWaitingForData();
+ break;
+ case NS_ERROR_DOM_MEDIA_CANCELED:
+ mMaster->EnsureVideoDecodeTaskQueued();
+ break;
+ case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+ VideoQueue().Finish();
+ HandleEndOfStream();
+ break;
+ default:
+ mMaster->DecodeError(aError);
+ }
+}
+
RefPtr<MediaDecoder::SeekPromise>
MediaDecoderStateMachine::
StateObject::HandleSeek(SeekTarget aTarget)
{
SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
SeekJob seekJob;
seekJob.mTarget = Some(aTarget);
return SetSeekingState(Move(seekJob), EventVisibility::Observable);
@@ -2135,16 +2048,102 @@ SeekingState::SeekCompleted()
mMaster->mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
}
SetState<DecodingState>();
}
void
MediaDecoderStateMachine::
+AccurateSeekingState::HandleAudioNotDecoded(const MediaResult& aError)
+{
+ if (mSeekJob.mTarget->IsVideoOnly()) {
+ return;
+ }
+ MOZ_ASSERT(!mDoneAudioSeeking);
+ switch (aError.Code()) {
+ case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+ mMaster->WaitForData(MediaData::AUDIO_DATA);
+ break;
+ case NS_ERROR_DOM_MEDIA_CANCELED:
+ RequestAudioData();
+ break;
+ case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+ AudioQueue().Finish();
+ mDoneAudioSeeking = true;
+ MaybeFinishSeek();
+ break;
+ default:
+ mMaster->DecodeError(aError);
+ }
+}
+
+void
+MediaDecoderStateMachine::
+AccurateSeekingState::HandleVideoNotDecoded(const MediaResult& aError)
+{
+ MOZ_ASSERT(!mDoneVideoSeeking);
+ switch (aError.Code()) {
+ case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+ mMaster->WaitForData(MediaData::VIDEO_DATA);
+ break;
+ case NS_ERROR_DOM_MEDIA_CANCELED:
+ RequestVideoData();
+ break;
+ case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+ if (mFirstVideoFrameAfterSeek) {
+ // Hit the end of stream. Move mFirstVideoFrameAfterSeek into
+ // mSeekedVideoData so we have something to display after seeking.
+ mMaster->PushVideo(mFirstVideoFrameAfterSeek);
+ }
+ VideoQueue().Finish();
+ mDoneVideoSeeking = true;
+ MaybeFinishSeek();
+ break;
+ default:
+ mMaster->DecodeError(aError);
+ }
+}
+
+void
+MediaDecoderStateMachine::
+NextFrameSeekingState::HandleAudioNotDecoded(const MediaResult& aError)
+{
+ MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
+ MOZ_ASSERT(NeedMoreVideo());
+ // We don't care about audio decode errors in this state which will be
+ // handled by other states after seeking.
+}
+
+void
+MediaDecoderStateMachine::
+NextFrameSeekingState::HandleVideoNotDecoded(const MediaResult& aError)
+{
+ MOZ_ASSERT(!mSeekJob.mPromise.IsEmpty(), "Seek shouldn't be finished");
+ MOZ_ASSERT(NeedMoreVideo());
+ // Video seek not finished.
+ switch (aError.Code()) {
+ case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
+ mMaster->WaitForData(MediaData::VIDEO_DATA);
+ break;
+ case NS_ERROR_DOM_MEDIA_CANCELED:
+ RequestVideoData();
+ break;
+ case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
+ VideoQueue().Finish();
+ FinishSeek();
+ break;
+ default:
+ // Raise an error since we can't finish video seek anyway.
+ mMaster->DecodeError(aError);
+ }
+}
+
+void
+MediaDecoderStateMachine::
BufferingState::Step()
{
TimeStamp now = TimeStamp::Now();
MOZ_ASSERT(!mBufferingStart.IsNull(), "Must know buffering start time.");
// With buffering heuristics we will remain in the buffering state if
// we've not decoded enough data to begin playback, or if we've not
// downloaded a reasonable amount of data inside our buffering time.
@@ -3003,17 +3002,17 @@ MediaDecoderStateMachine::RequestAudioDa
// audio->GetEndTime() is not always mono-increasing in chained ogg.
mDecodedAudioEndTime = std::max(aAudio->GetEndTime(), mDecodedAudioEndTime);
SAMPLE_LOG("OnAudioDecoded [%lld,%lld]", aAudio->mTime, aAudio->GetEndTime());
mStateObj->HandleAudioDecoded(aAudio);
},
[this] (const MediaResult& aError) {
SAMPLE_LOG("OnAudioNotDecoded aError=%u", aError.Code());
mAudioDataRequest.Complete();
- mStateObj->HandleNotDecoded(MediaData::AUDIO_DATA, aError);
+ mStateObj->HandleAudioNotDecoded(aError);
})
);
}
void
MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded()
{
MOZ_ASSERT(OnTaskQueue());
@@ -3069,17 +3068,17 @@ MediaDecoderStateMachine::RequestVideoDa
// Handle abnormal or negative timestamps.
mDecodedVideoEndTime = std::max(mDecodedVideoEndTime, aVideo->GetEndTime());
SAMPLE_LOG("OnVideoDecoded [%lld,%lld]", aVideo->mTime, aVideo->GetEndTime());
mStateObj->HandleVideoDecoded(aVideo, videoDecodeStartTime);
},
[this] (const MediaResult& aError) {
SAMPLE_LOG("OnVideoNotDecoded aError=%u", aError.Code());
mVideoDataRequest.Complete();
- mStateObj->HandleNotDecoded(MediaData::VIDEO_DATA, aError);
+ mStateObj->HandleVideoNotDecoded(aError);
})
);
}
void
MediaDecoderStateMachine::WaitForData(MediaData::Type aType)
{
MOZ_ASSERT(OnTaskQueue());