Diff
Modified: trunk/LayoutTests/ChangeLog (170335 => 170336)
--- trunk/LayoutTests/ChangeLog 2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/LayoutTests/ChangeLog 2014-06-24 00:08:25 UTC (rev 170336)
@@ -1,3 +1,13 @@
+2014-06-20 Jer Noble <jer.no...@apple.com>
+
+ HTMLMediaElement seek algorithm should allow cancelling previous seeks.
+ https://bugs.webkit.org/show_bug.cgi?id=134116
+
+ Reviewed by Eric Carlson.
+
+ * media/video-seek-double-expected.txt: Added.
+ * media/video-seek-double.html: Added.
+
2014-06-19 Jeffrey Pfau <jp...@apple.com>
Database process crashes when multiple transactions attempt to run at once
Added: trunk/LayoutTests/media/video-seek-double-expected.txt (0 => 170336)
--- trunk/LayoutTests/media/video-seek-double-expected.txt (rev 0)
+++ trunk/LayoutTests/media/video-seek-double-expected.txt 2014-06-24 00:08:25 UTC (rev 170336)
@@ -0,0 +1,13 @@
+Test that seeking twice in the same run loop will cancel the first seek.
+
+
+EVENT(canplaythrough)
+RUN(video.currentTime = 2)
+RUN(video.currentTime = 0.5)
+
+EVENT(seeked)
+EXPECTED (video.currentTime == '0.5') OK
+RUN(video.play())
+EVENT(play)
+END OF TEST
+
Added: trunk/LayoutTests/media/video-seek-double.html (0 => 170336)
--- trunk/LayoutTests/media/video-seek-double.html (rev 0)
+++ trunk/LayoutTests/media/video-seek-double.html 2014-06-24 00:08:25 UTC (rev 170336)
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+<head>
+ <script src=""
+ <script src=""
+ <script>
+ function runTest()
+ {
+ findMediaElement();
+ waitForEvent('canplaythrough', canplaythrough);
+ video.src = "" 'content/test');
+ }
+
+ function canplaythrough()
+ {
+ waitForEventOnce('seeked', seeked );
+ run('video.currentTime = 2');
+ run('video.currentTime = 0.5');
+ consoleWrite('');
+ }
+
+ function seeked()
+ {
+ testExpected('video.currentTime', 0.5);
+ waitForEventAndFail('seeked');
+ waitForEventAndEnd('play');
+ run('video.play()');
+ }
+ </script>
+</head>
+<body _onload_='runTest()'>
+ <p>Test that seeking twice in the same run loop will cancel the first seek.
+ </p>
+ <video controls></video>
+</body>
+</html>
\ No newline at end of file
Modified: trunk/Source/WebCore/ChangeLog (170335 => 170336)
--- trunk/Source/WebCore/ChangeLog 2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/ChangeLog 2014-06-24 00:08:25 UTC (rev 170336)
@@ -1,3 +1,38 @@
+2014-06-20 Jer Noble <jer.no...@apple.com>
+
+ HTMLMediaElement seek algorithm should allow cancelling previous seeks.
+ https://bugs.webkit.org/show_bug.cgi?id=134116
+
+ Reviewed by Eric Carlson.
+
+ Test: media/video-seek-double.html
+
+ Fulfill the requirement of the §4.7.14.9 seeking algorithm to do steps 5+ asynchronously and cancel
+ previous instances of the algorithm.
+
+ For the html/ parts of the algorithm, implement this by adding a seek timer, which when fired will
+ issue steps 5-12. MediaPlayerPrivateAVFoundation will already coalesce multiple seek operations, so nothing
+ additional needs be done there. However, MediaPlayerPrivateMediaSourceAVFObjC needs to implement the same
+ pending seek logic in case additional seeks were issued after the html/ algorithm reached step 12.
+
+ * html/HTMLMediaElement.cpp:
+ (WebCore::HTMLMediaElement::HTMLMediaElement): Initialize the new m_seekTimer.
+ (WebCore::HTMLMediaElement::parseAttribute): Clear the seek timer.
+ (WebCore::HTMLMediaElement::seekInternal): Differentiate between DOM seeks and internal seeks.
+ (WebCore::HTMLMediaElement::seekWithTolerance:) Split into the seekTimerFired() method.
+ (WebCore::HTMLMediaElement::seekTimerFired:) Added, split from seekWithTolerance().
+ * html/HTMLMediaElement.h:
+ * html/MediaController.cpp:
+ (MediaController::bringElementUpToSpeed): Call seekInternal().
+ (WebCore::HTMLMediaElement::PendingSeek::PendingSeek): Added convenience struct for storing seek requests.
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::PendingSeek::PendingSeek): Ditto.
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::MediaPlayerPrivateMediaSourceAVFObjC): Modify the time jumped
+ handler to not clear the m_seeking flag if another seek request is pending.
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::seekWithTolerance):
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::seekInternal):
+
2014-06-23 Timothy Horton <timothy_hor...@apple.com>
[WK2] Use the page background color instead of white when swipe snapshots were purged (134218)
Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (170335 => 170336)
--- trunk/Source/WebCore/html/HTMLMediaElement.cpp 2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp 2014-06-24 00:08:25 UTC (rev 170336)
@@ -256,6 +256,7 @@
, m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
, m_playbackProgressTimer(this, &HTMLMediaElement::playbackProgressTimerFired)
, m_scanTimer(this, &HTMLMediaElement::scanTimerFired)
+ , m_seekTimer(this, &HTMLMediaElement::seekTimerFired)
, m_playedTimeRanges()
, m_asyncEventQueue(*this)
, m_playbackRate(1.0f)
@@ -2316,17 +2317,23 @@
double negativeTolerance = delta >= 0 ? delta : std::numeric_limits<double>::infinity();
double positiveTolerance = delta < 0 ? -delta : std::numeric_limits<double>::infinity();
- seekWithTolerance(time, negativeTolerance, positiveTolerance);
+ seekWithTolerance(time, negativeTolerance, positiveTolerance, true);
}
void HTMLMediaElement::seek(double time)
{
LOG(Media, "HTMLMediaElement::seek(%f)", time);
- seekWithTolerance(time, 0, 0);
+ seekWithTolerance(time, 0, 0, true);
}
-void HTMLMediaElement::seekWithTolerance(double time, double negativeTolerance, double positiveTolerance)
+void HTMLMediaElement::seekInternal(double time)
{
+ LOG(Media, "HTMLMediaElement::seekInternal(%f)", time);
+ seekWithTolerance(time, 0, 0, false);
+}
+
+void HTMLMediaElement::seekWithTolerance(double time, double negativeTolerance, double positiveTolerance, bool fromDOM)
+{
// 4.8.10.9 Seeking
// 1 - Set the media element's show poster flag to false.
@@ -2347,16 +2354,38 @@
// 3 - If the element's seeking IDL attribute is true, then another instance of this algorithm is
// already running. Abort that other instance of the algorithm without waiting for the step that
// it is running to complete.
- // Nothing specific to be done here.
+ if (m_seeking) {
+ m_seekTimer.stop();
+ m_pendingSeek = nullptr;
+ }
// 4 - Set the seeking IDL attribute to true.
// The flag will be cleared when the engine tells us the time has actually changed.
m_seeking = true;
+ if (m_playing) {
+ if (m_lastSeekTime < now)
+ addPlayedRange(m_lastSeekTime, now);
+ }
+ m_lastSeekTime = time;
// 5 - If the seek was in response to a DOM method call or setting of an IDL attribute, then continue
// the script. The remainder of these steps must be run asynchronously.
- // Nothing to be done here.
+ m_pendingSeek = std::make_unique<PendingSeek>(now, time, negativeTolerance, positiveTolerance);
+ if (fromDOM)
+ m_seekTimer.startOneShot(0);
+ else
+ seekTimerFired(m_seekTimer);
+}
+void HTMLMediaElement::seekTimerFired(Timer<HTMLMediaElement>&)
+{
+ ASSERT(m_pendingSeek);
+ double now = m_pendingSeek->now;
+ double time = m_pendingSeek->targetTime;
+ double negativeTolerance = m_pendingSeek->negativeTolerance;
+ double positiveTolerance = m_pendingSeek->positiveTolerance;
+ m_pendingSeek = nullptr;
+
// 6 - If the new playback position is later than the end of the media resource, then let it be the end
// of the media resource instead.
time = std::min(time, duration());
@@ -2373,7 +2402,7 @@
#if !LOG_DISABLED
double mediaTime = m_player->mediaTimeForTimeValue(time);
if (time != mediaTime)
- LOG(Media, "HTMLMediaElement::seek(%f) - media timeline equivalent is %f", time, mediaTime);
+ LOG(Media, "HTMLMediaElement::seekTimerFired(%f) - media timeline equivalent is %f", time, mediaTime);
#endif
time = m_player->mediaTimeForTimeValue(time);
@@ -2406,12 +2435,8 @@
}
time = seekableRanges->nearest(time);
- if (m_playing) {
- if (m_lastSeekTime < now)
- addPlayedRange(m_lastSeekTime, now);
- }
+ m_sentEndEvent = false;
m_lastSeekTime = time;
- m_sentEndEvent = false;
// 10 - Queue a task to fire a simple event named seeking at the element.
scheduleEvent(eventNames().seekingEvent);
@@ -2562,7 +2587,7 @@
if (m_mediaController)
return;
- seek(time);
+ seekInternal(time);
}
void HTMLMediaElement::setCurrentTime(double time, ExceptionCode& ec)
@@ -2728,7 +2753,7 @@
scheduleDelayedAction(LoadMediaResource);
if (endedPlayback())
- seek(0);
+ seekInternal(0);
if (m_mediaController)
m_mediaController->bringElementUpToSpeed(this);
@@ -4075,7 +4100,7 @@
// then seek to the earliest possible position of the media resource and abort these steps when the direction of
// playback is forwards,
if (now >= dur)
- seek(0);
+ seekInternal(0);
} else if ((now <= 0 && playbackRate < 0) || (now >= dur && playbackRate > 0)) {
// If the media element does not have a current media controller, and the media element
// has still ended playback and paused is false,
@@ -4146,7 +4171,7 @@
double now = currentTime();
double dur = duration();
if (now > dur)
- seek(dur);
+ seekInternal(dur);
endProcessingMediaPlayerCallback();
}
Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (170335 => 170336)
--- trunk/Source/WebCore/html/HTMLMediaElement.h 2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h 2014-06-24 00:08:25 UTC (rev 170336)
@@ -576,12 +576,14 @@
void progressEventTimerFired(Timer<HTMLMediaElement>&);
void playbackProgressTimerFired(Timer<HTMLMediaElement>&);
void scanTimerFired(Timer<HTMLMediaElement>&);
+ void seekTimerFired(Timer<HTMLMediaElement>&);
void startPlaybackProgressTimer();
void startProgressEventTimer();
void stopPeriodicTimers();
void seek(double time);
- void seekWithTolerance(double time, double negativeTolerance, double positiveTolerance);
+ void seekInternal(double time);
+ void seekWithTolerance(double time, double negativeTolerance, double positiveTolerance, bool fromDOM);
void finishSeek();
void checkIfSeekNeeded();
void addPlayedRange(double start, double end);
@@ -701,6 +703,7 @@
Timer<HTMLMediaElement> m_progressEventTimer;
Timer<HTMLMediaElement> m_playbackProgressTimer;
Timer<HTMLMediaElement> m_scanTimer;
+ Timer<HTMLMediaElement> m_seekTimer;
RefPtr<TimeRanges> m_playedTimeRanges;
GenericEventQueue m_asyncEventQueue;
@@ -714,6 +717,21 @@
RefPtr<MediaError> m_error;
+ struct PendingSeek {
+ PendingSeek(double now, double targetTime, double negativeTolerance, double positiveTolerance)
+ : now(now)
+ , targetTime(targetTime)
+ , negativeTolerance(negativeTolerance)
+ , positiveTolerance(positiveTolerance)
+ {
+ }
+ double now;
+ double targetTime;
+ double negativeTolerance;
+ double positiveTolerance;
+ };
+ std::unique_ptr<PendingSeek> m_pendingSeek;
+
double m_volume;
bool m_volumeInitialized;
double m_lastSeekTime;
Modified: trunk/Source/WebCore/html/MediaController.cpp (170335 => 170336)
--- trunk/Source/WebCore/html/MediaController.cpp 2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/html/MediaController.cpp 2014-06-24 00:08:25 UTC (rev 170336)
@@ -479,7 +479,7 @@
// When the user agent is to bring a media element up to speed with its new media controller,
// it must seek that media element to the MediaController's media controller position relative
// to the media element's timeline.
- element->seek(currentTime());
+ element->seekInternal(currentTime());
}
bool MediaController::isBlocked() const
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h (170335 => 170336)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h 2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h 2014-06-24 00:08:25 UTC (rev 170336)
@@ -64,7 +64,7 @@
void setReadyState(MediaPlayer::ReadyState);
void setNetworkState(MediaPlayer::NetworkState);
- void seekInternal(double, double, double);
+ void seekInternal();
void setLoadingProgresssed(bool flag) { m_loadingProgressed = flag; }
void setHasAvailableVideoFrame(bool flag) { m_hasAvailableVideoFrame = flag; }
void durationChanged();
@@ -166,6 +166,19 @@
friend class MediaSourcePrivateAVFObjC;
+ struct PendingSeek {
+ PendingSeek(const MediaTime& targetTime, const MediaTime& negativeThreshold, const MediaTime& positiveThreshold)
+ : targetTime(targetTime)
+ , negativeThreshold(negativeThreshold)
+ , positiveThreshold(positiveThreshold)
+ {
+ }
+ MediaTime targetTime;
+ MediaTime negativeThreshold;
+ MediaTime positiveThreshold;
+ };
+ std::unique_ptr<PendingSeek> m_pendingSeek;
+
MediaPlayer* m_player;
WeakPtrFactory<MediaPlayerPrivateMediaSourceAVFObjC> m_weakPtrFactory;
RefPtr<MediaSourcePrivateClient> m_mediaSource;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm (170335 => 170336)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm 2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm 2014-06-24 00:08:25 UTC (rev 170336)
@@ -153,9 +153,12 @@
if (!weakThis)
return;
- if (m_seeking)
+ if (m_seeking && !m_pendingSeek)
m_seeking = false;
m_player->timeChanged();
+
+ if (m_pendingSeek)
+ seekInternal();
}];
}
@@ -424,23 +427,31 @@
{
m_seeking = true;
auto weakThis = createWeakPtr();
- callOnMainThread([weakThis, time, negativeThreshold, positiveThreshold]{
+ m_pendingSeek = std::make_unique<PendingSeek>(MediaTime::createWithDouble(time), MediaTime::createWithDouble(negativeThreshold), MediaTime::createWithDouble(positiveThreshold));
+
+ callOnMainThread([weakThis] {
if (!weakThis)
return;
- weakThis.get()->seekInternal(time, negativeThreshold, positiveThreshold);
+ weakThis.get()->seekInternal();
});
}
-void MediaPlayerPrivateMediaSourceAVFObjC::seekInternal(double time, double negativeThreshold, double positiveThreshold)
+void MediaPlayerPrivateMediaSourceAVFObjC::seekInternal()
{
+ std::unique_ptr<PendingSeek> pendingSeek;
+ pendingSeek.swap(m_pendingSeek);
+
+ if (!pendingSeek)
+ return;
+
if (!m_mediaSourcePrivate)
return;
MediaTime seekTime;
- if (!negativeThreshold && !positiveThreshold)
- seekTime = MediaTime::createWithDouble(time);
+ if (pendingSeek->negativeThreshold != MediaTime::zeroTime() && pendingSeek->positiveThreshold != MediaTime::zeroTime())
+ seekTime = pendingSeek->targetTime;
else
- seekTime = m_mediaSourcePrivate->fastSeekTimeForMediaTime(MediaTime::createWithDouble(time), MediaTime::createWithDouble(positiveThreshold), MediaTime::createWithDouble(negativeThreshold));
+ seekTime = m_mediaSourcePrivate->fastSeekTimeForMediaTime(pendingSeek->targetTime, pendingSeek->positiveThreshold, pendingSeek->negativeThreshold);
[m_synchronizer setRate:(m_playing ? m_rate : 0) time:toCMTime(seekTime)];
m_mediaSourcePrivate->seekToTime(seekTime);