Bug 1330254. Part 2 - move NeedToSkipToNextKeyframe() into DecodingState and remove some checks for mState.
MozReview-Commit-ID: FTsXX04rk2p
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -743,16 +743,17 @@ public:
{
SDUMP("mIsPrerolling=%d", mIsPrerolling);
}
private:
void DispatchDecodeTasksIfNeeded();
void EnsureAudioDecodeTaskQueued();
void EnsureVideoDecodeTaskQueued();
+ bool NeedToSkipToNextKeyframe();
void MaybeStartBuffering();
void CheckSlowDecoding(TimeStamp aDecodeStart)
{
// For non async readers, if the requested video sample was slow to
// arrive, increase the amount of audio we buffer to ensure that we
// don't run out of audio. This is unnecessary for async readers,
// since they decode audio and video on different threads so they
@@ -2172,20 +2173,70 @@ void
MediaDecoderStateMachine::
DecodingState::EnsureVideoDecodeTaskQueued()
{
if (!mMaster->IsVideoDecoding() ||
mMaster->IsRequestingVideoData() ||
mMaster->IsWaitingVideoData()) {
return;
}
- mMaster->RequestVideoData(mMaster->NeedToSkipToNextKeyframe(),
+ mMaster->RequestVideoData(NeedToSkipToNextKeyframe(),
media::TimeUnit::FromMicroseconds(mMaster->GetMediaTime()));
}
+bool
+MediaDecoderStateMachine::
+DecodingState::NeedToSkipToNextKeyframe()
+{
+ // Don't skip when we're still decoding first frames.
+ if (!mMaster->mSentFirstFrameLoadedEvent) {
+ return false;
+ }
+
+ // Since GetClock() can only be called after starting MediaSink, we return
+ // false quickly if it is not started because we won't fall behind playback
+ // when not consuming media data.
+ if (!mMaster->mMediaSink->IsStarted()) {
+ return false;
+ }
+
+ if (!mMaster->IsVideoDecoding()) {
+ return false;
+ }
+
+ // Don't skip frame for video-only decoded stream because the clock time of
+ // the stream relies on the video frame.
+ if (mMaster->mAudioCaptured && !mMaster->HasAudio()) {
+ return false;
+ }
+
+ // We'll skip the video decode to the next keyframe if we're low on
+ // audio, or if we're low on video, provided we're not running low on
+ // data to decode. If we're running low on downloaded data to decode,
+ // we won't start keyframe skipping, as we'll be pausing playback to buffer
+ // soon anyway and we'll want to be able to display frames immediately
+ // after buffering finishes. We ignore the low audio calculations for
+ // readers that are async, as since their audio decode runs on a different
+ // task queue it should never run low and skipping won't help their decode.
+ bool isLowOnDecodedAudio = !Reader()->IsAsync() &&
+ mMaster->IsAudioDecoding() &&
+ (mMaster->GetDecodedAudioDuration() <
+ mMaster->mLowAudioThresholdUsecs * mMaster->mPlaybackRate);
+ bool isLowOnDecodedVideo = (mMaster->GetClock() - mMaster->mDecodedVideoEndTime) * mMaster->mPlaybackRate >
+ LOW_VIDEO_THRESHOLD_USECS;
+ bool lowBuffered = mMaster->HasLowBufferedData();
+
+ if ((isLowOnDecodedAudio || isLowOnDecodedVideo) && !lowBuffered) {
+ SLOG("Skipping video decode to the next keyframe lowAudio=%d lowVideo=%d lowUndecoded=%d async=%d",
+ isLowOnDecodedAudio, isLowOnDecodedVideo, lowBuffered, Reader()->IsAsync());
+ return true;
+ }
+
+ return false;
+}
void
MediaDecoderStateMachine::
DecodingState::MaybeStartBuffering()
{
// Buffering makes senses only after decoding first frames.
MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent);
@@ -2602,72 +2653,16 @@ MediaDecoderStateMachine::HaveEnoughDeco
}
bool MediaDecoderStateMachine::HaveEnoughDecodedVideo()
{
MOZ_ASSERT(OnTaskQueue());
return VideoQueue().GetSize() >= GetAmpleVideoFrames() * mPlaybackRate + 1;
}
-bool
-MediaDecoderStateMachine::NeedToSkipToNextKeyframe()
-{
- MOZ_ASSERT(OnTaskQueue());
- // Don't skip when we're still decoding first frames.
- if (!mSentFirstFrameLoadedEvent) {
- return false;
- }
- MOZ_ASSERT(mState == DECODER_STATE_DECODING ||
- mState == DECODER_STATE_BUFFERING ||
- mState == DECODER_STATE_SEEKING);
-
- // Since GetClock() can only be called after starting MediaSink, we return
- // false quickly if it is not started because we won't fall behind playback
- // when not consuming media data.
- if (!mMediaSink->IsStarted()) {
- return false;
- }
-
- // We are in seeking or buffering states, don't skip frame.
- if (!IsVideoDecoding() || mState == DECODER_STATE_BUFFERING ||
- mState == DECODER_STATE_SEEKING) {
- return false;
- }
-
- // Don't skip frame for video-only decoded stream because the clock time of
- // the stream relies on the video frame.
- if (mAudioCaptured && !HasAudio()) {
- return false;
- }
-
- // We'll skip the video decode to the next keyframe if we're low on
- // audio, or if we're low on video, provided we're not running low on
- // data to decode. If we're running low on downloaded data to decode,
- // we won't start keyframe skipping, as we'll be pausing playback to buffer
- // soon anyway and we'll want to be able to display frames immediately
- // after buffering finishes. We ignore the low audio calculations for
- // readers that are async, as since their audio decode runs on a different
- // task queue it should never run low and skipping won't help their decode.
- bool isLowOnDecodedAudio = !mReader->IsAsync() &&
- IsAudioDecoding() &&
- (GetDecodedAudioDuration() <
- mLowAudioThresholdUsecs * mPlaybackRate);
- bool isLowOnDecodedVideo = (GetClock() - mDecodedVideoEndTime) * mPlaybackRate >
- LOW_VIDEO_THRESHOLD_USECS;
- bool lowBuffered = HasLowBufferedData();
-
- if ((isLowOnDecodedAudio || isLowOnDecodedVideo) && !lowBuffered) {
- DECODER_LOG("Skipping video decode to the next keyframe lowAudio=%d lowVideo=%d lowUndecoded=%d async=%d",
- isLowOnDecodedAudio, isLowOnDecodedVideo, lowBuffered, mReader->IsAsync());
- return true;
- }
-
- return false;
-}
-
void
MediaDecoderStateMachine::PushAudio(MediaData* aSample)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(aSample);
AudioQueue().Push(aSample);
}
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -461,20 +461,16 @@ private:
// work is complete and identify which part(a/v) of the sink is shutting down.
void OnMediaSinkAudioComplete();
void OnMediaSinkVideoComplete();
// Rejected by the MediaSink to signal errors for audio/video.
void OnMediaSinkAudioError(nsresult aResult);
void OnMediaSinkVideoError();
- // Return true if the video decoder's decode speed can not catch up the
- // play time.
- bool NeedToSkipToNextKeyframe();
-
void* const mDecoderID;
const RefPtr<FrameStatistics> mFrameStats;
const RefPtr<VideoFrameContainer> mVideoFrameContainer;
const dom::AudioChannel mAudioChannel;
// Task queue for running the state machine.
RefPtr<TaskQueue> mTaskQueue;