--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -381,17 +381,17 @@ public:
}
void HandleCDMProxyReady() override;
RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
{
SLOG("Not Enough Data to seek at this stage, queuing seek");
mPendingSeek.RejectIfExists(__func__);
- mPendingSeek.mTarget = aTarget;
+ mPendingSeek.mTarget.emplace(aTarget);
return mPendingSeek.mPromise.Ensure(__func__);
}
void HandleVideoSuspendTimeout() override
{
// Do nothing since no decoders are created yet.
}
@@ -422,17 +422,17 @@ public:
if (mMaster->IsPlaying()) {
mMaster->StopPlayback();
}
// Calculate the position to seek to when exiting dormant.
auto t = mMaster->mMediaSink->IsStarted()
? mMaster->GetClock()
: mMaster->GetMediaTime();
- mPendingSeek.mTarget = SeekTarget(t, SeekTarget::Accurate);
+ mPendingSeek.mTarget.emplace(t, SeekTarget::Accurate);
// SeekJob asserts |mTarget.IsValid() == !mPromise.IsEmpty()| so we
// need to create the promise even it is not used at all.
RefPtr<MediaDecoder::SeekPromise> x = mPendingSeek.mPromise.Ensure(__func__);
mMaster->Reset();
mMaster->mReader->ReleaseResources();
}
@@ -770,21 +770,21 @@ public:
mMaster->mVideoDecodeSuspended = false;
mMaster->mOnPlaybackEvent.Notify(MediaEventType::ExitVideoSuspend);
Reader()->SetVideoBlankDecode(false);
}
CreateSeekTask();
// Don't stop playback for a video-only seek since audio is playing.
- if (!mSeekJob.mTarget.IsVideoOnly()) {
+ if (!mSeekJob.mTarget->IsVideoOnly()) {
mMaster->StopPlayback();
}
- mMaster->UpdatePlaybackPositionInternal(mSeekJob.mTarget.GetTime().ToMicroseconds());
+ mMaster->UpdatePlaybackPositionInternal(mSeekJob.mTarget->GetTime().ToMicroseconds());
if (aVisibility == EventVisibility::Observable) {
mMaster->mOnPlaybackEvent.Notify(MediaEventType::SeekStarted);
// We want dormant actions to be transparent to the user.
// So we only notify the change when the seek request is from the user.
mMaster->UpdateNextFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING);
}
@@ -846,17 +846,17 @@ class MediaDecoderStateMachine::Accurate
public:
explicit AccurateSeekingState(Master* aPtr) : SeekingState(aPtr)
{
}
RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob aSeekJob,
EventVisibility aVisibility)
{
- MOZ_ASSERT(aSeekJob.mTarget.IsAccurate() || aSeekJob.mTarget.IsFast());
+ MOZ_ASSERT(aSeekJob.mTarget->IsAccurate() || aSeekJob.mTarget->IsFast());
return SeekingState::Enter(Move(aSeekJob), aVisibility);
}
void Exit() override
{
// Disconnect MediaDecoder.
mSeekJob.RejectIfExists(__func__);
@@ -867,24 +867,24 @@ public:
void HandleAudioDecoded(MediaData* aAudio) override
{
MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking, "Seek shouldn't be finished");
MOZ_ASSERT(aAudio);
// Video-only seek doesn't reset audio decoder. There might be pending audio
// requests when AccurateSeekTask::Seek() begins. We will just store the data
// without checking |mDiscontinuity| or calling DropAudioUpToSeekTarget().
- if (mSeekJob.mTarget.IsVideoOnly()) {
+ if (mSeekJob.mTarget->IsVideoOnly()) {
mMaster->Push(aAudio);
return;
}
AdjustFastSeekIfNeeded(aAudio);
- if (mSeekJob.mTarget.IsFast()) {
+ if (mSeekJob.mTarget->IsFast()) {
// Non-precise seek; we can stop the seek at the first sample.
mMaster->Push(aAudio);
mDoneAudioSeeking = true;
} else {
nsresult rv = DropAudioUpToSeekTarget(aAudio->As<AudioData>());
if (NS_FAILED(rv)) {
mMaster->DecodeError(rv);
return;
@@ -900,17 +900,17 @@ public:
void HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
{
MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking, "Seek shouldn't be finished");
MOZ_ASSERT(aVideo);
AdjustFastSeekIfNeeded(aVideo);
- if (mSeekJob.mTarget.IsFast()) {
+ if (mSeekJob.mTarget->IsFast()) {
// Non-precise seek. We can stop the seek at the first sample.
mMaster->Push(aVideo);
mDoneVideoSeeking = true;
} else {
nsresult rv = DropVideoUpToSeekTarget(aVideo);
if (NS_FAILED(rv)) {
mMaster->DecodeError(rv);
return;
@@ -924,17 +924,17 @@ public:
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()) {
+ 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) {
Reader()->WaitForData(aType);
return;
@@ -970,17 +970,17 @@ public:
mMaster->DecodeError(aError);
}
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()) {
+ if (mSeekJob.mTarget->IsVideoOnly()) {
return;
}
RequestAudioData();
}
void HandleVideoWaited(MediaData::Type aType) override
{
MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking, "Seek shouldn't be finished");
@@ -992,57 +992,57 @@ public:
{
MOZ_ASSERT(!mDoneAudioSeeking || !mDoneVideoSeeking, "Seek shouldn't be finished");
}
private:
void CreateSeekTask() override
{
mCurrentTimeBeforeSeek = TimeUnit::FromMicroseconds(mMaster->GetMediaTime());
- mDoneAudioSeeking = !Info().HasAudio() || mSeekJob.mTarget.IsVideoOnly();
+ mDoneAudioSeeking = !Info().HasAudio() || mSeekJob.mTarget->IsVideoOnly();
mDoneVideoSeeking = !Info().HasVideo();
}
void ResetMDSM() override
{
- if (mSeekJob.mTarget.IsVideoOnly()) {
+ if (mSeekJob.mTarget->IsVideoOnly()) {
mMaster->Reset(TrackInfo::kVideoTrack);
} else {
mMaster->Reset();
}
}
void DoSeek() override
{
// Request the demuxer to perform seek.
- mSeekRequest.Begin(Reader()->Seek(mSeekJob.mTarget, mMaster->Duration())
+ mSeekRequest.Begin(Reader()->Seek(mSeekJob.mTarget.ref(), mMaster->Duration())
->Then(OwnerThread(), __func__,
[this] (media::TimeUnit aUnit) {
OnSeekResolved(aUnit);
},
[this] (const MediaResult& aError) {
OnSeekRejected(aError);
}));
}
int64_t CalculateNewCurrentTime() const override
{
- const int64_t seekTime = mSeekJob.mTarget.GetTime().ToMicroseconds();
+ const int64_t seekTime = mSeekJob.mTarget->GetTime().ToMicroseconds();
// For the accurate seek, we always set the newCurrentTime = seekTime so that
// the updated HTMLMediaElement.currentTime will always be the seek target;
// we rely on the MediaSink to handles the gap between the newCurrentTime and
// the real decoded samples' start time.
- if (mSeekJob.mTarget.IsAccurate()) {
+ if (mSeekJob.mTarget->IsAccurate()) {
return seekTime;
}
// For the fast seek, we update the newCurrentTime with the decoded audio and
// video samples, set it to be the one which is closet to the seekTime.
- if (mSeekJob.mTarget.IsFast()) {
+ if (mSeekJob.mTarget->IsFast()) {
RefPtr<MediaData> audio = AudioQueue().PeekFront();
RefPtr<MediaData> video = VideoQueue().PeekFront();
// A situation that both audio and video approaches the end.
if (!audio && !video) {
return seekTime;
}
@@ -1089,68 +1089,68 @@ private:
MOZ_ASSERT(!mDoneVideoSeeking);
MOZ_ASSERT(!Reader()->IsRequestingVideoData());
MOZ_ASSERT(!Reader()->IsWaitingVideoData());
Reader()->RequestVideoData(false, media::TimeUnit());
}
void AdjustFastSeekIfNeeded(MediaData* aSample)
{
- if (mSeekJob.mTarget.IsFast() &&
- mSeekJob.mTarget.GetTime() > mCurrentTimeBeforeSeek &&
+ if (mSeekJob.mTarget->IsFast() &&
+ mSeekJob.mTarget->GetTime() > mCurrentTimeBeforeSeek &&
aSample->mTime < mCurrentTimeBeforeSeek.ToMicroseconds()) {
// We are doing a fastSeek, but we ended up *before* the previous
// playback position. This is surprising UX, so switch to an accurate
// seek and decode to the seek target. This is not conformant to the
// spec, fastSeek should always be fast, but until we get the time to
// change all Readers to seek to the keyframe after the currentTime
// in this case, we'll just decode forward. Bug 1026330.
- mSeekJob.mTarget.SetType(SeekTarget::Accurate);
+ mSeekJob.mTarget->SetType(SeekTarget::Accurate);
}
}
nsresult DropAudioUpToSeekTarget(AudioData* aAudio)
{
- MOZ_ASSERT(aAudio && mSeekJob.mTarget.IsAccurate());
+ MOZ_ASSERT(aAudio && mSeekJob.mTarget->IsAccurate());
CheckedInt64 sampleDuration = FramesToUsecs(aAudio->mFrames, Info().mAudio.mRate);
if (!sampleDuration.isValid()) {
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
- if (aAudio->mTime + sampleDuration.value() <= mSeekJob.mTarget.GetTime().ToMicroseconds()) {
+ if (aAudio->mTime + sampleDuration.value() <= mSeekJob.mTarget->GetTime().ToMicroseconds()) {
// Our seek target lies after the frames in this AudioData. Don't
// push it onto the audio queue, and keep decoding forwards.
return NS_OK;
}
- if (aAudio->mTime > mSeekJob.mTarget.GetTime().ToMicroseconds()) {
+ if (aAudio->mTime > mSeekJob.mTarget->GetTime().ToMicroseconds()) {
// The seek target doesn't lie in the audio block just after the last
// audio frames we've seen which were before the seek target. This
// could have been the first audio data we've seen after seek, i.e. the
// seek terminated after the seek target in the audio stream. Just
// abort the audio decode-to-target, the state machine will play
// silence to cover the gap. Typically this happens in poorly muxed
// files.
SWARN("Audio not synced after seek, maybe a poorly muxed file?");
mMaster->Push(aAudio);
mDoneAudioSeeking = true;
return NS_OK;
}
// The seek target lies somewhere in this AudioData's frames, strip off
// any frames which lie before the seek target, so we'll begin playback
// exactly at the seek target.
- NS_ASSERTION(mSeekJob.mTarget.GetTime().ToMicroseconds() >= aAudio->mTime,
+ NS_ASSERTION(mSeekJob.mTarget->GetTime().ToMicroseconds() >= aAudio->mTime,
"Target must at or be after data start.");
- NS_ASSERTION(mSeekJob.mTarget.GetTime().ToMicroseconds() < aAudio->mTime + sampleDuration.value(),
+ NS_ASSERTION(mSeekJob.mTarget->GetTime().ToMicroseconds() < aAudio->mTime + sampleDuration.value(),
"Data must end after target.");
CheckedInt64 framesToPrune =
- UsecsToFrames(mSeekJob.mTarget.GetTime().ToMicroseconds() - aAudio->mTime, Info().mAudio.mRate);
+ UsecsToFrames(mSeekJob.mTarget->GetTime().ToMicroseconds() - aAudio->mTime, Info().mAudio.mRate);
if (!framesToPrune.isValid()) {
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
if (framesToPrune.value() > aAudio->mFrames) {
// We've messed up somehow. Don't try to trim frames, the |frames|
// variable below will overflow.
SWARN("Can't prune more frames that we have!");
return NS_ERROR_FAILURE;
@@ -1165,17 +1165,17 @@ private:
memcpy(audioData.get(),
aAudio->mAudioData.get() + (framesToPrune.value() * channels),
frames * channels * sizeof(AudioDataValue));
CheckedInt64 duration = FramesToUsecs(frames, Info().mAudio.mRate);
if (!duration.isValid()) {
return NS_ERROR_DOM_MEDIA_OVERFLOW_ERR;
}
RefPtr<AudioData> data(new AudioData(aAudio->mOffset,
- mSeekJob.mTarget.GetTime().ToMicroseconds(),
+ mSeekJob.mTarget->GetTime().ToMicroseconds(),
duration.value(),
frames,
Move(audioData),
channels,
aAudio->mRate));
MOZ_ASSERT(AudioQueue().GetSize() == 0, "Should be the 1st sample after seeking");
mMaster->Push(data);
mDoneAudioSeeking = true;
@@ -1184,17 +1184,17 @@ private:
}
nsresult DropVideoUpToSeekTarget(MediaData* aSample)
{
RefPtr<VideoData> video(aSample->As<VideoData>());
MOZ_ASSERT(video);
SLOG("DropVideoUpToSeekTarget() frame [%lld, %lld]",
video->mTime, video->GetEndTime());
- const int64_t target = mSeekJob.mTarget.GetTime().ToMicroseconds();
+ const int64_t target = mSeekJob.mTarget->GetTime().ToMicroseconds();
// If the frame end time is less than the seek target, we won't want
// to display this frame after the seek, so discard it.
if (target >= video->GetEndTime()) {
SLOG("DropVideoUpToSeekTarget() pop video frame [%lld, %lld] target=%lld",
video->mTime, video->GetEndTime(), target);
mFirstVideoFrameAfterSeek = video;
} else {
@@ -1265,17 +1265,17 @@ class MediaDecoderStateMachine::NextFram
public:
explicit NextFrameSeekingState(Master* aPtr) : SeekingState(aPtr)
{
}
RefPtr<MediaDecoder::SeekPromise> Enter(SeekJob aSeekJob,
EventVisibility aVisibility)
{
- MOZ_ASSERT(aSeekJob.mTarget.IsNextFrame());
+ MOZ_ASSERT(aSeekJob.mTarget->IsNextFrame());
return SeekingState::Enter(Move(aSeekJob), aVisibility);
}
void Exit() override
{
// Disconnect my async seek operation.
mAsyncSeekTask->Cancel();
@@ -1490,17 +1490,17 @@ private:
MOZ_ASSERT_UNREACHABLE("We cannot handle RAW_DATA or NULL_DATA here.");
}
}
int64_t CalculateNewCurrentTime() const override
{
// The HTMLMediaElement.currentTime should be updated to the seek target
// which has been updated to the next frame's time.
- return mSeekJob.mTarget.GetTime().ToMicroseconds();
+ return mSeekJob.mTarget->GetTime().ToMicroseconds();
}
void OnSeekTaskResolved()
{
if (mSeekedAudioData) {
mMaster->Push(mSeekedAudioData);
mMaster->mDecodedAudioEndTime = std::max(
mSeekedAudioData->GetEndTime(), mMaster->mDecodedAudioEndTime);
@@ -1570,32 +1570,32 @@ private:
}
// Update the seek target's time before resolving this seek task, the updated
// time will be used in the MDSM::SeekCompleted() to update the MDSM's position.
void UpdateSeekTargetTime()
{
RefPtr<MediaData> data = VideoQueue().PeekFront();
if (data) {
- mSeekJob.mTarget.SetTime(TimeUnit::FromMicroseconds(data->mTime));
+ mSeekJob.mTarget->SetTime(TimeUnit::FromMicroseconds(data->mTime));
} else if (mSeekedVideoData) {
- mSeekJob.mTarget.SetTime(TimeUnit::FromMicroseconds(mSeekedVideoData->mTime));
+ mSeekJob.mTarget->SetTime(TimeUnit::FromMicroseconds(mSeekedVideoData->mTime));
} else if (mIsVideoQueueFinished || VideoQueue().AtEndOfStream()) {
- mSeekJob.mTarget.SetTime(mDuration);
+ mSeekJob.mTarget->SetTime(mDuration);
} else {
MOZ_ASSERT(false, "No data!");
}
}
void MaybeFinishSeek()
{
if (IsAudioSeekComplete() && IsVideoSeekComplete()) {
UpdateSeekTargetTime();
- auto time = mSeekJob.mTarget.GetTime().ToMicroseconds();
+ auto time = mSeekJob.mTarget->GetTime().ToMicroseconds();
DiscardFrames(AudioQueue(), [time] (int64_t aSampleTime) {
return aSampleTime < time;
});
OnSeekTaskResolved();
}
}
@@ -1912,17 +1912,17 @@ StateObject::HandleNotWaited(const WaitF
}
RefPtr<MediaDecoder::SeekPromise>
MediaDecoderStateMachine::
StateObject::HandleSeek(SeekTarget aTarget)
{
SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
SeekJob seekJob;
- seekJob.mTarget = aTarget;
+ seekJob.mTarget = Some(aTarget);
return SetSeekingState(Move(seekJob), EventVisibility::Observable);
}
RefPtr<ShutdownPromise>
MediaDecoderStateMachine::
StateObject::HandleShutdown()
{
return SetState<ShutdownState>();
@@ -1984,35 +1984,35 @@ StateObject::HandleResumeVideoDecoding()
// Start video-only seek to the current time.
SeekJob seekJob;
const SeekTarget::Type type = mMaster->HasAudio()
? SeekTarget::Type::Accurate
: SeekTarget::Type::PrevSyncPoint;
- seekJob.mTarget = SeekTarget(mMaster->GetMediaTime(),
- type,
- true /* aVideoOnly */);
+ seekJob.mTarget.emplace(mMaster->GetMediaTime(),
+ type,
+ true /* aVideoOnly */);
SetSeekingState(Move(seekJob), EventVisibility::Suppressed)->Then(
AbstractThread::MainThread(), __func__,
[start, info, hw](){ ReportRecoveryTelemetry(start, info, hw); },
[](){});
}
RefPtr<MediaDecoder::SeekPromise>
MediaDecoderStateMachine::
StateObject::SetSeekingState(SeekJob&& aSeekJob, EventVisibility aVisibility)
{
- if (aSeekJob.mTarget.IsAccurate() || aSeekJob.mTarget.IsFast()) {
+ if (aSeekJob.mTarget->IsAccurate() || aSeekJob.mTarget->IsFast()) {
return SetState<AccurateSeekingState>(Move(aSeekJob), aVisibility);
}
- if (aSeekJob.mTarget.IsNextFrame()) {
+ if (aSeekJob.mTarget->IsNextFrame()) {
return SetState<NextFrameSeekingState>(Move(aSeekJob), aVisibility);
}
MOZ_ASSERT_UNREACHABLE("Unknown SeekTarget::Type.");
return nullptr;
}
void
@@ -2226,17 +2226,17 @@ SeekingState::SeekCompleted()
// Notify FirstFrameLoaded now if we haven't since we've decoded some data
// for readyState to transition to HAVE_CURRENT_DATA and fire 'loadeddata'.
if (!mMaster->mSentFirstFrameLoadedEvent) {
mMaster->FinishDecodeFirstFrame();
}
// Ensure timestamps are up to date.
- if (!mSeekJob.mTarget.IsVideoOnly()) {
+ if (!mSeekJob.mTarget->IsVideoOnly()) {
// Don't update playback position for video-only seek.
// Otherwise we might have |newCurrentTime > mMediaSink->GetPosition()|
// and fail the assertion in GetClock() since we didn't stop MediaSink.
mMaster->UpdatePlaybackPositionInternal(newCurrentTime);
}
// Try to decode another frame to detect if we're at the end...
SLOG("Seek completed, mCurrentPosition=%lld", mMaster->mCurrentPosition.Ref());