Bug 1266027 part 2 - make MDSM and SeekTask to adopt new MediaDecoderReaderWrapper API; r=jwwang
MozReview-Commit-ID: LqZ59A8vju1
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -347,16 +347,19 @@ MediaDecoderStateMachine::Initialization
mWatchManager.Watch(mVideoCompleted, &MediaDecoderStateMachine::UpdateNextFrameStatus);
mWatchManager.Watch(mVolume, &MediaDecoderStateMachine::VolumeChanged);
mWatchManager.Watch(mLogicalPlaybackRate, &MediaDecoderStateMachine::LogicalPlaybackRateChanged);
mWatchManager.Watch(mPreservesPitch, &MediaDecoderStateMachine::PreservesPitchChanged);
mWatchManager.Watch(mEstimatedDuration, &MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mExplicitDuration, &MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mObservedDuration, &MediaDecoderStateMachine::RecomputeDuration);
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
+
+ // Configure MediaDecoderReaderWrapper.
+ SetMediaDecoderReaderWrapperCallback();
}
media::MediaSink*
MediaDecoderStateMachine::CreateAudioSink()
{
RefPtr<MediaDecoderStateMachine> self = this;
auto audioSinkCreator = [self] () {
MOZ_ASSERT(self->OnTaskQueue());
@@ -555,17 +558,16 @@ MediaDecoderStateMachine::NeedToDecodeAu
void
MediaDecoderStateMachine::OnAudioDecoded(MediaData* aAudioSample)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(mState != DECODER_STATE_SEEKING);
RefPtr<MediaData> audio(aAudioSample);
MOZ_ASSERT(audio);
- mAudioDataRequest.Complete();
// audio->GetEndTime() is not always mono-increasing in chained ogg.
mDecodedAudioEndTime = std::max(audio->GetEndTime(), mDecodedAudioEndTime);
SAMPLE_LOG("OnAudioDecoded [%lld,%lld] disc=%d",
(audio ? audio->mTime : -1),
(audio ? audio->GetEndTime() : -1),
(audio ? audio->mDiscontinuity : 0));
@@ -669,21 +671,16 @@ MediaDecoderStateMachine::OnNotDecoded(M
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(mState != DECODER_STATE_SEEKING);
SAMPLE_LOG("OnNotDecoded (aType=%u, aReason=%u)", aType, aReason);
bool isAudio = aType == MediaData::AUDIO_DATA;
MOZ_ASSERT_IF(!isAudio, aType == MediaData::VIDEO_DATA);
- if (isAudio) {
- mAudioDataRequest.Complete();
- } else {
- mVideoDataRequest.Complete();
- }
if (IsShutdown()) {
// Already shutdown;
return;
}
// If this is a decode error, delegate to the generic error path.
if (aReason == MediaDecoderReader::DECODE_ERROR) {
DecodeError();
@@ -788,17 +785,16 @@ void
MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample,
TimeStamp aDecodeStartTime)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(mState != DECODER_STATE_SEEKING);
RefPtr<MediaData> video(aVideoSample);
MOZ_ASSERT(video);
- mVideoDataRequest.Complete();
// Handle abnormal or negative timestamps.
mDecodedVideoEndTime = std::max(mDecodedVideoEndTime, video->GetEndTime());
SAMPLE_LOG("OnVideoDecoded [%lld,%lld] disc=%d",
(video ? video->mTime : -1),
(video ? video->GetEndTime() : -1),
(video ? video->mDiscontinuity : 0));
@@ -922,16 +918,43 @@ nsresult MediaDecoderStateMachine::Init(
NS_ENSURE_SUCCESS(rv, rv);
r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::ReadMetadata);
OwnerThread()->Dispatch(r.forget());
return NS_OK;
}
+void
+MediaDecoderStateMachine::SetMediaDecoderReaderWrapperCallback()
+{
+ mAudioCallbackID =
+ mReader->SetAudioCallback(this,
+ &MediaDecoderStateMachine::OnAudioDecoded,
+ &MediaDecoderStateMachine::OnAudioNotDecoded);
+
+ mVideoCallbackID =
+ mReader->SetVideoCallback(this,
+ &MediaDecoderStateMachine::OnVideoDecoded,
+ &MediaDecoderStateMachine::OnVideoNotDecoded);
+
+ DECODER_LOG("MDSM set audio callbacks: mAudioCallbackID = %d\n", (int)mAudioCallbackID);
+ DECODER_LOG("MDSM set video callbacks: mVideoCallbackID = %d\n", (int)mVideoCallbackID);
+}
+
+void
+MediaDecoderStateMachine::CancelMediaDecoderReaderWrapperCallback()
+{
+ DECODER_LOG("MDSM cancel audio callbacks: mVideoCallbackID = %d\n", (int)mAudioCallbackID);
+ mReader->CancelAudioCallback(mAudioCallbackID);
+
+ DECODER_LOG("MDSM cancel video callbacks: mVideoCallbackID = %d\n", (int)mVideoCallbackID);
+ mReader->CancelVideoCallback(mVideoCallbackID);
+}
+
void MediaDecoderStateMachine::StopPlayback()
{
MOZ_ASSERT(OnTaskQueue());
DECODER_LOG("StopPlayback()");
mOnPlaybackEvent.Notify(MediaEventType::PlaybackStopped);
if (IsPlaying()) {
@@ -1144,20 +1167,17 @@ MediaDecoderStateMachine::SetDormant(boo
SeekTarget::Accurate,
MediaDecoderEventVisibility::Suppressed);
// XXXbholley - Nobody is listening to this promise. Do we need to pass it
// back to MediaDecoder when we come out of dormant?
RefPtr<MediaDecoder::SeekPromise> unused = mQueuedSeek.mPromise.Ensure(__func__);
}
// Discard the current seek task.
- if (mSeekTask) {
- mSeekTask->Discard();
- mSeekTask = nullptr;
- }
+ DiscardSeekTaskIfExist();
SetState(DECODER_STATE_DORMANT);
if (IsPlaying()) {
StopPlayback();
}
Reset();
@@ -1184,29 +1204,30 @@ MediaDecoderStateMachine::Shutdown()
// Change state before issuing shutdown request to threads so those
// threads can start exiting cleanly during the Shutdown call.
ScheduleStateMachine();
SetState(DECODER_STATE_SHUTDOWN);
mBufferedUpdateRequest.DisconnectIfExists();
mQueuedSeek.RejectIfExists(__func__);
- if (mSeekTask) {
- mSeekTask->Discard();
- mSeekTask = nullptr;
- }
+
+ DiscardSeekTaskIfExist();
#ifdef MOZ_EME
mCDMProxyPromise.DisconnectIfExists();
#endif
if (IsPlaying()) {
StopPlayback();
}
+ // To break the cycle-reference between MediaDecoderReaderWrapper and MDSM.
+ CancelMediaDecoderReaderWrapperCallback();
+
Reset();
mMediaSink->Shutdown();
DECODER_LOG("Shutdown started");
// Put a task in the decode queue to shutdown the reader.
// the queue to spin down.
@@ -1452,22 +1473,23 @@ MediaDecoderStateMachine::DispatchDecode
}
void
MediaDecoderStateMachine::InitiateSeek(SeekJob aSeekJob)
{
MOZ_ASSERT(OnTaskQueue());
// Discard the existing seek task.
- if (mSeekTask) {
- mSeekTask->Discard();
- }
+ DiscardSeekTaskIfExist();
mSeekTaskRequest.DisconnectIfExists();
+ // SeekTask will register its callbacks to MediaDecoderReaderWrapper.
+ CancelMediaDecoderReaderWrapperCallback();
+
// Create a new SeekTask instance for the incoming seek task.
mSeekTask = SeekTask::CreateSeekTask(mDecoderID, OwnerThread(),
mReader.get(), Move(aSeekJob),
mInfo, Duration(), GetMediaTime());
// Stop playback now to ensure that while we're outside the monitor
// dispatching SeekingStarted, playback doesn't advance and mess with
// mCurrentPosition that we've setting to seekTime here.
@@ -1520,19 +1542,16 @@ MediaDecoderStateMachine::OnSeekTaskReso
StopPrerollingAudio();
}
if (aValue.mNeedToStopPrerollingVideo) {
StopPrerollingVideo();
}
SeekCompleted();
-
- mSeekTask->Discard();
- mSeekTask = nullptr;
}
void
MediaDecoderStateMachine::OnSeekTaskRejected(SeekTaskRejectValue aValue)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(mState == DECODER_STATE_SEEKING);
@@ -1553,18 +1572,29 @@ MediaDecoderStateMachine::OnSeekTaskReje
}
if (aValue.mNeedToStopPrerollingVideo) {
StopPrerollingVideo();
}
DecodeError();
- mSeekTask->Discard();
- mSeekTask = nullptr;
+ DiscardSeekTaskIfExist();
+}
+
+void
+MediaDecoderStateMachine::DiscardSeekTaskIfExist()
+{
+ if (mSeekTask) {
+ mSeekTask->Discard();
+ mSeekTask = nullptr;
+
+ // Reset the MediaDecoderReaderWrapper's callbask.
+ SetMediaDecoderReaderWrapperCallback();
+ }
}
nsresult
MediaDecoderStateMachine::DispatchAudioDecodeTaskIfNeeded()
{
MOZ_ASSERT(OnTaskQueue());
if (IsShutdown()) {
@@ -1587,17 +1617,17 @@ MediaDecoderStateMachine::EnsureAudioDec
SAMPLE_LOG("EnsureAudioDecodeTaskQueued isDecoding=%d status=%s",
IsAudioDecoding(), AudioRequestStatus());
if (mState != DECODER_STATE_DECODING &&
mState != DECODER_STATE_BUFFERING) {
return NS_OK;
}
- if (!IsAudioDecoding() || mAudioDataRequest.Exists() ||
+ if (!IsAudioDecoding() || mReader->IsRequestingAudioData() ||
mAudioWaitRequest.Exists()) {
return NS_OK;
}
RequestAudioData();
return NS_OK;
}
@@ -1605,21 +1635,17 @@ void
MediaDecoderStateMachine::RequestAudioData()
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(mState != DECODER_STATE_SEEKING);
SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o",
AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
- mAudioDataRequest.Begin(
- mReader->RequestAudioData()
- ->Then(OwnerThread(), __func__, this,
- &MediaDecoderStateMachine::OnAudioDecoded,
- &MediaDecoderStateMachine::OnAudioNotDecoded));
+ mReader->RequestAudioData();
}
nsresult
MediaDecoderStateMachine::DispatchVideoDecodeTaskIfNeeded()
{
MOZ_ASSERT(OnTaskQueue());
if (IsShutdown()) {
@@ -1642,55 +1668,45 @@ MediaDecoderStateMachine::EnsureVideoDec
SAMPLE_LOG("EnsureVideoDecodeTaskQueued isDecoding=%d status=%s",
IsVideoDecoding(), VideoRequestStatus());
if (mState != DECODER_STATE_DECODING &&
mState != DECODER_STATE_BUFFERING) {
return NS_OK;
}
- if (!IsVideoDecoding() || mVideoDataRequest.Exists() ||
+ if (!IsVideoDecoding() || mReader->IsRequestingVidoeData() ||
mVideoWaitRequest.Exists()) {
return NS_OK;
}
RequestVideoData();
return NS_OK;
}
void
MediaDecoderStateMachine::RequestVideoData()
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(mState != DECODER_STATE_SEEKING);
- // Time the video decode, so that if it's slow, we can increase our low
- // audio threshold to reduce the chance of an audio underrun while we're
- // waiting for a video decode to complete.
- TimeStamp videoDecodeStartTime = TimeStamp::Now();
-
bool skipToNextKeyFrame = mSentFirstFrameLoadedEvent &&
NeedToSkipToNextKeyframe();
media::TimeUnit currentTime = media::TimeUnit::FromMicroseconds(GetMediaTime());
SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
currentTime.ToMicroseconds());
- RefPtr<MediaDecoderStateMachine> self = this;
- mVideoDataRequest.Begin(
- mReader->RequestVideoData(skipToNextKeyFrame, currentTime)
- ->Then(OwnerThread(), __func__,
- [self, videoDecodeStartTime] (MediaData* aVideoSample) {
- self->OnVideoDecoded(aVideoSample, videoDecodeStartTime);
- },
- [self] (MediaDecoderReader::NotDecodedReason aReason) {
- self->OnVideoNotDecoded(aReason);
- }));
+ // MediaDecoderReaderWrapper::RequestVideoData() records the decoding start
+ // time and sent it back to MDSM::OnVideoDecoded() so that if the decoding is
+ // slow, we can increase our low audio threshold to reduce the chance of an
+ // audio underrun while we're waiting for a video decode to complete.
+ mReader->RequestVideoData(skipToNextKeyFrame, currentTime);
}
void
MediaDecoderStateMachine::StartMediaSink()
{
MOZ_ASSERT(OnTaskQueue());
if (!mMediaSink->IsStarted()) {
mAudioCompleted = false;
@@ -2001,16 +2017,25 @@ MediaDecoderStateMachine::SeekCompleted(
DECODER_LOG("Changed state from SEEKING (to %lld) to DECODING", seekTime);
nextState = DECODER_STATE_DECODING;
}
// We want to resolve the seek request prior finishing the first frame
// to ensure that the seeked event is fired prior loadeded.
mSeekTask->GetSeekJob().Resolve(nextState == DECODER_STATE_COMPLETED, __func__);
+ // Discard and nullify the seek task.
+ // Reset the MediaDecoderReaderWrapper's callbask.
+ DiscardSeekTaskIfExist();
+
+ // NOTE: Discarding the mSeekTask must be done before here. The following code
+ // might ask the MediaDecoderReaderWrapper to request media data, however, the
+ // SeekTask::Discard() will ask MediaDecoderReaderWrapper to discard media
+ // data requests.
+
if (mDecodingFirstFrame) {
// We were resuming from dormant, or initiated a seek early.
// We can fire loadeddata now.
FinishDecodeFirstFrame();
}
if (nextState == DECODER_STATE_DECODING) {
StartDecoding();
@@ -2153,18 +2178,18 @@ nsresult MediaDecoderStateMachine::RunSt
(mQuickBuffering ? "(quick exit)" : ""));
ScheduleStateMachineIn(USECS_PER_S);
return NS_OK;
}
} else if (OutOfDecodedAudio() || OutOfDecodedVideo()) {
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
"Don't yet have a strategy for non-heuristic + non-WaitForData");
DispatchDecodeTasksIfNeeded();
- MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mAudioDataRequest.Exists() || mAudioWaitRequest.Exists());
- MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mVideoDataRequest.Exists() || mVideoWaitRequest.Exists());
+ MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedAudio(), mReader->IsRequestingAudioData() || mAudioWaitRequest.Exists());
+ MOZ_ASSERT_IF(!mMinimizePreroll && OutOfDecodedVideo(), mReader->IsRequestingVidoeData() || mVideoWaitRequest.Exists());
DECODER_LOG("In buffering mode, waiting to be notified: outOfAudio: %d, "
"mAudioStatus: %s, outOfVideo: %d, mVideoStatus: %s",
OutOfDecodedAudio(), AudioRequestStatus(),
OutOfDecodedVideo(), VideoRequestStatus());
return NS_OK;
}
DECODER_LOG("Changed state from BUFFERING to DECODING");
@@ -2248,19 +2273,17 @@ MediaDecoderStateMachine::Reset()
mDecodedVideoEndTime = 0;
mDecodedAudioEndTime = 0;
mAudioCompleted = false;
mVideoCompleted = false;
AudioQueue().Reset();
VideoQueue().Reset();
mMetadataRequest.DisconnectIfExists();
- mAudioDataRequest.DisconnectIfExists();
mAudioWaitRequest.DisconnectIfExists();
- mVideoDataRequest.DisconnectIfExists();
mVideoWaitRequest.DisconnectIfExists();
mSeekTaskRequest.DisconnectIfExists();
mPlaybackOffset = 0;
mReader->ResetDecode();
}
@@ -2719,16 +2742,42 @@ MediaDecoderStateMachine::CanonicalBuffe
}
MediaEventSource<void>&
MediaDecoderStateMachine::OnMediaNotSeekable() const
{
return mReader->OnMediaNotSeekable();
}
+const char*
+MediaDecoderStateMachine::AudioRequestStatus() const
+{
+ MOZ_ASSERT(OnTaskQueue());
+ if (mReader->IsRequestingAudioData()) {
+ MOZ_DIAGNOSTIC_ASSERT(!mAudioWaitRequest.Exists());
+ return "pending";
+ } else if (mAudioWaitRequest.Exists()) {
+ return "waiting";
+ }
+ return "idle";
+}
+
+const char*
+MediaDecoderStateMachine::VideoRequestStatus() const
+{
+ MOZ_ASSERT(OnTaskQueue());
+ if (mReader->IsRequestingVidoeData()) {
+ MOZ_DIAGNOSTIC_ASSERT(!mVideoWaitRequest.Exists());
+ return "pending";
+ } else if (mVideoWaitRequest.Exists()) {
+ return "waiting";
+ }
+ return "idle";
+}
+
} // namespace mozilla
// avoid redefined macro in unified build
#undef LOG
#undef DECODER_LOG
#undef VERBOSE_LOG
#undef DECODER_WARN
#undef DECODER_WARN_HELPER
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -82,16 +82,17 @@ hardware (via AudioStream).
#if !defined(MediaDecoderStateMachine_h__)
#define MediaDecoderStateMachine_h__
#include "mozilla/Attributes.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/StateMirroring.h"
#include "nsThreadUtils.h"
+#include "MediaCallbackID.h"
#include "MediaDecoder.h"
#include "MediaDecoderReader.h"
#include "MediaDecoderOwner.h"
#include "MediaEventSource.h"
#include "MediaMetadataManager.h"
#include "MediaStatistics.h"
#include "MediaTimer.h"
#include "ImageContainer.h"
@@ -138,16 +139,19 @@ public:
typedef MediaDecoderOwner::NextFrameStatus NextFrameStatus;
typedef mozilla::layers::ImageContainer::FrameID FrameID;
MediaDecoderStateMachine(MediaDecoder* aDecoder,
MediaDecoderReader* aReader,
bool aRealTime = false);
nsresult Init(MediaDecoder* aDecoder);
+ void SetMediaDecoderReaderWrapperCallback();
+ void CancelMediaDecoderReaderWrapperCallback();
+
// Enumeration for the valid decoding states
enum State {
DECODER_STATE_DECODING_METADATA,
DECODER_STATE_WAIT_FOR_CDM,
DECODER_STATE_DORMANT,
DECODER_STATE_DECODING,
DECODER_STATE_SEEKING,
DECODER_STATE_BUFFERING,
@@ -674,16 +678,20 @@ private:
// mSeekTask is responsible for executing the current seek request.
RefPtr<SeekTask> mSeekTask;
MozPromiseRequestHolder<SeekTask::SeekTaskPromise> mSeekTaskRequest;
void OnSeekTaskResolved(SeekTaskResolveValue aValue);
void OnSeekTaskRejected(SeekTaskRejectValue aValue);
+ // This method discards the seek task and then get the ownership of
+ // MedaiDecoderReaderWarpper back via registering MDSM's callback into it.
+ void DiscardSeekTaskIfExist();
+
// Media Fragment end time in microseconds. Access controlled by decoder monitor.
int64_t mFragmentEndTime;
// The media sink resource. Used on the state machine thread.
RefPtr<media::MediaSink> mMediaSink;
const RefPtr<MediaDecoderReaderWrapper> mReader;
@@ -802,43 +810,23 @@ private:
// playback. The flags below are true when the corresponding stream is
// being "prerolled".
bool mIsAudioPrerolling;
bool mIsVideoPrerolling;
// Only one of a given pair of ({Audio,Video}DataPromise, WaitForDataPromise)
// should exist at any given moment.
- MozPromiseRequestHolder<MediaDecoderReader::MediaDataPromise> mAudioDataRequest;
+ CallbackID mAudioCallbackID;
MozPromiseRequestHolder<MediaDecoderReader::WaitForDataPromise> mAudioWaitRequest;
- const char* AudioRequestStatus()
- {
- MOZ_ASSERT(OnTaskQueue());
- if (mAudioDataRequest.Exists()) {
- MOZ_DIAGNOSTIC_ASSERT(!mAudioWaitRequest.Exists());
- return "pending";
- } else if (mAudioWaitRequest.Exists()) {
- return "waiting";
- }
- return "idle";
- }
+ const char* AudioRequestStatus() const;
+ CallbackID mVideoCallbackID;
MozPromiseRequestHolder<MediaDecoderReader::WaitForDataPromise> mVideoWaitRequest;
- MozPromiseRequestHolder<MediaDecoderReader::MediaDataPromise> mVideoDataRequest;
- const char* VideoRequestStatus()
- {
- MOZ_ASSERT(OnTaskQueue());
- if (mVideoDataRequest.Exists()) {
- MOZ_DIAGNOSTIC_ASSERT(!mVideoWaitRequest.Exists());
- return "pending";
- } else if (mVideoWaitRequest.Exists()) {
- return "waiting";
- }
- return "idle";
- }
+ const char* VideoRequestStatus() const;
MozPromiseRequestHolder<MediaDecoderReader::WaitForDataPromise>& WaitRequestRef(MediaData::Type aType)
{
MOZ_ASSERT(OnTaskQueue());
return aType == MediaData::AUDIO_DATA ? mAudioWaitRequest : mVideoWaitRequest;
}
// True if we shouldn't play our audio (but still write it to any capturing
--- a/dom/media/SeekTask.cpp
+++ b/dom/media/SeekTask.cpp
@@ -81,16 +81,19 @@ SeekTask::SeekTask(const void* aDecoderI
seekTime = std::min(seekTime, end);
seekTime = std::max(int64_t(0), seekTime);
NS_ASSERTION(seekTime >= 0 && seekTime <= end,
"Can only seek in range [0,duration]");
mSeekJob.mTarget.SetTime(media::TimeUnit::FromMicroseconds(seekTime));
mDropAudioUntilNextDiscontinuity = HasAudio();
mDropVideoUntilNextDiscontinuity = HasVideo();
+
+ // Configure MediaDecoderReaderWrapper.
+ SetMediaDecoderReaderWrapperCallback();
}
SeekTask::~SeekTask()
{
MOZ_ASSERT(mIsDiscarded);
}
void
@@ -147,22 +150,21 @@ void
SeekTask::Discard()
{
// Disconnect MediaDecoder.
mSeekJob.RejectIfExists(__func__);
// Disconnect MDSM.
RejectIfExist(__func__);
- // Disconnect MediaDecoderReader.
+ // Disconnect MediaDecoderReaderWrapper.
mSeekRequest.DisconnectIfExists();
- mAudioDataRequest.DisconnectIfExists();
- mVideoDataRequest.DisconnectIfExists();
mAudioWaitRequest.DisconnectIfExists();
mVideoWaitRequest.DisconnectIfExists();
+ CancelMediaDecoderReaderWrapperCallback();
mIsDiscarded = true;
}
bool
SeekTask::NeedToResetMDSM() const
{
return true;
@@ -211,17 +213,17 @@ nsresult
SeekTask::EnsureAudioDecodeTaskQueued()
{
AssertOwnerThread();
SAMPLE_LOG("EnsureAudioDecodeTaskQueued isDecoding=%d status=%s",
IsAudioDecoding(), AudioRequestStatus());
if (!IsAudioDecoding() ||
- mAudioDataRequest.Exists() ||
+ mReader->IsRequestingAudioData() ||
mAudioWaitRequest.Exists() ||
mSeekRequest.Exists()) {
return NS_OK;
}
RequestAudioData();
return NS_OK;
}
@@ -230,81 +232,76 @@ nsresult
SeekTask::EnsureVideoDecodeTaskQueued()
{
AssertOwnerThread();
SAMPLE_LOG("EnsureVideoDecodeTaskQueued isDecoding=%d status=%s",
IsVideoDecoding(), VideoRequestStatus());
if (!IsVideoDecoding() ||
- mVideoDataRequest.Exists() ||
+ mReader->IsRequestingVidoeData() ||
mVideoWaitRequest.Exists() ||
mSeekRequest.Exists()) {
return NS_OK;
}
RequestVideoData();
return NS_OK;
}
const char*
SeekTask::AudioRequestStatus()
{
AssertOwnerThread();
- if (mAudioDataRequest.Exists()) {
+ if (mReader->IsRequestingAudioData()) {
MOZ_DIAGNOSTIC_ASSERT(!mAudioWaitRequest.Exists());
return "pending";
} else if (mAudioWaitRequest.Exists()) {
return "waiting";
}
return "idle";
}
const char*
SeekTask::VideoRequestStatus()
{
AssertOwnerThread();
- if (mVideoDataRequest.Exists()) {
+ if (mReader->IsRequestingVidoeData()) {
MOZ_DIAGNOSTIC_ASSERT(!mVideoWaitRequest.Exists());
return "pending";
} else if (mVideoWaitRequest.Exists()) {
return "waiting";
}
return "idle";
}
void
SeekTask::RequestAudioData()
{
AssertOwnerThread();
SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o",
!!mSeekedAudioData, mReader->SizeOfAudioQueueInFrames());
- mAudioDataRequest.Begin(mReader->RequestAudioData()
- ->Then(OwnerThread(), __func__, this,
- &SeekTask::OnAudioDecoded, &SeekTask::OnAudioNotDecoded));
+ mReader->RequestAudioData();
}
void
SeekTask::RequestVideoData()
{
AssertOwnerThread();
//These two variables are not used in the SEEKING state.
const bool skipToNextKeyFrame = false;
const media::TimeUnit currentTime = media::TimeUnit::FromMicroseconds(0);
SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
!!mSeekedVideoData, mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
currentTime.ToMicroseconds());
- mVideoDataRequest.Begin(
- mReader->RequestVideoData(skipToNextKeyFrame, currentTime)
- ->Then(OwnerThread(), __func__, this,
- &SeekTask::OnVideoDecoded, &SeekTask::OnVideoNotDecoded));
+ mReader->RequestVideoData(skipToNextKeyFrame, currentTime);
}
nsresult
SeekTask::DropAudioUpToSeekTarget(MediaData* aSample)
{
AssertOwnerThread();
RefPtr<AudioData> audio(aSample->As<AudioData>());
MOZ_ASSERT(audio && mSeekJob.Exists() && mSeekJob.mTarget.IsAccurate());
@@ -495,17 +492,16 @@ SeekTask::OnSeekRejected(nsresult aResul
}
void
SeekTask::OnAudioDecoded(MediaData* aAudioSample)
{
AssertOwnerThread();
RefPtr<MediaData> audio(aAudioSample);
MOZ_ASSERT(audio);
- mAudioDataRequest.Complete();
// The MDSM::mDecodedAudioEndTime will be updated once the whole SeekTask is
// resolved.
SAMPLE_LOG("OnAudioDecoded [%lld,%lld] disc=%d",
(audio ? audio->mTime : -1),
(audio ? audio->GetEndTime() : -1),
(audio ? audio->mDiscontinuity : 0));
@@ -548,17 +544,16 @@ SeekTask::OnAudioDecoded(MediaData* aAud
CheckIfSeekComplete();
}
void
SeekTask::OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
{
AssertOwnerThread();
SAMPLE_LOG("OnAduioNotDecoded (aReason=%u)", aReason);
- mAudioDataRequest.Complete();
if (aReason == MediaDecoderReader::DECODE_ERROR) {
// If this is a decode error, delegate to the generic error path.
RejectIfExist(__func__);
return;
}
// If the decoder is waiting for data, we tell it to call us back when the
@@ -597,17 +592,16 @@ SeekTask::OnAudioNotDecoded(MediaDecoder
}
void
SeekTask::OnVideoDecoded(MediaData* aVideoSample)
{
AssertOwnerThread();
RefPtr<MediaData> video(aVideoSample);
MOZ_ASSERT(video);
- mVideoDataRequest.Complete();
// The MDSM::mDecodedVideoEndTime will be updated once the whole SeekTask is
// resolved.
SAMPLE_LOG("OnVideoDecoded [%lld,%lld] disc=%d",
(video ? video->mTime : -1),
(video ? video->GetEndTime() : -1),
(video ? video->mDiscontinuity : 0));
@@ -652,17 +646,16 @@ SeekTask::OnVideoDecoded(MediaData* aVid
CheckIfSeekComplete();
}
void
SeekTask::OnVideoNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
{
AssertOwnerThread();
SAMPLE_LOG("OnVideoNotDecoded (aReason=%u)", aReason);
- mVideoDataRequest.Complete();
if (aReason == MediaDecoderReader::DECODE_ERROR) {
// If this is a decode error, delegate to the generic error path.
RejectIfExist(__func__);
return;
}
// If the decoder is waiting for data, we tell it to call us back when the
@@ -705,9 +698,33 @@ SeekTask::OnVideoNotDecoded(MediaDecoder
}
mIsVideoQueueFinished = true;
mDropVideoUntilNextDiscontinuity = false; // To make IsVideoSeekComplete() return TRUE.
CheckIfSeekComplete();
}
}
+void
+SeekTask::SetMediaDecoderReaderWrapperCallback()
+{
+ mAudioCallbackID =
+ mReader->SetAudioCallback(this, &SeekTask::OnAudioDecoded,
+ &SeekTask::OnAudioNotDecoded);
+
+ mVideoCallbackID =
+ mReader->SetVideoCallback(this, &SeekTask::OnVideoDecoded,
+ &SeekTask::OnVideoNotDecoded);
+
+ DECODER_LOG("SeekTask set audio callbacks: mAudioCallbackID = %d\n", (int)mAudioCallbackID);
+ DECODER_LOG("SeekTask set video callbacks: mVideoCallbackID = %d\n", (int)mAudioCallbackID);
+}
+
+void
+SeekTask::CancelMediaDecoderReaderWrapperCallback()
+{
+ DECODER_LOG("SeekTask cancel audio callbacks: mVideoCallbackID = %d\n", (int)mAudioCallbackID);
+ mReader->CancelAudioCallback(mAudioCallbackID);
+
+ DECODER_LOG("SeekTask cancel video callbacks: mVideoCallbackID = %d\n", (int)mVideoCallbackID);
+ mReader->CancelVideoCallback(mVideoCallbackID);
+}
} // namespace mozilla
--- a/dom/media/SeekTask.h
+++ b/dom/media/SeekTask.h
@@ -3,16 +3,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef SEEK_TASK_H
#define SEEK_TASK_H
#include "mozilla/MozPromise.h"
+#include "MediaCallbackID.h"
#include "MediaDecoderReader.h"
#include "SeekJob.h"
namespace mozilla {
class AbstractThread;
class MediaData;
class MediaDecoderReaderWrapper;
@@ -122,16 +123,20 @@ protected:
virtual void OnAudioDecoded(MediaData* aAudioSample);
virtual void OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason);
virtual void OnVideoDecoded(MediaData* aVideoSample);
virtual void OnVideoNotDecoded(MediaDecoderReader::NotDecodedReason aReason);
+ void SetMediaDecoderReaderWrapperCallback();
+
+ void CancelMediaDecoderReaderWrapperCallback();
+
/*
* Data shared with MDSM.
*/
const void* mDecoderID; // For logging.
const RefPtr<AbstractThread> mOwnerThread;
const RefPtr<MediaDecoderReaderWrapper> mReader;
/*
@@ -152,18 +157,18 @@ protected:
// the seek target, we will still have a frame that we can display as the
// last frame in the media.
RefPtr<MediaData> mFirstVideoFrameAfterSeek;
/*
* Track the current seek promise made by the reader.
*/
MozPromiseRequestHolder<MediaDecoderReader::SeekPromise> mSeekRequest;
- MozPromiseRequestHolder<MediaDecoderReader::MediaDataPromise> mAudioDataRequest;
- MozPromiseRequestHolder<MediaDecoderReader::MediaDataPromise> mVideoDataRequest;
+ CallbackID mAudioCallbackID;
+ CallbackID mVideoCallbackID;
MozPromiseRequestHolder<MediaDecoderReader::WaitForDataPromise> mAudioWaitRequest;
MozPromiseRequestHolder<MediaDecoderReader::WaitForDataPromise> mVideoWaitRequest;
/*
* Information which are going to be returned to MDSM.
*/
RefPtr<MediaData> mSeekedAudioData;
RefPtr<MediaData> mSeekedVideoData;