summaryrefslogtreecommitdiffstats
path: root/WebCore/html/HTMLMediaElement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/html/HTMLMediaElement.cpp')
-rw-r--r--WebCore/html/HTMLMediaElement.cpp141
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;