Unreviewed, roll out http://trac.webkit.org/changeset/187972.
[WebKit-https.git] / Source / WebCore / platform / graphics / win / MediaPlayerPrivateMediaFoundation.cpp
1 /*
2  * Copyright (C) 2014 Alex Christensen <achristensen@webkit.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28 #include "MediaPlayerPrivateMediaFoundation.h"
29
30 #include "CachedResourceLoader.h"
31 #include "FrameView.h"
32 #include "GraphicsContext.h"
33 #include "HostWindow.h"
34 #include "NotImplemented.h"
35 #include "SoftLinking.h"
36
37 #if USE(MEDIA_FOUNDATION)
38
39 #include <wtf/MainThread.h>
40
41 SOFT_LINK_LIBRARY(Mf);
42 SOFT_LINK_OPTIONAL(Mf, MFCreateSourceResolver, HRESULT, STDAPICALLTYPE, (IMFSourceResolver**));
43 SOFT_LINK_OPTIONAL(Mf, MFCreateMediaSession, HRESULT, STDAPICALLTYPE, (IMFAttributes*, IMFMediaSession**));
44 SOFT_LINK_OPTIONAL(Mf, MFCreateTopology, HRESULT, STDAPICALLTYPE, (IMFTopology**));
45 SOFT_LINK_OPTIONAL(Mf, MFCreateTopologyNode, HRESULT, STDAPICALLTYPE, (MF_TOPOLOGY_TYPE, IMFTopologyNode**));
46 SOFT_LINK_OPTIONAL(Mf, MFGetService, HRESULT, STDAPICALLTYPE, (IUnknown*, REFGUID, REFIID, LPVOID*));
47 SOFT_LINK_OPTIONAL(Mf, MFCreateAudioRendererActivate, HRESULT, STDAPICALLTYPE, (IMFActivate**));
48 SOFT_LINK_OPTIONAL(Mf, MFCreateVideoRendererActivate, HRESULT, STDAPICALLTYPE, (HWND, IMFActivate**));
49
50 SOFT_LINK_LIBRARY(Mfplat);
51 SOFT_LINK_OPTIONAL(Mfplat, MFStartup, HRESULT, STDAPICALLTYPE, (ULONG, DWORD));
52 SOFT_LINK_OPTIONAL(Mfplat, MFShutdown, HRESULT, STDAPICALLTYPE, ());
53
54 namespace WebCore {
55
56 MediaPlayerPrivateMediaFoundation::MediaPlayerPrivateMediaFoundation(MediaPlayer* player) 
57     : m_player(player)
58     , m_visible(false)
59     , m_loadingProgress(false)
60     , m_paused(false)
61     , m_hasAudio(false)
62     , m_hasVideo(false)
63     , m_hwndVideo(nullptr)
64     , m_readyState(MediaPlayer::HaveNothing)
65     , m_mediaSession(nullptr)
66     , m_sourceResolver(nullptr)
67     , m_mediaSource(nullptr)
68     , m_topology(nullptr)
69     , m_sourcePD(nullptr)
70     , m_videoDisplay(nullptr)
71 {
72     createSession();
73     createVideoWindow();
74 }
75
76 MediaPlayerPrivateMediaFoundation::~MediaPlayerPrivateMediaFoundation()
77 {
78     notifyDeleted();
79     destroyVideoWindow();
80     endSession();
81     cancelCallOnMainThread(onTopologySetCallback, this);
82     cancelCallOnMainThread(onCreatedMediaSourceCallback, this);
83 }
84
85 void MediaPlayerPrivateMediaFoundation::registerMediaEngine(MediaEngineRegistrar registrar)
86 {
87     if (isAvailable())
88         registrar([](MediaPlayer* player) { return std::make_unique<MediaPlayerPrivateMediaFoundation>(player); },
89             getSupportedTypes, supportsType, 0, 0, 0, 0);
90 }
91
92 bool MediaPlayerPrivateMediaFoundation::isAvailable() 
93 {
94     notImplemented();
95     return true;
96 }
97
98 void MediaPlayerPrivateMediaFoundation::getSupportedTypes(HashSet<String>& types)
99 {
100     types.add(String("video/mp4"));
101 }
102
103 MediaPlayer::SupportsType MediaPlayerPrivateMediaFoundation::supportsType(const MediaEngineSupportParameters& parameters)
104 {
105     if (parameters.type.isNull() || parameters.type.isEmpty())
106         return MediaPlayer::IsNotSupported;
107
108     if (parameters.type == "video/mp4")
109         return MediaPlayer::IsSupported;
110
111     return MediaPlayer::IsNotSupported;
112 }
113
114 void MediaPlayerPrivateMediaFoundation::load(const String& url)
115 {
116     startCreateMediaSource(url);
117 }
118
119 void MediaPlayerPrivateMediaFoundation::cancelLoad()
120 {
121     notImplemented();
122 }
123
124 void MediaPlayerPrivateMediaFoundation::play()
125 {
126     if (!m_mediaSession)
127         return;
128
129     PROPVARIANT varStart;
130     PropVariantInit(&varStart);
131     varStart.vt = VT_EMPTY;
132
133     HRESULT hr = m_mediaSession->Start(nullptr, &varStart);
134     ASSERT(SUCCEEDED(hr));
135
136     PropVariantClear(&varStart);
137
138     m_paused = !SUCCEEDED(hr);
139 }
140
141 void MediaPlayerPrivateMediaFoundation::pause()
142 {
143     if (!m_mediaSession)
144         return;
145
146     m_paused = SUCCEEDED(m_mediaSession->Pause());
147 }
148
149 FloatSize MediaPlayerPrivateMediaFoundation::naturalSize() const 
150 {
151     return m_size;
152 }
153
154 bool MediaPlayerPrivateMediaFoundation::hasVideo() const
155 {
156     return m_hasVideo;
157 }
158
159 bool MediaPlayerPrivateMediaFoundation::hasAudio() const
160 {
161     return m_hasAudio;
162 }
163
164 void MediaPlayerPrivateMediaFoundation::setVisible(bool visible)
165 {
166     m_visible = visible;
167 }
168
169 bool MediaPlayerPrivateMediaFoundation::seeking() const
170 {
171     // We assume seeking is immediately complete.
172     return false;
173 }
174
175 void MediaPlayerPrivateMediaFoundation::seekDouble(double time)
176 {
177     const double tenMegahertz = 10000000;
178     PROPVARIANT propVariant;
179     PropVariantInit(&propVariant);
180     propVariant.vt = VT_I8;
181     propVariant.hVal.QuadPart = static_cast<__int64>(time * tenMegahertz);
182     
183     HRESULT hr = m_mediaSession->Start(&GUID_NULL, &propVariant);
184     ASSERT(SUCCEEDED(hr));
185     PropVariantClear(&propVariant);
186 }
187
188 double MediaPlayerPrivateMediaFoundation::durationDouble() const
189 {
190     const double tenMegahertz = 10000000;
191     if (!m_mediaSource)
192         return 0;
193
194     IMFPresentationDescriptor* descriptor;
195     if (!SUCCEEDED(m_mediaSource->CreatePresentationDescriptor(&descriptor)))
196         return 0;
197     
198     UINT64 duration;
199     if (!SUCCEEDED(descriptor->GetUINT64(MF_PD_DURATION, &duration)))
200         duration = 0;
201     descriptor->Release();
202     
203     return static_cast<double>(duration) / tenMegahertz;
204 }
205
206 bool MediaPlayerPrivateMediaFoundation::paused() const
207 {
208     return m_paused;
209 }
210
211 MediaPlayer::NetworkState MediaPlayerPrivateMediaFoundation::networkState() const
212
213     notImplemented();
214     return MediaPlayer::Empty;
215 }
216
217 MediaPlayer::ReadyState MediaPlayerPrivateMediaFoundation::readyState() const
218 {
219     return m_readyState;
220 }
221
222 std::unique_ptr<PlatformTimeRanges> MediaPlayerPrivateMediaFoundation::buffered() const
223
224     notImplemented();
225     return std::make_unique<PlatformTimeRanges>();
226 }
227
228 bool MediaPlayerPrivateMediaFoundation::didLoadingProgress() const
229 {
230     return m_loadingProgress;
231 }
232
233 void MediaPlayerPrivateMediaFoundation::setSize(const IntSize& size)
234 {
235     m_size = size;
236
237     if (!m_videoDisplay)
238         return;
239
240     LayoutSize scrollOffset;
241     IntPoint positionInWindow(m_lastPaintRect.location());
242
243     FrameView* view = nullptr;
244     if (m_player && m_player->cachedResourceLoader() && m_player->cachedResourceLoader()->document())
245         view = m_player->cachedResourceLoader()->document()->view();
246
247     if (view) {
248         scrollOffset = view->scrollOffsetForFixedPosition();
249         positionInWindow = view->convertToContainingWindow(IntPoint(m_lastPaintRect.location()));
250     }
251
252     positionInWindow.move(-scrollOffset.width().toInt(), -scrollOffset.height().toInt());
253
254     if (m_hwndVideo && !m_lastPaintRect.isEmpty())
255         ::MoveWindow(m_hwndVideo, positionInWindow.x(), positionInWindow.y(), m_size.width(), m_size.height(), FALSE);
256
257     RECT rc = { 0, 0, m_size.width(), m_size.height() };
258     m_videoDisplay->SetVideoPosition(nullptr, &rc);
259 }
260
261 void MediaPlayerPrivateMediaFoundation::paint(GraphicsContext* context, const FloatRect& rect)
262 {
263     if (context->paintingDisabled()
264         || !m_player->visible())
265         return;
266
267     m_lastPaintRect = rect;
268
269     // We currently let Media Foundation handle the drawing, by providing a handle to the window to draw in.
270     // We should instead read individual frames from the stream, and paint them into the graphics context here.
271
272     notImplemented();
273 }
274
275 bool MediaPlayerPrivateMediaFoundation::createSession()
276 {
277     if (!MFStartupPtr() || !MFCreateMediaSessionPtr())
278         return false;
279
280     if (FAILED(MFStartupPtr()(MF_VERSION, MFSTARTUP_FULL)))
281         return false;
282
283     if (FAILED(MFCreateMediaSessionPtr()(nullptr, &m_mediaSession)))
284         return false;
285
286     // Get next event.
287     AsyncCallback* callback = new AsyncCallback(this, true);
288     HRESULT hr = m_mediaSession->BeginGetEvent(callback, nullptr);
289     ASSERT(SUCCEEDED(hr));
290
291     return true;
292 }
293
294 bool MediaPlayerPrivateMediaFoundation::endSession()
295 {
296     if (m_mediaSession) {
297         m_mediaSession->Shutdown();
298         m_mediaSession = nullptr;
299     }
300
301     if (!MFShutdownPtr())
302         return false;
303
304     HRESULT hr = MFShutdownPtr()();
305     ASSERT(SUCCEEDED(hr));
306
307     return true;
308 }
309
310 bool MediaPlayerPrivateMediaFoundation::startCreateMediaSource(const String& url)
311 {
312     if (!MFCreateSourceResolverPtr())
313         return false;
314
315     if (FAILED(MFCreateSourceResolverPtr()(&m_sourceResolver)))
316         return false;
317
318     COMPtr<IUnknown> cancelCookie;
319     Vector<UChar> urlSource = url.charactersWithNullTermination();
320
321     AsyncCallback* callback = new AsyncCallback(this, false);
322
323     if (FAILED(m_sourceResolver->BeginCreateObjectFromURL(urlSource.data(), MF_RESOLUTION_MEDIASOURCE, nullptr, &cancelCookie, callback, nullptr)))
324         return false;
325
326     return true;
327 }
328
329 bool MediaPlayerPrivateMediaFoundation::endCreatedMediaSource(IMFAsyncResult* asyncResult)
330 {
331     MF_OBJECT_TYPE objectType;
332     COMPtr<IUnknown> source;
333
334     HRESULT hr = m_sourceResolver->EndCreateObjectFromURL(asyncResult, &objectType, &source);
335     if (FAILED(hr))
336         return false;
337
338     hr = source->QueryInterface(IID_PPV_ARGS(&m_mediaSource));
339     if (FAILED(hr))
340         return false;
341
342     hr = asyncResult->GetStatus();
343     m_loadingProgress = SUCCEEDED(hr);
344
345     callOnMainThread(onCreatedMediaSourceCallback, this);
346
347     return true;
348 }
349
350 bool MediaPlayerPrivateMediaFoundation::endGetEvent(IMFAsyncResult* asyncResult)
351 {
352     COMPtr<IMFMediaEvent> event;
353
354     if (!m_mediaSession)
355         return false;
356
357     // Get the event from the event queue.
358     HRESULT hr = m_mediaSession->EndGetEvent(asyncResult, &event);
359     if (FAILED(hr))
360         return false;
361
362     // Get the event type.
363     MediaEventType mediaEventType;
364     hr = event->GetType(&mediaEventType);
365     if (FAILED(hr))
366         return false;
367
368     switch (mediaEventType) {
369     case MESessionTopologySet:
370         callOnMainThread(onTopologySetCallback, this);
371         break;
372
373     case MESessionClosed:
374         break;
375     }
376
377     if (mediaEventType != MESessionClosed) {
378         // For all other events, ask the media session for the
379         // next event in the queue.
380         AsyncCallback* callback = new AsyncCallback(this, true);
381
382         hr = m_mediaSession->BeginGetEvent(callback, nullptr);
383         if (FAILED(hr))
384             return false;
385     }
386
387     return true;
388 }
389
390 bool MediaPlayerPrivateMediaFoundation::createTopologyFromSource()
391 {
392     if (!MFCreateTopologyPtr())
393         return false;
394
395     // Create a new topology.
396     if (FAILED(MFCreateTopologyPtr()(&m_topology)))
397         return false;
398
399     // Create the presentation descriptor for the media source.
400     if (FAILED(m_mediaSource->CreatePresentationDescriptor(&m_sourcePD)))
401         return false;
402
403     // Get the number of streams in the media source.
404     DWORD sourceStreams = 0;
405     if (FAILED(m_sourcePD->GetStreamDescriptorCount(&sourceStreams)))
406         return false;
407
408     // For each stream, create the topology nodes and add them to the topology.
409     for (DWORD i = 0; i < sourceStreams; i++) {
410         if (!addBranchToPartialTopology(i))
411             return false;
412     }
413
414     return true;
415 }
416
417 bool MediaPlayerPrivateMediaFoundation::addBranchToPartialTopology(int stream)
418 {
419     // Get the stream descriptor for this stream.
420     COMPtr<IMFStreamDescriptor> sourceSD;
421     BOOL selected = FALSE;
422     if (FAILED(m_sourcePD->GetStreamDescriptorByIndex(stream, &selected, &sourceSD)))
423         return false;
424
425     // Create the topology branch only if the stream is selected.
426     // Otherwise, do nothing.
427     if (!selected)
428         return true;
429
430     // Create a source node for this stream.
431     COMPtr<IMFTopologyNode> sourceNode;
432     if (!createSourceStreamNode(sourceSD, sourceNode))
433         return false;
434
435     COMPtr<IMFTopologyNode> outputNode;
436     if (!createOutputNode(sourceSD, outputNode))
437         return false;
438
439     // Add both nodes to the topology.
440     if (FAILED(m_topology->AddNode(sourceNode.get())))
441         return false;
442
443     if (FAILED(m_topology->AddNode(outputNode.get())))
444         return false;
445
446     // Connect the source node to the output node.
447     if (FAILED(sourceNode->ConnectOutput(0, outputNode.get(), 0)))
448         return false;
449
450     return true;
451 }
452
453 LRESULT CALLBACK MediaPlayerPrivateMediaFoundation::VideoViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
454 {
455     return DefWindowProc(hWnd, message, wParam, lParam);
456 }
457
458 LPCWSTR MediaPlayerPrivateMediaFoundation::registerVideoWindowClass()
459 {
460     const LPCWSTR kVideoWindowClassName = L"WebVideoWindowClass";
461
462     static bool haveRegisteredWindowClass = false;
463     if (haveRegisteredWindowClass)
464         return kVideoWindowClassName;
465
466     haveRegisteredWindowClass = true;
467
468     WNDCLASSEX wcex;
469
470     wcex.cbSize = sizeof(WNDCLASSEX);
471
472     wcex.style = CS_DBLCLKS;
473     wcex.lpfnWndProc = VideoViewWndProc;
474     wcex.cbClsExtra = 0;
475     wcex.cbWndExtra = 0;
476     wcex.hInstance = nullptr;
477     wcex.hIcon = nullptr;
478     wcex.hCursor = ::LoadCursor(0, IDC_ARROW);
479     wcex.hbrBackground = nullptr;
480     wcex.lpszMenuName = nullptr;
481     wcex.lpszClassName = kVideoWindowClassName;
482     wcex.hIconSm = nullptr;
483
484     if (RegisterClassEx(&wcex))
485         return kVideoWindowClassName;
486
487     return nullptr;
488 }
489
490 void MediaPlayerPrivateMediaFoundation::createVideoWindow()
491 {
492     HWND hWndParent = nullptr;
493     FrameView* view = nullptr;
494     if (!m_player || !m_player->cachedResourceLoader() || !m_player->cachedResourceLoader()->document())
495         return;
496     view = m_player->cachedResourceLoader()->document()->view();
497     if (!view || !view->hostWindow())
498         return;
499     hWndParent = view->hostWindow()->platformPageClient();
500
501     m_hwndVideo = CreateWindowEx(WS_EX_NOACTIVATE | WS_EX_TRANSPARENT, registerVideoWindowClass(), 0, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
502         0, 0, 0, 0, hWndParent, 0, 0, 0);
503 }
504
505 void MediaPlayerPrivateMediaFoundation::destroyVideoWindow()
506 {
507     if (m_hwndVideo) {
508         DestroyWindow(m_hwndVideo);
509         m_hwndVideo = nullptr;
510     }
511 }
512
513 void MediaPlayerPrivateMediaFoundation::addListener(MediaPlayerListener* listener)
514 {
515     MutexLocker locker(m_mutexListeners);
516
517     m_listeners.add(listener);
518 }
519
520 void MediaPlayerPrivateMediaFoundation::removeListener(MediaPlayerListener* listener)
521 {
522     MutexLocker locker(m_mutexListeners);
523
524     m_listeners.remove(listener);
525 }
526
527 void MediaPlayerPrivateMediaFoundation::notifyDeleted()
528 {
529     MutexLocker locker(m_mutexListeners);
530
531     for (HashSet<MediaPlayerListener*>::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
532         (*it)->onMediaPlayerDeleted();
533 }
534
535 bool MediaPlayerPrivateMediaFoundation::createOutputNode(COMPtr<IMFStreamDescriptor> sourceSD, COMPtr<IMFTopologyNode>& node)
536 {
537     if (!MFCreateTopologyNodePtr() || !MFCreateAudioRendererActivatePtr() || !MFCreateVideoRendererActivatePtr())
538         return false;
539
540     if (!sourceSD)
541         return false;
542
543 #ifndef NDEBUG
544     // Get the stream ID.
545     DWORD streamID = 0;
546     sourceSD->GetStreamIdentifier(&streamID); // Just for debugging, ignore any failures.
547 #endif
548
549     COMPtr<IMFMediaTypeHandler> handler;
550     if (FAILED(sourceSD->GetMediaTypeHandler(&handler)))
551         return false;
552
553     GUID guidMajorType = GUID_NULL;
554     if (FAILED(handler->GetMajorType(&guidMajorType)))
555         return false;
556
557     // Create a downstream node.
558     if (FAILED(MFCreateTopologyNodePtr()(MF_TOPOLOGY_OUTPUT_NODE, &node)))
559         return false;
560
561     // Create an IMFActivate object for the renderer, based on the media type.
562     COMPtr<IMFActivate> rendererActivate;
563     if (MFMediaType_Audio == guidMajorType) {
564         // Create the audio renderer.
565         if (FAILED(MFCreateAudioRendererActivatePtr()(&rendererActivate)))
566             return false;
567         m_hasAudio = true;
568     } else if (MFMediaType_Video == guidMajorType) {
569         // Create the video renderer.
570         if (FAILED(MFCreateVideoRendererActivatePtr()(m_hwndVideo, &rendererActivate)))
571             return false;
572         m_hasVideo = true;
573     } else
574         return false;
575
576     // Set the IActivate object on the output node.
577     if (FAILED(node->SetObject(rendererActivate.get())))
578         return false;
579
580     return true;
581 }
582
583 bool MediaPlayerPrivateMediaFoundation::createSourceStreamNode(COMPtr<IMFStreamDescriptor> sourceSD, COMPtr<IMFTopologyNode>& node)
584 {
585     if (!MFCreateTopologyNodePtr())
586         return false;
587
588     if (!m_mediaSource || !m_sourcePD || !sourceSD)
589         return false;
590
591     // Create the source-stream node.
592     HRESULT hr = MFCreateTopologyNodePtr()(MF_TOPOLOGY_SOURCESTREAM_NODE, &node);
593     if (FAILED(hr))
594         return false;
595
596     // Set attribute: Pointer to the media source.
597     hr = node->SetUnknown(MF_TOPONODE_SOURCE, m_mediaSource.get());
598     if (FAILED(hr))
599         return false;
600
601     // Set attribute: Pointer to the presentation descriptor.
602     hr = node->SetUnknown(MF_TOPONODE_PRESENTATION_DESCRIPTOR, m_sourcePD.get());
603     if (FAILED(hr))
604         return false;
605
606     // Set attribute: Pointer to the stream descriptor.
607     hr = node->SetUnknown(MF_TOPONODE_STREAM_DESCRIPTOR, sourceSD.get());
608     if (FAILED(hr))
609         return false;
610
611     return true;
612 }
613
614 void MediaPlayerPrivateMediaFoundation::onCreatedMediaSource()
615 {
616     if (!createTopologyFromSource())
617         return;
618
619     // Set the topology on the media session.
620     HRESULT hr = m_mediaSession->SetTopology(0, m_topology.get());
621     ASSERT(SUCCEEDED(hr));
622 }
623
624 void MediaPlayerPrivateMediaFoundation::onTopologySet()
625 {
626     if (!MFGetServicePtr())
627         return;
628
629     if (FAILED(MFGetServicePtr()(m_mediaSession.get(), MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_videoDisplay))))
630         return;
631
632     ASSERT(m_videoDisplay);
633
634     RECT rc = { 0, 0, m_size.width(), m_size.height() };
635     m_videoDisplay->SetVideoPosition(nullptr, &rc);
636
637     m_readyState = MediaPlayer::HaveFutureData;
638
639     ASSERT(m_player);
640     m_player->readyStateChanged();
641
642     play();
643     m_player->playbackStateChanged();
644 }
645
646 void MediaPlayerPrivateMediaFoundation::onCreatedMediaSourceCallback(void* context)
647 {
648     MediaPlayerPrivateMediaFoundation* mediaPlayer = static_cast<MediaPlayerPrivateMediaFoundation*>(context);
649     mediaPlayer->onCreatedMediaSource();
650 }
651
652 void MediaPlayerPrivateMediaFoundation::onTopologySetCallback(void* context)
653 {
654     MediaPlayerPrivateMediaFoundation* mediaPlayer = static_cast<MediaPlayerPrivateMediaFoundation*>(context);
655     mediaPlayer->onTopologySet();
656 }
657
658 MediaPlayerPrivateMediaFoundation::AsyncCallback::AsyncCallback(MediaPlayerPrivateMediaFoundation* mediaPlayer, bool event)
659     : m_refCount(0)
660     , m_mediaPlayer(mediaPlayer)
661     , m_event(event)
662 {
663     if (m_mediaPlayer)
664         m_mediaPlayer->addListener(this);
665 }
666
667 MediaPlayerPrivateMediaFoundation::AsyncCallback::~AsyncCallback()
668 {
669     if (m_mediaPlayer)
670         m_mediaPlayer->removeListener(this);
671 }
672
673 HRESULT MediaPlayerPrivateMediaFoundation::AsyncCallback::QueryInterface(REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
674 {
675     if (!IsEqualGUID(riid, IID_IMFAsyncCallback)) {
676         *ppvObject = nullptr;
677         return E_NOINTERFACE;
678     }
679     *ppvObject = this;
680     AddRef();
681     return S_OK;
682 }
683
684 ULONG STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::AddRef()
685 {
686     m_refCount++;
687     return m_refCount;
688 }
689
690 ULONG STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::Release()
691 {
692     m_refCount--;
693     ULONG refCount = m_refCount;
694     if (!refCount)
695         delete this;
696     return refCount;
697 }
698
699 HRESULT STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::GetParameters(__RPC__out DWORD *pdwFlags, __RPC__out DWORD *pdwQueue)
700 {
701     // Returning E_NOTIMPL gives default values.
702     return E_NOTIMPL;
703 }
704
705 HRESULT STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::Invoke(__RPC__in_opt IMFAsyncResult *pAsyncResult)
706 {
707     MutexLocker locker(m_mutex);
708
709     if (!m_mediaPlayer)
710         return S_OK;
711
712     if (m_event)
713         m_mediaPlayer->endGetEvent(pAsyncResult);
714     else
715         m_mediaPlayer->endCreatedMediaSource(pAsyncResult);
716
717     return S_OK;
718 }
719
720 void MediaPlayerPrivateMediaFoundation::AsyncCallback::onMediaPlayerDeleted()
721 {
722     MutexLocker locker(m_mutex);
723
724     m_mediaPlayer = nullptr;
725 }
726
727 }
728
729 #endif