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