mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1186367 - Make MDSM more ignorant of AudioData/VideoData via using MediaQueue<MediaData> instead. r=jwwang (344314a04) - missing of Bug 1123637 - Remove all code relevant to quota prompts; r=bent,ehsan (ac63ae831) - Bug 1185892. Part 1 - delegate the job of MediaSourceDecoder::IsExpectingMoreData to its MediaResource. r=jya. (64da133b6) - Bug 1185892. Part 2 - delegate the job of MediaDecoder::IsExpectingMoreData to its MediaResource. r=jya. (4bca8324d) - Bug 1185892. Part 3 - replace all calls to MediaDecoder::IsExpectingMoreData() with MediaResource::IsExpectingMoreData. r=jya. (3780bf754) - fix misspatch of Bug 1134434 (976064ea5) - Bug 1185972: P1. Remove DECODER_STATE_DECODING_FIRSTFRAME state. r=jwwang (dee513d1c) - Bug 1185972: P2. Refactor handling of first frame decoded. r=jwwang (95482e8b9) - Bug 1185972: P4. Initiate seek as early as conditions permit. r=jwwang (f938e673b) - Bug 1148103: P1. Fix mediasource "once" utility. r=karlt (ba3e21d59) - Bug 1148103: P2. Add MP4 mediasource mochitests. r=karlt (199372ab6) - Bug 1136399 - Add test_WaitingOnMissingData_mp4.html and disable the webm version for now. r=jya (ab349f245) - Bug 1185972: P6. Ensure exiting dormant mode has completed seek before notifying decoder. r=jwwang (5a9252b75) - Bug 1185972: P3. Don't reduce our buffer threshold coming out of dormant mode. r=jwwang (bf76f6b7d) - bug 1190285 remove unused GetCurrentTime() r=padenot (95c322cb6) - bug 1190285 unvirtualize MediaStream::AdvanceTimeVaryingValuesToCurrentTime() r=roc (80f536d5a) - bug 1190285 remove unused DispatchWhenNotEnoughBuffered r=padenot (6fa27d274) - bug 1190285 remove unused HaveEnoughBuffered r=padenot (0941a1af7) - bug 1190285 move GetIntervalForIteration() from base class to ThreadedDriver, where it is used r=padenot (0faaf6db8) - bug 1190285 share ThreadedDriver interval update code r=padenot (3d5d5ce35) - bug 1190285 only update mStateComputedTime once per iteration r=padenot (b6cea757a) - bug 1190285 remove unused MediaStreamGraphImpl::GetAudioPosition() r=roc (b14738229) - bug 1190285 remove unused graph update indices r=roc (475b980fe) - Bug 1188257 - Use MediaEventSource for MediaQueue to do the job. r=cpearce. (4d16a4595) - Bug 1189624 - Have AudioSink listen to MediaQueue events to know whether to continue playback. r=kinetik. (753ab8ca2) - Bug 1191173 - Mirror MediaDecoder::mSameOriginMedia in MDSM. r=jya. (d4690cb87) - Bug 1191170 - Move DecodedStreamData from the header to its source file. r=roc. (d5726e979) - Bug 1191171 - Add SetVolume() to DecodedStream. r=roc. (20e87ac20) - Bug 1182649 - Log a message when disabling DXVA due to too many invalid frames. r=jrmuizel (0d951a60c) - Bug 1185416 - Don't stop AudioSink prematurely when decoding is completed. r=kinetik. (1ac43f91e) - Bug 1186752 - Remove ScheduleStateMachine() in MediaDecoder.cpp since we have state mirror. r=jwwang (1e89c535c) - Bug 1191684 - Remove unnecessary calls to NotifyAll() on the decoder monitor since no one calls Wait(). r=cpearce. (54a95a5a0)
This commit is contained in:
@@ -214,6 +214,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
mDecodeToSeekTarget(false),
|
||||
mCurrentTimeBeforeSeek(0),
|
||||
mCorruptFrames(30),
|
||||
mDecodingFirstFrame(true),
|
||||
mDisabledHardwareAcceleration(false),
|
||||
mDecodingFrozenAtStateDecoding(false),
|
||||
mSentLoadedMetadataEvent(false),
|
||||
@@ -280,13 +281,13 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
nsRefPtr<MediaDecoderStateMachine> self = this;
|
||||
|
||||
AudioQueue().AddPopListener(
|
||||
[self] (const AudioData* aSample) {
|
||||
self->OnAudioPopped(aSample);
|
||||
}, mTaskQueue);
|
||||
[self] (const MediaData* aSample) {
|
||||
self->OnAudioPopped(aSample->As<AudioData>());
|
||||
}, mTaskQueue);
|
||||
|
||||
VideoQueue().AddPopListener(
|
||||
[self] (const VideoData* aSample) {
|
||||
self->OnVideoPopped(aSample);
|
||||
[self] (const MediaData* aSample) {
|
||||
self->OnVideoPopped(aSample->As<VideoData>());
|
||||
}, mTaskQueue);
|
||||
}
|
||||
|
||||
@@ -377,13 +378,14 @@ void MediaDecoderStateMachine::SendStreamData()
|
||||
|
||||
const auto clockTime = GetClock();
|
||||
while (true) {
|
||||
const AudioData* a = AudioQueue().PeekFront();
|
||||
const MediaData* a = AudioQueue().PeekFront();
|
||||
|
||||
// If we discard audio samples fed to the stream immediately, we will
|
||||
// keep decoding audio samples till the end and consume a lot of memory.
|
||||
// Therefore we only discard those behind the stream clock to throttle
|
||||
// the decoding speed.
|
||||
if (a && a->mTime <= clockTime) {
|
||||
nsRefPtr<AudioData> releaseMe = AudioQueue().PopFront();
|
||||
nsRefPtr<MediaData> releaseMe = AudioQueue().PopFront();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -406,9 +408,8 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs)
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't have to check SourceMediaStream::HaveEnoughBuffered() in the
|
||||
// case of stream-capture for MDSM will ensure buffering level is high enough
|
||||
// for playback speed at 1x at which the DecodedStream is playing.
|
||||
// MDSM will ensure buffering level is high enough for playback speed at 1x
|
||||
// at which the DecodedStream is playing.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -435,7 +436,7 @@ MediaDecoderStateMachine::NeedToDecodeVideo()
|
||||
HaveEnoughDecodedVideo());
|
||||
return IsVideoDecoding() &&
|
||||
((mState == DECODER_STATE_SEEKING && mDecodeToSeekTarget) ||
|
||||
(mState == DECODER_STATE_DECODING_FIRSTFRAME &&
|
||||
(IsDecodingFirstFrame() &&
|
||||
IsVideoDecoding() && VideoQueue().GetSize() == 0) ||
|
||||
(!mMinimizePreroll && !HaveEnoughDecodedVideo()));
|
||||
}
|
||||
@@ -445,7 +446,7 @@ MediaDecoderStateMachine::NeedToSkipToNextKeyframe()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
if (mState == DECODER_STATE_DECODING_FIRSTFRAME) {
|
||||
if (IsDecodingFirstFrame()) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(mState == DECODER_STATE_DECODING ||
|
||||
@@ -502,7 +503,7 @@ MediaDecoderStateMachine::NeedToDecodeAudio()
|
||||
|
||||
return IsAudioDecoding() &&
|
||||
((mState == DECODER_STATE_SEEKING && mDecodeToSeekTarget) ||
|
||||
(mState == DECODER_STATE_DECODING_FIRSTFRAME &&
|
||||
(IsDecodingFirstFrame() &&
|
||||
IsAudioDecoding() && AudioQueue().GetSize() == 0) ||
|
||||
(!mMinimizePreroll &&
|
||||
!HaveEnoughDecodedAudio(mAmpleAudioThresholdUsecs * mPlaybackRate) &&
|
||||
@@ -554,12 +555,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.
|
||||
@@ -570,6 +565,9 @@ MediaDecoderStateMachine::OnAudioDecoded(AudioData* aAudioSample)
|
||||
|
||||
case DECODER_STATE_DECODING: {
|
||||
Push(audio);
|
||||
if (MaybeFinishDecodeFirstFrame()) {
|
||||
return;
|
||||
}
|
||||
if (mIsAudioPrerolling && DonePrerollingAudio()) {
|
||||
StopPrerollingAudio();
|
||||
}
|
||||
@@ -773,13 +771,11 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
||||
StopPrerollingVideo();
|
||||
}
|
||||
switch (mState) {
|
||||
case DECODER_STATE_DECODING_FIRSTFRAME: {
|
||||
MaybeFinishDecodeFirstFrame();
|
||||
return;
|
||||
}
|
||||
|
||||
case DECODER_STATE_BUFFERING:
|
||||
case DECODER_STATE_DECODING: {
|
||||
if (MaybeFinishDecodeFirstFrame()) {
|
||||
return;
|
||||
}
|
||||
CheckIfDecodeComplete();
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
// Tell AudioSink to wake up for audio queue is finished.
|
||||
@@ -813,18 +809,26 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
MediaDecoderStateMachine::MaybeFinishDecodeFirstFrame()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
if ((IsAudioDecoding() && AudioQueue().GetSize() == 0) ||
|
||||
if (!IsDecodingFirstFrame() ||
|
||||
(IsAudioDecoding() && AudioQueue().GetSize() == 0) ||
|
||||
(IsVideoDecoding() && VideoQueue().GetSize() == 0)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (NS_FAILED(FinishDecodeFirstFrame())) {
|
||||
DecodeError();
|
||||
FinishDecodeFirstFrame();
|
||||
if (!mQueuedSeek.Exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can now complete the pending seek.
|
||||
mPendingSeek.Steal(mQueuedSeek);
|
||||
SetState(DECODER_STATE_SEEKING);
|
||||
ScheduleStateMachine();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -844,12 +848,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.
|
||||
@@ -860,6 +858,9 @@ MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
|
||||
|
||||
case DECODER_STATE_DECODING: {
|
||||
Push(video);
|
||||
if (MaybeFinishDecodeFirstFrame()) {
|
||||
return;
|
||||
}
|
||||
if (mIsVideoPrerolling && DonePrerollingVideo()) {
|
||||
StopPrerollingVideo();
|
||||
}
|
||||
@@ -884,7 +885,8 @@ MediaDecoderStateMachine::OnVideoDecoded(VideoData* aVideoSample)
|
||||
return;
|
||||
}
|
||||
TimeDuration decodeTime = TimeStamp::Now() - mVideoDecodeStartTime;
|
||||
if (THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > mLowAudioThresholdUsecs &&
|
||||
if (!IsDecodingFirstFrame() &&
|
||||
THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > mLowAudioThresholdUsecs &&
|
||||
!HasLowUndecodedData())
|
||||
{
|
||||
mLowAudioThresholdUsecs =
|
||||
@@ -1135,8 +1137,7 @@ static const char* const gMachineStateStr[] = {
|
||||
"NONE",
|
||||
"DECODING_METADATA",
|
||||
"WAIT_FOR_RESOURCES",
|
||||
"WAIT_FOR_RESOURCES",
|
||||
"DECODING_FIRSTFRAME",
|
||||
"WAIT_FOR_CDM",
|
||||
"DORMANT",
|
||||
"DECODING",
|
||||
"SEEKING",
|
||||
@@ -1262,6 +1263,7 @@ void MediaDecoderStateMachine::SetDormant(bool aDormant)
|
||||
} else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
|
||||
mDecodingFrozenAtStateDecoding = true;
|
||||
ScheduleStateMachine();
|
||||
mDecodingFirstFrame = true;
|
||||
SetState(DECODER_STATE_DECODING_NONE);
|
||||
mDecoder->GetReentrantMonitor().NotifyAll();
|
||||
}
|
||||
@@ -1307,11 +1309,32 @@ 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);
|
||||
|
||||
if (mDecodingFirstFrame &&
|
||||
(IsRealTime() || mSentFirstFrameLoadedEvent)) {
|
||||
if (IsRealTime()) {
|
||||
FinishDecodeFirstFrame();
|
||||
} else {
|
||||
// We're resuming from dormant state, so we don't need to request
|
||||
// the first samples in order to determine the media start time,
|
||||
// we have the start time from last time we loaded.
|
||||
// FinishDecodeFirstFrame will be launched upon completion of the seek when
|
||||
// we have data ready to play.
|
||||
MOZ_ASSERT(mQueuedSeek.Exists() && mSentFirstFrameLoadedEvent,
|
||||
"Return from dormant must have queued seek");
|
||||
}
|
||||
if (mQueuedSeek.Exists()) {
|
||||
mPendingSeek.Steal(mQueuedSeek);
|
||||
SetState(DECODER_STATE_SEEKING);
|
||||
ScheduleStateMachine();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mDecodeStartTime = TimeStamp::Now();
|
||||
|
||||
CheckIfDecodeComplete();
|
||||
@@ -1339,8 +1362,7 @@ void MediaDecoderStateMachine::NotifyWaitingForResourcesStatusChanged()
|
||||
ScheduleStateMachine();
|
||||
} else if (mState == DECODER_STATE_WAIT_FOR_CDM &&
|
||||
!mReader->IsWaitingOnCDMResource()) {
|
||||
SetState(DECODER_STATE_DECODING_FIRSTFRAME);
|
||||
EnqueueDecodeFirstFrameTask();
|
||||
StartDecoding();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1440,7 +1462,8 @@ 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() && !mReader->ForceZeroStartTime())) {
|
||||
DECODER_LOG("Seek() Not Enough Data to continue at this stage, queuing seek");
|
||||
mQueuedSeek.RejectIfExists(__func__);
|
||||
mQueuedSeek.mTarget = aTarget;
|
||||
@@ -1470,19 +1493,6 @@ void MediaDecoderStateMachine::StopAudioThread()
|
||||
mAudioSinkPromise.DisconnectIfExists();
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoderStateMachine::EnqueueDecodeFirstFrameTask()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
MOZ_ASSERT(mState == DECODER_STATE_DECODING_FIRSTFRAME);
|
||||
|
||||
nsCOMPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeFirstFrame));
|
||||
OwnerThread()->Dispatch(task.forget());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
|
||||
{
|
||||
@@ -1490,7 +1500,6 @@ MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
if (mState != DECODER_STATE_DECODING &&
|
||||
mState != DECODER_STATE_DECODING_FIRSTFRAME &&
|
||||
mState != DECODER_STATE_BUFFERING &&
|
||||
mState != DECODER_STATE_SEEKING) {
|
||||
return;
|
||||
@@ -1639,7 +1648,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;
|
||||
@@ -1711,7 +1719,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;
|
||||
@@ -1848,7 +1855,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
|
||||
@@ -1979,8 +1986,8 @@ MediaDecoderStateMachine::OnMetadataRead(MetadataHolder* aMetadata)
|
||||
return;
|
||||
}
|
||||
|
||||
SetState(DECODER_STATE_DECODING_FIRSTFRAME);
|
||||
EnqueueDecodeFirstFrameTask();
|
||||
StartDecoding();
|
||||
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
|
||||
@@ -2031,60 +2038,19 @@ MediaDecoderStateMachine::EnqueueFirstFrameLoadedEvent()
|
||||
mSentFirstFrameLoadedEvent = true;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaDecoderStateMachine::IsDecodingFirstFrame()
|
||||
{
|
||||
return mState == DECODER_STATE_DECODING && mDecodingFirstFrame;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::CallDecodeFirstFrame()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (mState != DECODER_STATE_DECODING_FIRSTFRAME) {
|
||||
return;
|
||||
}
|
||||
if (NS_FAILED(DecodeFirstFrame())) {
|
||||
DECODER_WARN("Decode failed to start, shutting down decoder");
|
||||
DecodeError();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoderStateMachine::DecodeFirstFrame()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
MOZ_ASSERT(mState == DECODER_STATE_DECODING_FIRSTFRAME);
|
||||
DECODER_LOG("DecodeFirstFrame started");
|
||||
|
||||
if (IsRealTime()) {
|
||||
nsresult res = FinishDecodeFirstFrame();
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
} else if (mSentFirstFrameLoadedEvent) {
|
||||
// We're resuming from dormant state, so we don't need to request
|
||||
// the first samples in order to determine the media start time,
|
||||
// we have the start time from last time we loaded.
|
||||
nsresult res = FinishDecodeFirstFrame();
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
} else {
|
||||
if (HasAudio()) {
|
||||
RequestAudioData();
|
||||
}
|
||||
if (HasVideo()) {
|
||||
RequestVideoData();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaDecoderStateMachine::FinishDecodeFirstFrame()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
AssertCurrentThreadInMonitor();
|
||||
DECODER_LOG("FinishDecodeFirstFrame");
|
||||
|
||||
if (IsShutdown()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!IsRealTime() && !mSentFirstFrameLoadedEvent) {
|
||||
RenderVideoFrames(1);
|
||||
}
|
||||
@@ -2098,7 +2064,7 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
|
||||
"transportSeekable=%d, mediaSeekable=%d",
|
||||
Duration().ToMicroseconds(), mDecoder->IsTransportSeekable(), mDecoder->IsMediaSeekable());
|
||||
|
||||
if (HasAudio() && !HasVideo()) {
|
||||
if (HasAudio() && !HasVideo() && !mSentFirstFrameLoadedEvent) {
|
||||
// We're playing audio only. We don't need to worry about slow video
|
||||
// decodes causing audio underruns, so don't buffer so much audio in
|
||||
// order to reduce memory usage.
|
||||
@@ -2119,16 +2085,7 @@ MediaDecoderStateMachine::FinishDecodeFirstFrame()
|
||||
}
|
||||
EnqueueFirstFrameLoadedEvent();
|
||||
|
||||
if (mQueuedSeek.Exists()) {
|
||||
mPendingSeek.Steal(mQueuedSeek);
|
||||
SetState(DECODER_STATE_SEEKING);
|
||||
ScheduleStateMachine();
|
||||
} else if (mState == DECODER_STATE_DECODING_FIRSTFRAME) {
|
||||
// StartDecoding() will also check if decode is completed.
|
||||
StartDecoding();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
mDecodingFirstFrame = false;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2142,11 +2099,11 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
int64_t newCurrentTime = seekTime;
|
||||
|
||||
// Setup timestamp state.
|
||||
nsRefPtr<VideoData> video = VideoQueue().PeekFront();
|
||||
nsRefPtr<MediaData> video = VideoQueue().PeekFront();
|
||||
if (seekTime == Duration().ToMicroseconds()) {
|
||||
newCurrentTime = seekTime;
|
||||
} else if (HasAudio()) {
|
||||
AudioData* audio = AudioQueue().PeekFront();
|
||||
MediaData* audio = AudioQueue().PeekFront();
|
||||
// Though we adjust the newCurrentTime in audio-based, and supplemented
|
||||
// by video. For better UX, should NOT bind the slide position to
|
||||
// the first audio data timestamp directly.
|
||||
@@ -2161,6 +2118,12 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
}
|
||||
mPlayDuration = newCurrentTime;
|
||||
|
||||
if (mDecodingFirstFrame) {
|
||||
// We were resuming from dormant, or initiated a seek early.
|
||||
// We can fire loadeddata now.
|
||||
FinishDecodeFirstFrame();
|
||||
}
|
||||
|
||||
// Change state to DECODING or COMPLETED now. SeekingStopped will
|
||||
// call MediaDecoderStateMachine::Seek to reset our state to SEEKING
|
||||
// if we need to seek again.
|
||||
@@ -2324,12 +2287,12 @@ 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()) {
|
||||
// We haven't completed decoding our first frames, we can't start
|
||||
// playback yet.
|
||||
return NS_OK;
|
||||
}
|
||||
if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING && IsPlaying())
|
||||
{
|
||||
// We're playing, but the element/decoder is in paused state. Stop
|
||||
@@ -2362,7 +2325,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
elapsed < TimeDuration::FromSeconds(mBufferingWait * mPlaybackRate) &&
|
||||
(mQuickBuffering ? HasLowDecodedData(mQuickBufferingLowDataThresholdUsecs)
|
||||
: HasLowUndecodedData(mBufferingWait * USECS_PER_S)) &&
|
||||
mDecoder->IsExpectingMoreData())
|
||||
mResource->IsExpectingMoreData())
|
||||
{
|
||||
DECODER_LOG("Buffering: wait %ds, timeout in %.3lfs %s",
|
||||
mBufferingWait, mBufferingWait - elapsed.ToSeconds(),
|
||||
@@ -2538,7 +2501,7 @@ void MediaDecoderStateMachine::RenderVideoFrames(int32_t aMaxFrames,
|
||||
AssertCurrentThreadInMonitor();
|
||||
|
||||
VideoFrameContainer* container = mDecoder->GetVideoFrameContainer();
|
||||
nsAutoTArray<nsRefPtr<VideoData>,16> frames;
|
||||
nsAutoTArray<nsRefPtr<MediaData>,16> frames;
|
||||
VideoQueue().GetFirstElements(aMaxFrames, &frames);
|
||||
if (frames.IsEmpty() || !container) {
|
||||
return;
|
||||
@@ -2547,7 +2510,7 @@ void MediaDecoderStateMachine::RenderVideoFrames(int32_t aMaxFrames,
|
||||
nsAutoTArray<ImageContainer::NonOwningImage,16> images;
|
||||
TimeStamp lastFrameTime;
|
||||
for (uint32_t i = 0; i < frames.Length(); ++i) {
|
||||
VideoData* frame = frames[i];
|
||||
VideoData* frame = frames[i]->As<VideoData>();
|
||||
frame->mSentToCompositor = true;
|
||||
|
||||
int64_t frameTime = frame->mTime;
|
||||
@@ -2585,7 +2548,7 @@ void MediaDecoderStateMachine::RenderVideoFrames(int32_t aMaxFrames,
|
||||
}
|
||||
|
||||
|
||||
container->SetCurrentFrames(frames[0]->mDisplay, images);
|
||||
container->SetCurrentFrames(frames[0]->As<VideoData>()->mDisplay, images);
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::ResyncAudioClock()
|
||||
@@ -2689,21 +2652,21 @@ void MediaDecoderStateMachine::UpdateRenderedVideoFrames()
|
||||
NS_ASSERTION(clockTime >= 0, "Should have positive clock time.");
|
||||
int64_t remainingTime = AUDIO_DURATION_USECS;
|
||||
if (VideoQueue().GetSize() > 0) {
|
||||
nsRefPtr<VideoData> currentFrame = VideoQueue().PopFront();
|
||||
nsRefPtr<MediaData> currentFrame = VideoQueue().PopFront();
|
||||
int32_t framesRemoved = 0;
|
||||
while (VideoQueue().GetSize() > 0) {
|
||||
VideoData* nextFrame = VideoQueue().PeekFront();
|
||||
MediaData* nextFrame = VideoQueue().PeekFront();
|
||||
if (!IsRealTime() && nextFrame->mTime > clockTime) {
|
||||
remainingTime = nextFrame->mTime - clockTime;
|
||||
break;
|
||||
}
|
||||
++framesRemoved;
|
||||
if (!currentFrame->mSentToCompositor) {
|
||||
if (!currentFrame->As<VideoData>()->mSentToCompositor) {
|
||||
mDecoder->NotifyDecodedFrames(0, 0, 1);
|
||||
VERBOSE_LOG("discarding video frame mTime=%lld clock_time=%lld",
|
||||
currentFrame->mTime, clockTime);
|
||||
}
|
||||
CheckTurningOffHardwareDecoder(currentFrame);
|
||||
CheckTurningOffHardwareDecoder(currentFrame->As<VideoData>());
|
||||
currentFrame = VideoQueue().PopFront();
|
||||
|
||||
}
|
||||
@@ -2721,7 +2684,7 @@ void MediaDecoderStateMachine::UpdateRenderedVideoFrames()
|
||||
// If we don't, switch to buffering mode.
|
||||
if (mState == DECODER_STATE_DECODING &&
|
||||
mPlayState == MediaDecoder::PLAY_STATE_PLAYING &&
|
||||
mDecoder->IsExpectingMoreData()) {
|
||||
mResource->IsExpectingMoreData()) {
|
||||
bool shouldBuffer;
|
||||
if (mReader->UseBufferingHeuristics()) {
|
||||
shouldBuffer = HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) &&
|
||||
@@ -2878,7 +2841,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()) {
|
||||
|
||||
Reference in New Issue
Block a user