Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights | 2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights |
| 3 * reserved. | 3 * reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 25 */ | 25 */ |
| 26 | 26 |
| 27 #include "core/html/HTMLMediaElement.h" | 27 #include "core/html/HTMLMediaElement.h" |
| 28 | 28 |
| 29 #include "bindings/core/v8/ExceptionState.h" | 29 #include "bindings/core/v8/ExceptionState.h" |
| 30 #include "bindings/core/v8/ExceptionStatePlaceholder.h" | 30 #include "bindings/core/v8/ExceptionStatePlaceholder.h" |
| 31 #include "bindings/core/v8/Microtask.h" | |
| 31 #include "bindings/core/v8/ScriptController.h" | 32 #include "bindings/core/v8/ScriptController.h" |
| 32 #include "bindings/core/v8/ScriptEventListener.h" | 33 #include "bindings/core/v8/ScriptEventListener.h" |
| 33 #include "bindings/core/v8/ScriptPromiseResolver.h" | 34 #include "bindings/core/v8/ScriptPromiseResolver.h" |
| 34 #include "core/HTMLNames.h" | 35 #include "core/HTMLNames.h" |
| 35 #include "core/css/MediaList.h" | 36 #include "core/css/MediaList.h" |
| 36 #include "core/dom/Attribute.h" | 37 #include "core/dom/Attribute.h" |
| 37 #include "core/dom/DOMException.h" | 38 #include "core/dom/DOMException.h" |
| 38 #include "core/dom/ElementTraversal.h" | 39 #include "core/dom/ElementTraversal.h" |
| 39 #include "core/dom/ElementVisibilityObserver.h" | 40 #include "core/dom/ElementVisibilityObserver.h" |
| 40 #include "core/dom/Fullscreen.h" | 41 #include "core/dom/Fullscreen.h" |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 101 #ifndef BLINK_MEDIA_LOG | 102 #ifndef BLINK_MEDIA_LOG |
| 102 #define BLINK_MEDIA_LOG DVLOG(3) | 103 #define BLINK_MEDIA_LOG DVLOG(3) |
| 103 #endif | 104 #endif |
| 104 | 105 |
| 105 #ifndef LOG_MEDIA_EVENTS | 106 #ifndef LOG_MEDIA_EVENTS |
| 106 // Default to not logging events because so many are generated they can | 107 // Default to not logging events because so many are generated they can |
| 107 // overwhelm the rest of the logging. | 108 // overwhelm the rest of the logging. |
| 108 #define LOG_MEDIA_EVENTS 0 | 109 #define LOG_MEDIA_EVENTS 0 |
| 109 #endif | 110 #endif |
| 110 | 111 |
| 111 #ifndef LOG_CACHED_TIME_WARNINGS | 112 #ifndef LOG_OFFICIAL_TIME_STATUS |
| 112 // Default to not logging warnings about excessive drift in the cached media | 113 // Default to not logging status of official time because it adds a fair amount |
| 113 // time because it adds a fair amount of overhead and logging. | 114 // of overhead and logging. |
| 114 #define LOG_CACHED_TIME_WARNINGS 0 | 115 #define LOG_OFFICIAL_TIME_STATUS 0 |
| 115 #endif | 116 #endif |
| 116 | 117 |
| 117 namespace blink { | 118 namespace blink { |
| 118 | 119 |
| 119 using namespace HTMLNames; | 120 using namespace HTMLNames; |
| 120 | 121 |
| 121 using WeakMediaElementSet = HeapHashSet<WeakMember<HTMLMediaElement>>; | 122 using WeakMediaElementSet = HeapHashSet<WeakMember<HTMLMediaElement>>; |
| 122 using DocumentElementSetMap = | 123 using DocumentElementSetMap = |
| 123 HeapHashMap<WeakMember<Document>, Member<WeakMediaElementSet>>; | 124 HeapHashMap<WeakMember<Document>, Member<WeakMediaElementSet>>; |
| 124 | 125 |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 416 m_playbackRate(1.0f), | 417 m_playbackRate(1.0f), |
| 417 m_defaultPlaybackRate(1.0f), | 418 m_defaultPlaybackRate(1.0f), |
| 418 m_networkState(kNetworkEmpty), | 419 m_networkState(kNetworkEmpty), |
| 419 m_readyState(kHaveNothing), | 420 m_readyState(kHaveNothing), |
| 420 m_readyStateMaximum(kHaveNothing), | 421 m_readyStateMaximum(kHaveNothing), |
| 421 m_volume(1.0f), | 422 m_volume(1.0f), |
| 422 m_lastSeekTime(0), | 423 m_lastSeekTime(0), |
| 423 m_previousProgressTime(std::numeric_limits<double>::max()), | 424 m_previousProgressTime(std::numeric_limits<double>::max()), |
| 424 m_duration(std::numeric_limits<double>::quiet_NaN()), | 425 m_duration(std::numeric_limits<double>::quiet_NaN()), |
| 425 m_lastTimeUpdateEventWallTime(0), | 426 m_lastTimeUpdateEventWallTime(0), |
| 426 m_lastTimeUpdateEventMovieTime(0), | 427 m_lastTimeUpdateEventMediaTime(std::numeric_limits<double>::quiet_NaN()), |
| 427 m_defaultPlaybackStartPosition(0), | 428 m_defaultPlaybackStartPosition(0), |
| 428 m_loadState(WaitingForSource), | 429 m_loadState(WaitingForSource), |
| 429 m_deferredLoadState(NotDeferred), | 430 m_deferredLoadState(NotDeferred), |
| 430 m_deferredLoadTimer(this, &HTMLMediaElement::deferredLoadTimerFired), | 431 m_deferredLoadTimer(this, &HTMLMediaElement::deferredLoadTimerFired), |
| 431 m_webLayer(nullptr), | 432 m_webLayer(nullptr), |
| 432 m_displayMode(Unknown), | 433 m_displayMode(Unknown), |
| 433 m_cachedTime(std::numeric_limits<double>::quiet_NaN()), | 434 m_officialPlaybackPosition(0), |
| 435 m_officialPlaybackPositionNeedsUpdate(true), | |
| 434 m_fragmentEndTime(std::numeric_limits<double>::quiet_NaN()), | 436 m_fragmentEndTime(std::numeric_limits<double>::quiet_NaN()), |
| 435 m_pendingActionFlags(0), | 437 m_pendingActionFlags(0), |
| 436 m_lockedPendingUserGesture(false), | 438 m_lockedPendingUserGesture(false), |
| 437 m_playing(false), | 439 m_playing(false), |
| 438 m_shouldDelayLoadEvent(false), | 440 m_shouldDelayLoadEvent(false), |
| 439 m_haveFiredLoadedData(false), | 441 m_haveFiredLoadedData(false), |
| 440 m_autoplaying(true), | 442 m_autoplaying(true), |
| 441 m_muted(false), | 443 m_muted(false), |
| 442 m_paused(true), | 444 m_paused(true), |
| 443 m_seeking(false), | 445 m_seeking(false), |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 837 "The play() request was interrupted by a new load request."); | 839 "The play() request was interrupted by a new load request."); |
| 838 } | 840 } |
| 839 | 841 |
| 840 // 4.7 - If seeking is true, set it to false. | 842 // 4.7 - If seeking is true, set it to false. |
| 841 m_seeking = false; | 843 m_seeking = false; |
| 842 | 844 |
| 843 // 4.8 - Set the current playback position to 0. | 845 // 4.8 - Set the current playback position to 0. |
| 844 // Set the official playback position to 0. | 846 // Set the official playback position to 0. |
| 845 // If this changed the official playback position, then queue a task | 847 // If this changed the official playback position, then queue a task |
| 846 // to fire a simple event named timeupdate at the media element. | 848 // to fire a simple event named timeupdate at the media element. |
| 847 // FIXME: Add support for firing this event. | |
| 848 | |
| 849 // 4.9 - Set the initial playback position to 0. | 849 // 4.9 - Set the initial playback position to 0. |
| 850 // FIXME: Make this less subtle. The position only becomes 0 because the | 850 setOfficialPlaybackPosition(0); |
| 851 // ready state is HAVE_NOTHING. | 851 scheduleTimeupdateEvent(false); |
| 852 invalidateCachedTime(); | |
| 853 | 852 |
| 854 // 4.10 - Set the timeline offset to Not-a-Number (NaN). | 853 // 4.10 - Set the timeline offset to Not-a-Number (NaN). |
| 855 // 4.11 - Update the duration attribute to Not-a-Number (NaN). | 854 // 4.11 - Update the duration attribute to Not-a-Number (NaN). |
| 856 | 855 |
| 857 cueTimeline().updateActiveCues(0); | 856 cueTimeline().updateActiveCues(0); |
| 858 } else if (!m_paused) { | 857 } else if (!m_paused) { |
| 859 // TODO(foolip): There is a proposal to always reset the paused state | 858 // TODO(foolip): There is a proposal to always reset the paused state |
| 860 // in the media element load algorithm, to avoid a bogus play() promise | 859 // in the media element load algorithm, to avoid a bogus play() promise |
| 861 // rejection: https://github.com/whatwg/html/issues/869 | 860 // rejection: https://github.com/whatwg/html/issues/869 |
| 862 // This is where that change would have an effect, and it is measured to | 861 // This is where that change would have an effect, and it is measured to |
| (...skipping 765 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1628 // attribute to change to a value lower than kHaveFutureData, then a waiting | 1627 // attribute to change to a value lower than kHaveFutureData, then a waiting |
| 1629 // will be fired at the element. | 1628 // will be fired at the element. |
| 1630 if (wasPotentiallyPlaying && m_readyState < kHaveFutureData) | 1629 if (wasPotentiallyPlaying && m_readyState < kHaveFutureData) |
| 1631 scheduleEvent(EventTypeNames::waiting); | 1630 scheduleEvent(EventTypeNames::waiting); |
| 1632 | 1631 |
| 1633 // 4.8.10.9 steps 12-14 | 1632 // 4.8.10.9 steps 12-14 |
| 1634 if (m_readyState >= kHaveCurrentData) | 1633 if (m_readyState >= kHaveCurrentData) |
| 1635 finishSeek(); | 1634 finishSeek(); |
| 1636 } else { | 1635 } else { |
| 1637 if (wasPotentiallyPlaying && m_readyState < kHaveFutureData) { | 1636 if (wasPotentiallyPlaying && m_readyState < kHaveFutureData) { |
| 1637 // Force an update to official playback position. Automatic updates from | |
| 1638 // currentPlaybackPosition() will be blocked while m_readyState remains | |
| 1639 // < kHaveFutureData. This blocking is desired after 'waiting' has been | |
| 1640 // fired, but its good to update it one final time to accurately reflect | |
| 1641 // media time at the moment we ran out of data to play. | |
| 1642 setOfficialPlaybackPosition(currentPlaybackPosition()); | |
| 1643 | |
| 1638 // 4.8.10.8 | 1644 // 4.8.10.8 |
| 1639 scheduleTimeupdateEvent(false); | 1645 scheduleTimeupdateEvent(false); |
| 1640 scheduleEvent(EventTypeNames::waiting); | 1646 scheduleEvent(EventTypeNames::waiting); |
| 1641 } | 1647 } |
| 1642 } | 1648 } |
| 1643 | 1649 |
| 1650 // Once enough of the media data has been fetched to determine the duration of | |
| 1651 // the media resource, its dimensions, and other metadata... | |
| 1644 if (m_readyState >= kHaveMetadata && oldState < kHaveMetadata) { | 1652 if (m_readyState >= kHaveMetadata && oldState < kHaveMetadata) { |
| 1645 createPlaceholderTracksIfNecessary(); | 1653 createPlaceholderTracksIfNecessary(); |
| 1646 | 1654 |
| 1647 selectInitialTracksIfNecessary(); | 1655 selectInitialTracksIfNecessary(); |
| 1648 | 1656 |
| 1649 MediaFragmentURIParser fragmentParser(m_currentSrc); | 1657 MediaFragmentURIParser fragmentParser(m_currentSrc); |
| 1650 m_fragmentEndTime = fragmentParser.endTime(); | 1658 m_fragmentEndTime = fragmentParser.endTime(); |
| 1651 | 1659 |
| 1660 // Set the current playback position and the official playback position to | |
| 1661 // the earliest possible position. | |
| 1662 setOfficialPlaybackPosition(earliestPossiblePosition()); | |
| 1663 | |
| 1652 m_duration = duration(); | 1664 m_duration = duration(); |
| 1653 scheduleEvent(EventTypeNames::durationchange); | 1665 scheduleEvent(EventTypeNames::durationchange); |
| 1654 | 1666 |
| 1655 if (isHTMLVideoElement()) | 1667 if (isHTMLVideoElement()) |
| 1656 scheduleEvent(EventTypeNames::resize); | 1668 scheduleEvent(EventTypeNames::resize); |
| 1657 scheduleEvent(EventTypeNames::loadedmetadata); | 1669 scheduleEvent(EventTypeNames::loadedmetadata); |
| 1658 | 1670 |
| 1659 bool jumped = false; | 1671 bool jumped = false; |
| 1660 if (m_defaultPlaybackStartPosition > 0) { | 1672 if (m_defaultPlaybackStartPosition > 0) { |
| 1661 seek(m_defaultPlaybackStartPosition); | 1673 seek(m_defaultPlaybackStartPosition); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1723 // creating a new one in this case. | 1735 // creating a new one in this case. |
| 1724 if (!m_autoplayVisibilityObserver) { | 1736 if (!m_autoplayVisibilityObserver) { |
| 1725 m_autoplayVisibilityObserver = new ElementVisibilityObserver( | 1737 m_autoplayVisibilityObserver = new ElementVisibilityObserver( |
| 1726 this, | 1738 this, |
| 1727 WTF::bind(&HTMLMediaElement::onVisibilityChangedForAutoplay, | 1739 WTF::bind(&HTMLMediaElement::onVisibilityChangedForAutoplay, |
| 1728 wrapWeakPersistent(this))); | 1740 wrapWeakPersistent(this))); |
| 1729 m_autoplayVisibilityObserver->start(); | 1741 m_autoplayVisibilityObserver->start(); |
| 1730 } | 1742 } |
| 1731 } else { | 1743 } else { |
| 1732 m_paused = false; | 1744 m_paused = false; |
| 1733 invalidateCachedTime(); | |
| 1734 scheduleEvent(EventTypeNames::play); | 1745 scheduleEvent(EventTypeNames::play); |
| 1735 scheduleNotifyPlaying(); | 1746 scheduleNotifyPlaying(); |
| 1736 m_autoplaying = false; | 1747 m_autoplaying = false; |
| 1737 } | 1748 } |
| 1738 } | 1749 } |
| 1739 } | 1750 } |
| 1740 | 1751 |
| 1741 scheduleEvent(EventTypeNames::canplaythrough); | 1752 scheduleEvent(EventTypeNames::canplaythrough); |
| 1742 | 1753 |
| 1743 shouldUpdateDisplayState = true; | 1754 shouldUpdateDisplayState = true; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1799 // m_webMediaPlayer is going out of sync with readystate. | 1810 // m_webMediaPlayer is going out of sync with readystate. |
| 1800 // m_webMediaPlayer is cleared but readystate is not set to HAVE_NOTHING. | 1811 // m_webMediaPlayer is cleared but readystate is not set to HAVE_NOTHING. |
| 1801 if (!m_webMediaPlayer || m_readyState == kHaveNothing) | 1812 if (!m_webMediaPlayer || m_readyState == kHaveNothing) |
| 1802 return; | 1813 return; |
| 1803 | 1814 |
| 1804 // Ignore preload none and start load if necessary. | 1815 // Ignore preload none and start load if necessary. |
| 1805 setIgnorePreloadNone(); | 1816 setIgnorePreloadNone(); |
| 1806 | 1817 |
| 1807 // Get the current time before setting m_seeking, m_lastSeekTime is returned | 1818 // Get the current time before setting m_seeking, m_lastSeekTime is returned |
| 1808 // once it is set. | 1819 // once it is set. |
| 1809 refreshCachedTime(); | 1820 double now = currentTime(); |
| 1810 // This is needed to avoid getting default playback start position from | |
| 1811 // currentTime(). | |
| 1812 double now = m_cachedTime; | |
| 1813 | 1821 |
| 1814 // 3 - If the element's seeking IDL attribute is true, then another instance | 1822 // 3 - If the element's seeking IDL attribute is true, then another instance |
| 1815 // of this algorithm is already running. Abort that other instance of the | 1823 // of this algorithm is already running. Abort that other instance of the |
| 1816 // algorithm without waiting for the step that it is running to complete. | 1824 // algorithm without waiting for the step that it is running to complete. |
| 1817 // Nothing specific to be done here. | 1825 // Nothing specific to be done here. |
| 1818 | 1826 |
| 1819 // 4 - Set the seeking IDL attribute to true. | 1827 // 4 - Set the seeking IDL attribute to true. |
| 1820 // The flag will be cleared when the engine tells us the time has actually | 1828 // The flag will be cleared when the engine tells us the time has actually |
| 1821 // changed. | 1829 // changed. |
| 1822 m_seeking = true; | 1830 m_seeking = true; |
| 1823 | 1831 |
| 1824 // 6 - If the new playback position is later than the end of the media | 1832 // 6 - If the new playback position is later than the end of the media |
| 1825 // resource, then let it be the end of the media resource instead. | 1833 // resource, then let it be the end of the media resource instead. |
| 1826 time = std::min(time, duration()); | 1834 time = std::min(time, duration()); |
| 1827 | 1835 |
| 1828 // 7 - If the new playback position is less than the earliest possible | 1836 // 7 - If the new playback position is less than the earliest possible |
| 1829 // position, let it be that position instead. | 1837 // position, let it be that position instead. |
| 1830 time = std::max(time, 0.0); | 1838 time = std::max(time, earliestPossiblePosition()); |
| 1831 | 1839 |
| 1832 // Ask the media engine for the time value in the movie's time scale before | 1840 // Ask the media engine for the time value in the movie's time scale before |
| 1833 // comparing with current time. This is necessary because if the seek time is | 1841 // comparing with current time. This is necessary because if the seek time is |
| 1834 // not equal to currentTime but the delta is less than the movie's time scale, | 1842 // not equal to currentTime but the delta is less than the movie's time scale, |
| 1835 // we will ask the media engine to "seek" to the current movie time, which may | 1843 // we will ask the media engine to "seek" to the current movie time, which may |
| 1836 // be a noop and not generate a timechanged callback. This means m_seeking | 1844 // be a noop and not generate a timechanged callback. This means m_seeking |
| 1837 // will never be cleared and we will never fire a 'seeked' event. | 1845 // will never be cleared and we will never fire a 'seeked' event. |
| 1838 double mediaTime = webMediaPlayer()->mediaTimeForTimeValue(time); | 1846 double mediaTime = webMediaPlayer()->mediaTimeForTimeValue(time); |
| 1839 if (time != mediaTime) { | 1847 if (time != mediaTime) { |
| 1840 BLINK_MEDIA_LOG << "seek(" << (void*)this << ", " << time | 1848 BLINK_MEDIA_LOG << "seek(" << (void*)this << ", " << time |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 1870 // 14-17 are handled, if necessary, when the engine signals a readystate | 1878 // 14-17 are handled, if necessary, when the engine signals a readystate |
| 1871 // change or otherwise satisfies seek completion and signals a time change. | 1879 // change or otherwise satisfies seek completion and signals a time change. |
| 1872 } | 1880 } |
| 1873 | 1881 |
| 1874 void HTMLMediaElement::finishSeek() { | 1882 void HTMLMediaElement::finishSeek() { |
| 1875 BLINK_MEDIA_LOG << "finishSeek(" << (void*)this << ")"; | 1883 BLINK_MEDIA_LOG << "finishSeek(" << (void*)this << ")"; |
| 1876 | 1884 |
| 1877 // 14 - Set the seeking IDL attribute to false. | 1885 // 14 - Set the seeking IDL attribute to false. |
| 1878 m_seeking = false; | 1886 m_seeking = false; |
| 1879 | 1887 |
| 1888 // Force an update to officialPlaybackPosition. Periodic updates generally | |
| 1889 // handle this, but may be skipped paused or waiting for data. | |
| 1890 setOfficialPlaybackPosition(currentPlaybackPosition()); | |
| 1891 | |
| 1880 // 16 - Queue a task to fire a simple event named timeupdate at the element. | 1892 // 16 - Queue a task to fire a simple event named timeupdate at the element. |
| 1881 scheduleTimeupdateEvent(false); | 1893 scheduleTimeupdateEvent(false); |
| 1882 | 1894 |
| 1883 // 17 - Queue a task to fire a simple event named seeked at the element. | 1895 // 17 - Queue a task to fire a simple event named seeked at the element. |
| 1884 scheduleEvent(EventTypeNames::seeked); | 1896 scheduleEvent(EventTypeNames::seeked); |
| 1885 | 1897 |
| 1886 setDisplayMode(Video); | 1898 setDisplayMode(Video); |
| 1887 } | 1899 } |
| 1888 | 1900 |
| 1889 HTMLMediaElement::ReadyState HTMLMediaElement::getReadyState() const { | 1901 HTMLMediaElement::ReadyState HTMLMediaElement::getReadyState() const { |
| 1890 return m_readyState; | 1902 return m_readyState; |
| 1891 } | 1903 } |
| 1892 | 1904 |
| 1893 bool HTMLMediaElement::hasVideo() const { | 1905 bool HTMLMediaElement::hasVideo() const { |
| 1894 return webMediaPlayer() && webMediaPlayer()->hasVideo(); | 1906 return webMediaPlayer() && webMediaPlayer()->hasVideo(); |
| 1895 } | 1907 } |
| 1896 | 1908 |
| 1897 bool HTMLMediaElement::hasAudio() const { | 1909 bool HTMLMediaElement::hasAudio() const { |
| 1898 return webMediaPlayer() && webMediaPlayer()->hasAudio(); | 1910 return webMediaPlayer() && webMediaPlayer()->hasAudio(); |
| 1899 } | 1911 } |
| 1900 | 1912 |
| 1901 bool HTMLMediaElement::seeking() const { | 1913 bool HTMLMediaElement::seeking() const { |
| 1902 return m_seeking; | 1914 return m_seeking; |
| 1903 } | 1915 } |
| 1904 | 1916 |
| 1905 void HTMLMediaElement::refreshCachedTime() const { | 1917 // https://www.w3.org/TR/html51/semantics-embedded-content.html#earliest-possibl e-position |
| 1906 if (!webMediaPlayer() || m_readyState < kHaveMetadata) | 1918 // The earliest possible position is not explicitly exposed in the API; it |
| 1907 return; | 1919 // corresponds to the start time of the first range in the seekable attribute’s |
| 1920 // TimeRanges object, if any, or the current playback position otherwise. | |
| 1921 double HTMLMediaElement::earliestPossiblePosition() const { | |
| 1922 TimeRanges* seekableRanges = seekable(); | |
| 1923 if (seekableRanges && seekableRanges->length() > 0) | |
| 1924 return seekableRanges->start(0, ASSERT_NO_EXCEPTION); | |
| 1908 | 1925 |
| 1909 m_cachedTime = webMediaPlayer()->currentTime(); | 1926 return currentPlaybackPosition(); |
| 1910 } | 1927 } |
| 1911 | 1928 |
| 1912 void HTMLMediaElement::invalidateCachedTime() { | 1929 double HTMLMediaElement::currentPlaybackPosition() const { |
| 1913 BLINK_MEDIA_LOG << "invalidateCachedTime(" << (void*)this << ")"; | 1930 // "Official" playback position won't take updates from "current" playback |
| 1914 m_cachedTime = std::numeric_limits<double>::quiet_NaN(); | 1931 // position until m_readyState > kHaveMetadata, but other callers (e.g. |
| 1932 // pauseInternal) may still request currentPlaybackPosition at any time. | |
| 1933 // From spec: "Media elements have a current playback position, which must | |
| 1934 // initially (i.e., in the absence of media data) be zero seconds." | |
| 1935 if (m_readyState == kHaveNothing) | |
| 1936 return 0; | |
| 1937 | |
| 1938 if (webMediaPlayer()) | |
| 1939 return webMediaPlayer()->currentTime(); | |
| 1940 | |
| 1941 if (m_readyState >= kHaveMetadata) { | |
| 1942 LOG(WARNING) << __func__ << " readyState = " << m_readyState | |
| 1943 << " but no webMeidaPlayer to provide currentPlaybackPosition"; | |
| 1944 } | |
| 1945 | |
| 1946 return 0; | |
| 1915 } | 1947 } |
| 1916 | 1948 |
| 1917 // playback state | 1949 double HTMLMediaElement::officialPlaybackPosition() const { |
| 1950 // Hold updates to official playback position while paused or waiting for more | |
| 1951 // data. The underlying media player may continue to make small advances in | |
| 1952 // currentTime (e.g. as samples in the last rendered audio buffer are played | |
| 1953 // played out), but advancing currentTime while paused/waiting sends a mixed | |
| 1954 // signal about the state of playback. | |
| 1955 bool waitingForData = m_readyState <= kHaveCurrentData; | |
| 1956 if (m_officialPlaybackPositionNeedsUpdate && !m_paused && !waitingForData) { | |
| 1957 // Internal player position may advance slightly beyond duration because | |
| 1958 // many files use imprecise duration. Clamp official position to duration. | |
| 1959 // REVIEWER: Not sure what the spec expects really. If I don't do this here, | |
|
DaleCurtis
2016/10/26 19:43:44
Remove or fix?
chcunningham
2016/10/26 21:57:07
Done.
| |
| 1960 // I at least need to update MediaControlsPainter::paintMediaSliderInternal | |
| 1961 // to not skip ranges when rangeEnd < currentTime. | |
| 1962 double newPosition = std::min(duration(), currentPlaybackPosition()); | |
| 1963 setOfficialPlaybackPosition(newPosition); | |
| 1964 } | |
| 1965 | |
| 1966 #if LOG_OFFICIAL_TIME_STATUS | |
| 1967 static const double minCachedDeltaForWarning = 0.01; | |
| 1968 double delta = | |
| 1969 std::abs(m_officialPlaybackPosition - currentPlaybackPosition()); | |
| 1970 if (delta > minCachedDeltaForWarning) { | |
| 1971 BLINK_MEDIA_LOG << "currentTime(" << (void*)this | |
| 1972 << ") - WARNING, cached time is " << delta | |
| 1973 << "seconds off of media time when paused/waiting"; | |
| 1974 } | |
| 1975 #endif | |
| 1976 | |
| 1977 return m_officialPlaybackPosition; | |
| 1978 } | |
| 1979 | |
| 1980 void HTMLMediaElement::setOfficialPlaybackPosition(double position) const { | |
| 1981 #if LOG_OFFICIAL_TIME_STATUS | |
| 1982 BLINK_MEDIA_LOG << "setOfficialPlaybackPosition(" << (void*)this | |
| 1983 << ") was:" << m_officialPlaybackPosition | |
| 1984 << " now:" << position; | |
| 1985 #endif | |
| 1986 | |
| 1987 m_officialPlaybackPosition = position; | |
| 1988 | |
| 1989 // Once set, official playback position should hold steady until the next | |
| 1990 // stable state. We approximate this by using a microtask to mark the | |
| 1991 // need for an update after the current (micro)task has completed. When | |
| 1992 // needed, the update is applied in the next call to | |
| 1993 // officialPlaybackPosition(). | |
| 1994 m_officialPlaybackPositionNeedsUpdate = false; | |
| 1995 Microtask::enqueueMicrotask( | |
| 1996 WTF::bind(&HTMLMediaElement::requireOfficialPlaybackPositionUpdate, | |
| 1997 wrapWeakPersistent(this))); | |
| 1998 } | |
| 1999 | |
| 2000 void HTMLMediaElement::requireOfficialPlaybackPositionUpdate() const { | |
| 2001 m_officialPlaybackPositionNeedsUpdate = true; | |
| 2002 } | |
| 2003 | |
| 1918 double HTMLMediaElement::currentTime() const { | 2004 double HTMLMediaElement::currentTime() const { |
| 1919 if (m_defaultPlaybackStartPosition) | 2005 if (m_defaultPlaybackStartPosition) |
| 1920 return m_defaultPlaybackStartPosition; | 2006 return m_defaultPlaybackStartPosition; |
| 1921 | 2007 |
| 1922 if (m_readyState == kHaveNothing) | |
| 1923 return 0; | |
| 1924 | |
| 1925 if (m_seeking) { | 2008 if (m_seeking) { |
| 1926 BLINK_MEDIA_LOG << "currentTime(" << (void*)this | 2009 BLINK_MEDIA_LOG << "currentTime(" << (void*)this |
| 1927 << ") - seeking, returning " << m_lastSeekTime; | 2010 << ") - seeking, returning " << m_lastSeekTime; |
| 1928 return m_lastSeekTime; | 2011 return m_lastSeekTime; |
| 1929 } | 2012 } |
| 1930 | 2013 |
| 1931 if (!std::isnan(m_cachedTime) && m_paused) { | 2014 return officialPlaybackPosition(); |
| 1932 #if LOG_CACHED_TIME_WARNINGS | |
| 1933 static const double minCachedDeltaForWarning = 0.01; | |
| 1934 double delta = m_cachedTime - webMediaPlayer()->currentTime(); | |
| 1935 if (delta > minCachedDeltaForWarning) | |
| 1936 BLINK_MEDIA_LOG << "currentTime(" << (void*)this | |
| 1937 << ") - WARNING, cached time is " << delta | |
| 1938 << "seconds off of media time when paused"; | |
| 1939 #endif | |
| 1940 return m_cachedTime; | |
| 1941 } | |
| 1942 | |
| 1943 refreshCachedTime(); | |
| 1944 | |
| 1945 return m_cachedTime; | |
| 1946 } | 2015 } |
| 1947 | 2016 |
| 1948 void HTMLMediaElement::setCurrentTime(double time) { | 2017 void HTMLMediaElement::setCurrentTime(double time) { |
| 1949 // If the media element's readyState is kHaveNothing, then set the default | 2018 // If the media element's readyState is kHaveNothing, then set the default |
| 1950 // playback start position to that time. | 2019 // playback start position to that time. |
| 1951 if (m_readyState == kHaveNothing) { | 2020 if (m_readyState == kHaveNothing) { |
| 1952 m_defaultPlaybackStartPosition = time; | 2021 m_defaultPlaybackStartPosition = time; |
| 1953 return; | 2022 return; |
| 1954 } | 2023 } |
| 1955 | 2024 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1997 | 2066 |
| 1998 double HTMLMediaElement::playbackRate() const { | 2067 double HTMLMediaElement::playbackRate() const { |
| 1999 return m_playbackRate; | 2068 return m_playbackRate; |
| 2000 } | 2069 } |
| 2001 | 2070 |
| 2002 void HTMLMediaElement::setPlaybackRate(double rate) { | 2071 void HTMLMediaElement::setPlaybackRate(double rate) { |
| 2003 BLINK_MEDIA_LOG << "setPlaybackRate(" << (void*)this << ", " << rate << ")"; | 2072 BLINK_MEDIA_LOG << "setPlaybackRate(" << (void*)this << ", " << rate << ")"; |
| 2004 | 2073 |
| 2005 if (m_playbackRate != rate) { | 2074 if (m_playbackRate != rate) { |
| 2006 m_playbackRate = rate; | 2075 m_playbackRate = rate; |
| 2007 invalidateCachedTime(); | |
| 2008 scheduleEvent(EventTypeNames::ratechange); | 2076 scheduleEvent(EventTypeNames::ratechange); |
| 2009 } | 2077 } |
| 2010 | 2078 |
| 2011 updatePlaybackRate(); | 2079 updatePlaybackRate(); |
| 2012 } | 2080 } |
| 2013 | 2081 |
| 2014 HTMLMediaElement::DirectionOfPlayback HTMLMediaElement::getDirectionOfPlayback() | 2082 HTMLMediaElement::DirectionOfPlayback HTMLMediaElement::getDirectionOfPlayback() |
| 2015 const { | 2083 const { |
| 2016 return m_playbackRate >= 0 ? Forward : Backward; | 2084 return m_playbackRate >= 0 ? Forward : Backward; |
| 2017 } | 2085 } |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2204 invokeResourceSelectionAlgorithm(); | 2272 invokeResourceSelectionAlgorithm(); |
| 2205 | 2273 |
| 2206 // Generally "ended" and "looping" are exclusive. Here, the loop attribute | 2274 // Generally "ended" and "looping" are exclusive. Here, the loop attribute |
| 2207 // is ignored to seek back to start in case loop was set after playback | 2275 // is ignored to seek back to start in case loop was set after playback |
| 2208 // ended. See http://crbug.com/364442 | 2276 // ended. See http://crbug.com/364442 |
| 2209 if (endedPlayback(LoopCondition::Ignored)) | 2277 if (endedPlayback(LoopCondition::Ignored)) |
| 2210 seek(0); | 2278 seek(0); |
| 2211 | 2279 |
| 2212 if (m_paused) { | 2280 if (m_paused) { |
| 2213 m_paused = false; | 2281 m_paused = false; |
| 2214 invalidateCachedTime(); | |
| 2215 scheduleEvent(EventTypeNames::play); | 2282 scheduleEvent(EventTypeNames::play); |
| 2216 | 2283 |
| 2217 if (m_readyState <= kHaveCurrentData) | 2284 if (m_readyState <= kHaveCurrentData) |
| 2218 scheduleEvent(EventTypeNames::waiting); | 2285 scheduleEvent(EventTypeNames::waiting); |
| 2219 else if (m_readyState >= kHaveFutureData) | 2286 else if (m_readyState >= kHaveFutureData) |
| 2220 scheduleNotifyPlaying(); | 2287 scheduleNotifyPlaying(); |
| 2221 } else if (m_readyState >= kHaveFutureData) { | 2288 } else if (m_readyState >= kHaveFutureData) { |
| 2222 scheduleResolvePlayPromises(); | 2289 scheduleResolvePlayPromises(); |
| 2223 } | 2290 } |
| 2224 | 2291 |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 2247 invokeResourceSelectionAlgorithm(); | 2314 invokeResourceSelectionAlgorithm(); |
| 2248 | 2315 |
| 2249 m_autoplayHelper->pauseMethodCalled(); | 2316 m_autoplayHelper->pauseMethodCalled(); |
| 2250 | 2317 |
| 2251 m_autoplaying = false; | 2318 m_autoplaying = false; |
| 2252 | 2319 |
| 2253 if (!m_paused) { | 2320 if (!m_paused) { |
| 2254 m_paused = true; | 2321 m_paused = true; |
| 2255 scheduleTimeupdateEvent(false); | 2322 scheduleTimeupdateEvent(false); |
| 2256 scheduleEvent(EventTypeNames::pause); | 2323 scheduleEvent(EventTypeNames::pause); |
| 2324 | |
| 2325 // Force an update to official playback position. Automatic updates from | |
| 2326 // currentPlaybackPosition() will be blocked while m_paused = true. This | |
| 2327 // blocking is desired while paused, but its good to update it one final | |
| 2328 // time to accurately reflect movie time at the moment we paused. | |
| 2329 setOfficialPlaybackPosition(currentPlaybackPosition()); | |
| 2330 | |
| 2257 scheduleRejectPlayPromises(AbortError); | 2331 scheduleRejectPlayPromises(AbortError); |
| 2258 } | 2332 } |
| 2259 | 2333 |
| 2260 updatePlayState(); | 2334 updatePlayState(); |
| 2261 } | 2335 } |
| 2262 | 2336 |
| 2263 void HTMLMediaElement::requestRemotePlayback() { | 2337 void HTMLMediaElement::requestRemotePlayback() { |
| 2264 if (webMediaPlayer()) | 2338 if (webMediaPlayer()) |
| 2265 webMediaPlayer()->requestRemotePlayback(); | 2339 webMediaPlayer()->requestRemotePlayback(); |
| 2266 } | 2340 } |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2431 if (!playbackRate()) | 2505 if (!playbackRate()) |
| 2432 return; | 2506 return; |
| 2433 | 2507 |
| 2434 if (!m_paused && mediaControls()) | 2508 if (!m_paused && mediaControls()) |
| 2435 mediaControls()->playbackProgressed(); | 2509 mediaControls()->playbackProgressed(); |
| 2436 | 2510 |
| 2437 cueTimeline().updateActiveCues(currentTime()); | 2511 cueTimeline().updateActiveCues(currentTime()); |
| 2438 } | 2512 } |
| 2439 | 2513 |
| 2440 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent) { | 2514 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent) { |
| 2515 // Per spec, consult current playback position to check for changing time. | |
| 2516 double mediaTime = currentPlaybackPosition(); | |
| 2441 double now = WTF::currentTime(); | 2517 double now = WTF::currentTime(); |
| 2442 double movieTime = currentTime(); | |
| 2443 | 2518 |
| 2444 bool haveNotRecentlyFiredTimeupdate = | 2519 bool haveNotRecentlyFiredTimeupdate = |
| 2445 (now - m_lastTimeUpdateEventWallTime) >= maxTimeupdateEventFrequency; | 2520 (now - m_lastTimeUpdateEventWallTime) >= maxTimeupdateEventFrequency; |
| 2446 bool movieTimeHasProgressed = movieTime != m_lastTimeUpdateEventMovieTime; | 2521 bool mediaTimeHasProgressed = mediaTime != m_lastTimeUpdateEventMediaTime; |
| 2447 | 2522 |
| 2448 // Non-periodic timeupdate events must always fire as mandated by the spec, | 2523 // Non-periodic timeupdate events must always fire as mandated by the spec, |
| 2449 // otherwise we shouldn't fire duplicate periodic timeupdate events when the | 2524 // otherwise we shouldn't fire duplicate periodic timeupdate events when the |
| 2450 // movie time hasn't changed. | 2525 // movie time hasn't changed. |
| 2451 if (!periodicEvent || | 2526 if (!periodicEvent || |
| 2452 (haveNotRecentlyFiredTimeupdate && movieTimeHasProgressed)) { | 2527 (haveNotRecentlyFiredTimeupdate && mediaTimeHasProgressed)) { |
| 2453 scheduleEvent(EventTypeNames::timeupdate); | 2528 scheduleEvent(EventTypeNames::timeupdate); |
| 2454 m_lastTimeUpdateEventWallTime = now; | 2529 m_lastTimeUpdateEventWallTime = now; |
| 2455 m_lastTimeUpdateEventMovieTime = movieTime; | 2530 m_lastTimeUpdateEventMediaTime = mediaTime; |
| 2456 } | 2531 } |
| 2457 } | 2532 } |
| 2458 | 2533 |
| 2459 void HTMLMediaElement::togglePlayState() { | 2534 void HTMLMediaElement::togglePlayState() { |
| 2460 if (paused()) | 2535 if (paused()) |
| 2461 play(); | 2536 play(); |
| 2462 else | 2537 else |
| 2463 pause(); | 2538 pause(); |
| 2464 } | 2539 } |
| 2465 | 2540 |
| (...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2977 BLINK_MEDIA_LOG << "sourceWasRemoved(" << (void*)this | 3052 BLINK_MEDIA_LOG << "sourceWasRemoved(" << (void*)this |
| 2978 << ") - m_currentSourceNode set to 0"; | 3053 << ") - m_currentSourceNode set to 0"; |
| 2979 } | 3054 } |
| 2980 } | 3055 } |
| 2981 | 3056 |
| 2982 void HTMLMediaElement::timeChanged() { | 3057 void HTMLMediaElement::timeChanged() { |
| 2983 BLINK_MEDIA_LOG << "timeChanged(" << (void*)this << ")"; | 3058 BLINK_MEDIA_LOG << "timeChanged(" << (void*)this << ")"; |
| 2984 | 3059 |
| 2985 cueTimeline().updateActiveCues(currentTime()); | 3060 cueTimeline().updateActiveCues(currentTime()); |
| 2986 | 3061 |
| 2987 invalidateCachedTime(); | |
| 2988 | |
| 2989 // 4.8.10.9 steps 12-14. Needed if no ReadyState change is associated with the | 3062 // 4.8.10.9 steps 12-14. Needed if no ReadyState change is associated with the |
| 2990 // seek. | 3063 // seek. |
| 2991 if (m_seeking && m_readyState >= kHaveCurrentData && | 3064 if (m_seeking && m_readyState >= kHaveCurrentData && |
| 2992 !webMediaPlayer()->seeking()) | 3065 !webMediaPlayer()->seeking()) |
| 2993 finishSeek(); | 3066 finishSeek(); |
| 2994 | 3067 |
| 2995 // Always call scheduleTimeupdateEvent when the media engine reports a time | 3068 // Always call scheduleTimeupdateEvent when the media engine reports a time |
| 2996 // discontinuity, it will only queue a 'timeupdate' event if we haven't | 3069 // discontinuity, it will only queue a 'timeupdate' event if we haven't |
| 2997 // already posted one at the current movie time. | 3070 // already posted one at the current movie time. |
| 2998 scheduleTimeupdateEvent(false); | 3071 scheduleTimeupdateEvent(false); |
| 2999 | 3072 |
| 3000 double now = currentTime(); | 3073 double now = currentPlaybackPosition(); |
| 3001 double dur = duration(); | 3074 double dur = duration(); |
| 3002 | 3075 |
| 3003 // When the current playback position reaches the end of the media resource | 3076 // When the current playback position reaches the end of the media resource |
| 3004 // when the direction of playback is forwards, then the user agent must follow | 3077 // when the direction of playback is forwards, then the user agent must follow |
| 3005 // these steps: | 3078 // these steps: |
| 3006 if (!std::isnan(dur) && dur && now >= dur && | 3079 if (!std::isnan(dur) && dur && now >= dur && |
| 3007 getDirectionOfPlayback() == Forward) { | 3080 getDirectionOfPlayback() == Forward) { |
| 3008 // If the media element has a loop attribute specified | 3081 // If the media element has a loop attribute specified |
| 3009 if (loop()) { | 3082 if (loop()) { |
| 3010 // then seek to the earliest possible position of the media resource and | 3083 // then seek to the earliest possible position of the media resource and |
| 3011 // abort these steps. | 3084 // abort these steps. |
| 3012 seek(0); | 3085 seek(earliestPossiblePosition()); |
| 3013 } else { | 3086 } else { |
| 3014 // If the media element has still ended playback, and the direction of | 3087 // If the media element has still ended playback, and the direction of |
| 3015 // playback is still forwards, and paused is false, | 3088 // playback is still forwards, and paused is false, |
| 3016 if (!m_paused) { | 3089 if (!m_paused) { |
| 3017 // changes paused to true and fires a simple event named pause at the | 3090 // changes paused to true and fires a simple event named pause at the |
| 3018 // media element. | 3091 // media element. |
| 3019 m_paused = true; | 3092 m_paused = true; |
| 3020 scheduleEvent(EventTypeNames::pause); | 3093 scheduleEvent(EventTypeNames::pause); |
| 3021 scheduleRejectPlayPromises(AbortError); | 3094 scheduleRejectPlayPromises(AbortError); |
| 3022 } | 3095 } |
| 3023 // Queue a task to fire a simple event named ended at the media element. | 3096 // Queue a task to fire a simple event named ended at the media element. |
| 3024 scheduleEvent(EventTypeNames::ended); | 3097 scheduleEvent(EventTypeNames::ended); |
| 3025 } | 3098 } |
| 3026 } | 3099 } |
| 3027 updatePlayState(); | 3100 updatePlayState(); |
| 3028 } | 3101 } |
| 3029 | 3102 |
| 3030 void HTMLMediaElement::durationChanged() { | 3103 void HTMLMediaElement::durationChanged() { |
| 3031 BLINK_MEDIA_LOG << "durationChanged(" << (void*)this << ")"; | 3104 BLINK_MEDIA_LOG << "durationChanged(" << (void*)this << ")"; |
| 3032 // FIXME: Change WebMediaPlayer to convey the currentTime | 3105 // If the duration is changed such that the *current playback position* ends |
| 3033 // when the duration change occured. The current WebMediaPlayer | 3106 // up being greater than the time of the end of the media resource, then the |
| 3034 // implementations always clamp currentTime() to duration() | 3107 // user agent must also seek to the time of the end of the media resource. |
| 3035 // so the requestSeek condition here is always false. | 3108 durationChanged(duration(), currentPlaybackPosition() > duration()); |
| 3036 durationChanged(duration(), currentTime() > duration()); | |
| 3037 } | 3109 } |
| 3038 | 3110 |
| 3039 void HTMLMediaElement::durationChanged(double duration, bool requestSeek) { | 3111 void HTMLMediaElement::durationChanged(double duration, bool requestSeek) { |
| 3040 BLINK_MEDIA_LOG << "durationChanged(" << (void*)this << ", " << duration | 3112 BLINK_MEDIA_LOG << "durationChanged(" << (void*)this << ", " << duration |
| 3041 << ", " << boolString(requestSeek) << ")"; | 3113 << ", " << boolString(requestSeek) << ")"; |
| 3042 | 3114 |
| 3043 // Abort if duration unchanged. | 3115 // Abort if duration unchanged. |
| 3044 if (m_duration == duration) | 3116 if (m_duration == duration) |
| 3045 return; | 3117 return; |
| 3046 | 3118 |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3189 // 4.8.10.8 Playing the media resource | 3261 // 4.8.10.8 Playing the media resource |
| 3190 | 3262 |
| 3191 // A media element is said to have ended playback when the element's | 3263 // A media element is said to have ended playback when the element's |
| 3192 // readyState attribute is HAVE_METADATA or greater, | 3264 // readyState attribute is HAVE_METADATA or greater, |
| 3193 if (m_readyState < kHaveMetadata) | 3265 if (m_readyState < kHaveMetadata) |
| 3194 return false; | 3266 return false; |
| 3195 | 3267 |
| 3196 // and the current playback position is the end of the media resource and the | 3268 // and the current playback position is the end of the media resource and the |
| 3197 // direction of playback is forwards, Either the media element does not have a | 3269 // direction of playback is forwards, Either the media element does not have a |
| 3198 // loop attribute specified, | 3270 // loop attribute specified, |
| 3199 double now = currentTime(); | 3271 double now = currentPlaybackPosition(); |
| 3200 if (getDirectionOfPlayback() == Forward) | 3272 if (getDirectionOfPlayback() == Forward) |
| 3201 return dur > 0 && now >= dur && | 3273 return dur > 0 && now >= dur && |
| 3202 (loopCondition == LoopCondition::Ignored || !loop()); | 3274 (loopCondition == LoopCondition::Ignored || !loop()); |
| 3203 | 3275 |
| 3204 // or the current playback position is the earliest possible position and the | 3276 // or the current playback position is the earliest possible position and the |
| 3205 // direction of playback is backwards | 3277 // direction of playback is backwards |
| 3206 DCHECK_EQ(getDirectionOfPlayback(), Backward); | 3278 DCHECK_EQ(getDirectionOfPlayback(), Backward); |
| 3207 return now <= 0; | 3279 return now <= earliestPossiblePosition(); |
| 3208 } | 3280 } |
| 3209 | 3281 |
| 3210 bool HTMLMediaElement::stoppedDueToErrors() const { | 3282 bool HTMLMediaElement::stoppedDueToErrors() const { |
| 3211 if (m_readyState >= kHaveMetadata && m_error) { | 3283 if (m_readyState >= kHaveMetadata && m_error) { |
| 3212 TimeRanges* seekableRanges = seekable(); | 3284 TimeRanges* seekableRanges = seekable(); |
| 3213 if (!seekableRanges->contain(currentTime())) | 3285 if (!seekableRanges->contain(currentTime())) |
| 3214 return true; | 3286 return true; |
| 3215 } | 3287 } |
| 3216 | 3288 |
| 3217 return false; | 3289 return false; |
| 3218 } | 3290 } |
| 3219 | 3291 |
| 3220 void HTMLMediaElement::updatePlayState() { | 3292 void HTMLMediaElement::updatePlayState() { |
| 3221 bool isPlaying = webMediaPlayer() && !webMediaPlayer()->paused(); | 3293 bool isPlaying = webMediaPlayer() && !webMediaPlayer()->paused(); |
| 3222 bool shouldBePlaying = potentiallyPlaying(); | 3294 bool shouldBePlaying = potentiallyPlaying(); |
| 3223 | 3295 |
| 3224 BLINK_MEDIA_LOG << "updatePlayState(" << (void*)this | 3296 BLINK_MEDIA_LOG << "updatePlayState(" << (void*)this |
| 3225 << ") - shouldBePlaying = " << boolString(shouldBePlaying) | 3297 << ") - shouldBePlaying = " << boolString(shouldBePlaying) |
| 3226 << ", isPlaying = " << boolString(isPlaying); | 3298 << ", isPlaying = " << boolString(isPlaying); |
| 3227 | 3299 |
| 3228 if (shouldBePlaying) { | 3300 if (shouldBePlaying) { |
| 3229 setDisplayMode(Video); | 3301 setDisplayMode(Video); |
| 3230 invalidateCachedTime(); | |
| 3231 | 3302 |
| 3232 if (!isPlaying) { | 3303 if (!isPlaying) { |
| 3233 // Set rate, muted before calling play in case they were set before the | 3304 // Set rate, muted before calling play in case they were set before the |
| 3234 // media engine was setup. The media engine should just stash the rate | 3305 // media engine was setup. The media engine should just stash the rate |
| 3235 // and muted values since it isn't already playing. | 3306 // and muted values since it isn't already playing. |
| 3236 webMediaPlayer()->setRate(playbackRate()); | 3307 webMediaPlayer()->setRate(playbackRate()); |
| 3237 updateVolume(); | 3308 updateVolume(); |
| 3238 webMediaPlayer()->play(); | 3309 webMediaPlayer()->play(); |
| 3239 m_autoplayHelper->playbackStarted(); | 3310 m_autoplayHelper->playbackStarted(); |
| 3240 } | 3311 } |
| 3241 | 3312 |
| 3242 if (mediaControls()) | 3313 if (mediaControls()) |
| 3243 mediaControls()->playbackStarted(); | 3314 mediaControls()->playbackStarted(); |
| 3244 startPlaybackProgressTimer(); | 3315 startPlaybackProgressTimer(); |
| 3245 m_playing = true; | 3316 m_playing = true; |
| 3246 | 3317 |
| 3247 } else { // Should not be playing right now | 3318 } else { // Should not be playing right now |
| 3248 if (isPlaying) { | 3319 if (isPlaying) { |
| 3249 webMediaPlayer()->pause(); | 3320 webMediaPlayer()->pause(); |
| 3250 m_autoplayHelper->playbackStopped(); | 3321 m_autoplayHelper->playbackStopped(); |
| 3251 } | 3322 } |
| 3252 | 3323 |
| 3253 refreshCachedTime(); | |
| 3254 | |
| 3255 m_playbackProgressTimer.stop(); | 3324 m_playbackProgressTimer.stop(); |
| 3256 m_playing = false; | 3325 m_playing = false; |
| 3257 double time = currentTime(); | 3326 double time = currentTime(); |
| 3258 if (time > m_lastSeekTime) | 3327 if (time > m_lastSeekTime) |
| 3259 addPlayedRange(m_lastSeekTime, time); | 3328 addPlayedRange(m_lastSeekTime, time); |
| 3260 | 3329 |
| 3261 if (mediaControls()) | 3330 if (mediaControls()) |
| 3262 mediaControls()->playbackStopped(); | 3331 mediaControls()->playbackStopped(); |
| 3263 } | 3332 } |
| 3264 | 3333 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3315 cancelPendingEventsAndCallbacks(); | 3384 cancelPendingEventsAndCallbacks(); |
| 3316 m_asyncEventQueue->close(); | 3385 m_asyncEventQueue->close(); |
| 3317 | 3386 |
| 3318 // Clear everything in the Media Element | 3387 // Clear everything in the Media Element |
| 3319 clearMediaPlayer(); | 3388 clearMediaPlayer(); |
| 3320 m_readyState = kHaveNothing; | 3389 m_readyState = kHaveNothing; |
| 3321 m_readyStateMaximum = kHaveNothing; | 3390 m_readyStateMaximum = kHaveNothing; |
| 3322 setNetworkState(kNetworkEmpty); | 3391 setNetworkState(kNetworkEmpty); |
| 3323 setShouldDelayLoadEvent(false); | 3392 setShouldDelayLoadEvent(false); |
| 3324 m_currentSourceNode = nullptr; | 3393 m_currentSourceNode = nullptr; |
| 3325 invalidateCachedTime(); | 3394 m_officialPlaybackPosition = 0; |
| 3395 m_officialPlaybackPositionNeedsUpdate = true; | |
| 3326 cueTimeline().updateActiveCues(0); | 3396 cueTimeline().updateActiveCues(0); |
| 3327 m_playing = false; | 3397 m_playing = false; |
| 3328 m_paused = true; | 3398 m_paused = true; |
| 3329 m_seeking = false; | 3399 m_seeking = false; |
| 3330 | 3400 |
| 3331 if (layoutObject()) | 3401 if (layoutObject()) |
| 3332 layoutObject()->updateFromElement(); | 3402 layoutObject()->updateFromElement(); |
| 3333 | 3403 |
| 3334 stopPeriodicTimers(); | 3404 stopPeriodicTimers(); |
| 3335 | 3405 |
| (...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3967 ("Media.Controls.Show.Audio", MediaControlsShowMax)); | 4037 ("Media.Controls.Show.Audio", MediaControlsShowMax)); |
| 3968 return histogram; | 4038 return histogram; |
| 3969 } | 4039 } |
| 3970 | 4040 |
| 3971 void HTMLMediaElement::onVisibilityChangedForAutoplay(bool isVisible) { | 4041 void HTMLMediaElement::onVisibilityChangedForAutoplay(bool isVisible) { |
| 3972 if (!isVisible) | 4042 if (!isVisible) |
| 3973 return; | 4043 return; |
| 3974 | 4044 |
| 3975 if (shouldAutoplay()) { | 4045 if (shouldAutoplay()) { |
| 3976 m_paused = false; | 4046 m_paused = false; |
| 3977 invalidateCachedTime(); | |
| 3978 scheduleEvent(EventTypeNames::play); | 4047 scheduleEvent(EventTypeNames::play); |
| 3979 scheduleNotifyPlaying(); | 4048 scheduleNotifyPlaying(); |
| 3980 m_autoplaying = false; | 4049 m_autoplaying = false; |
| 3981 | 4050 |
| 3982 updatePlayState(); | 4051 updatePlayState(); |
| 3983 } | 4052 } |
| 3984 | 4053 |
| 3985 // TODO(zqzhang): There's still flaky leak if onVisibilityChangedForAutoplay() | 4054 // TODO(zqzhang): There's still flaky leak if onVisibilityChangedForAutoplay() |
| 3986 // is never called. The leak comes from either ElementVisibilityObserver or | 4055 // is never called. The leak comes from either ElementVisibilityObserver or |
| 3987 // IntersectionObserver. Should keep an eye on it. See | 4056 // IntersectionObserver. Should keep an eye on it. See |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4092 | 4161 |
| 4093 IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect() | 4162 IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect() |
| 4094 const { | 4163 const { |
| 4095 IntRect result; | 4164 IntRect result; |
| 4096 if (LayoutObject* object = m_element->layoutObject()) | 4165 if (LayoutObject* object = m_element->layoutObject()) |
| 4097 result = object->absoluteBoundingBoxRect(); | 4166 result = object->absoluteBoundingBoxRect(); |
| 4098 return result; | 4167 return result; |
| 4099 } | 4168 } |
| 4100 | 4169 |
| 4101 } // namespace blink | 4170 } // namespace blink |
| OLD | NEW |