[WinCairo][Video] Windows Media Foundation implementation is not completed.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 19 Jan 2015 21:03:02 +0000 (21:03 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 19 Jan 2015 21:03:02 +0000 (21:03 +0000)
https://bugs.webkit.org/show_bug.cgi?id=140337

Patch by peavo@outlook.com <peavo@outlook.com> on 2015-01-19
Reviewed by Alex Christensen.

Source/WebCore:

This patch aims to complete some of the methods which are not implemented.
Currently, only MP4 is supported.
Video is rendered in a child window of the main window.
We should eventually render the video directly in the main window,
by reading and painting individual video frames from the stream.

* platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp:
(WebCore::MediaPlayerPrivateMediaFoundation::MediaPlayerPrivateMediaFoundation):
(WebCore::MediaPlayerPrivateMediaFoundation::~MediaPlayerPrivateMediaFoundation):
(WebCore::MediaPlayerPrivateMediaFoundation::getSupportedTypes):
(WebCore::MediaPlayerPrivateMediaFoundation::supportsType):
(WebCore::MediaPlayerPrivateMediaFoundation::load):
(WebCore::MediaPlayerPrivateMediaFoundation::play):
(WebCore::MediaPlayerPrivateMediaFoundation::pause):
(WebCore::MediaPlayerPrivateMediaFoundation::naturalSize):
(WebCore::MediaPlayerPrivateMediaFoundation::hasVideo):
(WebCore::MediaPlayerPrivateMediaFoundation::hasAudio):
(WebCore::MediaPlayerPrivateMediaFoundation::setVisible):
(WebCore::MediaPlayerPrivateMediaFoundation::paused):
(WebCore::MediaPlayerPrivateMediaFoundation::readyState):
(WebCore::MediaPlayerPrivateMediaFoundation::didLoadingProgress):
(WebCore::MediaPlayerPrivateMediaFoundation::setSize):
(WebCore::MediaPlayerPrivateMediaFoundation::paint):
(WebCore::MediaPlayerPrivateMediaFoundation::createSession):
(WebCore::MediaPlayerPrivateMediaFoundation::endSession):
(WebCore::MediaPlayerPrivateMediaFoundation::startCreateMediaSource):
(WebCore::MediaPlayerPrivateMediaFoundation::endCreatedMediaSource):
(WebCore::MediaPlayerPrivateMediaFoundation::endGetEvent):
(WebCore::MediaPlayerPrivateMediaFoundation::createTopologyFromSource):
(WebCore::MediaPlayerPrivateMediaFoundation::addBranchToPartialTopology):
(WebCore::MediaPlayerPrivateMediaFoundation::VideoViewWndProc):
(WebCore::MediaPlayerPrivateMediaFoundation::registerVideoWindowClass):
(WebCore::MediaPlayerPrivateMediaFoundation::createVideoWindow):
(WebCore::MediaPlayerPrivateMediaFoundation::destroyVideoWindow):
(WebCore::MediaPlayerPrivateMediaFoundation::createOutputNode):
(WebCore::MediaPlayerPrivateMediaFoundation::createSourceStreamNode):
(WebCore::MediaPlayerPrivateMediaFoundation::onCreatedMediaSource):
(WebCore::MediaPlayerPrivateMediaFoundation::onTopologySet):
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::AsyncCallback):
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::~AsyncCallback):
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::QueryInterface):
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::AddRef):
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::Release):
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::GetParameters):
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::Invoke):
* platform/graphics/win/MediaPlayerPrivateMediaFoundation.h:

WebKitLibraries:

Link with Media Foundation libraries.

* win/tools/vsprops/WinCairo.props:

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

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp
Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.h
WebKitLibraries/ChangeLog
WebKitLibraries/win/tools/vsprops/WinCairo.props

index 3bc49d9..fd2615b 100644 (file)
@@ -1,3 +1,57 @@
+2015-01-19  peavo@outlook.com  <peavo@outlook.com>
+
+        [WinCairo][Video] Windows Media Foundation implementation is not completed.
+        https://bugs.webkit.org/show_bug.cgi?id=140337
+
+        Reviewed by Alex Christensen.
+
+        This patch aims to complete some of the methods which are not implemented.
+        Currently, only MP4 is supported.
+        Video is rendered in a child window of the main window.
+        We should eventually render the video directly in the main window,
+        by reading and painting individual video frames from the stream.
+
+        * platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp:
+        (WebCore::MediaPlayerPrivateMediaFoundation::MediaPlayerPrivateMediaFoundation):
+        (WebCore::MediaPlayerPrivateMediaFoundation::~MediaPlayerPrivateMediaFoundation):
+        (WebCore::MediaPlayerPrivateMediaFoundation::getSupportedTypes):
+        (WebCore::MediaPlayerPrivateMediaFoundation::supportsType):
+        (WebCore::MediaPlayerPrivateMediaFoundation::load):
+        (WebCore::MediaPlayerPrivateMediaFoundation::play):
+        (WebCore::MediaPlayerPrivateMediaFoundation::pause):
+        (WebCore::MediaPlayerPrivateMediaFoundation::naturalSize):
+        (WebCore::MediaPlayerPrivateMediaFoundation::hasVideo):
+        (WebCore::MediaPlayerPrivateMediaFoundation::hasAudio):
+        (WebCore::MediaPlayerPrivateMediaFoundation::setVisible):
+        (WebCore::MediaPlayerPrivateMediaFoundation::paused):
+        (WebCore::MediaPlayerPrivateMediaFoundation::readyState):
+        (WebCore::MediaPlayerPrivateMediaFoundation::didLoadingProgress):
+        (WebCore::MediaPlayerPrivateMediaFoundation::setSize):
+        (WebCore::MediaPlayerPrivateMediaFoundation::paint):
+        (WebCore::MediaPlayerPrivateMediaFoundation::createSession):
+        (WebCore::MediaPlayerPrivateMediaFoundation::endSession):
+        (WebCore::MediaPlayerPrivateMediaFoundation::startCreateMediaSource):
+        (WebCore::MediaPlayerPrivateMediaFoundation::endCreatedMediaSource):
+        (WebCore::MediaPlayerPrivateMediaFoundation::endGetEvent):
+        (WebCore::MediaPlayerPrivateMediaFoundation::createTopologyFromSource):
+        (WebCore::MediaPlayerPrivateMediaFoundation::addBranchToPartialTopology):
+        (WebCore::MediaPlayerPrivateMediaFoundation::VideoViewWndProc):
+        (WebCore::MediaPlayerPrivateMediaFoundation::registerVideoWindowClass):
+        (WebCore::MediaPlayerPrivateMediaFoundation::createVideoWindow):
+        (WebCore::MediaPlayerPrivateMediaFoundation::destroyVideoWindow):
+        (WebCore::MediaPlayerPrivateMediaFoundation::createOutputNode):
+        (WebCore::MediaPlayerPrivateMediaFoundation::createSourceStreamNode):
+        (WebCore::MediaPlayerPrivateMediaFoundation::onCreatedMediaSource):
+        (WebCore::MediaPlayerPrivateMediaFoundation::onTopologySet):
+        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::AsyncCallback):
+        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::~AsyncCallback):
+        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::QueryInterface):
+        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::AddRef):
+        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::Release):
+        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::GetParameters):
+        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::Invoke):
+        * platform/graphics/win/MediaPlayerPrivateMediaFoundation.h:
+
 2015-01-19  Brian J. Burg  <burg@cs.washington.edu>
 
         Web Replay: convert to is<T> and downcast<T> for decoding replay inputs
index 8a1cee6..ce8e33e 100644 (file)
 #include "config.h"
 #include "MediaPlayerPrivateMediaFoundation.h"
 
+#include "CachedResourceLoader.h"
+#include "FrameView.h"
 #include "GraphicsContext.h"
+#include "HostWindow.h"
 #include "NotImplemented.h"
 
 #if USE(MEDIA_FOUNDATION)
 
-namespace WebCore {
+#include <wtf/MainThread.h>
 
-// TODO: Implement video functionality using Media Foundation
+namespace WebCore {
 
 MediaPlayerPrivateMediaFoundation::MediaPlayerPrivateMediaFoundation(MediaPlayer* player) 
     : m_player(player)
+    , m_visible(false)
+    , m_loadingProgress(false)
+    , m_paused(false)
+    , m_hasAudio(false)
+    , m_hasVideo(false)
+    , m_hwndVideo(nullptr)
+    , m_readyState(MediaPlayer::HaveNothing)
+    , m_mediaSession(nullptr)
+    , m_sourceResolver(nullptr)
+    , m_mediaSource(nullptr)
+    , m_topology(nullptr)
+    , m_sourcePD(nullptr)
+    , m_videoDisplay(nullptr)
+{
+    createSession();
+    createVideoWindow();
+}
+
+MediaPlayerPrivateMediaFoundation::~MediaPlayerPrivateMediaFoundation()
 {
+    destroyVideoWindow();
+    endSession();
 }
 
 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivateMediaFoundation::create(MediaPlayer* player)
@@ -60,19 +84,23 @@ bool MediaPlayerPrivateMediaFoundation::isAvailable()
 
 void MediaPlayerPrivateMediaFoundation::getSupportedTypes(HashSet<String>& types)
 {
-    notImplemented();
-    types = HashSet<String>();
+    types.add(String("video/mp4"));
 }
 
 MediaPlayer::SupportsType MediaPlayerPrivateMediaFoundation::supportsType(const MediaEngineSupportParameters& parameters)
 {
-    notImplemented();
+    if (parameters.type.isNull() || parameters.type.isEmpty())
+        return MediaPlayer::IsNotSupported;
+
+    if (parameters.type == "video/mp4")
+        return MediaPlayer::IsSupported;
+
     return MediaPlayer::IsNotSupported;
 }
 
-void MediaPlayerPrivateMediaFoundation::load(const String&)
+void MediaPlayerPrivateMediaFoundation::load(const String& url)
 {
-    notImplemented();
+    startCreateMediaSource(url);
 }
 
 void MediaPlayerPrivateMediaFoundation::cancelLoad()
@@ -82,35 +110,47 @@ void MediaPlayerPrivateMediaFoundation::cancelLoad()
 
 void MediaPlayerPrivateMediaFoundation::play()
 {
-    notImplemented();
+    if (!m_mediaSession)
+        return;
+
+    PROPVARIANT varStart;
+    PropVariantInit(&varStart);
+    varStart.vt = VT_EMPTY;
+
+    HRESULT hr = m_mediaSession->Start(nullptr, &varStart);
+    ASSERT(SUCCEEDED(hr));
+
+    PropVariantClear(&varStart);
+
+    m_paused = !SUCCEEDED(hr);
 }
 
 void MediaPlayerPrivateMediaFoundation::pause()
 {
-    notImplemented();
+    if (!m_mediaSession)
+        return;
+
+    m_paused = SUCCEEDED(m_mediaSession->Pause());
 }
 
 IntSize MediaPlayerPrivateMediaFoundation::naturalSize() const 
 {
-    notImplemented();
-    return IntSize(0, 0);
+    return m_size;
 }
 
 bool MediaPlayerPrivateMediaFoundation::hasVideo() const
 {
-    notImplemented();
-    return false;
+    return m_hasVideo;
 }
 
 bool MediaPlayerPrivateMediaFoundation::hasAudio() const
 {
-    notImplemented();
-    return false;
+    return m_hasAudio;
 }
 
-void MediaPlayerPrivateMediaFoundation::setVisible(bool)
+void MediaPlayerPrivateMediaFoundation::setVisible(bool visible)
 {
-    notImplemented();
+    m_visible = visible;
 }
 
 bool MediaPlayerPrivateMediaFoundation::seeking() const
@@ -121,8 +161,7 @@ bool MediaPlayerPrivateMediaFoundation::seeking() const
 
 bool MediaPlayerPrivateMediaFoundation::paused() const
 {
-    notImplemented();
-    return false;
+    return m_paused;
 }
 
 MediaPlayer::NetworkState MediaPlayerPrivateMediaFoundation::networkState() const
@@ -133,8 +172,7 @@ MediaPlayer::NetworkState MediaPlayerPrivateMediaFoundation::networkState() cons
 
 MediaPlayer::ReadyState MediaPlayerPrivateMediaFoundation::readyState() const
 {
-    notImplemented();
-    return MediaPlayer::HaveNothing;
+    return m_readyState;
 }
 
 std::unique_ptr<PlatformTimeRanges> MediaPlayerPrivateMediaFoundation::buffered() const
@@ -145,13 +183,32 @@ std::unique_ptr<PlatformTimeRanges> MediaPlayerPrivateMediaFoundation::buffered(
 
 bool MediaPlayerPrivateMediaFoundation::didLoadingProgress() const
 {
-    notImplemented();
-    return false;
+    return m_loadingProgress;
 }
 
-void MediaPlayerPrivateMediaFoundation::setSize(const IntSize&)
+void MediaPlayerPrivateMediaFoundation::setSize(const IntSize& size)
 {
-    notImplemented();
+    m_size = size;
+
+    if (!m_videoDisplay)
+        return;
+
+    LayoutSize scrollOffset;
+
+    FrameView* view = nullptr;
+    if (m_player && m_player->cachedResourceLoader() && m_player->cachedResourceLoader()->document())
+        view = m_player->cachedResourceLoader()->document()->view();
+    if (view)
+        scrollOffset = view->scrollOffsetForFixedPosition();
+
+    int xPos = -scrollOffset.width().toInt() + m_lastPaintRect.x();
+    int yPos = -scrollOffset.height().toInt() + m_lastPaintRect.y();
+
+    if (m_hwndVideo && !m_lastPaintRect.isEmpty())
+        ::MoveWindow(m_hwndVideo, xPos, yPos, m_size.width(), m_size.height(), FALSE);
+
+    RECT rc = { 0, 0, m_size.width(), m_size.height() };
+    m_videoDisplay->SetVideoPosition(nullptr, &rc);
 }
 
 void MediaPlayerPrivateMediaFoundation::paint(GraphicsContext* context, const IntRect& rect)
@@ -160,10 +217,397 @@ void MediaPlayerPrivateMediaFoundation::paint(GraphicsContext* context, const In
         || !m_player->visible())
         return;
 
-    // TODO: Paint the contents of the video to the context
+    m_lastPaintRect = rect;
+
+    // We currently let Media Foundation handle the drawing, by providing a handle to the window to draw in.
+    // We should instead read individual frames from the stream, and paint them into the graphics context here.
+
     notImplemented();
 }
 
+bool MediaPlayerPrivateMediaFoundation::createSession()
+{
+    if (FAILED(MFStartup(MF_VERSION, MFSTARTUP_FULL)))
+        return false;
+
+    if (FAILED(MFCreateMediaSession(nullptr, &m_mediaSession)))
+        return false;
+
+    // Get next event.
+    AsyncCallback* callback = new AsyncCallback(this, true);
+    HRESULT hr = m_mediaSession->BeginGetEvent(callback, nullptr);
+    ASSERT(SUCCEEDED(hr));
+
+    return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::endSession()
+{
+    if (m_mediaSession) {
+        m_mediaSession->Shutdown();
+        m_mediaSession->Release();
+        m_mediaSession = nullptr;
+    }
+
+    HRESULT hr = MFShutdown();
+    ASSERT(SUCCEEDED(hr));
+
+    return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::startCreateMediaSource(const String& url)
+{
+    if (FAILED(MFCreateSourceResolver(&m_sourceResolver)))
+        return false;
+
+    COMPtr<IUnknown> cancelCookie;
+    Vector<UChar> urlSource = url.charactersWithNullTermination();
+
+    AsyncCallback* callback = new AsyncCallback(this, false);
+
+    if (FAILED(m_sourceResolver->BeginCreateObjectFromURL(urlSource.data(), MF_RESOLUTION_MEDIASOURCE, nullptr, &cancelCookie, callback, nullptr)))
+        return false;
+
+    return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::endCreatedMediaSource(IMFAsyncResult* asyncResult)
+{
+    MF_OBJECT_TYPE objectType;
+    COMPtr<IUnknown> source;
+
+    HRESULT hr = m_sourceResolver->EndCreateObjectFromURL(asyncResult, &objectType, &source);
+    if (FAILED(hr))
+        return false;
+
+    hr = source->QueryInterface(IID_PPV_ARGS(&m_mediaSource));
+    if (FAILED(hr))
+        return false;
+
+    hr = asyncResult->GetStatus();
+    m_loadingProgress = SUCCEEDED(hr);
+
+    callOnMainThread([this] {
+        onCreatedMediaSource();
+    });
+
+    return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::endGetEvent(IMFAsyncResult* asyncResult)
+{
+    COMPtr<IMFMediaEvent> event;
+
+    // Get the event from the event queue.
+    HRESULT hr = m_mediaSession->EndGetEvent(asyncResult, &event);
+    if (FAILED(hr))
+        return false;
+
+    // Get the event type.
+    MediaEventType mediaEventType;
+    hr = event->GetType(&mediaEventType);
+    if (FAILED(hr))
+        return false;
+
+    switch (mediaEventType) {
+    case MESessionTopologySet:
+        callOnMainThread([this] {
+            onTopologySet();
+        });
+        break;
+
+    case MESessionClosed:
+        break;
+    }
+
+    if (mediaEventType != MESessionClosed) {
+        // For all other events, ask the media session for the
+        // next event in the queue.
+        AsyncCallback* callback = new AsyncCallback(this, true);
+
+        hr = m_mediaSession->BeginGetEvent(callback, nullptr);
+        if (FAILED(hr))
+            return false;
+    }
+
+    return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::createTopologyFromSource()
+{
+    // Create a new topology.
+    if (FAILED(MFCreateTopology(&m_topology)))
+        return false;
+
+    // Create the presentation descriptor for the media source.
+    if (FAILED(m_mediaSource->CreatePresentationDescriptor(&m_sourcePD)))
+        return false;
+
+    // Get the number of streams in the media source.
+    DWORD sourceStreams = 0;
+    if (FAILED(m_sourcePD->GetStreamDescriptorCount(&sourceStreams)))
+        return false;
+
+    // For each stream, create the topology nodes and add them to the topology.
+    for (DWORD i = 0; i < sourceStreams; i++) {
+        if (!addBranchToPartialTopology(i))
+            return false;
+    }
+
+    return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::addBranchToPartialTopology(int stream)
+{
+    // Get the stream descriptor for this stream.
+    COMPtr<IMFStreamDescriptor> sourceSD;
+    BOOL selected = FALSE;
+    if (FAILED(m_sourcePD->GetStreamDescriptorByIndex(stream, &selected, &sourceSD)))
+        return false;
+
+    // Create the topology branch only if the stream is selected.
+    // Otherwise, do nothing.
+    if (!selected)
+        return true;
+
+    // Create a source node for this stream.
+    COMPtr<IMFTopologyNode> sourceNode;
+    if (!createSourceStreamNode(sourceSD, sourceNode))
+        return false;
+
+    COMPtr<IMFTopologyNode> outputNode;
+    if (!createOutputNode(sourceSD, outputNode))
+        return false;
+
+    // Add both nodes to the topology.
+    if (FAILED(m_topology->AddNode(sourceNode.get())))
+        return false;
+
+    if (FAILED(m_topology->AddNode(outputNode.get())))
+        return false;
+
+    // Connect the source node to the output node.
+    if (FAILED(sourceNode->ConnectOutput(0, outputNode.get(), 0)))
+        return false;
+
+    return true;
+}
+
+LRESULT CALLBACK MediaPlayerPrivateMediaFoundation::VideoViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+LPCWSTR MediaPlayerPrivateMediaFoundation::registerVideoWindowClass()
+{
+    const LPCWSTR kVideoWindowClassName = L"WebVideoWindowClass";
+
+    static bool haveRegisteredWindowClass = false;
+    if (haveRegisteredWindowClass)
+        return kVideoWindowClassName;
+
+    haveRegisteredWindowClass = true;
+
+    WNDCLASSEX wcex;
+
+    wcex.cbSize = sizeof(WNDCLASSEX);
+
+    wcex.style = CS_DBLCLKS;
+    wcex.lpfnWndProc = VideoViewWndProc;
+    wcex.cbClsExtra = 0;
+    wcex.cbWndExtra = 0;
+    wcex.hInstance = nullptr;
+    wcex.hIcon = nullptr;
+    wcex.hCursor = ::LoadCursor(0, IDC_ARROW);
+    wcex.hbrBackground = nullptr;
+    wcex.lpszMenuName = nullptr;
+    wcex.lpszClassName = kVideoWindowClassName;
+    wcex.hIconSm = nullptr;
+
+    if (RegisterClassEx(&wcex))
+        return kVideoWindowClassName;
+
+    return nullptr;
+}
+
+void MediaPlayerPrivateMediaFoundation::createVideoWindow()
+{
+    HWND hWndParent = nullptr;
+    FrameView* view = nullptr;
+    if (!m_player || !m_player->cachedResourceLoader() || !m_player->cachedResourceLoader()->document())
+        return;
+    view = m_player->cachedResourceLoader()->document()->view();
+    if (!view || !view->hostWindow())
+        return;
+    hWndParent = view->hostWindow()->platformPageClient();
+
+    m_hwndVideo = CreateWindowEx(WS_EX_NOACTIVATE | WS_EX_TRANSPARENT, registerVideoWindowClass(), 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+        0, 0, 0, 0, hWndParent, 0, 0, 0);
+}
+
+void MediaPlayerPrivateMediaFoundation::destroyVideoWindow()
+{
+    if (m_hwndVideo) {
+        DestroyWindow(m_hwndVideo);
+        m_hwndVideo = nullptr;
+    }
+}
+
+bool MediaPlayerPrivateMediaFoundation::createOutputNode(COMPtr<IMFStreamDescriptor> sourceSD, COMPtr<IMFTopologyNode>& node)
+{
+    if (!sourceSD)
+        return false;
+
+#ifndef NDEBUG
+    // Get the stream ID.
+    DWORD streamID = 0;
+    sourceSD->GetStreamIdentifier(&streamID); // Just for debugging, ignore any failures.
+#endif
+
+    COMPtr<IMFMediaTypeHandler> handler;
+    if (FAILED(sourceSD->GetMediaTypeHandler(&handler)))
+        return false;
+
+    GUID guidMajorType = GUID_NULL;
+    if (FAILED(handler->GetMajorType(&guidMajorType)))
+        return false;
+
+    // Create a downstream node.
+    if (FAILED(MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &node)))
+        return false;
+
+    // Create an IMFActivate object for the renderer, based on the media type.
+    COMPtr<IMFActivate> rendererActivate;
+    if (MFMediaType_Audio == guidMajorType) {
+        // Create the audio renderer.
+        if (FAILED(MFCreateAudioRendererActivate(&rendererActivate)))
+            return false;
+        m_hasAudio = true;
+    } else if (MFMediaType_Video == guidMajorType) {
+        // Create the video renderer.
+        if (FAILED(MFCreateVideoRendererActivate(m_hwndVideo, &rendererActivate)))
+            return false;
+        m_hasVideo = true;
+    } else
+        return false;
+
+    // Set the IActivate object on the output node.
+    if (FAILED(node->SetObject(rendererActivate.get())))
+        return false;
+
+    return true;
+}
+
+bool MediaPlayerPrivateMediaFoundation::createSourceStreamNode(COMPtr<IMFStreamDescriptor> sourceSD, COMPtr<IMFTopologyNode>& node)
+{
+    if (!m_mediaSource || !m_sourcePD || !sourceSD)
+        return false;
+
+    // Create the source-stream node.
+    HRESULT hr = MFCreateTopologyNode(MF_TOPOLOGY_SOURCESTREAM_NODE, &node);
+    if (FAILED(hr))
+        return false;
+
+    // Set attribute: Pointer to the media source.
+    hr = node->SetUnknown(MF_TOPONODE_SOURCE, m_mediaSource.get());
+    if (FAILED(hr))
+        return false;
+
+    // Set attribute: Pointer to the presentation descriptor.
+    hr = node->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, m_sourcePD.get());
+    if (FAILED(hr))
+        return false;
+
+    // Set attribute: Pointer to the stream descriptor.
+    hr = node->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, sourceSD.get());
+    if (FAILED(hr))
+        return false;
+
+    return true;
+}
+
+void MediaPlayerPrivateMediaFoundation::onCreatedMediaSource()
+{
+    if (!createTopologyFromSource())
+        return;
+
+    // Set the topology on the media session.
+    HRESULT hr = m_mediaSession->SetTopology(0, m_topology.get());
+    ASSERT(SUCCEEDED(hr));
+}
+
+void MediaPlayerPrivateMediaFoundation::onTopologySet()
+{
+    if (FAILED(MFGetService(m_mediaSession.get(), MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_videoDisplay))))
+        return;
+
+    ASSERT(m_videoDisplay);
+
+    RECT rc = { 0, 0, m_size.width(), m_size.height() };
+    m_videoDisplay->SetVideoPosition(nullptr, &rc);
+
+    m_readyState = MediaPlayer::HaveFutureData;
+
+    ASSERT(m_player);
+    m_player->readyStateChanged();
+
+    play();
+    m_player->playbackStateChanged();
+}
+
+MediaPlayerPrivateMediaFoundation::AsyncCallback::AsyncCallback(MediaPlayerPrivateMediaFoundation* mediaPlayer, bool event)
+    : m_refCount(0)
+    , m_mediaPlayer(mediaPlayer)
+    , m_event(event)
+{
+}
+
+MediaPlayerPrivateMediaFoundation::AsyncCallback::~AsyncCallback()
+{
+}
+
+HRESULT MediaPlayerPrivateMediaFoundation::AsyncCallback::QueryInterface(REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
+{
+    if (!IsEqualGUID(riid, IID_IMFAsyncCallback)) {
+        *ppvObject = nullptr;
+        return E_NOINTERFACE;
+    }
+    *ppvObject = this;
+    AddRef();
+    return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::AddRef()
+{
+    m_refCount++;
+    return m_refCount;
+}
+
+ULONG STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::Release()
+{
+    m_refCount--;
+    ULONG refCount = m_refCount;
+    if (!refCount)
+        delete this;
+    return refCount;
+}
+
+HRESULT STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::GetParameters(__RPC__out DWORD *pdwFlags, __RPC__out DWORD *pdwQueue)
+{
+    // Returning E_NOTIMPL gives default values.
+    return E_NOTIMPL;
+}
+
+HRESULT STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::Invoke(__RPC__in_opt IMFAsyncResult *pAsyncResult)
+{
+    if (m_event)
+        m_mediaPlayer->endGetEvent(pAsyncResult);
+    else
+        m_mediaPlayer->endCreatedMediaSource(pAsyncResult);
+
+    return S_OK;
+}
+
 }
 
 #endif
index b9ae0c5..eed8981 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "COMPtr.h"
 #include "MediaPlayerPrivate.h"
 
+#include <Mfapi.h>
+#include <Mfidl.h>
+#include <evr.h>
+
 namespace WebCore {
 
 class MediaPlayerPrivateMediaFoundation : public MediaPlayerPrivateInterface {
 public:
     MediaPlayerPrivateMediaFoundation(MediaPlayer*);
+    ~MediaPlayerPrivateMediaFoundation();
     static void registerMediaEngine(MediaEngineRegistrar);
 
     static PassOwnPtr<MediaPlayerPrivateInterface> create(MediaPlayer*);
@@ -67,8 +73,60 @@ public:
     virtual void paint(GraphicsContext*, const IntRect&);
 
 private:
-
     MediaPlayer* m_player;
+    IntSize m_size;
+    bool m_visible;
+    bool m_loadingProgress;
+    bool m_paused;
+    bool m_hasAudio;
+    bool m_hasVideo;
+    HWND m_hwndVideo;
+    MediaPlayer::ReadyState m_readyState;
+    IntRect m_lastPaintRect;
+
+    COMPtr<IMFMediaSession> m_mediaSession;
+    COMPtr<IMFSourceResolver> m_sourceResolver;
+    COMPtr<IMFMediaSource> m_mediaSource;
+    COMPtr<IMFTopology> m_topology;
+    COMPtr<IMFPresentationDescriptor> m_sourcePD;
+    COMPtr<IMFVideoDisplayControl> m_videoDisplay;
+
+    bool createSession();
+    bool endSession();
+    bool startCreateMediaSource(const String& url);
+    bool endCreatedMediaSource(IMFAsyncResult*);
+    bool endGetEvent(IMFAsyncResult*);
+    bool createTopologyFromSource();
+    bool addBranchToPartialTopology(int stream);
+    bool createOutputNode(COMPtr<IMFStreamDescriptor> sourceSD, COMPtr<IMFTopologyNode>&);
+    bool createSourceStreamNode(COMPtr<IMFStreamDescriptor> sourceSD, COMPtr<IMFTopologyNode>&);
+
+    void onCreatedMediaSource();
+    void onTopologySet();
+
+    LPCWSTR registerVideoWindowClass();
+    void createVideoWindow();
+    void destroyVideoWindow();
+
+    static LRESULT CALLBACK VideoViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+    class AsyncCallback : public IMFAsyncCallback {
+    public:
+        AsyncCallback(MediaPlayerPrivateMediaFoundation*, bool event);
+        ~AsyncCallback();
+
+        virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject) override;
+        virtual ULONG STDMETHODCALLTYPE AddRef() override;
+        virtual ULONG STDMETHODCALLTYPE Release() override;
+
+        virtual HRESULT STDMETHODCALLTYPE GetParameters(__RPC__out DWORD *pdwFlags, __RPC__out DWORD *pdwQueue) override;
+        virtual HRESULT STDMETHODCALLTYPE Invoke(__RPC__in_opt IMFAsyncResult *pAsyncResult) override;
+
+    private:
+        ULONG m_refCount;
+        MediaPlayerPrivateMediaFoundation* m_mediaPlayer;
+        bool m_event;
+    };
 
 };
 
index 6353799..742a5a0 100644 (file)
@@ -1,3 +1,14 @@
+2015-01-19  peavo@outlook.com  <peavo@outlook.com>
+
+        [WinCairo][Video] Windows Media Foundation implementation is not completed.
+        https://bugs.webkit.org/show_bug.cgi?id=140337
+
+        Reviewed by Alex Christensen.
+
+        Link with Media Foundation libraries.
+
+        * win/tools/vsprops/WinCairo.props:
+
 2015-01-01  Jeff Miller  <jeffm@apple.com>
 
         Update user-visible copyright strings to include 2015
index 953a317..7d998d9 100644 (file)
@@ -9,7 +9,7 @@
       <PreprocessorDefinitions>WIN_CAIRO=1;WTF_PLATFORM_WIN_CAIRO=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
     <Link>
-      <AdditionalDependencies>cairo.lib;libjpeg.lib;zdll.lib;libpng.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>cairo.lib;libjpeg.lib;zdll.lib;libpng.lib;Mf.lib;Mfplat.lib;Mfuuid.lib;strmiids.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>$(WebKit_Libraries)\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Link>
   </ItemDefinitionGroup>