2011-05-14 Eric Carlson <eric.carlson@apple.com>
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 15 May 2011 05:39:36 +0000 (05:39 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 15 May 2011 05:39:36 +0000 (05:39 +0000)
        Reviewed by Dan Bernstein.

        HTTP video-on-demand streams frequently have live stream UI
        https://bugs.webkit.org/show_bug.cgi?id=60849
        <rdar://problem/9440502>

        No new tests, we don't currently have tests for http live streams. Changes verified manually.

        * html/HTMLMediaElement.cpp:
        (WebCore::HTMLMediaElement::mediaPlayerDurationChanged): Reset the media controls so
            a duration change which identifies a format will be picked up.
        (WebCore::HTMLMediaElement::mediaPlayerCharacteristicChanged): New, reset media controls
            so they can be reconfigured for the media file characteristics.
        * html/HTMLMediaElement.h:

        * platform/graphics/MediaPlayer.cpp:
        (WebCore::MediaPlayer::characteristicChanged): New, pass through to the element.
        * platform/graphics/MediaPlayer.h:
        (WebCore::MediaPlayerClient::mediaPlayerCharacteristicChanged):

        * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp:
        (WebCore::MediaPlayerPrivateAVFoundation::setHasVideo): Call characteristicChanged when
            setting changes.
        (WebCore::MediaPlayerPrivateAVFoundation::setHasAudio): Ditto.
        (WebCore::MediaPlayerPrivateAVFoundation::setHasClosedCaptions): Ditto.
        (WebCore::MediaPlayerPrivateAVFoundation::loadedTimeRangesChanged): Move the duration
            change notification logic to invalidateCachedDuration.
        (WebCore::MediaPlayerPrivateAVFoundation::invalidateCachedDuration): New, invalidate
            the cached duration and notify the element when it changes.
        (WebCore::MediaPlayerPrivateAVFoundation::dispatchNotification): Call invalidateCachedDuration
            for the DurationChanged notification.
        * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h: Define DurationChanged.

        * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm:
        (WebCore::MediaPlayerPrivateAVFoundationObjC::platformDuration): Don't check asset or
            item duration until they have been loaded.
        (WebCore::itemKVOProperties): Listen for duration change.
        (-[WebCoreAVFMovieObserver observeValueForKeyPath:ofObject:change:context:]): Deal with
            duration change notification.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@86501 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/platform/graphics/MediaPlayer.cpp
Source/WebCore/platform/graphics/MediaPlayer.h
Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp
Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h
Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm

index 33573ef..2bd38f9 100644 (file)
@@ -1,3 +1,45 @@
+2011-05-14  Eric Carlson  <eric.carlson@apple.com>
+
+        Reviewed by Dan Bernstein.
+
+        HTTP video-on-demand streams frequently have live stream UI
+        https://bugs.webkit.org/show_bug.cgi?id=60849
+        <rdar://problem/9440502>
+
+        No new tests, we don't currently have tests for http live streams. Changes verified manually.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::mediaPlayerDurationChanged): Reset the media controls so
+            a duration change which identifies a format will be picked up.
+        (WebCore::HTMLMediaElement::mediaPlayerCharacteristicChanged): New, reset media controls
+            so they can be reconfigured for the media file characteristics.
+        * html/HTMLMediaElement.h:
+
+        * platform/graphics/MediaPlayer.cpp:
+        (WebCore::MediaPlayer::characteristicChanged): New, pass through to the element.
+        * platform/graphics/MediaPlayer.h:
+        (WebCore::MediaPlayerClient::mediaPlayerCharacteristicChanged):
+
+        * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp:
+        (WebCore::MediaPlayerPrivateAVFoundation::setHasVideo): Call characteristicChanged when
+            setting changes.
+        (WebCore::MediaPlayerPrivateAVFoundation::setHasAudio): Ditto.
+        (WebCore::MediaPlayerPrivateAVFoundation::setHasClosedCaptions): Ditto.
+        (WebCore::MediaPlayerPrivateAVFoundation::loadedTimeRangesChanged): Move the duration
+            change notification logic to invalidateCachedDuration.
+        (WebCore::MediaPlayerPrivateAVFoundation::invalidateCachedDuration): New, invalidate
+            the cached duration and notify the element when it changes.
+        (WebCore::MediaPlayerPrivateAVFoundation::dispatchNotification): Call invalidateCachedDuration
+            for the DurationChanged notification.
+        * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.h: Define DurationChanged.
+
+        * platform/graphics/avfoundation/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::platformDuration): Don't check asset or
+            item duration until they have been loaded.
+        (WebCore::itemKVOProperties): Listen for duration change.
+        (-[WebCoreAVFMovieObserver observeValueForKeyPath:ofObject:change:context:]): Deal with
+            duration change notification.
+
 2011-05-14  Abhishek Arya  <inferno@chromium.org>
 
         Reviewed by Dan Bernstein.
index d32fce6..68d26a0 100644 (file)
@@ -1932,14 +1932,13 @@ void HTMLMediaElement::mediaPlayerMuteChanged(MediaPlayer*)
     endProcessingMediaPlayerCallback();
 }
 
-void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer*)
+void HTMLMediaElement::mediaPlayerDurationChanged(MediaPlayer* player)
 {
     LOG(Media, "HTMLMediaElement::mediaPlayerDurationChanged");
 
     beginProcessingMediaPlayerCallback();
     scheduleEvent(eventNames().durationchangeEvent);
-    if (renderer())
-        renderer()->updateFromElement();
+    mediaPlayerCharacteristicChanged(player);
     endProcessingMediaPlayerCallback();
 }
 
@@ -2047,6 +2046,18 @@ void HTMLMediaElement::mediaPlayerFirstVideoFrameAvailable(MediaPlayer*)
     endProcessingMediaPlayerCallback();
 }
 
+void HTMLMediaElement::mediaPlayerCharacteristicChanged(MediaPlayer*)
+{
+    LOG(Media, "HTMLMediaElement::mediaPlayerCharacteristicChanged");
+    
+    beginProcessingMediaPlayerCallback();
+    if (hasMediaControls())
+        mediaControls()->reset();
+    if (renderer())
+        renderer()->updateFromElement();
+    endProcessingMediaPlayerCallback();
+}
+
 PassRefPtr<TimeRanges> HTMLMediaElement::buffered() const
 {
     if (!m_player)
index a4f3335..f9e93b4 100644 (file)
@@ -259,7 +259,9 @@ private:
     virtual void mediaPlayerRenderingModeChanged(MediaPlayer*);
 #endif
     virtual void mediaPlayerEngineUpdated(MediaPlayer*);
+    
     virtual void mediaPlayerFirstVideoFrameAvailable(MediaPlayer*);
+    virtual void mediaPlayerCharacteristicChanged(MediaPlayer*);
 
     void loadTimerFired(Timer<HTMLMediaElement>*);
     void asyncEventTimerFired(Timer<HTMLMediaElement>*);
index 40ea0ae..9dbe34a 100644 (file)
@@ -859,6 +859,12 @@ void MediaPlayer::firstVideoFrameAvailable()
         m_mediaPlayerClient->mediaPlayerFirstVideoFrameAvailable(this);
 }
 
+void MediaPlayer::characteristicChanged()
+{
+    if (m_mediaPlayerClient)
+        m_mediaPlayerClient->mediaPlayerCharacteristicChanged(this);
+}
+
 }
 
 #endif
index 13f6d58..8c5ad56 100644 (file)
@@ -147,6 +147,9 @@ public:
     // first frame is not available immediately when prepareForRendering is called.
     virtual void mediaPlayerFirstVideoFrameAvailable(MediaPlayer*) { }
 
+    // A characteristic of the media file, eg. video, audio, closed captions, etc, has changed.
+    virtual void mediaPlayerCharacteristicChanged(MediaPlayer*) { }
+    
 #if USE(ACCELERATED_COMPOSITING)
     // whether the rendering system can accelerate the display of this MediaPlayer.
     virtual bool mediaPlayerRenderingCanBeAccelerated(MediaPlayer*) { return false; }
@@ -262,6 +265,8 @@ public:
     void playbackStateChanged();
     void durationChanged();
     void firstVideoFrameAvailable();
+    void characteristicChanged();
+
 
     void repaint();
 
index 2f138f4..0336077 100644 (file)
@@ -313,6 +313,30 @@ void MediaPlayerPrivateAVFoundation::setNaturalSize(IntSize size)
         m_player->sizeChanged();
 }
 
+void MediaPlayerPrivateAVFoundation::setHasVideo(bool b)
+{
+    if (m_cachedHasVideo != b) {
+        m_cachedHasVideo = b;
+        m_player->characteristicChanged();
+    }
+}
+
+void MediaPlayerPrivateAVFoundation::setHasAudio(bool b)
+{
+    if (m_cachedHasAudio != b) {
+        m_cachedHasAudio = b;
+        m_player->characteristicChanged();
+    }
+}
+
+void MediaPlayerPrivateAVFoundation::setHasClosedCaptions(bool b)
+{
+    if (m_cachedHasCaptions != b) {
+        m_cachedHasCaptions = b;
+        m_player->characteristicChanged();
+    }
+}
+
 PassRefPtr<TimeRanges> MediaPlayerPrivateAVFoundation::buffered() const
 {
     if (!m_cachedLoadedTimeRanges)
@@ -516,15 +540,7 @@ void MediaPlayerPrivateAVFoundation::loadedTimeRangesChanged()
 {
     m_cachedLoadedTimeRanges = 0;
     m_cachedMaxTimeLoaded = 0;
-
-    // For some media files, reported duration is estimated and updated as media is loaded
-    // so report duration changed when the estimate is upated.
-    float dur = duration();
-    if (dur != m_reportedDuration) {
-        if (m_reportedDuration != invalidTime())
-            m_player->durationChanged();
-        m_reportedDuration = dur;
-    }
+    invalidateCachedDuration();
 }
 
 void MediaPlayerPrivateAVFoundation::seekableTimeRangesChanged()
@@ -572,6 +588,23 @@ void MediaPlayerPrivateAVFoundation::didEnd()
     m_player->timeChanged();
 }
 
+void MediaPlayerPrivateAVFoundation::invalidateCachedDuration()
+{
+    LOG(Media, "MediaPlayerPrivateAVFoundation::invalidateCachedDuration(%p)", this);
+    
+    m_cachedDuration = invalidTime();
+
+    // For some media files, reported duration is estimated and updated as media is loaded
+    // so report duration changed when the estimate is upated.
+    float duration = this->duration();
+    if (duration != m_reportedDuration) {
+        if (m_reportedDuration != invalidTime())
+            m_player->durationChanged();
+        m_reportedDuration = duration;
+    }
+    
+}
+
 void MediaPlayerPrivateAVFoundation::repaint()
 {
     m_player->repaint();
@@ -761,6 +794,10 @@ void MediaPlayerPrivateAVFoundation::dispatchNotification()
         updateStates();
         playabilityKnown();
         break;
+    case Notification::DurationChanged:
+        invalidateCachedDuration();
+        break;
+
     case Notification::None:
         ASSERT_NOT_REACHED();
         break;
index 7a0cb9c..503d54d 100644 (file)
@@ -68,6 +68,7 @@ public:
             PlayerRateChanged,
             PlayerTimeChanged,
             SeekCompleted,
+            DurationChanged,
         };
         
         Notification()
@@ -217,9 +218,9 @@ protected:
 protected:
     void updateStates();
 
-    void setHasVideo(bool b) { m_cachedHasVideo = b; };
-    void setHasAudio(bool b) { m_cachedHasAudio = b; }
-    void setHasClosedCaptions(bool b) { m_cachedHasCaptions = b; }
+    void setHasVideo(bool);
+    void setHasAudio(bool);
+    void setHasClosedCaptions(bool);
     void setDelayCallbacks(bool);
     void setIgnoreLoadStateChanges(bool delay) { m_ignoreLoadStateChanges = delay; }
     void setNaturalSize(IntSize);
@@ -240,6 +241,7 @@ protected:
     static void mainThreadCallback(void*);
     
     float invalidTime() const { return -1.0f; }
+    void invalidateCachedDuration();
 
 private:
     MediaPlayer* m_player;
index 95f9c86..8778f4a 100644 (file)
@@ -414,13 +414,15 @@ void MediaPlayerPrivateAVFoundationObjC::platformPause()
 
 float MediaPlayerPrivateAVFoundationObjC::platformDuration() const
 {
-    if (!m_avAsset)
-        return invalidTime();
+    // Do not ask the asset for duration before it has been loaded or it will fetch the
+    // answer synchronously.
+    if (!m_avAsset || assetStatus() < MediaPlayerAVAssetStatusLoaded)
+         return invalidTime();
     
     CMTime cmDuration;
     
-    // Check the AVItem if we have one, some assets never report duration.
-    if (m_avPlayerItem)
+    // Check the AVItem if we have one and it has loaded duration, some assets never report duration.
+    if (m_avPlayerItem && playerItemStatus() >= MediaPlayerAVPlayerItemStatusReadyToPlay)
         cmDuration = [m_avPlayerItem.get() duration];
     else
         cmDuration= [m_avAsset.get() duration];
@@ -431,7 +433,7 @@ float MediaPlayerPrivateAVFoundationObjC::platformDuration() const
     if (CMTIME_IS_INDEFINITE(cmDuration))
         return numeric_limits<float>::infinity();
 
-    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::duration(%p) - invalid duration, returning %.0f", this, invalidTime());
+    LOG(Media, "MediaPlayerPrivateAVFoundationObjC::platformDuration(%p) - invalid duration, returning %.0f", this, invalidTime());
     return invalidTime();
 }
 
@@ -796,6 +798,7 @@ NSArray* itemKVOProperties()
                 @"playbackLikelyToKeepUp",
                 @"playbackBufferFull",
                 @"playbackBufferEmpty",
+                @"duration",
                 nil];
     }
     return keys;
@@ -886,6 +889,8 @@ NSArray* itemKVOProperties()
             m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemTracksChanged);
         else if ([keyPath isEqualToString:@"presentationSize"])
             m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::ItemPresentationSizeChanged);
+        else if ([keyPath isEqualToString:@"duration"])
+            m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::DurationChanged);
 
         return;
     }
@@ -894,7 +899,7 @@ NSArray* itemKVOProperties()
         // A value changed for an AVPlayer.
         if ([keyPath isEqualToString:@"rate"])
             m_callback->scheduleMainThreadNotification(MediaPlayerPrivateAVFoundation::Notification::PlayerRateChanged);
-}
+    }
 }
 
 @end