Commit 4238e896 authored by acolwell@chromium.org's avatar acolwell@chromium.org

Fix HTMLMediaElement "direction of playback" behavior.

This change cleans up the code a little to make it easier to see that
the "direction of playback" is being used and corrects the definition of
"forward" to include playbackRate == 0. New test cases were added to
expose the change in behavior.

BUG=385343
TESTS=LayoutTests/media/media-ended.html LayoutTests/media/video-seek-to-duration-with-playbackrate-zero.html

Review URL: https://codereview.chromium.org/331063006

git-svn-id: svn://svn.chromium.org/blink/trunk@176264 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent ff9157f8
...@@ -4,7 +4,12 @@ Play to the end. ...@@ -4,7 +4,12 @@ Play to the end.
When 'ended' event fires, change the source. When 'ended' event fires, change the source.
Verify that 'ended' event fires again on different source. Verify that 'ended' event fires again on different source.
EVENT(ended) EVENT(ended)
EXPECTED (audio.playbackRate > '0') OK
EXPECTED (audio.ended == 'true') OK EXPECTED (audio.ended == 'true') OK
RUN(audio.playbackRate = 0)
EXPECTED (audio.ended == 'true') OK
RUN(audio.playbackRate = -0.1)
EXPECTED (audio.ended == 'false') OK
EXPECTED (audio.ended == 'false') OK EXPECTED (audio.ended == 'false') OK
EVENT(ended) EVENT(ended)
......
...@@ -22,8 +22,19 @@ ...@@ -22,8 +22,19 @@
switch (++endedCount) switch (++endedCount)
{ {
case 1: case 1:
testExpected("audio.playbackRate", 0, ">");
testExpected("audio.ended", true); testExpected("audio.ended", true);
// Verify ended stays true even if playbackRate == 0
// since that is technically still "forward".
run("audio.playbackRate = 0");
testExpected("audio.ended", true);
// Verify "backward" playback causes ended to become false.
run("audio.playbackRate = -0.1");
testExpected("audio.ended", false);
// Change src but don't seek so that internal state isn't reset. // Change src but don't seek so that internal state isn't reset.
audio.src = findMediaFile("audio", "content/silence") audio.src = findMediaFile("audio", "content/silence")
testExpected("audio.ended", false); testExpected("audio.ended", false);
......
EVENT(loadedmetadata)
Seeking to duration
EVENT(seeking)
EVENT(seeked)
EVENT(ended)
EXPECTED (video.currentTime == video.duration == 'true') OK
Seeking to the middle of the video
EVENT(seeking)
EVENT(seeked)
Setting loop to true and seeking to duration.
EVENT(seeking)
EVENT(seeked)
Seek to duration completed. Waiting for a seek to the beginning.
EVENT(seeking)
EVENT(seeked)
EXPECTED (video.currentTime == '0') OK
END OF TEST
<!doctype html>
<html>
<head>
<title>Test behavior when seeking to the duration and the playback rate equals 0.</title>
<script src="media-file.js"></script>
<script src="video-test.js"></script>
<script>
function onLoad()
{
findMediaElement();
video.src = findMediaFile("video", "content/test");
video.load();
waitForEvent("seeking");
waitForEventOnce("loadedmetadata", function()
{
consoleWrite("Seeking to duration");
video.currentTime = video.duration;
video.playbackRate = 0;
waitForEventOnce("seeked");
waitForEventOnce("ended", firstEnded);
});
function firstEnded()
{
testExpected("video.currentTime == video.duration", true);
consoleWrite("Seeking to the middle of the video");
video.currentTime = video.duration / 2;
waitForEventOnce("seeked", seekToMiddleDone);
}
function seekToMiddleDone()
{
consoleWrite("Setting loop to true and seeking to duration.");
video.loop = true;
video.currentTime = video.duration;
waitForEventOnce("seeked", seekToDurationComplete);
}
function seekToDurationComplete()
{
consoleWrite("Seek to duration completed. Waiting for a seek to the beginning.");
waitForEventOnce("seeked", seekToBeginningComplete);
}
function seekToBeginningComplete()
{
testExpected("video.currentTime", 0);
endTest();
}
}
</script>
</head>
<body onload="onLoad()">
<video id="v" preload="metadata"></video>
</body>
</html>
...@@ -2119,6 +2119,11 @@ void HTMLMediaElement::setPlaybackRate(double rate) ...@@ -2119,6 +2119,11 @@ void HTMLMediaElement::setPlaybackRate(double rate)
m_player->setRate(rate); m_player->setRate(rate);
} }
HTMLMediaElement::DirectionOfPlayback HTMLMediaElement::directionOfPlayback() const
{
return m_playbackRate >= 0 ? Forward : Backward;
}
void HTMLMediaElement::updatePlaybackRate() void HTMLMediaElement::updatePlaybackRate()
{ {
double effectiveRate = m_mediaController ? m_mediaController->playbackRate() : m_playbackRate; double effectiveRate = m_mediaController ? m_mediaController->playbackRate() : m_playbackRate;
...@@ -2131,7 +2136,7 @@ bool HTMLMediaElement::ended() const ...@@ -2131,7 +2136,7 @@ bool HTMLMediaElement::ended() const
// 4.8.10.8 Playing the media resource // 4.8.10.8 Playing the media resource
// The ended attribute must return true if the media element has ended // The ended attribute must return true if the media element has ended
// playback and the direction of playback is forwards, and false otherwise. // playback and the direction of playback is forwards, and false otherwise.
return endedPlayback() && m_playbackRate > 0; return endedPlayback() && directionOfPlayback() == Forward;
} }
bool HTMLMediaElement::autoplay() const bool HTMLMediaElement::autoplay() const
...@@ -2322,7 +2327,7 @@ void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*) ...@@ -2322,7 +2327,7 @@ void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
{ {
ASSERT(m_player); ASSERT(m_player);
if (m_fragmentEndTime != MediaPlayer::invalidTime() && currentTime() >= m_fragmentEndTime && m_playbackRate > 0) { if (m_fragmentEndTime != MediaPlayer::invalidTime() && currentTime() >= m_fragmentEndTime && directionOfPlayback() == Forward) {
m_fragmentEndTime = MediaPlayer::invalidTime(); m_fragmentEndTime = MediaPlayer::invalidTime();
if (!m_mediaController && !m_paused) { if (!m_mediaController && !m_paused) {
UseCounter::count(document(), UseCounter::HTMLMediaElementPauseAtFragmentEnd); UseCounter::count(document(), UseCounter::HTMLMediaElementPauseAtFragmentEnd);
...@@ -3019,7 +3024,7 @@ void HTMLMediaElement::mediaPlayerTimeChanged() ...@@ -3019,7 +3024,7 @@ void HTMLMediaElement::mediaPlayerTimeChanged()
// When the current playback position reaches the end of the media resource when the direction of // When the current playback position reaches the end of the media resource when the direction of
// playback is forwards, then the user agent must follow these steps: // playback is forwards, then the user agent must follow these steps:
if (!std::isnan(dur) && dur && now >= dur && m_playbackRate > 0) { if (!std::isnan(dur) && dur && now >= dur && directionOfPlayback() == Forward) {
// If the media element has a loop attribute specified and does not have a current media controller, // If the media element has a loop attribute specified and does not have a current media controller,
if (loop() && !m_mediaController) { if (loop() && !m_mediaController) {
m_sentEndEvent = false; m_sentEndEvent = false;
...@@ -3199,15 +3204,13 @@ bool HTMLMediaElement::endedPlayback() const ...@@ -3199,15 +3204,13 @@ bool HTMLMediaElement::endedPlayback() const
// of playback is forwards, Either the media element does not have a loop attribute specified, // of playback is forwards, Either the media element does not have a loop attribute specified,
// or the media element has a current media controller. // or the media element has a current media controller.
double now = currentTime(); double now = currentTime();
if (m_playbackRate > 0) if (directionOfPlayback() == Forward)
return dur > 0 && now >= dur && (!loop() || m_mediaController); return dur > 0 && now >= dur && (!loop() || m_mediaController);
// or the current playback position is the earliest possible position and the direction // or the current playback position is the earliest possible position and the direction
// of playback is backwards // of playback is backwards
if (m_playbackRate < 0) ASSERT(directionOfPlayback() == Backward);
return now <= 0; return now <= 0;
return false;
} }
bool HTMLMediaElement::stoppedDueToErrors() const bool HTMLMediaElement::stoppedDueToErrors() const
......
...@@ -447,6 +447,10 @@ private: ...@@ -447,6 +447,10 @@ private:
blink::WebMediaPlayer::CORSMode corsMode() const; blink::WebMediaPlayer::CORSMode corsMode() const;
// Returns the "direction of playback" value as specified in the HTML5 spec.
enum DirectionOfPlayback { Backward, Forward };
DirectionOfPlayback directionOfPlayback() const;
// Creates placeholder AudioTrack and/or VideoTrack objects when WebMemediaPlayer objects // Creates placeholder AudioTrack and/or VideoTrack objects when WebMemediaPlayer objects
// advertise they have audio and/or video, but don't explicitly signal them via // advertise they have audio and/or video, but don't explicitly signal them via
// addAudioTrack() and addVideoTrack(). // addAudioTrack() and addVideoTrack().
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment