Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: Source/core/html/HTMLMediaElement.cpp

Issue 319213002: Fix MediaSource.duration setter behavior to match the current spec. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Rebase Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. 2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 1627 matching lines...) Expand 10 before | Expand all | Expand 10 after
1638 } else { 1638 } else {
1639 if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) { 1639 if (wasPotentiallyPlaying && m_readyState < HAVE_FUTURE_DATA) {
1640 // 4.8.10.8 1640 // 4.8.10.8
1641 scheduleTimeupdateEvent(false); 1641 scheduleTimeupdateEvent(false);
1642 scheduleEvent(EventTypeNames::waiting); 1642 scheduleEvent(EventTypeNames::waiting);
1643 } 1643 }
1644 } 1644 }
1645 1645
1646 if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) { 1646 if (m_readyState >= HAVE_METADATA && oldState < HAVE_METADATA) {
1647 prepareMediaFragmentURI(); 1647 prepareMediaFragmentURI();
1648
1649 m_duration = duration();
1648 scheduleEvent(EventTypeNames::durationchange); 1650 scheduleEvent(EventTypeNames::durationchange);
1651
1649 if (isHTMLVideoElement(*this)) 1652 if (isHTMLVideoElement(*this))
1650 scheduleEvent(EventTypeNames::resize); 1653 scheduleEvent(EventTypeNames::resize);
1651 scheduleEvent(EventTypeNames::loadedmetadata); 1654 scheduleEvent(EventTypeNames::loadedmetadata);
1652 if (hasMediaControls()) 1655 if (hasMediaControls())
1653 mediaControls()->reset(); 1656 mediaControls()->reset();
1654 if (renderer()) 1657 if (renderer())
1655 renderer()->updateFromElement(); 1658 renderer()->updateFromElement();
1656 } 1659 }
1657 1660
1658 bool shouldUpdateDisplayState = false; 1661 bool shouldUpdateDisplayState = false;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
1742 { 1745 {
1743 WTF_LOG(Media, "HTMLMediaElement::prepareToPlay(%p)", this); 1746 WTF_LOG(Media, "HTMLMediaElement::prepareToPlay(%p)", this);
1744 if (m_havePreparedToPlay) 1747 if (m_havePreparedToPlay)
1745 return; 1748 return;
1746 m_havePreparedToPlay = true; 1749 m_havePreparedToPlay = true;
1747 1750
1748 if (m_delayingLoadForPreloadNone) 1751 if (m_delayingLoadForPreloadNone)
1749 startDelayedLoad(); 1752 startDelayedLoad();
1750 } 1753 }
1751 1754
1752 void HTMLMediaElement::seek(double time, ExceptionState& exceptionState) 1755 void HTMLMediaElement::seek(SeekSkipPermission seekSkip, double time, ExceptionS tate& exceptionState)
1753 { 1756 {
1754 WTF_LOG(Media, "HTMLMediaElement::seek(%f)", time); 1757 WTF_LOG(Media, "HTMLMediaElement::seek(%d, %f)", seekSkip, time);
1755 1758
1756 // 4.8.10.9 Seeking 1759 // 4.8.10.9 Seeking
1757 1760
1758 // 1 - If the media element's readyState is HAVE_NOTHING, then raise an Inva lidStateError exception. 1761 // 1 - If the media element's readyState is HAVE_NOTHING, then raise an Inva lidStateError exception.
1759 if (m_readyState == HAVE_NOTHING || !m_player) { 1762 if (m_readyState == HAVE_NOTHING || !m_player) {
1760 exceptionState.throwDOMException(InvalidStateError, "The element's ready State is HAVE_NOTHING."); 1763 exceptionState.throwDOMException(InvalidStateError, "The element's ready State is HAVE_NOTHING.");
1761 return; 1764 return;
1762 } 1765 }
1763 1766
1764 // If the media engine has been told to postpone loading data, let it go ahe ad now. 1767 // If the media engine has been told to postpone loading data, let it go ahe ad now.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1800 1803
1801 // 7 - If the (possibly now changed) new playback position is not in one of the ranges given in the 1804 // 7 - If the (possibly now changed) new playback position is not in one of the ranges given in the
1802 // seekable attribute, then let it be the position in one of the ranges give n in the seekable attribute 1805 // seekable attribute, then let it be the position in one of the ranges give n in the seekable attribute
1803 // that is the nearest to the new playback position. ... If there are no ran ges given in the seekable 1806 // that is the nearest to the new playback position. ... If there are no ran ges given in the seekable
1804 // attribute then set the seeking IDL attribute to false and abort these ste ps. 1807 // attribute then set the seeking IDL attribute to false and abort these ste ps.
1805 RefPtr<TimeRanges> seekableRanges = seekable(); 1808 RefPtr<TimeRanges> seekableRanges = seekable();
1806 1809
1807 // Short circuit seeking to the current time by just firing the events if no seek is required. 1810 // Short circuit seeking to the current time by just firing the events if no seek is required.
1808 // Don't skip calling the media engine if we are in poster mode because a se ek should always 1811 // Don't skip calling the media engine if we are in poster mode because a se ek should always
1809 // cancel poster display. 1812 // cancel poster display.
1810 bool noSeekRequired = !seekableRanges->length() || (time == now && displayMo de() != Poster); 1813 if (!seekableRanges->length()
1811 1814 || (seekSkip == SkipAllowed && time == now && displayMode() != Poster)) {
philipj_slow 2014/06/16 13:26:19 Do you know why we actually need this short circui
acolwell GONE FROM CHROMIUM 2014/06/17 01:24:02 I've never been a fan of this block of code. I'll
philipj_slow 2014/06/17 11:59:06 Thanks, I hope it turns out that the short circuit
acolwell GONE FROM CHROMIUM 2014/06/17 22:39:02 I've removed the short circuiting in https://coder
1812 if (noSeekRequired) {
1813 if (time == now) { 1815 if (time == now) {
1814 scheduleEvent(EventTypeNames::seeking); 1816 scheduleEvent(EventTypeNames::seeking);
1815 if (previousSeekStillPending) 1817 if (previousSeekStillPending)
1816 return; 1818 return;
1817 // FIXME: There must be a stable state before timeupdate+seeked are dispatched and seeking 1819 // FIXME: There must be a stable state before timeupdate+seeked are dispatched and seeking
1818 // is reset to false. See http://crbug.com/266631 1820 // is reset to false. See http://crbug.com/266631
1819 scheduleTimeupdateEvent(false); 1821 scheduleTimeupdateEvent(false);
1820 scheduleEvent(EventTypeNames::seeked); 1822 scheduleEvent(EventTypeNames::seeked);
1821 } 1823 }
1822 m_seeking = false; 1824 m_seeking = false;
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
1920 1922
1921 return m_cachedTime; 1923 return m_cachedTime;
1922 } 1924 }
1923 1925
1924 void HTMLMediaElement::setCurrentTime(double time, ExceptionState& exceptionStat e) 1926 void HTMLMediaElement::setCurrentTime(double time, ExceptionState& exceptionStat e)
1925 { 1927 {
1926 if (m_mediaController) { 1928 if (m_mediaController) {
1927 exceptionState.throwDOMException(InvalidStateError, "The element is slav ed to a MediaController."); 1929 exceptionState.throwDOMException(InvalidStateError, "The element is slav ed to a MediaController.");
1928 return; 1930 return;
1929 } 1931 }
1930 seek(time, exceptionState); 1932 seek(SkipAllowed, time, exceptionState);
1931 } 1933 }
1932 1934
1933 double HTMLMediaElement::duration() const 1935 double HTMLMediaElement::duration() const
1934 { 1936 {
1935 if (!m_player || m_readyState < HAVE_METADATA) 1937 if (!m_player || m_readyState < HAVE_METADATA)
1936 return numeric_limits<double>::quiet_NaN(); 1938 return numeric_limits<double>::quiet_NaN();
1937 1939
1938 // FIXME: Refactor so m_duration is kept current (in both MSE and 1940 // FIXME: Refactor so m_duration is kept current (in both MSE and
1939 // non-MSE cases) once we have transitioned from HAVE_NOTHING -> 1941 // non-MSE cases) once we have transitioned from HAVE_NOTHING ->
1940 // HAVE_METADATA. Currently, m_duration may be out of date for at least MSE 1942 // HAVE_METADATA. Currently, m_duration may be out of date for at least MSE
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
2047 2049
2048 void HTMLMediaElement::playInternal() 2050 void HTMLMediaElement::playInternal()
2049 { 2051 {
2050 WTF_LOG(Media, "HTMLMediaElement::playInternal"); 2052 WTF_LOG(Media, "HTMLMediaElement::playInternal");
2051 2053
2052 // 4.8.10.9. Playing the media resource 2054 // 4.8.10.9. Playing the media resource
2053 if (!m_player || m_networkState == NETWORK_EMPTY) 2055 if (!m_player || m_networkState == NETWORK_EMPTY)
2054 scheduleDelayedAction(LoadMediaResource); 2056 scheduleDelayedAction(LoadMediaResource);
2055 2057
2056 if (endedPlayback()) 2058 if (endedPlayback())
2057 seek(0, IGNORE_EXCEPTION); 2059 seek(SkipAllowed, 0, IGNORE_EXCEPTION);
2058 2060
2059 if (m_mediaController) 2061 if (m_mediaController)
2060 m_mediaController->bringElementUpToSpeed(this); 2062 m_mediaController->bringElementUpToSpeed(this);
2061 2063
2062 if (m_paused) { 2064 if (m_paused) {
2063 m_paused = false; 2065 m_paused = false;
2064 invalidateCachedTime(); 2066 invalidateCachedTime();
2065 scheduleEvent(EventTypeNames::play); 2067 scheduleEvent(EventTypeNames::play);
2066 2068
2067 if (m_readyState <= HAVE_CURRENT_DATA) 2069 if (m_readyState <= HAVE_CURRENT_DATA)
(...skipping 707 matching lines...) Expand 10 before | Expand all | Expand 10 after
2775 double now = currentTime(); 2777 double now = currentTime();
2776 double dur = duration(); 2778 double dur = duration();
2777 2779
2778 // When the current playback position reaches the end of the media resource when the direction of 2780 // When the current playback position reaches the end of the media resource when the direction of
2779 // playback is forwards, then the user agent must follow these steps: 2781 // playback is forwards, then the user agent must follow these steps:
2780 if (!std::isnan(dur) && dur && now >= dur && m_playbackRate > 0) { 2782 if (!std::isnan(dur) && dur && now >= dur && m_playbackRate > 0) {
2781 // If the media element has a loop attribute specified and does not have a current media controller, 2783 // If the media element has a loop attribute specified and does not have a current media controller,
2782 if (loop() && !m_mediaController) { 2784 if (loop() && !m_mediaController) {
2783 m_sentEndEvent = false; 2785 m_sentEndEvent = false;
2784 // then seek to the earliest possible position of the media resourc e and abort these steps. 2786 // then seek to the earliest possible position of the media resourc e and abort these steps.
2785 seek(0, IGNORE_EXCEPTION); 2787 seek(SkipAllowed, 0, IGNORE_EXCEPTION);
2786 } else { 2788 } else {
2787 // If the media element does not have a current media controller, an d the media element 2789 // If the media element does not have a current media controller, an d the media element
2788 // has still ended playback, and the direction of playback is still forwards, and paused 2790 // has still ended playback, and the direction of playback is still forwards, and paused
2789 // is false, 2791 // is false,
2790 if (!m_mediaController && !m_paused) { 2792 if (!m_mediaController && !m_paused) {
2791 // changes paused to true and fires a simple event named pause a t the media element. 2793 // changes paused to true and fires a simple event named pause a t the media element.
2792 m_paused = true; 2794 m_paused = true;
2793 scheduleEvent(EventTypeNames::pause); 2795 scheduleEvent(EventTypeNames::pause);
2794 } 2796 }
2795 // Queue a task to fire a simple event named ended at the media elem ent. 2797 // Queue a task to fire a simple event named ended at the media elem ent.
2796 if (!m_sentEndEvent) { 2798 if (!m_sentEndEvent) {
2797 m_sentEndEvent = true; 2799 m_sentEndEvent = true;
2798 scheduleEvent(EventTypeNames::ended); 2800 scheduleEvent(EventTypeNames::ended);
2799 } 2801 }
2800 // If the media element has a current media controller, then report the controller state 2802 // If the media element has a current media controller, then report the controller state
2801 // for the media element's current media controller. 2803 // for the media element's current media controller.
2802 updateMediaController(); 2804 updateMediaController();
2803 } 2805 }
2804 } 2806 }
2805 else 2807 else
2806 m_sentEndEvent = false; 2808 m_sentEndEvent = false;
2807 2809
2808 updatePlayState(); 2810 updatePlayState();
2809 } 2811 }
2810 2812
2811 void HTMLMediaElement::mediaPlayerDurationChanged() 2813 void HTMLMediaElement::mediaPlayerDurationChanged()
2812 { 2814 {
2813 WTF_LOG(Media, "HTMLMediaElement::mediaPlayerDurationChanged"); 2815 WTF_LOG(Media, "HTMLMediaElement::mediaPlayerDurationChanged");
2814 durationChanged(duration()); 2816 durationChanged(duration(), currentTime() > duration());
philipj_slow 2014/06/16 13:26:19 This was already the case, but isn't it weird that
acolwell GONE FROM CHROMIUM 2014/06/17 01:24:02 With the current code this condition should always
philipj_slow 2014/06/17 11:59:06 A FIXME or ASSERT to clarify the current status of
acolwell GONE FROM CHROMIUM 2014/06/17 22:39:02 Done.
2815 } 2817 }
2816 2818
2817 void HTMLMediaElement::durationChanged(double duration) 2819 void HTMLMediaElement::durationChanged(double duration, bool requestSeek)
2818 { 2820 {
2819 WTF_LOG(Media, "HTMLMediaElement::durationChanged(%f)", duration); 2821 WTF_LOG(Media, "HTMLMediaElement::durationChanged(%f, %d)", duration, reques tSeek);
2820 2822
2821 // Abort if duration unchanged. 2823 // Abort if duration unchanged.
2822 if (m_duration == duration) 2824 if (m_duration == duration)
2823 return; 2825 return;
2824 2826
2827 double oldDuration = m_duration;
2825 m_duration = duration; 2828 m_duration = duration;
2829
2830 WTF_LOG(Media, "HTMLMediaElement::durationChanged : %f -> %f", oldDuration, duration);
2831
2826 scheduleEvent(EventTypeNames::durationchange); 2832 scheduleEvent(EventTypeNames::durationchange);
2827 2833
2828 if (hasMediaControls()) 2834 if (hasMediaControls())
2829 mediaControls()->reset(); 2835 mediaControls()->reset();
2830 if (renderer()) 2836 if (renderer())
2831 renderer()->updateFromElement(); 2837 renderer()->updateFromElement();
2832 2838
2833 if (currentTime() > duration) 2839 if (requestSeek) {
2834 seek(duration, IGNORE_EXCEPTION); 2840 // Prevent seek skipping if the duration is getting smaller. The webMedi aPlayer()
2841 // may be clamping currentTime to duration() so the normal "are we seeki ng to the current location?"
2842 // skip check may not be reliable.
2843 SeekSkipPermission seekSkip = (duration < oldDuration) ? SkipNotAllowed : SkipAllowed;
acolwell GONE FROM CHROMIUM 2014/06/06 23:20:04 This change and ones related to it are needed beca
philipj_slow 2014/06/16 13:26:19 OK, that explains why requestSeek is initialized w
2844 seek(seekSkip, duration, IGNORE_EXCEPTION);
2845 }
2835 } 2846 }
2836 2847
2837 void HTMLMediaElement::mediaPlayerPlaybackStateChanged() 2848 void HTMLMediaElement::mediaPlayerPlaybackStateChanged()
2838 { 2849 {
2839 WTF_LOG(Media, "HTMLMediaElement::mediaPlayerPlaybackStateChanged"); 2850 WTF_LOG(Media, "HTMLMediaElement::mediaPlayerPlaybackStateChanged");
2840 2851
2841 if (!m_player || m_pausedInternal) 2852 if (!m_player || m_pausedInternal)
2842 return; 2853 return;
2843 2854
2844 if (m_player->paused()) 2855 if (m_player->paused())
(...skipping 747 matching lines...) Expand 10 before | Expand all | Expand 10 after
3592 3603
3593 if (m_fragmentStartTime != MediaPlayer::invalidTime() && m_readyState < HAVE _FUTURE_DATA) 3604 if (m_fragmentStartTime != MediaPlayer::invalidTime() && m_readyState < HAVE _FUTURE_DATA)
3594 prepareToPlay(); 3605 prepareToPlay();
3595 } 3606 }
3596 3607
3597 void HTMLMediaElement::applyMediaFragmentURI() 3608 void HTMLMediaElement::applyMediaFragmentURI()
3598 { 3609 {
3599 if (m_fragmentStartTime != MediaPlayer::invalidTime()) { 3610 if (m_fragmentStartTime != MediaPlayer::invalidTime()) {
3600 m_sentEndEvent = false; 3611 m_sentEndEvent = false;
3601 UseCounter::count(document(), UseCounter::HTMLMediaElementSeekToFragment Start); 3612 UseCounter::count(document(), UseCounter::HTMLMediaElementSeekToFragment Start);
3602 seek(m_fragmentStartTime, IGNORE_EXCEPTION); 3613 seek(SkipAllowed, m_fragmentStartTime, IGNORE_EXCEPTION);
3603 } 3614 }
3604 } 3615 }
3605 3616
3606 WebMediaPlayer::CORSMode HTMLMediaElement::corsMode() const 3617 WebMediaPlayer::CORSMode HTMLMediaElement::corsMode() const
3607 { 3618 {
3608 const AtomicString& crossOriginMode = fastGetAttribute(crossoriginAttr); 3619 const AtomicString& crossOriginMode = fastGetAttribute(crossoriginAttr);
3609 if (crossOriginMode.isNull()) 3620 if (crossOriginMode.isNull())
3610 return WebMediaPlayer::CORSModeUnspecified; 3621 return WebMediaPlayer::CORSModeUnspecified;
3611 if (equalIgnoringCase(crossOriginMode, "use-credentials")) 3622 if (equalIgnoringCase(crossOriginMode, "use-credentials"))
3612 return WebMediaPlayer::CORSModeUseCredentials; 3623 return WebMediaPlayer::CORSModeUseCredentials;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
3654 visitor->trace(m_error); 3665 visitor->trace(m_error);
3655 visitor->trace(m_currentSourceNode); 3666 visitor->trace(m_currentSourceNode);
3656 visitor->trace(m_nextChildNodeToConsider); 3667 visitor->trace(m_nextChildNodeToConsider);
3657 visitor->trace(m_textTracks); 3668 visitor->trace(m_textTracks);
3658 visitor->trace(m_textTracksWhenResourceSelectionBegan); 3669 visitor->trace(m_textTracksWhenResourceSelectionBegan);
3659 WillBeHeapSupplementable<HTMLMediaElement>::trace(visitor); 3670 WillBeHeapSupplementable<HTMLMediaElement>::trace(visitor);
3660 HTMLElement::trace(visitor); 3671 HTMLElement::trace(visitor);
3661 } 3672 }
3662 3673
3663 } 3674 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698