Bug 1309516 part 7 - modify the seek operation;r?jwwang
MozReview-Commit-ID: AZ9yK050ElM
--- a/dom/media/AccurateSeekTask.cpp
+++ b/dom/media/AccurateSeekTask.cpp
@@ -72,16 +72,46 @@ AccurateSeekTask::Discard()
bool
AccurateSeekTask::NeedToResetMDSM() const
{
AssertOwnerThread();
return true;
}
+int64_t
+AccurateSeekTask::CalculateNewCurrentTime() const
+{
+ AssertOwnerThread();
+
+ const int64_t seekTime = 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 (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 (mTarget.IsFast()) {
+ MOZ_ASSERT(mSeekedAudioData || mSeekedVideoData);
+ const int64_t audioStart = mSeekedAudioData ? mSeekedAudioData->mTime : INT64_MAX;
+ const int64_t videoStart = mSeekedVideoData ? mSeekedVideoData->mTime : INT64_MAX;
+ const int64_t audioGap = std::abs(audioStart - seekTime);
+ const int64_t videoGap = std::abs(videoStart - seekTime);
+ return audioGap <= videoGap ? audioStart : videoStart;
+ }
+
+ MOZ_ASSERT(false, "AccurateSeekTask doesn't handle other seek types.");
+ return 0;
+}
+
RefPtr<AccurateSeekTask::SeekTaskPromise>
AccurateSeekTask::Seek(const media::TimeUnit& aDuration)
{
AssertOwnerThread();
// Do the seek.
mSeekRequest.Begin(mReader->Seek(mTarget, aDuration)
->Then(OwnerThread(), __func__, this,
--- a/dom/media/AccurateSeekTask.h
+++ b/dom/media/AccurateSeekTask.h
@@ -24,16 +24,18 @@ public:
int64_t aCurrentMediaTime);
void Discard() override;
RefPtr<SeekTaskPromise> Seek(const media::TimeUnit& aDuration) override;
bool NeedToResetMDSM() const override;
+ int64_t CalculateNewCurrentTime() const override;
+
private:
~AccurateSeekTask();
void RequestVideoData();
void RequestAudioData();
nsresult DropAudioUpToSeekTarget(MediaData* aSample);
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -1446,42 +1446,17 @@ DecodingState::MaybeStartBuffering()
SetState<BufferingState>();
}
}
void
MediaDecoderStateMachine::
SeekingState::SeekCompleted()
{
- int64_t seekTime = mSeekTask->GetSeekTarget().GetTime().ToMicroseconds();
- int64_t newCurrentTime = seekTime;
-
- // Setup timestamp state.
- RefPtr<MediaData> video = mMaster->VideoQueue().PeekFront();
- if (seekTime == mMaster->Duration().ToMicroseconds()) {
- newCurrentTime = seekTime;
- } else if (mMaster->HasAudio()) {
- RefPtr<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.
- // While seeking to a position where there's only either audio or video, or
- // seeking to a position lies before audio or video, we need to check if
- // seekTime is bounded in suitable duration. See Bug 1112438.
- int64_t audioStart = audio ? audio->mTime : seekTime;
- // We only pin the seek time to the video start time if the video frame
- // contains the seek time.
- if (video && video->mTime <= seekTime && video->GetEndTime() > seekTime) {
- newCurrentTime = std::min(audioStart, video->mTime);
- } else {
- newCurrentTime = audioStart;
- }
- } else {
- newCurrentTime = video ? video->mTime : seekTime;
- }
+ const int64_t newCurrentTime = mSeekTask->CalculateNewCurrentTime();
bool isLiveStream = Resource()->IsLiveStream();
if (newCurrentTime == mMaster->Duration().ToMicroseconds() && !isLiveStream) {
// Seeked to end of media. Explicitly finish the queues so DECODING
// will transition to COMPLETED immediately. Note we don't do
// this when playing a live stream, since the end of media will advance
// once we download more data!
AudioQueue().Finish();
@@ -1512,17 +1487,17 @@ SeekingState::SeekCompleted()
// 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());
- if (video) {
+ if (mMaster->VideoQueue().PeekFront()) {
mMaster->mMediaSink->Redraw(Info().mVideo);
mMaster->mOnPlaybackEvent.Notify(MediaEventType::Invalidate);
}
if (mVisibility == EventVisibility::Observable) {
mMaster->UpdateNextFrameStatus();
}
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1955,26 +1955,18 @@ MediaFormatReader::Seek(SeekTarget aTarg
return p;
}
void
MediaFormatReader::SetSeekTarget(const SeekTarget& aTarget)
{
MOZ_ASSERT(OnTaskQueue());
- SeekTarget target = aTarget;
-
- // Transform the seek target time to the demuxer timeline.
- if (!ForceZeroStartTime()) {
- target.SetTime(aTarget.GetTime() - TimeUnit::FromMicroseconds(StartTime())
- + mInfo.mStartTime);
- }
-
- mOriginalSeekTarget = target;
- mFallbackSeekTime = mPendingSeekTime = Some(target.GetTime());
+ mOriginalSeekTarget = aTarget;
+ mFallbackSeekTime = mPendingSeekTime = Some(aTarget.GetTime());
}
void
MediaFormatReader::ScheduleSeek()
{
if (mSeekScheduled) {
return;
}
--- a/dom/media/NextFrameSeekTask.cpp
+++ b/dom/media/NextFrameSeekTask.cpp
@@ -63,16 +63,26 @@ NextFrameSeekTask::Discard()
bool
NextFrameSeekTask::NeedToResetMDSM() const
{
AssertOwnerThread();
return false;
}
+int64_t
+NextFrameSeekTask::CalculateNewCurrentTime() const
+{
+ AssertOwnerThread();
+
+ // The HTMLMediaElement.currentTime should be updated to the seek target
+ // which has been updated to the next frame's time.
+ return mTarget.GetTime().ToMicroseconds();
+}
+
/*
* Remove samples from the queue until aCompare() returns false.
* aCompare A function object with the signature bool(int64_t) which returns
* true for samples that should be removed.
*/
template <typename Function> static void
DiscardFrames(MediaQueue<MediaData>& aQueue, const Function& aCompare)
{
--- a/dom/media/NextFrameSeekTask.h
+++ b/dom/media/NextFrameSeekTask.h
@@ -35,16 +35,18 @@ public:
MediaQueue<MediaData>& aVideoQueue);
void Discard() override;
RefPtr<SeekTaskPromise> Seek(const media::TimeUnit& aDuration) override;
bool NeedToResetMDSM() const override;
+ int64_t CalculateNewCurrentTime() const override;
+
private:
~NextFrameSeekTask();
void RequestVideoData();
bool NeedMoreVideo() const;
bool IsVideoRequestPending() const;
--- a/dom/media/SeekTask.h
+++ b/dom/media/SeekTask.h
@@ -53,16 +53,18 @@ public:
MozPromise<SeekTaskResolveValue, SeekTaskRejectValue, IsExclusive>;
virtual void Discard() = 0;
virtual RefPtr<SeekTaskPromise> Seek(const media::TimeUnit& aDuration) = 0;
virtual bool NeedToResetMDSM() const = 0;
+ virtual int64_t CalculateNewCurrentTime() const = 0;
+
const SeekTarget& GetSeekTarget();
protected:
SeekTask(const void* aDecoderID,
AbstractThread* aThread,
MediaDecoderReaderWrapper* aReader,
const SeekTarget& aTarget);