Bug 1235301 part 3 - export HTMLMediaElement::seekToNextFrame(); r=jwwang
MozReview-Commit-ID: 8WMpwOwfqxz
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1460,16 +1460,22 @@ void
HTMLMediaElement::FastSeek(double aTime, ErrorResult& aRv)
{
LOG(LogLevel::Debug, ("Reporting telemetry VIDEO_FASTSEEK_USED"));
Telemetry::Accumulate(Telemetry::VIDEO_FASTSEEK_USED, 1);
Seek(aTime, SeekTarget::PrevSyncPoint, aRv);
}
void
+HTMLMediaElement::SeekToNextFrame(ErrorResult& aRv)
+{
+ Seek(CurrentTime(), SeekTarget::NextFrame, aRv);
+}
+
+void
HTMLMediaElement::SetCurrentTime(double aCurrentTime, ErrorResult& aRv)
{
Seek(aCurrentTime, SeekTarget::Accurate, aRv);
}
/**
* Check if aValue is inside a range of aRanges, and if so sets aIsInRanges
* to true and put the range index in aIntervalIndex. If aValue is not
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -475,16 +475,18 @@ public:
bool Seeking() const;
double CurrentTime() const;
void SetCurrentTime(double aCurrentTime, ErrorResult& aRv);
void FastSeek(double aTime, ErrorResult& aRv);
+ void SeekToNextFrame(ErrorResult& aRv);
+
double Duration() const;
bool HasAudio() const
{
return mMediaInfo.HasAudio();
}
bool HasVideo() const
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -42,16 +42,17 @@
#include "DOMMediaStream.h"
#include "ImageContainer.h"
#include "MediaDecoder.h"
#include "MediaDecoderReader.h"
#include "MediaDecoderReaderWrapper.h"
#include "MediaDecoderStateMachine.h"
#include "MediaShutdownManager.h"
#include "MediaTimer.h"
+#include "NextFrameSeekTask.h"
#include "TimeUnits.h"
#include "VideoSegment.h"
#include "VideoUtils.h"
#include "gfxPrefs.h"
namespace mozilla {
using namespace mozilla::dom;
@@ -1463,16 +1464,21 @@ MediaDecoderStateMachine::Seek(SeekTarge
}
// We need to be able to seek in some way
if (!mMediaSeekable && !mMediaSeekableOnlyInBufferedRanges) {
DECODER_WARN("Seek() function should not be called on a non-seekable state machine");
return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__);
}
+ if (aTarget.IsNextFrame() && !HasVideo()) {
+ DECODER_WARN("Ignore a NextFrameSeekTask on a media file without video track.");
+ return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__);
+ }
+
MOZ_ASSERT(mState > DECODER_STATE_DECODING_METADATA,
"We should have got duration already");
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;
@@ -1575,19 +1581,27 @@ MediaDecoderStateMachine::InitiateSeek(S
DiscardSeekTaskIfExist();
mSeekTaskRequest.DisconnectIfExists();
// SeekTask will register its callbacks to MediaDecoderReaderWrapper.
CancelMediaDecoderReaderWrapperCallback();
// Create a new SeekTask instance for the incoming seek task.
- mSeekTask = new AccurateSeekTask(mDecoderID, OwnerThread(),
- mReader.get(), Move(aSeekJob),
- mInfo, Duration(), GetMediaTime());
+ if (aSeekJob.mTarget.IsAccurate() || aSeekJob.mTarget.IsFast()) {
+ mSeekTask = new AccurateSeekTask(mDecoderID, OwnerThread(),
+ mReader.get(), Move(aSeekJob),
+ mInfo, Duration(), GetMediaTime());
+ } else if (aSeekJob.mTarget.IsNextFrame()) {
+ mSeekTask = new NextFrameSeekTask(mDecoderID, OwnerThread(), mReader.get(),
+ Move(aSeekJob), mInfo, Duration(),
+ GetMediaTime(), AudioQueue(), VideoQueue());
+ } else {
+ MOZ_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);