| 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 15 matching lines...) Expand all Loading... |
| 1677 if (mediaControls()) | 1689 if (mediaControls()) |
| 1678 mediaControls()->reset(); | 1690 mediaControls()->reset(); |
| 1679 if (layoutObject()) | 1691 if (layoutObject()) |
| 1680 layoutObject()->updateFromElement(); | 1692 layoutObject()->updateFromElement(); |
| 1681 } | 1693 } |
| 1682 | 1694 |
| 1683 bool shouldUpdateDisplayState = false; | 1695 bool shouldUpdateDisplayState = false; |
| 1684 | 1696 |
| 1685 if (m_readyState >= kHaveCurrentData && oldState < kHaveCurrentData && | 1697 if (m_readyState >= kHaveCurrentData && oldState < kHaveCurrentData && |
| 1686 !m_haveFiredLoadedData) { | 1698 !m_haveFiredLoadedData) { |
| 1699 // Force an update to official playback position to catch non-zero start |
| 1700 // times that were not known at kHaveMetadata, but are known now that the |
| 1701 // first packets have been demuxed. |
| 1702 setOfficialPlaybackPosition(currentPlaybackPosition()); |
| 1703 |
| 1687 m_haveFiredLoadedData = true; | 1704 m_haveFiredLoadedData = true; |
| 1688 shouldUpdateDisplayState = true; | 1705 shouldUpdateDisplayState = true; |
| 1689 scheduleEvent(EventTypeNames::loadeddata); | 1706 scheduleEvent(EventTypeNames::loadeddata); |
| 1690 setShouldDelayLoadEvent(false); | 1707 setShouldDelayLoadEvent(false); |
| 1691 } | 1708 } |
| 1692 | 1709 |
| 1693 bool isPotentiallyPlaying = potentiallyPlaying(); | 1710 bool isPotentiallyPlaying = potentiallyPlaying(); |
| 1694 if (m_readyState == kHaveFutureData && oldState <= kHaveCurrentData && | 1711 if (m_readyState == kHaveFutureData && oldState <= kHaveCurrentData && |
| 1695 tracksAreReady) { | 1712 tracksAreReady) { |
| 1696 scheduleEvent(EventTypeNames::canplay); | 1713 scheduleEvent(EventTypeNames::canplay); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1723 // creating a new one in this case. | 1740 // creating a new one in this case. |
| 1724 if (!m_autoplayVisibilityObserver) { | 1741 if (!m_autoplayVisibilityObserver) { |
| 1725 m_autoplayVisibilityObserver = new ElementVisibilityObserver( | 1742 m_autoplayVisibilityObserver = new ElementVisibilityObserver( |
| 1726 this, | 1743 this, |
| 1727 WTF::bind(&HTMLMediaElement::onVisibilityChangedForAutoplay, | 1744 WTF::bind(&HTMLMediaElement::onVisibilityChangedForAutoplay, |
| 1728 wrapWeakPersistent(this))); | 1745 wrapWeakPersistent(this))); |
| 1729 m_autoplayVisibilityObserver->start(); | 1746 m_autoplayVisibilityObserver->start(); |
| 1730 } | 1747 } |
| 1731 } else { | 1748 } else { |
| 1732 m_paused = false; | 1749 m_paused = false; |
| 1733 invalidateCachedTime(); | |
| 1734 scheduleEvent(EventTypeNames::play); | 1750 scheduleEvent(EventTypeNames::play); |
| 1735 scheduleNotifyPlaying(); | 1751 scheduleNotifyPlaying(); |
| 1736 m_autoplaying = false; | 1752 m_autoplaying = false; |
| 1737 } | 1753 } |
| 1738 } | 1754 } |
| 1739 } | 1755 } |
| 1740 | 1756 |
| 1741 scheduleEvent(EventTypeNames::canplaythrough); | 1757 scheduleEvent(EventTypeNames::canplaythrough); |
| 1742 | 1758 |
| 1743 shouldUpdateDisplayState = true; | 1759 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. | 1815 // m_webMediaPlayer is going out of sync with readystate. |
| 1800 // m_webMediaPlayer is cleared but readystate is not set to HAVE_NOTHING. | 1816 // m_webMediaPlayer is cleared but readystate is not set to HAVE_NOTHING. |
| 1801 if (!m_webMediaPlayer || m_readyState == kHaveNothing) | 1817 if (!m_webMediaPlayer || m_readyState == kHaveNothing) |
| 1802 return; | 1818 return; |
| 1803 | 1819 |
| 1804 // Ignore preload none and start load if necessary. | 1820 // Ignore preload none and start load if necessary. |
| 1805 setIgnorePreloadNone(); | 1821 setIgnorePreloadNone(); |
| 1806 | 1822 |
| 1807 // Get the current time before setting m_seeking, m_lastSeekTime is returned | 1823 // Get the current time before setting m_seeking, m_lastSeekTime is returned |
| 1808 // once it is set. | 1824 // once it is set. |
| 1809 refreshCachedTime(); | 1825 double now = currentTime(); |
| 1810 // This is needed to avoid getting default playback start position from | |
| 1811 // currentTime(). | |
| 1812 double now = m_cachedTime; | |
| 1813 | 1826 |
| 1814 // 3 - If the element's seeking IDL attribute is true, then another instance | 1827 // 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 | 1828 // 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. | 1829 // algorithm without waiting for the step that it is running to complete. |
| 1817 // Nothing specific to be done here. | 1830 // Nothing specific to be done here. |
| 1818 | 1831 |
| 1819 // 4 - Set the seeking IDL attribute to true. | 1832 // 4 - Set the seeking IDL attribute to true. |
| 1820 // The flag will be cleared when the engine tells us the time has actually | 1833 // The flag will be cleared when the engine tells us the time has actually |
| 1821 // changed. | 1834 // changed. |
| 1822 m_seeking = true; | 1835 m_seeking = true; |
| 1823 | 1836 |
| 1824 // 6 - If the new playback position is later than the end of the media | 1837 // 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. | 1838 // resource, then let it be the end of the media resource instead. |
| 1826 time = std::min(time, duration()); | 1839 time = std::min(time, duration()); |
| 1827 | 1840 |
| 1828 // 7 - If the new playback position is less than the earliest possible | 1841 // 7 - If the new playback position is less than the earliest possible |
| 1829 // position, let it be that position instead. | 1842 // position, let it be that position instead. |
| 1830 time = std::max(time, 0.0); | 1843 time = std::max(time, earliestPossiblePosition()); |
| 1831 | 1844 |
| 1832 // Ask the media engine for the time value in the movie's time scale before | 1845 // 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 | 1846 // 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, | 1847 // 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 | 1848 // 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 | 1849 // 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. | 1850 // will never be cleared and we will never fire a 'seeked' event. |
| 1838 double mediaTime = webMediaPlayer()->mediaTimeForTimeValue(time); | 1851 double mediaTime = webMediaPlayer()->mediaTimeForTimeValue(time); |
| 1839 if (time != mediaTime) { | 1852 if (time != mediaTime) { |
| 1840 BLINK_MEDIA_LOG << "seek(" << (void*)this << ", " << time | 1853 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 | 1883 // 14-17 are handled, if necessary, when the engine signals a readystate |
| 1871 // change or otherwise satisfies seek completion and signals a time change. | 1884 // change or otherwise satisfies seek completion and signals a time change. |
| 1872 } | 1885 } |
| 1873 | 1886 |
| 1874 void HTMLMediaElement::finishSeek() { | 1887 void HTMLMediaElement::finishSeek() { |
| 1875 BLINK_MEDIA_LOG << "finishSeek(" << (void*)this << ")"; | 1888 BLINK_MEDIA_LOG << "finishSeek(" << (void*)this << ")"; |
| 1876 | 1889 |
| 1877 // 14 - Set the seeking IDL attribute to false. | 1890 // 14 - Set the seeking IDL attribute to false. |
| 1878 m_seeking = false; | 1891 m_seeking = false; |
| 1879 | 1892 |
| 1893 // Force an update to officialPlaybackPosition. Periodic updates generally |
| 1894 // handle this, but may be skipped paused or waiting for data. |
| 1895 setOfficialPlaybackPosition(currentPlaybackPosition()); |
| 1896 |
| 1880 // 16 - Queue a task to fire a simple event named timeupdate at the element. | 1897 // 16 - Queue a task to fire a simple event named timeupdate at the element. |
| 1881 scheduleTimeupdateEvent(false); | 1898 scheduleTimeupdateEvent(false); |
| 1882 | 1899 |
| 1883 // 17 - Queue a task to fire a simple event named seeked at the element. | 1900 // 17 - Queue a task to fire a simple event named seeked at the element. |
| 1884 scheduleEvent(EventTypeNames::seeked); | 1901 scheduleEvent(EventTypeNames::seeked); |
| 1885 | 1902 |
| 1886 setDisplayMode(Video); | 1903 setDisplayMode(Video); |
| 1887 } | 1904 } |
| 1888 | 1905 |
| 1889 HTMLMediaElement::ReadyState HTMLMediaElement::getReadyState() const { | 1906 HTMLMediaElement::ReadyState HTMLMediaElement::getReadyState() const { |
| 1890 return m_readyState; | 1907 return m_readyState; |
| 1891 } | 1908 } |
| 1892 | 1909 |
| 1893 bool HTMLMediaElement::hasVideo() const { | 1910 bool HTMLMediaElement::hasVideo() const { |
| 1894 return webMediaPlayer() && webMediaPlayer()->hasVideo(); | 1911 return webMediaPlayer() && webMediaPlayer()->hasVideo(); |
| 1895 } | 1912 } |
| 1896 | 1913 |
| 1897 bool HTMLMediaElement::hasAudio() const { | 1914 bool HTMLMediaElement::hasAudio() const { |
| 1898 return webMediaPlayer() && webMediaPlayer()->hasAudio(); | 1915 return webMediaPlayer() && webMediaPlayer()->hasAudio(); |
| 1899 } | 1916 } |
| 1900 | 1917 |
| 1901 bool HTMLMediaElement::seeking() const { | 1918 bool HTMLMediaElement::seeking() const { |
| 1902 return m_seeking; | 1919 return m_seeking; |
| 1903 } | 1920 } |
| 1904 | 1921 |
| 1905 void HTMLMediaElement::refreshCachedTime() const { | 1922 // https://www.w3.org/TR/html51/semantics-embedded-content.html#earliest-possibl
e-position |
| 1906 if (!webMediaPlayer() || m_readyState < kHaveMetadata) | 1923 // The earliest possible position is not explicitly exposed in the API; it |
| 1907 return; | 1924 // corresponds to the start time of the first range in the seekable attribute’s |
| 1925 // TimeRanges object, if any, or the current playback position otherwise. |
| 1926 double HTMLMediaElement::earliestPossiblePosition() const { |
| 1927 TimeRanges* seekableRanges = seekable(); |
| 1928 if (seekableRanges && seekableRanges->length() > 0) |
| 1929 return seekableRanges->start(0, ASSERT_NO_EXCEPTION); |
| 1908 | 1930 |
| 1909 m_cachedTime = webMediaPlayer()->currentTime(); | 1931 return currentPlaybackPosition(); |
| 1910 } | 1932 } |
| 1911 | 1933 |
| 1912 void HTMLMediaElement::invalidateCachedTime() { | 1934 double HTMLMediaElement::currentPlaybackPosition() const { |
| 1913 BLINK_MEDIA_LOG << "invalidateCachedTime(" << (void*)this << ")"; | 1935 // "Official" playback position won't take updates from "current" playback |
| 1914 m_cachedTime = std::numeric_limits<double>::quiet_NaN(); | 1936 // position until m_readyState > kHaveMetadata, but other callers (e.g. |
| 1937 // pauseInternal) may still request currentPlaybackPosition at any time. |
| 1938 // From spec: "Media elements have a current playback position, which must |
| 1939 // initially (i.e., in the absence of media data) be zero seconds." |
| 1940 if (m_readyState == kHaveNothing) |
| 1941 return 0; |
| 1942 |
| 1943 if (webMediaPlayer()) |
| 1944 return webMediaPlayer()->currentTime(); |
| 1945 |
| 1946 if (m_readyState >= kHaveMetadata) { |
| 1947 LOG(WARNING) << __func__ << " readyState = " << m_readyState |
| 1948 << " but no webMeidaPlayer to provide currentPlaybackPosition"; |
| 1949 } |
| 1950 |
| 1951 return 0; |
| 1915 } | 1952 } |
| 1916 | 1953 |
| 1917 // playback state | 1954 double HTMLMediaElement::officialPlaybackPosition() const { |
| 1955 // Hold updates to official playback position while paused or waiting for more |
| 1956 // data. The underlying media player may continue to make small advances in |
| 1957 // currentTime (e.g. as samples in the last rendered audio buffer are played |
| 1958 // played out), but advancing currentTime while paused/waiting sends a mixed |
| 1959 // signal about the state of playback. |
| 1960 bool waitingForData = m_readyState <= kHaveCurrentData; |
| 1961 if (m_officialPlaybackPositionNeedsUpdate && !m_paused && !waitingForData) { |
| 1962 // Internal player position may advance slightly beyond duration because |
| 1963 // many files use imprecise duration. Clamp official position to duration. |
| 1964 double newPosition = std::min(duration(), currentPlaybackPosition()); |
| 1965 setOfficialPlaybackPosition(newPosition); |
| 1966 } |
| 1967 |
| 1968 #if LOG_OFFICIAL_TIME_STATUS |
| 1969 static const double minCachedDeltaForWarning = 0.01; |
| 1970 double delta = |
| 1971 std::abs(m_officialPlaybackPosition - currentPlaybackPosition()); |
| 1972 if (delta > minCachedDeltaForWarning) { |
| 1973 BLINK_MEDIA_LOG << "currentTime(" << (void*)this |
| 1974 << ") - WARNING, cached time is " << delta |
| 1975 << "seconds off of media time when paused/waiting"; |
| 1976 } |
| 1977 #endif |
| 1978 |
| 1979 return m_officialPlaybackPosition; |
| 1980 } |
| 1981 |
| 1982 void HTMLMediaElement::setOfficialPlaybackPosition(double position) const { |
| 1983 #if LOG_OFFICIAL_TIME_STATUS |
| 1984 BLINK_MEDIA_LOG << "setOfficialPlaybackPosition(" << (void*)this |
| 1985 << ") was:" << m_officialPlaybackPosition |
| 1986 << " now:" << position; |
| 1987 #endif |
| 1988 |
| 1989 m_officialPlaybackPosition = position; |
| 1990 |
| 1991 // Once set, official playback position should hold steady until the next |
| 1992 // stable state. We approximate this by using a microtask to mark the |
| 1993 // need for an update after the current (micro)task has completed. When |
| 1994 // needed, the update is applied in the next call to |
| 1995 // officialPlaybackPosition(). |
| 1996 m_officialPlaybackPositionNeedsUpdate = false; |
| 1997 Microtask::enqueueMicrotask( |
| 1998 WTF::bind(&HTMLMediaElement::requireOfficialPlaybackPositionUpdate, |
| 1999 wrapWeakPersistent(this))); |
| 2000 } |
| 2001 |
| 2002 void HTMLMediaElement::requireOfficialPlaybackPositionUpdate() const { |
| 2003 m_officialPlaybackPositionNeedsUpdate = true; |
| 2004 } |
| 2005 |
| 1918 double HTMLMediaElement::currentTime() const { | 2006 double HTMLMediaElement::currentTime() const { |
| 1919 if (m_defaultPlaybackStartPosition) | 2007 if (m_defaultPlaybackStartPosition) |
| 1920 return m_defaultPlaybackStartPosition; | 2008 return m_defaultPlaybackStartPosition; |
| 1921 | 2009 |
| 1922 if (m_readyState == kHaveNothing) | |
| 1923 return 0; | |
| 1924 | |
| 1925 if (m_seeking) { | 2010 if (m_seeking) { |
| 1926 BLINK_MEDIA_LOG << "currentTime(" << (void*)this | 2011 BLINK_MEDIA_LOG << "currentTime(" << (void*)this |
| 1927 << ") - seeking, returning " << m_lastSeekTime; | 2012 << ") - seeking, returning " << m_lastSeekTime; |
| 1928 return m_lastSeekTime; | 2013 return m_lastSeekTime; |
| 1929 } | 2014 } |
| 1930 | 2015 |
| 1931 if (!std::isnan(m_cachedTime) && m_paused) { | 2016 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 } | 2017 } |
| 1947 | 2018 |
| 1948 void HTMLMediaElement::setCurrentTime(double time) { | 2019 void HTMLMediaElement::setCurrentTime(double time) { |
| 1949 // If the media element's readyState is kHaveNothing, then set the default | 2020 // If the media element's readyState is kHaveNothing, then set the default |
| 1950 // playback start position to that time. | 2021 // playback start position to that time. |
| 1951 if (m_readyState == kHaveNothing) { | 2022 if (m_readyState == kHaveNothing) { |
| 1952 m_defaultPlaybackStartPosition = time; | 2023 m_defaultPlaybackStartPosition = time; |
| 1953 return; | 2024 return; |
| 1954 } | 2025 } |
| 1955 | 2026 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1997 | 2068 |
| 1998 double HTMLMediaElement::playbackRate() const { | 2069 double HTMLMediaElement::playbackRate() const { |
| 1999 return m_playbackRate; | 2070 return m_playbackRate; |
| 2000 } | 2071 } |
| 2001 | 2072 |
| 2002 void HTMLMediaElement::setPlaybackRate(double rate) { | 2073 void HTMLMediaElement::setPlaybackRate(double rate) { |
| 2003 BLINK_MEDIA_LOG << "setPlaybackRate(" << (void*)this << ", " << rate << ")"; | 2074 BLINK_MEDIA_LOG << "setPlaybackRate(" << (void*)this << ", " << rate << ")"; |
| 2004 | 2075 |
| 2005 if (m_playbackRate != rate) { | 2076 if (m_playbackRate != rate) { |
| 2006 m_playbackRate = rate; | 2077 m_playbackRate = rate; |
| 2007 invalidateCachedTime(); | |
| 2008 scheduleEvent(EventTypeNames::ratechange); | 2078 scheduleEvent(EventTypeNames::ratechange); |
| 2009 } | 2079 } |
| 2010 | 2080 |
| 2011 updatePlaybackRate(); | 2081 updatePlaybackRate(); |
| 2012 } | 2082 } |
| 2013 | 2083 |
| 2014 HTMLMediaElement::DirectionOfPlayback HTMLMediaElement::getDirectionOfPlayback() | 2084 HTMLMediaElement::DirectionOfPlayback HTMLMediaElement::getDirectionOfPlayback() |
| 2015 const { | 2085 const { |
| 2016 return m_playbackRate >= 0 ? Forward : Backward; | 2086 return m_playbackRate >= 0 ? Forward : Backward; |
| 2017 } | 2087 } |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2204 invokeResourceSelectionAlgorithm(); | 2274 invokeResourceSelectionAlgorithm(); |
| 2205 | 2275 |
| 2206 // Generally "ended" and "looping" are exclusive. Here, the loop attribute | 2276 // 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 | 2277 // is ignored to seek back to start in case loop was set after playback |
| 2208 // ended. See http://crbug.com/364442 | 2278 // ended. See http://crbug.com/364442 |
| 2209 if (endedPlayback(LoopCondition::Ignored)) | 2279 if (endedPlayback(LoopCondition::Ignored)) |
| 2210 seek(0); | 2280 seek(0); |
| 2211 | 2281 |
| 2212 if (m_paused) { | 2282 if (m_paused) { |
| 2213 m_paused = false; | 2283 m_paused = false; |
| 2214 invalidateCachedTime(); | |
| 2215 scheduleEvent(EventTypeNames::play); | 2284 scheduleEvent(EventTypeNames::play); |
| 2216 | 2285 |
| 2217 if (m_readyState <= kHaveCurrentData) | 2286 if (m_readyState <= kHaveCurrentData) |
| 2218 scheduleEvent(EventTypeNames::waiting); | 2287 scheduleEvent(EventTypeNames::waiting); |
| 2219 else if (m_readyState >= kHaveFutureData) | 2288 else if (m_readyState >= kHaveFutureData) |
| 2220 scheduleNotifyPlaying(); | 2289 scheduleNotifyPlaying(); |
| 2221 } else if (m_readyState >= kHaveFutureData) { | 2290 } else if (m_readyState >= kHaveFutureData) { |
| 2222 scheduleResolvePlayPromises(); | 2291 scheduleResolvePlayPromises(); |
| 2223 } | 2292 } |
| 2224 | 2293 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2247 invokeResourceSelectionAlgorithm(); | 2316 invokeResourceSelectionAlgorithm(); |
| 2248 | 2317 |
| 2249 m_autoplayHelper->pauseMethodCalled(); | 2318 m_autoplayHelper->pauseMethodCalled(); |
| 2250 | 2319 |
| 2251 m_autoplaying = false; | 2320 m_autoplaying = false; |
| 2252 | 2321 |
| 2253 if (!m_paused) { | 2322 if (!m_paused) { |
| 2254 m_paused = true; | 2323 m_paused = true; |
| 2255 scheduleTimeupdateEvent(false); | 2324 scheduleTimeupdateEvent(false); |
| 2256 scheduleEvent(EventTypeNames::pause); | 2325 scheduleEvent(EventTypeNames::pause); |
| 2326 |
| 2327 // Force an update to official playback position. Automatic updates from |
| 2328 // currentPlaybackPosition() will be blocked while m_paused = true. This |
| 2329 // blocking is desired while paused, but its good to update it one final |
| 2330 // time to accurately reflect movie time at the moment we paused. |
| 2331 setOfficialPlaybackPosition(currentPlaybackPosition()); |
| 2332 |
| 2257 scheduleRejectPlayPromises(AbortError); | 2333 scheduleRejectPlayPromises(AbortError); |
| 2258 } | 2334 } |
| 2259 | 2335 |
| 2260 updatePlayState(); | 2336 updatePlayState(); |
| 2261 } | 2337 } |
| 2262 | 2338 |
| 2263 void HTMLMediaElement::requestRemotePlayback() { | 2339 void HTMLMediaElement::requestRemotePlayback() { |
| 2264 if (webMediaPlayer()) | 2340 if (webMediaPlayer()) |
| 2265 webMediaPlayer()->requestRemotePlayback(); | 2341 webMediaPlayer()->requestRemotePlayback(); |
| 2266 } | 2342 } |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2431 if (!playbackRate()) | 2507 if (!playbackRate()) |
| 2432 return; | 2508 return; |
| 2433 | 2509 |
| 2434 if (!m_paused && mediaControls()) | 2510 if (!m_paused && mediaControls()) |
| 2435 mediaControls()->playbackProgressed(); | 2511 mediaControls()->playbackProgressed(); |
| 2436 | 2512 |
| 2437 cueTimeline().updateActiveCues(currentTime()); | 2513 cueTimeline().updateActiveCues(currentTime()); |
| 2438 } | 2514 } |
| 2439 | 2515 |
| 2440 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent) { | 2516 void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent) { |
| 2517 // Per spec, consult current playback position to check for changing time. |
| 2518 double mediaTime = currentPlaybackPosition(); |
| 2441 double now = WTF::currentTime(); | 2519 double now = WTF::currentTime(); |
| 2442 double movieTime = currentTime(); | |
| 2443 | 2520 |
| 2444 bool haveNotRecentlyFiredTimeupdate = | 2521 bool haveNotRecentlyFiredTimeupdate = |
| 2445 (now - m_lastTimeUpdateEventWallTime) >= maxTimeupdateEventFrequency; | 2522 (now - m_lastTimeUpdateEventWallTime) >= maxTimeupdateEventFrequency; |
| 2446 bool movieTimeHasProgressed = movieTime != m_lastTimeUpdateEventMovieTime; | 2523 bool mediaTimeHasProgressed = mediaTime != m_lastTimeUpdateEventMediaTime; |
| 2447 | 2524 |
| 2448 // Non-periodic timeupdate events must always fire as mandated by the spec, | 2525 // Non-periodic timeupdate events must always fire as mandated by the spec, |
| 2449 // otherwise we shouldn't fire duplicate periodic timeupdate events when the | 2526 // otherwise we shouldn't fire duplicate periodic timeupdate events when the |
| 2450 // movie time hasn't changed. | 2527 // movie time hasn't changed. |
| 2451 if (!periodicEvent || | 2528 if (!periodicEvent || |
| 2452 (haveNotRecentlyFiredTimeupdate && movieTimeHasProgressed)) { | 2529 (haveNotRecentlyFiredTimeupdate && mediaTimeHasProgressed)) { |
| 2453 scheduleEvent(EventTypeNames::timeupdate); | 2530 scheduleEvent(EventTypeNames::timeupdate); |
| 2454 m_lastTimeUpdateEventWallTime = now; | 2531 m_lastTimeUpdateEventWallTime = now; |
| 2455 m_lastTimeUpdateEventMovieTime = movieTime; | 2532 m_lastTimeUpdateEventMediaTime = mediaTime; |
| 2456 } | 2533 } |
| 2457 } | 2534 } |
| 2458 | 2535 |
| 2459 void HTMLMediaElement::togglePlayState() { | 2536 void HTMLMediaElement::togglePlayState() { |
| 2460 if (paused()) | 2537 if (paused()) |
| 2461 play(); | 2538 play(); |
| 2462 else | 2539 else |
| 2463 pause(); | 2540 pause(); |
| 2464 } | 2541 } |
| 2465 | 2542 |
| (...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2977 BLINK_MEDIA_LOG << "sourceWasRemoved(" << (void*)this | 3054 BLINK_MEDIA_LOG << "sourceWasRemoved(" << (void*)this |
| 2978 << ") - m_currentSourceNode set to 0"; | 3055 << ") - m_currentSourceNode set to 0"; |
| 2979 } | 3056 } |
| 2980 } | 3057 } |
| 2981 | 3058 |
| 2982 void HTMLMediaElement::timeChanged() { | 3059 void HTMLMediaElement::timeChanged() { |
| 2983 BLINK_MEDIA_LOG << "timeChanged(" << (void*)this << ")"; | 3060 BLINK_MEDIA_LOG << "timeChanged(" << (void*)this << ")"; |
| 2984 | 3061 |
| 2985 cueTimeline().updateActiveCues(currentTime()); | 3062 cueTimeline().updateActiveCues(currentTime()); |
| 2986 | 3063 |
| 2987 invalidateCachedTime(); | |
| 2988 | |
| 2989 // 4.8.10.9 steps 12-14. Needed if no ReadyState change is associated with the | 3064 // 4.8.10.9 steps 12-14. Needed if no ReadyState change is associated with the |
| 2990 // seek. | 3065 // seek. |
| 2991 if (m_seeking && m_readyState >= kHaveCurrentData && | 3066 if (m_seeking && m_readyState >= kHaveCurrentData && |
| 2992 !webMediaPlayer()->seeking()) | 3067 !webMediaPlayer()->seeking()) |
| 2993 finishSeek(); | 3068 finishSeek(); |
| 2994 | 3069 |
| 2995 // Always call scheduleTimeupdateEvent when the media engine reports a time | 3070 // Always call scheduleTimeupdateEvent when the media engine reports a time |
| 2996 // discontinuity, it will only queue a 'timeupdate' event if we haven't | 3071 // discontinuity, it will only queue a 'timeupdate' event if we haven't |
| 2997 // already posted one at the current movie time. | 3072 // already posted one at the current movie time. |
| 2998 scheduleTimeupdateEvent(false); | 3073 scheduleTimeupdateEvent(false); |
| 2999 | 3074 |
| 3000 double now = currentTime(); | 3075 double now = currentPlaybackPosition(); |
| 3001 double dur = duration(); | 3076 double dur = duration(); |
| 3002 | 3077 |
| 3003 // When the current playback position reaches the end of the media resource | 3078 // 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 | 3079 // when the direction of playback is forwards, then the user agent must follow |
| 3005 // these steps: | 3080 // these steps: |
| 3006 if (!std::isnan(dur) && dur && now >= dur && | 3081 if (!std::isnan(dur) && dur && now >= dur && |
| 3007 getDirectionOfPlayback() == Forward) { | 3082 getDirectionOfPlayback() == Forward) { |
| 3008 // If the media element has a loop attribute specified | 3083 // If the media element has a loop attribute specified |
| 3009 if (loop()) { | 3084 if (loop()) { |
| 3010 // then seek to the earliest possible position of the media resource and | 3085 // then seek to the earliest possible position of the media resource and |
| 3011 // abort these steps. | 3086 // abort these steps. |
| 3012 seek(0); | 3087 seek(earliestPossiblePosition()); |
| 3013 } else { | 3088 } else { |
| 3014 // If the media element has still ended playback, and the direction of | 3089 // If the media element has still ended playback, and the direction of |
| 3015 // playback is still forwards, and paused is false, | 3090 // playback is still forwards, and paused is false, |
| 3016 if (!m_paused) { | 3091 if (!m_paused) { |
| 3017 // changes paused to true and fires a simple event named pause at the | 3092 // changes paused to true and fires a simple event named pause at the |
| 3018 // media element. | 3093 // media element. |
| 3019 m_paused = true; | 3094 m_paused = true; |
| 3020 scheduleEvent(EventTypeNames::pause); | 3095 scheduleEvent(EventTypeNames::pause); |
| 3021 scheduleRejectPlayPromises(AbortError); | 3096 scheduleRejectPlayPromises(AbortError); |
| 3022 } | 3097 } |
| 3023 // Queue a task to fire a simple event named ended at the media element. | 3098 // Queue a task to fire a simple event named ended at the media element. |
| 3024 scheduleEvent(EventTypeNames::ended); | 3099 scheduleEvent(EventTypeNames::ended); |
| 3025 } | 3100 } |
| 3026 } | 3101 } |
| 3027 updatePlayState(); | 3102 updatePlayState(); |
| 3028 } | 3103 } |
| 3029 | 3104 |
| 3030 void HTMLMediaElement::durationChanged() { | 3105 void HTMLMediaElement::durationChanged() { |
| 3031 BLINK_MEDIA_LOG << "durationChanged(" << (void*)this << ")"; | 3106 BLINK_MEDIA_LOG << "durationChanged(" << (void*)this << ")"; |
| 3032 // FIXME: Change WebMediaPlayer to convey the currentTime | 3107 // If the duration is changed such that the *current playback position* ends |
| 3033 // when the duration change occured. The current WebMediaPlayer | 3108 // up being greater than the time of the end of the media resource, then the |
| 3034 // implementations always clamp currentTime() to duration() | 3109 // user agent must also seek to the time of the end of the media resource. |
| 3035 // so the requestSeek condition here is always false. | 3110 durationChanged(duration(), currentPlaybackPosition() > duration()); |
| 3036 durationChanged(duration(), currentTime() > duration()); | |
| 3037 } | 3111 } |
| 3038 | 3112 |
| 3039 void HTMLMediaElement::durationChanged(double duration, bool requestSeek) { | 3113 void HTMLMediaElement::durationChanged(double duration, bool requestSeek) { |
| 3040 BLINK_MEDIA_LOG << "durationChanged(" << (void*)this << ", " << duration | 3114 BLINK_MEDIA_LOG << "durationChanged(" << (void*)this << ", " << duration |
| 3041 << ", " << boolString(requestSeek) << ")"; | 3115 << ", " << boolString(requestSeek) << ")"; |
| 3042 | 3116 |
| 3043 // Abort if duration unchanged. | 3117 // Abort if duration unchanged. |
| 3044 if (m_duration == duration) | 3118 if (m_duration == duration) |
| 3045 return; | 3119 return; |
| 3046 | 3120 |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3189 // 4.8.10.8 Playing the media resource | 3263 // 4.8.10.8 Playing the media resource |
| 3190 | 3264 |
| 3191 // A media element is said to have ended playback when the element's | 3265 // A media element is said to have ended playback when the element's |
| 3192 // readyState attribute is HAVE_METADATA or greater, | 3266 // readyState attribute is HAVE_METADATA or greater, |
| 3193 if (m_readyState < kHaveMetadata) | 3267 if (m_readyState < kHaveMetadata) |
| 3194 return false; | 3268 return false; |
| 3195 | 3269 |
| 3196 // and the current playback position is the end of the media resource and the | 3270 // 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 | 3271 // direction of playback is forwards, Either the media element does not have a |
| 3198 // loop attribute specified, | 3272 // loop attribute specified, |
| 3199 double now = currentTime(); | 3273 double now = currentPlaybackPosition(); |
| 3200 if (getDirectionOfPlayback() == Forward) | 3274 if (getDirectionOfPlayback() == Forward) |
| 3201 return dur > 0 && now >= dur && | 3275 return dur > 0 && now >= dur && |
| 3202 (loopCondition == LoopCondition::Ignored || !loop()); | 3276 (loopCondition == LoopCondition::Ignored || !loop()); |
| 3203 | 3277 |
| 3204 // or the current playback position is the earliest possible position and the | 3278 // or the current playback position is the earliest possible position and the |
| 3205 // direction of playback is backwards | 3279 // direction of playback is backwards |
| 3206 DCHECK_EQ(getDirectionOfPlayback(), Backward); | 3280 DCHECK_EQ(getDirectionOfPlayback(), Backward); |
| 3207 return now <= 0; | 3281 return now <= earliestPossiblePosition(); |
| 3208 } | 3282 } |
| 3209 | 3283 |
| 3210 bool HTMLMediaElement::stoppedDueToErrors() const { | 3284 bool HTMLMediaElement::stoppedDueToErrors() const { |
| 3211 if (m_readyState >= kHaveMetadata && m_error) { | 3285 if (m_readyState >= kHaveMetadata && m_error) { |
| 3212 TimeRanges* seekableRanges = seekable(); | 3286 TimeRanges* seekableRanges = seekable(); |
| 3213 if (!seekableRanges->contain(currentTime())) | 3287 if (!seekableRanges->contain(currentTime())) |
| 3214 return true; | 3288 return true; |
| 3215 } | 3289 } |
| 3216 | 3290 |
| 3217 return false; | 3291 return false; |
| 3218 } | 3292 } |
| 3219 | 3293 |
| 3220 void HTMLMediaElement::updatePlayState() { | 3294 void HTMLMediaElement::updatePlayState() { |
| 3221 bool isPlaying = webMediaPlayer() && !webMediaPlayer()->paused(); | 3295 bool isPlaying = webMediaPlayer() && !webMediaPlayer()->paused(); |
| 3222 bool shouldBePlaying = potentiallyPlaying(); | 3296 bool shouldBePlaying = potentiallyPlaying(); |
| 3223 | 3297 |
| 3224 BLINK_MEDIA_LOG << "updatePlayState(" << (void*)this | 3298 BLINK_MEDIA_LOG << "updatePlayState(" << (void*)this |
| 3225 << ") - shouldBePlaying = " << boolString(shouldBePlaying) | 3299 << ") - shouldBePlaying = " << boolString(shouldBePlaying) |
| 3226 << ", isPlaying = " << boolString(isPlaying); | 3300 << ", isPlaying = " << boolString(isPlaying); |
| 3227 | 3301 |
| 3228 if (shouldBePlaying) { | 3302 if (shouldBePlaying) { |
| 3229 setDisplayMode(Video); | 3303 setDisplayMode(Video); |
| 3230 invalidateCachedTime(); | |
| 3231 | 3304 |
| 3232 if (!isPlaying) { | 3305 if (!isPlaying) { |
| 3233 // Set rate, muted before calling play in case they were set before the | 3306 // 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 | 3307 // media engine was setup. The media engine should just stash the rate |
| 3235 // and muted values since it isn't already playing. | 3308 // and muted values since it isn't already playing. |
| 3236 webMediaPlayer()->setRate(playbackRate()); | 3309 webMediaPlayer()->setRate(playbackRate()); |
| 3237 updateVolume(); | 3310 updateVolume(); |
| 3238 webMediaPlayer()->play(); | 3311 webMediaPlayer()->play(); |
| 3239 m_autoplayHelper->playbackStarted(); | 3312 m_autoplayHelper->playbackStarted(); |
| 3240 } | 3313 } |
| 3241 | 3314 |
| 3242 if (mediaControls()) | 3315 if (mediaControls()) |
| 3243 mediaControls()->playbackStarted(); | 3316 mediaControls()->playbackStarted(); |
| 3244 startPlaybackProgressTimer(); | 3317 startPlaybackProgressTimer(); |
| 3245 m_playing = true; | 3318 m_playing = true; |
| 3246 | 3319 |
| 3247 } else { // Should not be playing right now | 3320 } else { // Should not be playing right now |
| 3248 if (isPlaying) { | 3321 if (isPlaying) { |
| 3249 webMediaPlayer()->pause(); | 3322 webMediaPlayer()->pause(); |
| 3250 m_autoplayHelper->playbackStopped(); | 3323 m_autoplayHelper->playbackStopped(); |
| 3251 } | 3324 } |
| 3252 | 3325 |
| 3253 refreshCachedTime(); | |
| 3254 | |
| 3255 m_playbackProgressTimer.stop(); | 3326 m_playbackProgressTimer.stop(); |
| 3256 m_playing = false; | 3327 m_playing = false; |
| 3257 double time = currentTime(); | 3328 double time = currentTime(); |
| 3258 if (time > m_lastSeekTime) | 3329 if (time > m_lastSeekTime) |
| 3259 addPlayedRange(m_lastSeekTime, time); | 3330 addPlayedRange(m_lastSeekTime, time); |
| 3260 | 3331 |
| 3261 if (mediaControls()) | 3332 if (mediaControls()) |
| 3262 mediaControls()->playbackStopped(); | 3333 mediaControls()->playbackStopped(); |
| 3263 } | 3334 } |
| 3264 | 3335 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3315 cancelPendingEventsAndCallbacks(); | 3386 cancelPendingEventsAndCallbacks(); |
| 3316 m_asyncEventQueue->close(); | 3387 m_asyncEventQueue->close(); |
| 3317 | 3388 |
| 3318 // Clear everything in the Media Element | 3389 // Clear everything in the Media Element |
| 3319 clearMediaPlayer(); | 3390 clearMediaPlayer(); |
| 3320 m_readyState = kHaveNothing; | 3391 m_readyState = kHaveNothing; |
| 3321 m_readyStateMaximum = kHaveNothing; | 3392 m_readyStateMaximum = kHaveNothing; |
| 3322 setNetworkState(kNetworkEmpty); | 3393 setNetworkState(kNetworkEmpty); |
| 3323 setShouldDelayLoadEvent(false); | 3394 setShouldDelayLoadEvent(false); |
| 3324 m_currentSourceNode = nullptr; | 3395 m_currentSourceNode = nullptr; |
| 3325 invalidateCachedTime(); | 3396 m_officialPlaybackPosition = 0; |
| 3397 m_officialPlaybackPositionNeedsUpdate = true; |
| 3326 cueTimeline().updateActiveCues(0); | 3398 cueTimeline().updateActiveCues(0); |
| 3327 m_playing = false; | 3399 m_playing = false; |
| 3328 m_paused = true; | 3400 m_paused = true; |
| 3329 m_seeking = false; | 3401 m_seeking = false; |
| 3330 | 3402 |
| 3331 if (layoutObject()) | 3403 if (layoutObject()) |
| 3332 layoutObject()->updateFromElement(); | 3404 layoutObject()->updateFromElement(); |
| 3333 | 3405 |
| 3334 stopPeriodicTimers(); | 3406 stopPeriodicTimers(); |
| 3335 | 3407 |
| (...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3962 ("Media.Controls.Show.Audio", MediaControlsShowMax)); | 4034 ("Media.Controls.Show.Audio", MediaControlsShowMax)); |
| 3963 return histogram; | 4035 return histogram; |
| 3964 } | 4036 } |
| 3965 | 4037 |
| 3966 void HTMLMediaElement::onVisibilityChangedForAutoplay(bool isVisible) { | 4038 void HTMLMediaElement::onVisibilityChangedForAutoplay(bool isVisible) { |
| 3967 if (!isVisible) | 4039 if (!isVisible) |
| 3968 return; | 4040 return; |
| 3969 | 4041 |
| 3970 if (shouldAutoplay()) { | 4042 if (shouldAutoplay()) { |
| 3971 m_paused = false; | 4043 m_paused = false; |
| 3972 invalidateCachedTime(); | |
| 3973 scheduleEvent(EventTypeNames::play); | 4044 scheduleEvent(EventTypeNames::play); |
| 3974 scheduleNotifyPlaying(); | 4045 scheduleNotifyPlaying(); |
| 3975 m_autoplaying = false; | 4046 m_autoplaying = false; |
| 3976 | 4047 |
| 3977 updatePlayState(); | 4048 updatePlayState(); |
| 3978 } | 4049 } |
| 3979 | 4050 |
| 3980 // TODO(zqzhang): There's still flaky leak if onVisibilityChangedForAutoplay() | 4051 // TODO(zqzhang): There's still flaky leak if onVisibilityChangedForAutoplay() |
| 3981 // is never called. The leak comes from either ElementVisibilityObserver or | 4052 // is never called. The leak comes from either ElementVisibilityObserver or |
| 3982 // IntersectionObserver. Should keep an eye on it. See | 4053 // IntersectionObserver. Should keep an eye on it. See |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4087 | 4158 |
| 4088 IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect() | 4159 IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect() |
| 4089 const { | 4160 const { |
| 4090 IntRect result; | 4161 IntRect result; |
| 4091 if (LayoutObject* object = m_element->layoutObject()) | 4162 if (LayoutObject* object = m_element->layoutObject()) |
| 4092 result = object->absoluteBoundingBoxRect(); | 4163 result = object->absoluteBoundingBoxRect(); |
| 4093 return result; | 4164 return result; |
| 4094 } | 4165 } |
| 4095 | 4166 |
| 4096 } // namespace blink | 4167 } // namespace blink |
| OLD | NEW |