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.
When 'ended' event fires, change the source.
Verify that 'ended' event fires again on different source.
EVENT(ended)
EXPECTED (audio.playbackRate > '0') 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
EVENT(ended)
......
......@@ -22,8 +22,19 @@
switch (++endedCount)
{
case 1:
testExpected("audio.playbackRate", 0, ">");
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.
audio.src = findMediaFile("audio", "content/silence")
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)
m_player->setRate(rate);
}
HTMLMediaElement::DirectionOfPlayback HTMLMediaElement::directionOfPlayback() const
{
return m_playbackRate >= 0 ? Forward : Backward;
}
void HTMLMediaElement::updatePlaybackRate()
{
double effectiveRate = m_mediaController ? m_mediaController->playbackRate() : m_playbackRate;
......@@ -2131,7 +2136,7 @@ bool HTMLMediaElement::ended() const
// 4.8.10.8 Playing the media resource
// The ended attribute must return true if the media element has ended
// playback and the direction of playback is forwards, and false otherwise.
return endedPlayback() && m_playbackRate > 0;
return endedPlayback() && directionOfPlayback() == Forward;
}
bool HTMLMediaElement::autoplay() const
......@@ -2322,7 +2327,7 @@ void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
{
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();
if (!m_mediaController && !m_paused) {
UseCounter::count(document(), UseCounter::HTMLMediaElementPauseAtFragmentEnd);
......@@ -3019,7 +3024,7 @@ void HTMLMediaElement::mediaPlayerTimeChanged()
// 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:
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 (loop() && !m_mediaController) {
m_sentEndEvent = false;
......@@ -3199,15 +3204,13 @@ bool HTMLMediaElement::endedPlayback() const
// of playback is forwards, Either the media element does not have a loop attribute specified,
// or the media element has a current media controller.
double now = currentTime();
if (m_playbackRate > 0)
if (directionOfPlayback() == Forward)
return dur > 0 && now >= dur && (!loop() || m_mediaController);
// or the current playback position is the earliest possible position and the direction
// of playback is backwards
if (m_playbackRate < 0)
return now <= 0;
return false;
ASSERT(directionOfPlayback() == Backward);
return now <= 0;
}
bool HTMLMediaElement::stoppedDueToErrors() const
......
......@@ -447,6 +447,10 @@ private:
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
// advertise they have audio and/or video, but don't explicitly signal them via
// 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