Diff
Modified: trunk/LayoutTests/ChangeLog (159207 => 159208)
--- trunk/LayoutTests/ChangeLog 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/LayoutTests/ChangeLog 2013-11-13 18:30:03 UTC (rev 159208)
@@ -1,3 +1,13 @@
+2013-11-12 Jer Noble <[email protected]>
+
+ Add support for HTMLMediaElement.fastSeek()
+ https://bugs.webkit.org/show_bug.cgi?id=124262
+
+ Reviewed by Eric Carlson.
+
+ * media/video-fast-seek-expected.txt: Added.
+ * media/video-fast-seek.html: Added.
+
2013-11-13 Antti Koivisto <[email protected]>
* TestExpectations: Skip crypto/subtle/rsassa-pkcs1-v1_5-import-jwk.html
Added: trunk/LayoutTests/media/video-fast-seek-expected.txt (0 => 159208)
--- trunk/LayoutTests/media/video-fast-seek-expected.txt (rev 0)
+++ trunk/LayoutTests/media/video-fast-seek-expected.txt 2013-11-13 18:30:03 UTC (rev 159208)
@@ -0,0 +1,22 @@
+
+Test that fastSeek() commands work correctly.
+
+EVENT(canplaythrough)
+Seek past the 4th sync sample:
+RUN(video.currentTime = 2.5)
+EVENT(timeupdate)
+EXPECTED (video.currentTime == '2.5') OK
+Test that fastSeek() past the currentTime will not result in a seek before the currentTime:
+RUN(video.fastSeek(2.6))
+EVENT(timeupdate)
+EXPECTED (video.currentTime >= '2.6') OK
+Seek before the 4th sync sample:
+RUN(video.currentTime = 2.3)
+EVENT(timeupdate)
+EXPECTED (video.currentTime == '2.3') OK
+Test that fastSeek() before the currentTime will not result in a seek past the currentTime:
+RUN(video.fastSeek(2.2))
+EVENT(timeupdate)
+EXPECTED (video.currentTime <= '2.2') OK
+END OF TEST
+
Added: trunk/LayoutTests/media/video-fast-seek.html (0 => 159208)
--- trunk/LayoutTests/media/video-fast-seek.html (rev 0)
+++ trunk/LayoutTests/media/video-fast-seek.html 2013-11-13 18:30:03 UTC (rev 159208)
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script src=""
+ <script src=""
+ <script>
+
+ // The test.mp4 file has sync samples at the following presentation time stamps:
+ // 0.0000, 0.7968, 1.5936, 2.3904, 3.1872, 3.9840, 4.7808, 5.5776
+
+ function runTest()
+ {
+ findMediaElement();
+ waitForEvent('canplaythrough', canplaythrough);
+
+ // Other media files may have sync samples at completely different points, so
+ // explicitly use the .mp4 here.
+ video.src = ""
+ }
+
+ function canplaythrough()
+ {
+ waitForEventOnce('timeupdate', seek1);
+ consoleWrite('Seek past the 4th sync sample:');
+ run('video.currentTime = 2.5');
+ }
+
+ function seek1()
+ {
+ testExpected('video.currentTime', 2.5);
+ consoleWrite('Test that fastSeek() past the currentTime will not result in a seek before the currentTime:');
+ waitForEventOnce('timeupdate', seek2);
+ run('video.fastSeek(2.6)');
+ }
+
+ function seek2()
+ {
+ testExpected('video.currentTime', 2.6, '>=');
+ consoleWrite('Seek before the 4th sync sample:');
+ waitForEventOnce('timeupdate', seek3);
+ run('video.currentTime = 2.3');
+ }
+
+ function seek3()
+ {
+ testExpected('video.currentTime', 2.3);
+ consoleWrite('Test that fastSeek() before the currentTime will not result in a seek past the currentTime:');
+ waitForEventOnce('timeupdate', seek4);
+ run('video.fastSeek(2.2)');
+ }
+
+ function seek4()
+ {
+ testExpected('video.currentTime', 2.2, '<=');
+ endTest();
+ }
+
+ </script>
+</head>
+<body _onload_="runTest()">
+ <video controls></video>
+ <p>Test that fastSeek() commands work correctly.</p>
+</body>
+</html>
\ No newline at end of file
Modified: trunk/Source/WebCore/ChangeLog (159207 => 159208)
--- trunk/Source/WebCore/ChangeLog 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/ChangeLog 2013-11-13 18:30:03 UTC (rev 159208)
@@ -1,3 +1,46 @@
+2013-11-12 Jer Noble <[email protected]>
+
+ Add support for HTMLMediaElement.fastSeek()
+ https://bugs.webkit.org/show_bug.cgi?id=124262
+
+ Reviewed by Eric Carlson.
+
+ Test: media/video-fast-seek.html
+
+ Add the fastSeek() method to HTMLMediaElement, and use fastSeek() in
+ the _javascript_ media controls.
+
+ Add the new fastSeek() method:
+ * html/HTMLMediaElement.cpp:
+ (HTMLMediaElement::fastSeek): Call seekWithTolerance.
+ (HTMLMediaElement::seek): Call seekWithTolerance with 0 tolerance.
+ (HTMLMediaElement::seekWithTolerance): Renamed from seek().
+ * html/HTMLMediaElement.h:
+ * html/HTMLMediaElement.idl:
+
+ Add seekWithTolerance() to MediaPlayer:
+ * platform/graphics/MediaPlayer.cpp:
+ (WebCore::MediaPlayer::seekWithTolerance): Pass to MediaPlayerPrivate.
+ * platform/graphics/MediaPlayer.h:
+ * platform/graphics/MediaPlayerPrivate.h:
+ (WebCore::MediaPlayerPrivateInterface::seekWithTolerance): Default implementation which
+ calls seek().
+ * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp:
+ (WebCore::MediaPlayerPrivateAVFoundation::seek): Call seekWithTolerance with 0 tolerance.
+ (WebCore::MediaPlayerPrivateAVFoundation::seekWithTolerance): Renamed from seek().
+ * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h:
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::seekToTime): Take tolerance parameters.
+
+ Use the new fastSeek() method while actively scrubbing.
+ * Modules/mediacontrols/mediaControlsApple.js:
+ (Controller.prototype.createControls): Add mouse up and down handlers.
+ (Controller.prototype.handleTimeUpdate): Only update the timeline when not scrubbing.
+ (Controller.prototype.handleTimelineChange): Use fastSeek().
+ (Controller.prototype.handleTimelineMouseDown): Start scrubbing.
+ (Controller.prototype.handleTimelineMouseUp): Stop scrubbing.
+
2013-11-13 Andreas Kling <[email protected]>
Generate casting helpers for scrolling tree classes.
Modified: trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js (159207 => 159208)
--- trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/Modules/mediacontrols/mediaControlsApple.js 2013-11-13 18:30:03 UTC (rev 159208)
@@ -295,6 +295,8 @@
this.listenFor(timeline, 'mouseover', this.handleTimelineMouseOver);
this.listenFor(timeline, 'mouseout', this.handleTimelineMouseOut);
this.listenFor(timeline, 'mousemove', this.handleTimelineMouseMove);
+ this.listenFor(timeline, 'mousedown', this.handleTimelineMouseDown);
+ this.listenFor(timeline, 'mouseup', this.handleTimelineMouseUp);
timeline.step = .01;
var thumbnailTrack = this.controls.thumbnailTrack = document.createElement('div');
@@ -463,7 +465,8 @@
handleTimeUpdate: function(event)
{
- this.updateTime();
+ if (!this.scrubbing)
+ this.updateTime();
},
handleDurationChange: function(event)
@@ -622,7 +625,7 @@
handleTimelineChange: function(event)
{
- this.video.currentTime = this.controls.timeline.value;
+ this.video.fastSeek(this.controls.timeline.value);
},
handleTimelineDown: function(event)
@@ -675,6 +678,19 @@
}
},
+ handleTimelineMouseDown: function(event)
+ {
+ this.scrubbing = true;
+ },
+
+ handleTimelineMouseUp: function(event)
+ {
+ this.scrubbing = false;
+
+ // Do a precise seek when we lift the mouse:
+ this.video.currentTime = this.controls.timeline.value;
+ },
+
handleMuteButtonClicked: function(event)
{
this.video.muted = !this.video.muted;
Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (159207 => 159208)
--- trunk/Source/WebCore/html/HTMLMediaElement.cpp 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp 2013-11-13 18:30:03 UTC (rev 159208)
@@ -2146,10 +2146,31 @@
m_player->prepareToPlay();
}
+void HTMLMediaElement::fastSeek(double time, ExceptionCode& ec)
+{
+ LOG(Media, "HTMLMediaElement::fastSeek(%f)", time);
+ // 4.7.10.9 Seeking
+ // 9. If the approximate-for-speed flag is set, adjust the new playback position to a value that will
+ // allow for playback to resume promptly. If new playback position before this step is before current
+ // playback position, then the adjusted new playback position must also be before the current playback
+ // position. Similarly, if the new playback position before this step is after current playback position,
+ // then the adjusted new playback position must also be after the current playback position.
+ refreshCachedTime();
+ double delta = time - currentTime();
+ double negativeTolerance = delta >= 0 ? delta : std::numeric_limits<double>::infinity();
+ double positiveTolerance = delta < 0 ? -delta : std::numeric_limits<double>::infinity();
+
+ seekWithTolerance(time, negativeTolerance, positiveTolerance, ec);
+}
+
void HTMLMediaElement::seek(double time, ExceptionCode& ec)
{
LOG(Media, "HTMLMediaElement::seek(%f)", time);
+ seekWithTolerance(time, 0, 0, ec);
+}
+void HTMLMediaElement::seekWithTolerance(double time, double negativeTolerance, double positiveTolerance, ExceptionCode& ec)
+{
// 4.8.9.9 Seeking
// 1 - If the media element's readyState is HAVE_NOTHING, then raise an INVALID_STATE_ERR exception.
@@ -2232,7 +2253,7 @@
m_sentEndEvent = false;
// 8 - Set the current playback position to the given new playback position
- m_player->seek(time);
+ m_player->seekWithTolerance(time, negativeTolerance, positiveTolerance);
// 9 - Queue a task to fire a simple event named seeking at the element.
scheduleEvent(eventNames().seekingEvent);
Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (159207 => 159208)
--- trunk/Source/WebCore/html/HTMLMediaElement.h 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h 2013-11-13 18:30:03 UTC (rev 159208)
@@ -178,6 +178,7 @@
void setLoop(bool b);
virtual void play() OVERRIDE;
virtual void pause() OVERRIDE;
+ void fastSeek(double, ExceptionCode&);
// captions
bool webkitHasClosedCaptions() const;
@@ -536,6 +537,7 @@
void stopPeriodicTimers();
void seek(double time, ExceptionCode&);
+ void seekWithTolerance(double time, double negativeTolerance, double positiveTolerance, ExceptionCode&);
void finishSeek();
void checkIfSeekNeeded();
void addPlayedRange(double start, double end);
Modified: trunk/Source/WebCore/html/HTMLMediaElement.idl (159207 => 159208)
--- trunk/Source/WebCore/html/HTMLMediaElement.idl 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/html/HTMLMediaElement.idl 2013-11-13 18:30:03 UTC (rev 159208)
@@ -75,6 +75,7 @@
[Reflect] attribute boolean loop;
void play();
void pause();
+[RaisesException] void fastSeek(double time);
// controls
attribute boolean controls;
Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp (159207 => 159208)
--- trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp 2013-11-13 18:30:03 UTC (rev 159208)
@@ -538,6 +538,11 @@
return m_private->currentTimeDouble();
}
+void MediaPlayer::seekWithTolerance(double time, double negativeTolerance, double positiveTolerance)
+{
+ m_private->seekWithTolerance(time, negativeTolerance, positiveTolerance);
+}
+
void MediaPlayer::seek(double time)
{
m_private->seekDouble(time);
Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.h (159207 => 159208)
--- trunk/Source/WebCore/platform/graphics/MediaPlayer.h 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.h 2013-11-13 18:30:03 UTC (rev 159208)
@@ -326,6 +326,7 @@
double duration() const;
double currentTime() const;
void seek(double time);
+ void seekWithTolerance(double time, double negativeTolerance, double positiveTolerance);
double startTime() const;
Modified: trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h (159207 => 159208)
--- trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayerPrivate.h 2013-11-13 18:30:03 UTC (rev 159208)
@@ -79,6 +79,7 @@
virtual void seek(float) { }
virtual void seekDouble(double time) { seek(time); }
+ virtual void seekWithTolerance(double time, double, double) { seek(time); }
virtual bool seeking() const = 0;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp (159207 => 159208)
--- trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp 2013-11-13 18:30:03 UTC (rev 159208)
@@ -266,6 +266,11 @@
void MediaPlayerPrivateAVFoundation::seek(float time)
{
+ seekWithTolerance(time, 0, 0);
+}
+
+void MediaPlayerPrivateAVFoundation::seekWithTolerance(double time, double negativeTolerance, double positiveTolerance)
+{
if (!metaDataAvailable())
return;
@@ -282,7 +287,7 @@
m_seekTo = time;
++m_seekCount;
- seekToTime(time);
+ seekToTime(time, negativeTolerance, positiveTolerance);
}
void MediaPlayerPrivateAVFoundation::setRate(float rate)
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h (159207 => 159208)
--- trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h 2013-11-13 18:30:03 UTC (rev 159208)
@@ -159,6 +159,7 @@
virtual float duration() const OVERRIDE;
virtual float currentTime() const = 0;
virtual void seek(float) OVERRIDE;
+ virtual void seekWithTolerance(double, double, double) OVERRIDE;
virtual bool seeking() const OVERRIDE;
virtual void setRate(float) OVERRIDE;
virtual bool paused() const OVERRIDE;
@@ -223,7 +224,7 @@
virtual void checkPlayability() = 0;
virtual void updateRate() = 0;
virtual float rate() const = 0;
- virtual void seekToTime(double time) = 0;
+ virtual void seekToTime(double time, double negativeTolerance, double positiveTolerance) = 0;
virtual unsigned totalBytes() const = 0;
virtual PassRefPtr<TimeRanges> platformBufferedTimeRanges() const = 0;
virtual double platformMaxTimeSeekable() const = 0;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h (159207 => 159208)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h 2013-11-13 18:30:03 UTC (rev 159208)
@@ -142,7 +142,7 @@
virtual void checkPlayability();
virtual void updateRate();
virtual float rate() const;
- virtual void seekToTime(double time);
+ virtual void seekToTime(double time, double negativeTolerance, double positiveTolerance);
virtual unsigned totalBytes() const;
virtual PassRefPtr<TimeRanges> platformBufferedTimeRanges() const;
virtual double platformMinTimeSeekable() const;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (159207 => 159208)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm 2013-11-13 18:17:40 UTC (rev 159207)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm 2013-11-13 18:30:03 UTC (rev 159208)
@@ -644,13 +644,16 @@
return 0;
}
-void MediaPlayerPrivateAVFoundationObjC::seekToTime(double time)
+void MediaPlayerPrivateAVFoundationObjC::seekToTime(double time, double negativeTolerance, double positiveTolerance)
{
// setCurrentTime generates several event callbacks, update afterwards.
setDelayCallbacks(true);
WebCoreAVFMovieObserver *observer = m_objcObserver.get();
- [m_avPlayerItem.get() seekToTime:CMTimeMakeWithSeconds(time, 600) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
+ CMTime cmTime = CMTimeMakeWithSeconds(time, 600);
+ CMTime cmBefore = CMTimeMakeWithSeconds(negativeTolerance, 600);
+ CMTime cmAfter = CMTimeMakeWithSeconds(positiveTolerance, 600);
+ [m_avPlayerItem.get() seekToTime:cmTime toleranceBefore:cmBefore toleranceAfter:cmAfter completionHandler:^(BOOL finished) {
[observer seekCompleted:finished];
}];