diff options
Diffstat (limited to 'WebCore/html/HTMLMediaElement.cpp')
-rw-r--r-- | WebCore/html/HTMLMediaElement.cpp | 141 |
1 files changed, 96 insertions, 45 deletions
diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp index 5b75dde..7c061d0 100644 --- a/WebCore/html/HTMLMediaElement.cpp +++ b/WebCore/html/HTMLMediaElement.cpp @@ -82,7 +82,7 @@ namespace WebCore { #if !LOG_DISABLED static String urlForLogging(const String& url) { - static unsigned maximumURLLengthForLogging = 128; + static const unsigned maximumURLLengthForLogging = 128; if (url.length() < maximumURLLengthForLogging) return url; @@ -101,6 +101,14 @@ static const char *boolString(bool val) #define LOG_MEDIA_EVENTS 0 #endif +#ifndef LOG_CACHED_TIME_WARNINGS +// Default to not logging warnings about excessive drift in the cached media time because it adds a +// fair amount of overhead and logging. +#define LOG_CACHED_TIME_WARNINGS 0 +#endif + +static const float invalidMediaTime = -1; + using namespace HTMLNames; HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* document) @@ -134,6 +142,9 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum , m_preload(MediaPlayer::Auto) , m_displayMode(Unknown) , m_processingMediaPlayerCallback(0) + , m_cachedTime(invalidMediaTime) + , m_cachedTimeWallClockUpdateTime(0) + , m_minimumWallClockTimeToCacheMediaTime(0) , m_playing(false) , m_isWaitingUntilMediaCanStart(false) , m_shouldDelayLoadEvent(false) @@ -430,42 +441,6 @@ void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*) loadInternal(); } -static String serializeTimeOffset(float time) -{ - String timeString = String::number(time); - // FIXME serialize time offset values properly (format not specified yet) - timeString.append("s"); - return timeString; -} - -static float parseTimeOffset(const String& timeString, bool* ok = 0) -{ - const UChar* characters = timeString.characters(); - unsigned length = timeString.length(); - - if (length && characters[length - 1] == 's') - length--; - - // FIXME parse time offset values (format not specified yet) - float val = charactersToFloat(characters, length, ok); - return val; -} - -float HTMLMediaElement::getTimeOffsetAttribute(const QualifiedName& name, float valueOnError) const -{ - bool ok; - String timeString = getAttribute(name); - float result = parseTimeOffset(timeString, &ok); - if (ok) - return result; - return valueOnError; -} - -void HTMLMediaElement::setTimeOffsetAttribute(const QualifiedName& name, float value) -{ - setAttribute(name, serializeTimeOffset(value)); -} - PassRefPtr<MediaError> HTMLMediaElement::error() const { return m_error; @@ -562,6 +537,7 @@ void HTMLMediaElement::prepareForLoad() m_networkState = NETWORK_EMPTY; m_readyState = HAVE_NOTHING; m_readyStateMaximum = HAVE_NOTHING; + refreshCachedTime(); m_paused = true; m_seeking = false; scheduleEvent(eventNames().emptiedEvent); @@ -1100,6 +1076,7 @@ void HTMLMediaElement::seek(float time, ExceptionCode& ec) } // Get the current time before setting m_seeking, m_lastSeekTime is returned once it is set. + refreshCachedTime(); float now = currentTime(); // 2 - If the element's seeking IDL attribute is true, then another instance of this algorithm is @@ -1204,14 +1181,80 @@ bool HTMLMediaElement::seeking() const return m_seeking; } +void HTMLMediaElement::refreshCachedTime() const +{ + m_cachedTime = m_player->currentTime(); + m_cachedTimeWallClockUpdateTime = WTF::currentTime(); +} + +void HTMLMediaElement::invalidateCachedTime() +{ + LOG(Media, "HTMLMediaElement::invalidateCachedTime"); + + // Don't try to cache movie time when playback first starts as the time reported by the engine + // sometimes fluctuates for a short amount of time, so the cached time will be off if we take it + // too early. + static const double minimumTimePlayingBeforeCacheSnapshot = 0.5; + + m_minimumWallClockTimeToCacheMediaTime = WTF::currentTime() + minimumTimePlayingBeforeCacheSnapshot; + m_cachedTime = invalidMediaTime; +} + // playback state float HTMLMediaElement::currentTime() const { +#if LOG_CACHED_TIME_WARNINGS + static const double minCachedDeltaForWarning = 0.01; +#endif + if (!m_player) return 0; - if (m_seeking) + + if (m_seeking) { + LOG(Media, "HTMLMediaElement::currentTime - seeking, returning %f", m_lastSeekTime); return m_lastSeekTime; - return m_player->currentTime(); + } + + if (m_cachedTime != invalidMediaTime && m_paused) { +#if LOG_CACHED_TIME_WARNINGS + float delta = m_cachedTime - m_player->currentTime(); + if (delta > minCachedDeltaForWarning) + LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when paused", delta); +#endif + return m_cachedTime; + } + + // Is it too soon use a cached time? + double now = WTF::currentTime(); + double maximumDurationToCacheMediaTime = m_player->maximumDurationToCacheMediaTime(); + + if (maximumDurationToCacheMediaTime && m_cachedTime != invalidMediaTime && !m_paused && now > m_minimumWallClockTimeToCacheMediaTime) { + double wallClockDelta = now - m_cachedTimeWallClockUpdateTime; + + // Not too soon, use the cached time only if it hasn't expired. + if (wallClockDelta < maximumDurationToCacheMediaTime) { + float adjustedCacheTime = static_cast<float>(m_cachedTime + (m_playbackRate * wallClockDelta)); + +#if LOG_CACHED_TIME_WARNINGS + float delta = adjustedCacheTime - m_player->currentTime(); + if (delta > minCachedDeltaForWarning) + LOG(Media, "HTMLMediaElement::currentTime - WARNING, cached time is %f seconds off of media time when playing", delta); +#endif + return adjustedCacheTime; + } + } + +#if LOG_CACHED_TIME_WARNINGS + if (maximumDurationToCacheMediaTime && now > m_minimumWallClockTimeToCacheMediaTime && m_cachedTime != invalidMediaTime) { + double wallClockDelta = now - m_cachedTimeWallClockUpdateTime; + float delta = m_cachedTime + (m_playbackRate * wallClockDelta) - m_player->currentTime(); + LOG(Media, "HTMLMediaElement::currentTime - cached time was %f seconds off of media time when it expired", delta); + } +#endif + + refreshCachedTime(); + + return m_cachedTime; } void HTMLMediaElement::setCurrentTime(float time, ExceptionCode& ec) @@ -1515,7 +1558,7 @@ void HTMLMediaElement::beginScrubbing() void HTMLMediaElement::endScrubbing() { - LOG(Media, "HTMLMediaElement::beginScrubbing - m_pausedInternal is %s", boolString(m_pausedInternal)); + LOG(Media, "HTMLMediaElement::endScrubbing - m_pausedInternal is %s", boolString(m_pausedInternal)); if (m_pausedInternal) setPausedInternal(false); @@ -1557,7 +1600,7 @@ void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent) // Some media engines make multiple "time changed" callbacks at the same time, but we only want one // event at a given time so filter here - float movieTime = m_player ? m_player->currentTime() : 0; + float movieTime = currentTime(); if (movieTime != m_lastTimeUpdateEventMovieTime) { scheduleEvent(eventNames().timeupdateEvent); m_lastTimeUpdateEventWallTime = now; @@ -1779,15 +1822,17 @@ void HTMLMediaElement::mediaPlayerTimeChanged(MediaPlayer*) beginProcessingMediaPlayerCallback(); - // Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity, - // it will only queue a 'timeupdate' event if we haven't already posted one at the current - // movie time. - scheduleTimeupdateEvent(false); + invalidateCachedTime(); // 4.8.10.9 step 14 & 15. Needed if no ReadyState change is associated with the seek. if (m_seeking && m_readyState >= HAVE_CURRENT_DATA) finishSeek(); + // Always call scheduleTimeupdateEvent when the media engine reports a time discontinuity, + // it will only queue a 'timeupdate' event if we haven't already posted one at the current + // movie time. + scheduleTimeupdateEvent(false); + float now = currentTime(); float dur = duration(); if (!isnan(dur) && dur && now >= dur) { @@ -1846,6 +1891,9 @@ void HTMLMediaElement::mediaPlayerRateChanged(MediaPlayer*) LOG(Media, "HTMLMediaElement::mediaPlayerRateChanged"); beginProcessingMediaPlayerCallback(); + + invalidateCachedTime(); + // Stash the rate in case the one we tried to set isn't what the engine is // using (eg. it can't handle the rate we set) m_playbackRate = m_player->rate(); @@ -2042,6 +2090,7 @@ void HTMLMediaElement::updatePlayState() if (m_pausedInternal) { if (!m_player->paused()) m_player->pause(); + refreshCachedTime(); m_playbackProgressTimer.stop(); return; } @@ -2054,6 +2103,7 @@ void HTMLMediaElement::updatePlayState() if (shouldBePlaying) { setDisplayMode(Video); + invalidateCachedTime(); if (playerPaused) { // Set rate before calling play in case the rate was set before the media engine was setup. @@ -2068,6 +2118,7 @@ void HTMLMediaElement::updatePlayState() } else { // Should not be playing right now if (!playerPaused) m_player->pause(); + refreshCachedTime(); m_playbackProgressTimer.stop(); m_playing = false; |