Bug 1284399. Part 1 - add GetSeekTarget() to remove direct access to mSeekJob. r=kaku
MozReview-Commit-ID: 60wIW9gHYKt
--- a/dom/media/AccurateSeekTask.cpp
+++ b/dom/media/AccurateSeekTask.cpp
@@ -47,18 +47,17 @@ AccurateSeekTask::AccurateSeekTask(const
, mAudioRate(aInfo.mAudio.mRate)
, mDoneAudioSeeking(!aInfo.HasAudio() || mSeekJob.mTarget.IsVideoOnly())
, mDoneVideoSeeking(!aInfo.HasVideo())
{
AssertOwnerThread();
// Bound the seek time to be inside the media range.
NS_ASSERTION(aEnd.ToMicroseconds() != -1, "Should know end time by now");
- mSeekJob.mTarget.SetTime(
- std::max(media::TimeUnit(), std::min(mSeekJob.mTarget.GetTime(), aEnd)));
+ mTarget.SetTime(std::max(media::TimeUnit(), std::min(mTarget.GetTime(), aEnd)));
// Configure MediaDecoderReaderWrapper.
SetCallbacks();
}
AccurateSeekTask::~AccurateSeekTask()
{
AssertOwnerThread();
@@ -91,17 +90,17 @@ AccurateSeekTask::NeedToResetMDSM() cons
}
RefPtr<AccurateSeekTask::SeekTaskPromise>
AccurateSeekTask::Seek(const media::TimeUnit& aDuration)
{
AssertOwnerThread();
// Do the seek.
- mSeekRequest.Begin(mReader->Seek(mSeekJob.mTarget, aDuration)
+ mSeekRequest.Begin(mReader->Seek(mTarget, aDuration)
->Then(OwnerThread(), __func__, this,
&AccurateSeekTask::OnSeekResolved, &AccurateSeekTask::OnSeekRejected));
return mSeekTaskPromise.Ensure(__func__);
}
void
AccurateSeekTask::RequestAudioData()
@@ -124,53 +123,53 @@ AccurateSeekTask::RequestVideoData()
}
nsresult
AccurateSeekTask::DropAudioUpToSeekTarget(MediaData* aSample)
{
AssertOwnerThread();
RefPtr<AudioData> audio(aSample->As<AudioData>());
- MOZ_ASSERT(audio && mSeekJob.Exists() && mSeekJob.mTarget.IsAccurate());
+ MOZ_ASSERT(audio && mSeekJob.Exists() && mTarget.IsAccurate());
CheckedInt64 sampleDuration = FramesToUsecs(audio->mFrames, mAudioRate);
if (!sampleDuration.isValid()) {
return NS_ERROR_FAILURE;
}
- if (audio->mTime + sampleDuration.value() <= mSeekJob.mTarget.GetTime().ToMicroseconds()) {
+ if (audio->mTime + sampleDuration.value() <= 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 (audio->mTime > mSeekJob.mTarget.GetTime().ToMicroseconds()) {
+ if (audio->mTime > 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.
DECODER_WARN("Audio not synced after seek, maybe a poorly muxed file?");
mSeekedAudioData = audio;
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() >= audio->mTime,
+ NS_ASSERTION(mTarget.GetTime().ToMicroseconds() >= audio->mTime,
"Target must at or be after data start.");
- NS_ASSERTION(mSeekJob.mTarget.GetTime().ToMicroseconds() < audio->mTime + sampleDuration.value(),
+ NS_ASSERTION(mTarget.GetTime().ToMicroseconds() < audio->mTime + sampleDuration.value(),
"Data must end after target.");
CheckedInt64 framesToPrune =
- UsecsToFrames(mSeekJob.mTarget.GetTime().ToMicroseconds() - audio->mTime, mAudioRate);
+ UsecsToFrames(mTarget.GetTime().ToMicroseconds() - audio->mTime, mAudioRate);
if (!framesToPrune.isValid()) {
return NS_ERROR_FAILURE;
}
if (framesToPrune.value() > audio->mFrames) {
// We've messed up somehow. Don't try to trim frames, the |frames|
// variable below will overflow.
DECODER_WARN("Can't prune more frames that we have!");
return NS_ERROR_FAILURE;
@@ -185,17 +184,17 @@ AccurateSeekTask::DropAudioUpToSeekTarge
memcpy(audioData.get(),
audio->mAudioData.get() + (framesToPrune.value() * channels),
frames * channels * sizeof(AudioDataValue));
CheckedInt64 duration = FramesToUsecs(frames, mAudioRate);
if (!duration.isValid()) {
return NS_ERROR_FAILURE;
}
RefPtr<AudioData> data(new AudioData(audio->mOffset,
- mSeekJob.mTarget.GetTime().ToMicroseconds(),
+ mTarget.GetTime().ToMicroseconds(),
duration.value(),
frames,
Move(audioData),
channels,
audio->mRate));
MOZ_ASSERT(!mSeekedAudioData, "Should be the 1st sample after seeking");
mSeekedAudioData = data;
mDoneAudioSeeking = true;
@@ -208,17 +207,17 @@ AccurateSeekTask::DropVideoUpToSeekTarge
{
AssertOwnerThread();
RefPtr<VideoData> video(aSample->As<VideoData>());
MOZ_ASSERT(video);
DECODER_LOG("DropVideoUpToSeekTarget() frame [%lld, %lld]",
video->mTime, video->GetEndTime());
MOZ_ASSERT(mSeekJob.Exists());
- const int64_t target = mSeekJob.mTarget.GetTime().ToMicroseconds();
+ const int64_t target = 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()) {
DECODER_LOG("DropVideoUpToSeekTarget() pop video frame [%lld, %lld] target=%lld",
video->mTime, video->GetEndTime(), target);
mFirstVideoFrameAfterSeek = video;
} else {
@@ -276,26 +275,26 @@ AccurateSeekTask::OnSeekRejected(nsresul
MOZ_ASSERT(NS_FAILED(aResult), "Cancels should also disconnect mSeekRequest");
RejectIfExist(__func__);
}
void
AccurateSeekTask::AdjustFastSeekIfNeeded(MediaData* aSample)
{
AssertOwnerThread();
- if (mSeekJob.mTarget.IsFast() &&
- mSeekJob.mTarget.GetTime() > mCurrentTimeBeforeSeek &&
+ if (mTarget.IsFast() &&
+ 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);
+ mTarget.SetType(SeekTarget::Accurate);
}
}
void
AccurateSeekTask::OnAudioDecoded(MediaData* aAudioSample)
{
AssertOwnerThread();
MOZ_ASSERT(!mSeekTaskPromise.IsEmpty(), "Seek shouldn't be finished");
@@ -319,17 +318,17 @@ AccurateSeekTask::OnAudioDecoded(MediaDa
if (mFirstAudioSample) {
mFirstAudioSample = false;
MOZ_ASSERT(audio->mDiscontinuity);
}
AdjustFastSeekIfNeeded(audio);
- if (mSeekJob.mTarget.IsFast()) {
+ if (mTarget.IsFast()) {
// Non-precise seek; we can stop the seek at the first sample.
mSeekedAudioData = audio;
mDoneAudioSeeking = true;
} else if (NS_FAILED(DropAudioUpToSeekTarget(audio))) {
RejectIfExist(__func__);
return;
}
@@ -410,17 +409,17 @@ AccurateSeekTask::OnVideoDecoded(MediaDa
if (mFirstVideoSample) {
mFirstVideoSample = false;
MOZ_ASSERT(video->mDiscontinuity);
}
AdjustFastSeekIfNeeded(video);
- if (mSeekJob.mTarget.IsFast()) {
+ if (mTarget.IsFast()) {
// Non-precise seek. We can stop the seek at the first sample.
mSeekedVideoData = video;
mDoneVideoSeeking = true;
} else if (NS_FAILED(DropVideoUpToSeekTarget(video.get()))) {
RejectIfExist(__func__);
return;
}
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1166,18 +1166,18 @@ MediaDecoderStateMachine::SetDormant(boo
if (mState == DECODER_STATE_SEEKING) {
if (mQueuedSeek.Exists()) {
// Keep latest seek target
} else if (mSeekTask && mSeekTask->Exists()) {
// Because both audio and video decoders are going to be reset in this
// method later, we treat a VideoOnly seek task as a normal Accurate
// seek task so that while it is resumed, both audio and video playback
// are handled.
- if (mSeekTask->GetSeekJob().mTarget.IsVideoOnly()) {
- mSeekTask->GetSeekJob().mTarget.SetType(SeekTarget::Accurate);
+ if (mSeekTask->GetSeekTarget().IsVideoOnly()) {
+ mSeekTask->GetSeekTarget().SetType(SeekTarget::Accurate);
}
mQueuedSeek = Move(mSeekTask->GetSeekJob());
mSeekTaskRequest.DisconnectIfExists();
} else {
mQueuedSeek.mTarget = SeekTarget(mCurrentPosition,
SeekTarget::Accurate,
MediaDecoderEventVisibility::Suppressed);
// XXXbholley - Nobody is listening to this promise. Do we need to pass it
@@ -1653,19 +1653,19 @@ MediaDecoderStateMachine::InitiateSeek(S
} else {
MOZ_DIAGNOSTIC_ASSERT(false, "Cannot handle this seek task.");
}
// 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.
StopPlayback();
- UpdatePlaybackPositionInternal(mSeekTask->GetSeekJob().mTarget.GetTime().ToMicroseconds());
-
- mOnSeekingStart.Notify(mSeekTask->GetSeekJob().mTarget.mEventVisibility);
+ UpdatePlaybackPositionInternal(mSeekTask->GetSeekTarget().GetTime().ToMicroseconds());
+
+ mOnSeekingStart.Notify(mSeekTask->GetSeekTarget().mEventVisibility);
// Reset our state machine and decoding pipeline before seeking.
if (mSeekTask->NeedToResetMDSM()) { Reset(); }
// Do the seek.
mSeekTaskRequest.Begin(mSeekTask->Seek(Duration())
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnSeekTaskResolved,
@@ -2141,17 +2141,17 @@ MediaDecoderStateMachine::FinishDecodeFi
}
void
MediaDecoderStateMachine::SeekCompleted()
{
MOZ_ASSERT(OnTaskQueue());
MOZ_ASSERT(mState == DECODER_STATE_SEEKING);
- int64_t seekTime = mSeekTask->GetSeekJob().mTarget.GetTime().ToMicroseconds();
+ int64_t seekTime = mSeekTask->GetSeekTarget().GetTime().ToMicroseconds();
int64_t newCurrentTime = seekTime;
// Setup timestamp state.
RefPtr<MediaData> video = VideoQueue().PeekFront();
if (seekTime == Duration().ToMicroseconds()) {
newCurrentTime = seekTime;
} else if (HasAudio()) {
RefPtr<MediaData> audio = AudioQueue().PeekFront();
--- a/dom/media/NextFrameSeekTask.cpp
+++ b/dom/media/NextFrameSeekTask.cpp
@@ -151,17 +151,17 @@ NextFrameSeekTask::IsVideoSeekComplete()
void
NextFrameSeekTask::MaybeFinishSeek()
{
AssertOwnerThread();
if (IsAudioSeekComplete() && IsVideoSeekComplete()) {
UpdateSeekTargetTime();
- auto time = mSeekJob.mTarget.GetTime().ToMicroseconds();
+ auto time = mTarget.GetTime().ToMicroseconds();
DiscardFrames(mAudioQueue, [time] (int64_t aSampleTime) {
return aSampleTime < time;
});
Resolve(__func__); // Call to MDSM::SeekCompleted();
}
}
@@ -328,19 +328,19 @@ NextFrameSeekTask::CancelCallbacks()
void
NextFrameSeekTask::UpdateSeekTargetTime()
{
AssertOwnerThread();
RefPtr<MediaData> data = mVideoQueue.PeekFront();
if (data) {
- mSeekJob.mTarget.SetTime(TimeUnit::FromMicroseconds(data->mTime));
+ mTarget.SetTime(TimeUnit::FromMicroseconds(data->mTime));
} else if (mSeekedVideoData) {
- mSeekJob.mTarget.SetTime(TimeUnit::FromMicroseconds(mSeekedVideoData->mTime));
+ mTarget.SetTime(TimeUnit::FromMicroseconds(mSeekedVideoData->mTime));
} else if (mIsVideoQueueFinished || mVideoQueue.AtEndOfStream()) {
- mSeekJob.mTarget.SetTime(mDuration);
+ mTarget.SetTime(mDuration);
} else {
MOZ_ASSERT(false, "No data!");
}
}
} // namespace media
} // namespace mozilla
--- a/dom/media/SeekTask.cpp
+++ b/dom/media/SeekTask.cpp
@@ -13,16 +13,17 @@ namespace mozilla {
SeekTask::SeekTask(const void* aDecoderID,
AbstractThread* aThread,
MediaDecoderReaderWrapper* aReader,
SeekJob&& aSeekJob)
: mDecoderID(aDecoderID)
, mOwnerThread(aThread)
, mReader(aReader)
, mSeekJob(Move(aSeekJob))
+ , mTarget(mSeekJob.mTarget)
, mIsDiscarded(false)
, mIsAudioQueueFinished(false)
, mIsVideoQueueFinished(false)
, mNeedToStopPrerollingAudio(false)
, mNeedToStopPrerollingVideo(false)
{
AssertOwnerThread();
}
@@ -78,16 +79,23 @@ SeekTask::OwnerThread() const
SeekJob&
SeekTask::GetSeekJob()
{
AssertOwnerThread();
return mSeekJob;
}
+SeekTarget&
+SeekTask::GetSeekTarget()
+{
+ AssertOwnerThread();
+ return mTarget;
+}
+
bool
SeekTask::Exists() const
{
AssertOwnerThread();
// mSeekTaskPromise communicates SeekTask and MDSM;
// mSeekJob communicates MDSM and MediaDecoder;
// Either one exists means the current seek task has yet finished.
--- a/dom/media/SeekTask.h
+++ b/dom/media/SeekTask.h
@@ -53,16 +53,18 @@ public:
virtual void Discard() = 0;
virtual RefPtr<SeekTaskPromise> Seek(const media::TimeUnit& aDuration) = 0;
virtual bool NeedToResetMDSM() const = 0;
SeekJob& GetSeekJob();
+ SeekTarget& GetSeekTarget();
+
bool Exists() const;
protected:
SeekTask(const void* aDecoderID,
AbstractThread* aThread,
MediaDecoderReaderWrapper* aReader,
SeekJob&& aSeekJob);
@@ -82,16 +84,17 @@ protected:
const void* mDecoderID; // For logging.
const RefPtr<AbstractThread> mOwnerThread;
const RefPtr<MediaDecoderReaderWrapper> mReader;
/*
* Internal state.
*/
SeekJob mSeekJob;
+ SeekTarget& mTarget;
MozPromiseHolder<SeekTaskPromise> mSeekTaskPromise;
bool mIsDiscarded;
/*
* Information which are going to be returned to MDSM.
*/
RefPtr<MediaData> mSeekedAudioData;
RefPtr<MediaData> mSeekedVideoData;