[WinCairo][MediaFoundation] Videos are always autoplaying.
authorpeavo@outlook.com <peavo@outlook.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Apr 2016 20:41:48 +0000 (20:41 +0000)
committerpeavo@outlook.com <peavo@outlook.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 6 Apr 2016 20:41:48 +0000 (20:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=156284

Reviewed by Alex Christensen.

Videos are autoplaying because the MediaFoundation implementation always starts playback
after the load method has been called. When the load method has been called, we should
only start buffering data, not automatically start the playback. This has been fixed by
implementing the prepareToPlay method, and calling this instead of the play method.

* platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp:
(WebCore::MediaPlayerPrivateMediaFoundation::MediaPlayerPrivateMediaFoundation):
(WebCore::MediaPlayerPrivateMediaFoundation::load):
(WebCore::MediaPlayerPrivateMediaFoundation::prepareToPlay):
(WebCore::MediaPlayerPrivateMediaFoundation::play):
(WebCore::MediaPlayerPrivateMediaFoundation::networkState):
(WebCore::MediaPlayerPrivateMediaFoundation::startSession):
(WebCore::MediaPlayerPrivateMediaFoundation::endGetEvent):
(WebCore::MediaPlayerPrivateMediaFoundation::updateReadyState):
(WebCore::MediaPlayerPrivateMediaFoundation::onTopologySet):
(WebCore::MediaPlayerPrivateMediaFoundation::onBufferingStarted):
(WebCore::MediaPlayerPrivateMediaFoundation::onBufferingStopped):
(WebCore::MediaPlayerPrivateMediaFoundation::onSessionEnded):
(WebCore::MediaPlayerPrivateMediaFoundation::Direct3DPresenter::updateDestRect):
* platform/graphics/win/MediaPlayerPrivateMediaFoundation.h:

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

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp
Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.h

index e21c6a7..85a3a4c 100644 (file)
@@ -1,3 +1,31 @@
+2016-04-06  Per Arne Vollan  <peavo@outlook.com>
+
+        [WinCairo][MediaFoundation] Videos are always autoplaying.
+        https://bugs.webkit.org/show_bug.cgi?id=156284
+
+        Reviewed by Alex Christensen.
+
+        Videos are autoplaying because the MediaFoundation implementation always starts playback
+        after the load method has been called. When the load method has been called, we should
+        only start buffering data, not automatically start the playback. This has been fixed by
+        implementing the prepareToPlay method, and calling this instead of the play method.
+
+        * platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp:
+        (WebCore::MediaPlayerPrivateMediaFoundation::MediaPlayerPrivateMediaFoundation):
+        (WebCore::MediaPlayerPrivateMediaFoundation::load):
+        (WebCore::MediaPlayerPrivateMediaFoundation::prepareToPlay):
+        (WebCore::MediaPlayerPrivateMediaFoundation::play):
+        (WebCore::MediaPlayerPrivateMediaFoundation::networkState):
+        (WebCore::MediaPlayerPrivateMediaFoundation::startSession):
+        (WebCore::MediaPlayerPrivateMediaFoundation::endGetEvent):
+        (WebCore::MediaPlayerPrivateMediaFoundation::updateReadyState):
+        (WebCore::MediaPlayerPrivateMediaFoundation::onTopologySet):
+        (WebCore::MediaPlayerPrivateMediaFoundation::onBufferingStarted):
+        (WebCore::MediaPlayerPrivateMediaFoundation::onBufferingStopped):
+        (WebCore::MediaPlayerPrivateMediaFoundation::onSessionEnded):
+        (WebCore::MediaPlayerPrivateMediaFoundation::Direct3DPresenter::updateDestRect):
+        * platform/graphics/win/MediaPlayerPrivateMediaFoundation.h:
+
 2016-04-06  Zalan Bujtas  <zalan@apple.com>
 
         Add ASSERT_WITH_SECURITY_IMPLICATION when a float box is referenced by multiple RootInlineBoxes.
index 9879a4d..8e577ff 100644 (file)
@@ -88,10 +88,12 @@ MediaPlayerPrivateMediaFoundation::MediaPlayerPrivateMediaFoundation(MediaPlayer
     : m_player(player)
     , m_visible(false)
     , m_loadingProgress(false)
-    , m_paused(false)
+    , m_paused(true)
     , m_hasAudio(false)
     , m_hasVideo(false)
+    , m_preparingToPlay(false)
     , m_hwndVideo(nullptr)
+    , m_networkState(MediaPlayer::Empty)
     , m_readyState(MediaPlayer::HaveNothing)
     , m_weakPtrFactory(this)
 {
@@ -167,6 +169,11 @@ MediaPlayer::SupportsType MediaPlayerPrivateMediaFoundation::supportsType(const
 void MediaPlayerPrivateMediaFoundation::load(const String& url)
 {
     startCreateMediaSource(url);
+
+    m_networkState = MediaPlayer::Loading;
+    m_player->networkStateChanged();
+    m_readyState = MediaPlayer::HaveNothing;
+    m_player->readyStateChanged();
 }
 
 void MediaPlayerPrivateMediaFoundation::cancelLoad()
@@ -174,21 +181,20 @@ void MediaPlayerPrivateMediaFoundation::cancelLoad()
     notImplemented();
 }
 
-void MediaPlayerPrivateMediaFoundation::play()
+void MediaPlayerPrivateMediaFoundation::prepareToPlay()
 {
-    if (!m_mediaSession)
-        return;
-
-    PROPVARIANT varStart;
-    PropVariantInit(&varStart);
-    varStart.vt = VT_EMPTY;
-
-    HRESULT hr = m_mediaSession->Start(nullptr, &varStart);
-    ASSERT(SUCCEEDED(hr));
+    // We call startSession() to start buffering video data.
+    // When we have received enough data, we pause, so that we don't actually start the playback.
+    ASSERT(m_paused);
+    ASSERT(!m_preparingToPlay);
+    m_preparingToPlay = startSession();
+}
 
-    PropVariantClear(&varStart);
+void MediaPlayerPrivateMediaFoundation::play()
+{
+    m_paused = !startSession();
 
-    m_paused = !SUCCEEDED(hr);
+    m_preparingToPlay = false;
 }
 
 void MediaPlayerPrivateMediaFoundation::pause()
@@ -319,8 +325,7 @@ void MediaPlayerPrivateMediaFoundation::setMuted(bool muted)
 
 MediaPlayer::NetworkState MediaPlayerPrivateMediaFoundation::networkState() const
 { 
-    notImplemented();
-    return MediaPlayer::Empty;
+    return m_networkState;
 }
 
 MediaPlayer::ReadyState MediaPlayerPrivateMediaFoundation::readyState() const
@@ -413,6 +418,23 @@ bool MediaPlayerPrivateMediaFoundation::createSession()
     return true;
 }
 
+bool MediaPlayerPrivateMediaFoundation::startSession()
+{
+    if (!m_mediaSession)
+        return false;
+
+    PROPVARIANT varStart;
+    PropVariantInit(&varStart);
+    varStart.vt = VT_EMPTY;
+
+    HRESULT hr = m_mediaSession->Start(nullptr, &varStart);
+    ASSERT(SUCCEEDED(hr));
+
+    PropVariantClear(&varStart);
+
+    return SUCCEEDED(hr);
+}
+
 bool MediaPlayerPrivateMediaFoundation::endSession()
 {
     if (m_mediaSession) {
@@ -503,11 +525,44 @@ bool MediaPlayerPrivateMediaFoundation::endGetEvent(IMFAsyncResult* asyncResult)
         break;
     }
 
-    case MESessionClosed:
+    case MEBufferingStarted: {
+        auto weakPtr = m_weakPtrFactory.createWeakPtr();
+        callOnMainThread([weakPtr] {
+            if (!weakPtr)
+                return;
+            weakPtr->onBufferingStarted();
+        });
         break;
+    }
+
+    case MEBufferingStopped: {
+        auto weakPtr = m_weakPtrFactory.createWeakPtr();
+        callOnMainThread([weakPtr] {
+            if (!weakPtr)
+                return;
+            weakPtr->onBufferingStopped();
+        });
+        break;
+    }
+
+    case MESessionEnded: {
+        auto weakPtr = m_weakPtrFactory.createWeakPtr();
+        callOnMainThread([weakPtr] {
+            if (!weakPtr)
+                return;
+            weakPtr->onSessionEnded();
+        });
+        break;
+    }
 
     case MEMediaSample:
         break;
+
+    case MEError: {
+        HRESULT status = S_OK;
+        event->GetStatus(&status);
+        break;
+    }
     }
 
     if (mediaEventType != MESessionClosed) {
@@ -764,6 +819,49 @@ bool MediaPlayerPrivateMediaFoundation::createSourceStreamNode(COMPtr<IMFStreamD
     return true;
 }
 
+void MediaPlayerPrivateMediaFoundation::updateReadyState()
+{
+    if (!MFGetServicePtr())
+        return;
+
+    COMPtr<IPropertyStore> prop;
+
+    // Get the property store from the media session.
+    HRESULT hr = MFGetServicePtr()(m_mediaSession.get(), MFNETSOURCE_STATISTICS_SERVICE, IID_PPV_ARGS(&prop));
+
+    if (FAILED(hr))
+        return;
+
+    PROPERTYKEY key;
+    key.fmtid = MFNETSOURCE_STATISTICS;
+    key.pid = MFNETSOURCE_BUFFERPROGRESS_ID;
+
+    PROPVARIANT var;
+    hr = prop->GetValue(key, &var);
+
+    const LONG percentageOfPlaybackBufferFilled = var.lVal;
+
+    PropVariantClear(&var);
+
+    if (FAILED(hr))
+        return;
+
+    MediaPlayer::ReadyState oldReadyState = m_readyState;
+    if (percentageOfPlaybackBufferFilled >= 100) {
+        m_readyState = MediaPlayer::HaveEnoughData;
+        if (m_preparingToPlay) {
+            pause();
+            m_preparingToPlay = false;
+        }
+    } else if (percentageOfPlaybackBufferFilled > 0)
+        m_readyState = MediaPlayer::HaveFutureData;
+    else
+        m_readyState = MediaPlayer::HaveCurrentData;
+
+    if (m_readyState != oldReadyState)
+        m_player->readyStateChanged();
+}
+
 COMPtr<IMFVideoDisplayControl> MediaPlayerPrivateMediaFoundation::videoDisplay()
 {
     if (m_videoDisplay)
@@ -789,17 +887,33 @@ void MediaPlayerPrivateMediaFoundation::onCreatedMediaSource()
 
 void MediaPlayerPrivateMediaFoundation::onTopologySet()
 {
+    // This method is called on the main thread as a result of load() being called.
+
     if (auto videoDisplay = this->videoDisplay()) {
         RECT rc = { 0, 0, m_size.width(), m_size.height() };
         videoDisplay->SetVideoPosition(nullptr, &rc);
     }
 
-    m_readyState = MediaPlayer::HaveFutureData;
+    // It is expected that we start buffering data from the network now.
+    prepareToPlay();
+}
 
-    ASSERT(m_player);
-    m_player->readyStateChanged();
+void MediaPlayerPrivateMediaFoundation::onBufferingStarted()
+{
+    updateReadyState();
+}
 
-    play();
+void MediaPlayerPrivateMediaFoundation::onBufferingStopped()
+{
+    updateReadyState();
+}
+
+void MediaPlayerPrivateMediaFoundation::onSessionEnded()
+{
+    m_networkState = MediaPlayer::Loaded;
+    m_player->networkStateChanged();
+
+    m_paused = true;
     m_player->playbackStateChanged();
 }
 
@@ -2974,7 +3088,8 @@ HRESULT MediaPlayerPrivateMediaFoundation::Direct3DPresenter::updateDestRect()
         return S_FALSE;
 
     RECT rcView;
-    GetClientRect(m_hwnd, &rcView);
+    if (!GetClientRect(m_hwnd, &rcView))
+        return E_FAIL;
 
     // Clip to the client area of the window.
     if (m_destRect.right > rcView.right)
index 2687131..ba644d3 100644 (file)
@@ -60,6 +60,8 @@ public:
     void load(const String& url) override;
     void cancelLoad() override;
 
+    void prepareToPlay() override;
+
     void play() override;
     void pause() override;
 
@@ -109,7 +111,9 @@ private:
     bool m_paused;
     bool m_hasAudio;
     bool m_hasVideo;
+    bool m_preparingToPlay;
     HWND m_hwndVideo;
+    MediaPlayer::NetworkState m_networkState;
     MediaPlayer::ReadyState m_readyState;
     FloatRect m_lastPaintRect;
 
@@ -126,6 +130,7 @@ private:
     COMPtr<IMFVideoDisplayControl> m_videoDisplay;
 
     bool createSession();
+    bool startSession();
     bool endSession();
     bool startCreateMediaSource(const String& url);
     bool endCreatedMediaSource(IMFAsyncResult*);
@@ -135,10 +140,15 @@ private:
     bool createOutputNode(COMPtr<IMFStreamDescriptor> sourceSD, COMPtr<IMFTopologyNode>&);
     bool createSourceStreamNode(COMPtr<IMFStreamDescriptor> sourceSD, COMPtr<IMFTopologyNode>&);
 
+    void updateReadyState();
+
     COMPtr<IMFVideoDisplayControl> videoDisplay();
 
     void onCreatedMediaSource();
     void onTopologySet();
+    void onBufferingStarted();
+    void onBufferingStopped();
+    void onSessionEnded();
 
     LPCWSTR registerVideoWindowClass();
     void createVideoWindow();