[SCM] WebKit Debian packaging branch, debian/experimental, updated. upstream/1.3.3-9427-gc2be6fc

eric.carlson at apple.com eric.carlson at apple.com
Wed Dec 22 15:44:31 UTC 2010


The following commit has been merged in the debian/experimental branch:
commit 31801db0cb898608a994f4bd4ba4a8d281bfef9c
Author: eric.carlson at apple.com <eric.carlson at apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Nov 11 16:08:15 2010 +0000

    2010-11-11  Eric Carlson  <eric.carlson at apple.com>
    
            Reviewed by Antti Koivisto.
    
            Lots of time spent in MediaPlayerPrivate::currentTime() when playing multiple videos.
            https://bugs.webkit.org/show_bug.cgi?id=49009
    
            Make it possible for HTMLMediaElement to cache the movie time and report 'currentTime'
            as [cached time + elapsed wall time]. The media engine returns the maximum duration it
            is safe to calculate time before resampling the actual movie time with the new
            maximumDurationToCacheMovieTime method. Because this may be different for different media
            engines the default return value is 0, making it an opt-in feature.
    
            No new tests were added because the existing tests already check currentTime, and because
            it is only possible to look for drift between the calculated and actual media time by
            calculating the time AND getting the actual media time - which the defeats the purpose of
            the change. Building with LOG_CACHED_TIME_WARNINGS defined enables code that does both
            and logs warnings when the delta between calculated and observed is greater than 0.01.
    
            * html/HTMLMediaElement.cpp:
            (WebCore::HTMLMediaElement::HTMLMediaElement): Initialize new member variables.
            (WebCore::HTMLMediaElement::prepareForLoad): Force a time resync before setting m_paused.
            (WebCore::HTMLMediaElement::seek): Force a time resync before getting the current time before
            seeking so there is no drift.
            (WebCore::HTMLMediaElement::refreshCachedTime): New, update the cached movie time and the
            wall clock time it was recorded.
            (WebCore::HTMLMediaElement::invalidateCachedTime): New, flag the cached time as invalid.
            (WebCore::HTMLMediaElement::currentTime): Use a cached movie time for as long as the media
            engine says it is safe. Lots of optional logging can be enabled to help ports fine tune
            the maximum cache interval.
            (WebCore::HTMLMediaElement::ended): Force a time resync before setting m_paused.
            (WebCore::HTMLMediaElement::endScrubbing): Fix a typo in the logging.
            (WebCore::HTMLMediaElement::scheduleTimeupdateEvent): Call currentTime() instead of calling
            MediaPlayer so we use the cached time as much as it possible.
            (WebCore::HTMLMediaElement::mediaPlayerTimeChanged): Invalidate cached time because the engine
            seeked.
            (WebCore::HTMLMediaElement::mediaPlayerRateChanged): Ditto.
            (WebCore::HTMLMediaElement::updatePlayState): Invalidate cached time before changing m_paused.
            * html/HTMLMediaElement.h:
    
            * platform/graphics/MediaPlayer.cpp:
            (WebCore::MediaPlayer::maximumDurationToCacheMovieTime): New.
            * platform/graphics/MediaPlayer.h:
            * platform/graphics/MediaPlayerPrivate.h:
            (WebCore::MediaPlayerPrivateInterface::maximumDurationToCacheMovieTime): New.
    
            * platform/graphics/mac/MediaPlayerPrivateQTKit.h:
            (WebCore::MediaPlayerPrivate::maximumDurationToCacheMovieTime): New, say it is safe to cache
            time for five seconds (based on lots of experimenting with LOG_CACHED_TIME_WARNINGS enabled).
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@71824 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 0633b2e..35c84da 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,53 @@
+2010-11-11  Eric Carlson  <eric.carlson at apple.com>
+
+        Reviewed by Antti Koivisto.
+
+        Lots of time spent in MediaPlayerPrivate::currentTime() when playing multiple videos.
+        https://bugs.webkit.org/show_bug.cgi?id=49009
+
+        Make it possible for HTMLMediaElement to cache the movie time and report 'currentTime'
+        as [cached time + elapsed wall time]. The media engine returns the maximum duration it 
+        is safe to calculate time before resampling the actual movie time with the new
+        maximumDurationToCacheMovieTime method. Because this may be different for different media
+        engines the default return value is 0, making it an opt-in feature.
+
+        No new tests were added because the existing tests already check currentTime, and because
+        it is only possible to look for drift between the calculated and actual media time by 
+        calculating the time AND getting the actual media time - which the defeats the purpose of
+        the change. Building with LOG_CACHED_TIME_WARNINGS defined enables code that does both
+        and logs warnings when the delta between calculated and observed is greater than 0.01.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::HTMLMediaElement): Initialize new member variables.
+        (WebCore::HTMLMediaElement::prepareForLoad): Force a time resync before setting m_paused.
+        (WebCore::HTMLMediaElement::seek): Force a time resync before getting the current time before
+        seeking so there is no drift.
+        (WebCore::HTMLMediaElement::refreshCachedTime): New, update the cached movie time and the
+        wall clock time it was recorded.
+        (WebCore::HTMLMediaElement::invalidateCachedTime): New, flag the cached time as invalid.
+        (WebCore::HTMLMediaElement::currentTime): Use a cached movie time for as long as the media
+        engine says it is safe. Lots of optional logging can be enabled to help ports fine tune
+        the maximum cache interval.
+        (WebCore::HTMLMediaElement::ended): Force a time resync before setting m_paused.
+        (WebCore::HTMLMediaElement::endScrubbing): Fix a typo in the logging.
+        (WebCore::HTMLMediaElement::scheduleTimeupdateEvent): Call currentTime() instead of calling
+        MediaPlayer so we use the cached time as much as it possible.
+        (WebCore::HTMLMediaElement::mediaPlayerTimeChanged): Invalidate cached time because the engine
+        seeked.
+        (WebCore::HTMLMediaElement::mediaPlayerRateChanged): Ditto.
+        (WebCore::HTMLMediaElement::updatePlayState): Invalidate cached time before changing m_paused.
+        * html/HTMLMediaElement.h:
+
+        * platform/graphics/MediaPlayer.cpp:
+        (WebCore::MediaPlayer::maximumDurationToCacheMovieTime): New.
+        * platform/graphics/MediaPlayer.h:
+        * platform/graphics/MediaPlayerPrivate.h:
+        (WebCore::MediaPlayerPrivateInterface::maximumDurationToCacheMovieTime): New.
+
+        * platform/graphics/mac/MediaPlayerPrivateQTKit.h:
+        (WebCore::MediaPlayerPrivate::maximumDurationToCacheMovieTime): New, say it is safe to cache
+        time for five seconds (based on lots of experimenting with LOG_CACHED_TIME_WARNINGS enabled).
+
 2010-11-11  Adam Roben  <aroben at apple.com>
 
         Windows build fix after r71816
diff --git a/WebCore/html/HTMLMediaElement.cpp b/WebCore/html/HTMLMediaElement.cpp
index 30bd31d..fc3b31f 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)
@@ -562,6 +573,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);
@@ -1094,6 +1106,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
@@ -1198,14 +1211,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 float 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 = 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)
@@ -1360,6 +1439,7 @@ void HTMLMediaElement::playInternal()
     setPlaybackRate(defaultPlaybackRate());
     
     if (m_paused) {
+        invalidateCachedTime();
         m_paused = false;
         scheduleEvent(eventNames().playEvent);
 
@@ -1395,6 +1475,7 @@ void HTMLMediaElement::pauseInternal()
     m_autoplaying = false;
     
     if (!m_paused) {
+        refreshCachedTime();
         m_paused = true;
         scheduleTimeupdateEvent(false);
         scheduleEvent(eventNames().pauseEvent);
@@ -1509,7 +1590,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);
@@ -1551,7 +1632,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;
@@ -1773,15 +1854,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) {
@@ -1840,6 +1923,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();
@@ -2034,6 +2120,7 @@ void HTMLMediaElement::updatePlayState()
         return;
 
     if (m_pausedInternal) {
+        refreshCachedTime();
         if (!m_player->paused())
             m_player->pause();
         m_playbackProgressTimer.stop();
@@ -2048,6 +2135,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.
@@ -2060,6 +2148,7 @@ void HTMLMediaElement::updatePlayState()
         m_playing = true;
 
     } else { // Should not be playing right now
+        refreshCachedTime();
         if (!playerPaused)
             m_player->pause();
 
diff --git a/WebCore/html/HTMLMediaElement.h b/WebCore/html/HTMLMediaElement.h
index e5e7ae0..ffcee5f 100644
--- a/WebCore/html/HTMLMediaElement.h
+++ b/WebCore/html/HTMLMediaElement.h
@@ -293,6 +293,9 @@ private:
 
     void setShouldDelayLoadEvent(bool);
 
+    void invalidateCachedTime();
+    void refreshCachedTime() const;
+
     // Restrictions to change default behaviors. This is effectively a compile time choice at the moment
     // because there are no accessor functions.
     enum BehaviorRestrictions {
@@ -352,6 +355,10 @@ private:
     // calling the media engine recursively.
     int m_processingMediaPlayerCallback;
 
+    mutable float m_cachedTime;
+    mutable double m_cachedTimeWallClockUpdateTime;
+    mutable double m_minimumWallClockTimeToCacheMediaTime;
+
     bool m_playing : 1;
     bool m_isWaitingUntilMediaCanStart : 1;
     bool m_shouldDelayLoadEvent : 1;
diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp
index 4e3e88e..f459b15 100644
--- a/WebCore/platform/graphics/MediaPlayer.cpp
+++ b/WebCore/platform/graphics/MediaPlayer.cpp
@@ -648,6 +648,11 @@ float MediaPlayer::mediaTimeForTimeValue(float timeValue) const
     return m_private->mediaTimeForTimeValue(timeValue);
 }
 
+double MediaPlayer::maximumDurationToCacheMediaTime() const
+{
+    return m_private->maximumDurationToCacheMediaTime();
+}
+
 // Client callbacks.
 void MediaPlayer::networkStateChanged()
 {
diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h
index 150c6ca..c9c042b 100644
--- a/WebCore/platform/graphics/MediaPlayer.h
+++ b/WebCore/platform/graphics/MediaPlayer.h
@@ -276,6 +276,8 @@ public:
 
     float mediaTimeForTimeValue(float) const;
 
+    double maximumDurationToCacheMediaTime() const;
+
 private:
     MediaPlayer(MediaPlayerClient*);
 
diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h
index 6a74714..d956286 100644
--- a/WebCore/platform/graphics/MediaPlayerPrivate.h
+++ b/WebCore/platform/graphics/MediaPlayerPrivate.h
@@ -129,6 +129,11 @@ public:
     // engine uses rational numbers to represent media time.
     virtual float mediaTimeForTimeValue(float timeValue) const { return timeValue; }
 
+    // Overide this if it is safe for HTMLMediaElement to cache movie time and report
+    // 'currentTime' as [cached time + elapsed wall time]. Returns the maximum wall time
+    // it is OK to calculate movie time before refreshing the cached time.
+    virtual double maximumDurationToCacheMediaTime() const { return 0; }
+
 };
 
 }
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
index 876bc16..d446219 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
@@ -175,6 +175,8 @@ private:
     
     virtual float mediaTimeForTimeValue(float) const;
 
+    virtual double maximumDurationToCacheMediaTime() const { return 5; }
+
     MediaPlayer* m_player;
     RetainPtr<QTMovie> m_qtMovie;
     RetainPtr<QTMovieView> m_qtMovieView;

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list