⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 293765 in webkit


Ignore:
Timestamp:
May 4, 2022, 1:31:55 AM (4 years ago)
Author:
Fujii Hironori
Message:

[WinCairo] Crash during MediaPlayerPrivateMediaFoundation::removeListener in the async callback thread
​https://bugs.webkit.org/show_bug.cgi?id=239485

Reviewed by Don Olmstead.

WinCairo debug layout tests were observing a random crash while
MediaPlayerPrivateMediaFoundation::AsyncCallback was destructing.

m_mediaPlayer was being accessed without locking m_mutex in
~AsyncCallback.

m_mediaPlayer can be replaced with using a WeakPtr.

There is one more multi-threading problem. IMFAsyncCallback should
use InterlockedIncrement and InterlockedDecrement for
ref-counting.
Implementing the Asynchronous Callback - Win32 apps | Microsoft Docs
<​https://docs.microsoft.com/en-us/windows/win32/medfound/implementing-the-asynchronous-callback>

This change re-implemented AsyncCallback with a WeakPtr, Function,
QISearch and Interlocked{In,De}crement.

  • platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp:

(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::AsyncCallback):
(WebCore::beginGetEvent):
(WebCore::MediaPlayerPrivateMediaFoundation::createSession):
(WebCore::MediaPlayerPrivateMediaFoundation::startCreateMediaSource):
(WebCore::MediaPlayerPrivateMediaFoundation::onCreatedMediaSource):
(WebCore::MediaPlayerPrivateMediaFoundation::onNetworkStateChanged):
(WebCore::MediaPlayerPrivateMediaFoundation::endCreatedMediaSource): Deleted.
(WebCore::MediaPlayerPrivateMediaFoundation::endGetEvent): Deleted.
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::~AsyncCallback): Deleted.
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::QueryInterface): Deleted.
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::AddRef): Deleted.
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::Release): Deleted.
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::GetParameters): Deleted.
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::Invoke): Deleted.
(WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::onMediaPlayerDeleted): Deleted.

  • platform/graphics/win/MediaPlayerPrivateMediaFoundation.h:
Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r293757 r293765  
     12022-05-04  Fujii Hironori  <Hironori.Fujii@sony.com>
     2
     3        [WinCairo] Crash during MediaPlayerPrivateMediaFoundation::removeListener in the async callback thread
     4        https://bugs.webkit.org/show_bug.cgi?id=239485
     5
     6        Reviewed by Don Olmstead.
     7
     8        WinCairo debug layout tests were observing a random crash while
     9        MediaPlayerPrivateMediaFoundation::AsyncCallback was destructing.
     10
     11        m_mediaPlayer was being accessed without locking m_mutex in
     12        ~AsyncCallback.
     13
     14        m_mediaPlayer can be replaced with using a WeakPtr.
     15
     16        There is one more multi-threading problem. IMFAsyncCallback should
     17        use InterlockedIncrement and InterlockedDecrement for
     18        ref-counting.
     19        Implementing the Asynchronous Callback - Win32 apps | Microsoft Docs
     20        <https://docs.microsoft.com/en-us/windows/win32/medfound/implementing-the-asynchronous-callback>
     21
     22        This change re-implemented AsyncCallback with a WeakPtr, Function,
     23        QISearch and Interlocked{In,De}crement.
     24
     25        * platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp:
     26        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::AsyncCallback):
     27        (WebCore::beginGetEvent):
     28        (WebCore::MediaPlayerPrivateMediaFoundation::createSession):
     29        (WebCore::MediaPlayerPrivateMediaFoundation::startCreateMediaSource):
     30        (WebCore::MediaPlayerPrivateMediaFoundation::onCreatedMediaSource):
     31        (WebCore::MediaPlayerPrivateMediaFoundation::onNetworkStateChanged):
     32        (WebCore::MediaPlayerPrivateMediaFoundation::endCreatedMediaSource): Deleted.
     33        (WebCore::MediaPlayerPrivateMediaFoundation::endGetEvent): Deleted.
     34        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::~AsyncCallback): Deleted.
     35        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::QueryInterface): Deleted.
     36        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::AddRef): Deleted.
     37        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::Release): Deleted.
     38        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::GetParameters): Deleted.
     39        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::Invoke): Deleted.
     40        (WebCore::MediaPlayerPrivateMediaFoundation::AsyncCallback::onMediaPlayerDeleted): Deleted.
     41        * platform/graphics/win/MediaPlayerPrivateMediaFoundation.h:
     42
    1432022-05-03  Yusuke Suzuki  <ysuzuki@apple.com>
    244
  • trunk/Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp

    r292696 r293765  
    2828#include "MediaPlayerPrivateMediaFoundation.h"
    2929
     30#if USE(MEDIA_FOUNDATION)
     31
    3032#include "CachedResourceLoader.h"
    3133#include "FrameView.h"
    … …  
    3436#include "HostWindow.h"
    3537#include "NotImplemented.h"
     38#include <shlwapi.h>
     39#include <wtf/MainThread.h>
     40#include <wtf/NeverDestroyed.h>
     41
    3642#if USE(CAIRO)
    3743#include "CairoOperations.h"
    3844#include <cairo.h>
    3945#endif
    40 
    41 #if USE(MEDIA_FOUNDATION)
    42 
    43 #include <wtf/MainThread.h>
    44 #include <wtf/NeverDestroyed.h>
    4546
    4647// MFSamplePresenterSampleCounter
    … …  
    5657
    5758namespace WebCore {
     59
     60class MediaPlayerPrivateMediaFoundation::AsyncCallback : public IMFAsyncCallback {
     61    WTF_MAKE_FAST_ALLOCATED;
     62public:
     63    AsyncCallback(Function<void(IMFAsyncResult*)>&& callback)
     64        : m_callback(WTFMove(callback))
     65    {
     66    }
     67
     68    HRESULT STDMETHODCALLTYPE QueryInterface(_In_ REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject) override
     69    {
     70        static const QITAB qit[] = {
     71            QITABENT(AsyncCallback, IMFAsyncCallback),
     72            { }
     73        };
     74        return QISearch(this, qit, riid, ppvObject);
     75    }
     76
     77    ULONG STDMETHODCALLTYPE AddRef() override
     78    {
     79        return InterlockedIncrement(&m_refCount);
     80    }
     81
     82    ULONG STDMETHODCALLTYPE Release() override
     83    {
     84        long refCount = InterlockedDecrement(&m_refCount);
     85        if (!refCount)
     86            delete this;
     87        return refCount;
     88    }
     89
     90    HRESULT STDMETHODCALLTYPE GetParameters(__RPC__out DWORD *pdwFlags, __RPC__out DWORD *pdwQueue) override
     91    {
     92        // Implementation of this method is optional. Returning E_NOTIMPL gives default values.
     93        return E_NOTIMPL;
     94    }
     95
     96    HRESULT STDMETHODCALLTYPE Invoke(__RPC__in_opt IMFAsyncResult *pAsyncResult) override
     97    {
     98        m_callback(pAsyncResult);
     99        return S_OK;
     100    }
     101
     102private:
     103    ULONG m_refCount { 1 };
     104    Function<void(IMFAsyncResult*)> m_callback;
     105};
    58106
    59107MediaPlayerPrivateMediaFoundation::MediaPlayerPrivateMediaFoundation(MediaPlayer* player)
    … …  
    364412}
    365413
     414HRESULT beginGetEvent(WeakPtr<MediaPlayerPrivateMediaFoundation> weakThis, COMPtr<IMFMediaSession> mediaSession)
     415{
     416    auto callback = adoptCOM(new MediaPlayerPrivateMediaFoundation::AsyncCallback([weakThis, mediaSession](IMFAsyncResult* asyncResult) {
     417        COMPtr<IMFMediaEvent> event;
     418
     419        // Get the event from the event queue.
     420        HRESULT hr = mediaSession->EndGetEvent(asyncResult, &event);
     421        if (FAILED(hr))
     422            return;
     423
     424        // Get the event type.
     425        MediaEventType mediaEventType;
     426        hr = event->GetType(&mediaEventType);
     427        if (FAILED(hr))
     428            return;
     429
     430        HRESULT status;
     431        hr = event->GetStatus(&status);
     432        if (FAILED(hr))
     433            return;
     434
     435        if (status == MF_E_TOPO_CODEC_NOT_FOUND) {
     436            callOnMainThread([weakThis] {
     437                if (!weakThis)
     438                    return;
     439                weakThis->onNetworkStateChanged(MediaPlayer::NetworkState::FormatError);
     440            });
     441            return;
     442        }
     443
     444        switch (mediaEventType) {
     445        case MESessionTopologySet: {
     446            callOnMainThread([weakThis] {
     447                if (!weakThis)
     448                    return;
     449                weakThis->onTopologySet();
     450            });
     451            break;
     452        }
     453
     454        case MESessionStarted: {
     455            callOnMainThread([weakThis] {
     456                if (!weakThis)
     457                    return;
     458                weakThis->onSessionStarted();
     459            });
     460            break;
     461        }
     462
     463        case MEBufferingStarted: {
     464            callOnMainThread([weakThis] {
     465                if (!weakThis)
     466                    return;
     467                weakThis->onBufferingStarted();
     468            });
     469            break;
     470        }
     471
     472        case MEBufferingStopped: {
     473            callOnMainThread([weakThis] {
     474                if (!weakThis)
     475                    return;
     476                weakThis->onBufferingStopped();
     477            });
     478            break;
     479        }
     480
     481        case MESessionEnded: {
     482            callOnMainThread([weakThis] {
     483                if (!weakThis)
     484                    return;
     485                weakThis->onSessionEnded();
     486            });
     487            break;
     488        }
     489
     490        case MEMediaSample:
     491            break;
     492
     493        case MEError:
     494            callOnMainThread([weakThis] {
     495                if (!weakThis)
     496                    return;
     497                weakThis->onNetworkStateChanged(MediaPlayer::NetworkState::DecodeError);
     498            });
     499            return;
     500        }
     501
     502        if (mediaEventType != MESessionClosed) {
     503            // For all other events, ask the media session for the
     504            // next event in the queue.
     505            hr = beginGetEvent(weakThis, mediaSession.get());
     506            if (FAILED(hr))
     507                return;
     508        }
     509    }));
     510    return mediaSession->BeginGetEvent(callback.get(), nullptr);
     511}
     512
    366513bool MediaPlayerPrivateMediaFoundation::createSession()
    367514{
    … …  
    373520
    374521    // Get next event.
    375     AsyncCallback* callback = new AsyncCallback(this, true);
    376     HRESULT hr = m_mediaSession->BeginGetEvent(callback, nullptr);
     522    HRESULT hr = beginGetEvent(m_weakThis, m_mediaSession);
    377523    ASSERT_UNUSED(hr, SUCCEEDED(hr));
    378524
    … …  
    418564    Vector<wchar_t> urlSource = url.wideCharacters();
    419565
    420     AsyncCallback* callback = new AsyncCallback(this, false);
    421 
    422     if (FAILED(m_sourceResolver->BeginCreateObjectFromURL(urlSource.data(), MF_RESOLUTION_MEDIASOURCE, nullptr, &cancelCookie, callback, nullptr)))
     566    auto callback = adoptCOM(new AsyncCallback([this, weakThis = m_weakThis, sourceResolver = m_sourceResolver](IMFAsyncResult* asyncResult) {
     567        MF_OBJECT_TYPE objectType;
     568        COMPtr<IUnknown> source;
     569
     570        HRESULT hr = sourceResolver->EndCreateObjectFromURL(asyncResult, &objectType, &source);
     571        if (FAILED(hr)) {
     572            callOnMainThread([this, weakThis = weakThis, hr] {
     573                if (!weakThis)
     574                    return;
     575                onNetworkStateChanged(hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE ? MediaPlayer::NetworkState::FormatError : MediaPlayer::NetworkState::NetworkError);
     576            });
     577            return;
     578        }
     579
     580        COMPtr<IMFMediaSource> mediaSource;
     581        hr = source->QueryInterface(IID_PPV_ARGS(&mediaSource));
     582        if (FAILED(hr))
     583            return;
     584
     585        hr = asyncResult->GetStatus();
     586        bool loadingProgress = SUCCEEDED(hr);
     587
     588        callOnMainThread([this, weakThis, mediaSource = WTFMove(mediaSource), loadingProgress]() mutable {
     589            if (!weakThis)
     590                return;
     591            onCreatedMediaSource(WTFMove(mediaSource), loadingProgress);
     592        });
     593    }));
     594
     595    if (FAILED(m_sourceResolver->BeginCreateObjectFromURL(urlSource.data(), MF_RESOLUTION_MEDIASOURCE, nullptr, &cancelCookie, callback.get(), nullptr)))
    423596        return false;
    424 
    425     return true;
    426 }
    427 
    428 bool MediaPlayerPrivateMediaFoundation::endCreatedMediaSource(IMFAsyncResult* asyncResult)
    429 {
    430     MF_OBJECT_TYPE objectType;
    431     COMPtr<IUnknown> source;
    432 
    433     HRESULT hr = m_sourceResolver->EndCreateObjectFromURL(asyncResult, &objectType, &source);
    434     if (FAILED(hr)) {
    435         callOnMainThread([this, weakPtr = m_weakThis, hr] {
    436             if (!weakPtr)
    437                 return;
    438             if (hr == MF_E_UNSUPPORTED_BYTESTREAM_TYPE)
    439                 m_networkState = MediaPlayer::NetworkState::FormatError;
    440             else
    441                 m_networkState = MediaPlayer::NetworkState::NetworkError;
    442             m_player->networkStateChanged();
    443         });
    444         return false;
    445     }
    446 
    447     hr = source->QueryInterface(IID_PPV_ARGS(&m_mediaSource));
    448     if (FAILED(hr))
    449         return false;
    450 
    451     hr = asyncResult->GetStatus();
    452     m_loadingProgress = SUCCEEDED(hr);
    453 
    454     callOnMainThread([weakPtr = m_weakThis] {
    455         if (!weakPtr)
    456             return;
    457         weakPtr->onCreatedMediaSource();
    458     });
    459 
    460     return true;
    461 }
    462 
    463 bool MediaPlayerPrivateMediaFoundation::endGetEvent(IMFAsyncResult* asyncResult)
    464 {
    465     COMPtr<IMFMediaEvent> event;
    466 
    467     if (!m_mediaSession)
    468         return false;
    469 
    470     // Get the event from the event queue.
    471     HRESULT hr = m_mediaSession->EndGetEvent(asyncResult, &event);
    472     if (FAILED(hr))
    473         return false;
    474 
    475     // Get the event type.
    476     MediaEventType mediaEventType;
    477     hr = event->GetType(&mediaEventType);
    478     if (FAILED(hr))
    479         return false;
    480 
    481     HRESULT status;
    482     hr = event->GetStatus(&status);
    483     if (FAILED(hr))
    484         return false;
    485 
    486     if (status == MF_E_TOPO_CODEC_NOT_FOUND) {
    487         callOnMainThread([this, weakPtr = m_weakThis] {
    488             if (!weakPtr)
    489                 return;
    490             m_networkState = MediaPlayer::NetworkState::FormatError;
    491             m_player->networkStateChanged();
    492         });
    493         return false;
    494     }
    495 
    496     switch (mediaEventType) {
    497     case MESessionTopologySet: {
    498         callOnMainThread([weakPtr = m_weakThis] {
    499             if (!weakPtr)
    500                 return;
    501             weakPtr->onTopologySet();
    502         });
    503         break;
    504     }
    505 
    506     case MESessionStarted: {
    507         callOnMainThread([weakPtr = m_weakThis] {
    508             if (!weakPtr)
    509                 return;
    510             weakPtr->onSessionStarted();
    511         });
    512         break;
    513     }
    514 
    515     case MEBufferingStarted: {
    516         callOnMainThread([weakPtr = m_weakThis] {
    517             if (!weakPtr)
    518                 return;
    519             weakPtr->onBufferingStarted();
    520         });
    521         break;
    522     }
    523 
    524     case MEBufferingStopped: {
    525         callOnMainThread([weakPtr = m_weakThis] {
    526             if (!weakPtr)
    527                 return;
    528             weakPtr->onBufferingStopped();
    529         });
    530         break;
    531     }
    532 
    533     case MESessionEnded: {
    534         callOnMainThread([weakPtr = m_weakThis] {
    535             if (!weakPtr)
    536                 return;
    537             weakPtr->onSessionEnded();
    538         });
    539         break;
    540     }
    541 
    542     case MEMediaSample:
    543         break;
    544 
    545     case MEError:
    546         callOnMainThread([this, weakPtr = m_weakThis] {
    547             if (!weakPtr)
    548                 return;
    549             m_networkState = MediaPlayer::NetworkState::DecodeError;
    550             m_player->networkStateChanged();
    551         });
    552         return false;
    553     }
    554 
    555     if (mediaEventType != MESessionClosed) {
    556         // For all other events, ask the media session for the
    557         // next event in the queue.
    558         AsyncCallback* callback = new AsyncCallback(this, true);
    559 
    560         hr = m_mediaSession->BeginGetEvent(callback, nullptr);
    561         if (FAILED(hr))
    562             return false;
    563     }
    564597
    565598    return true;
    … …  
    796829}
    797830
    798 void MediaPlayerPrivateMediaFoundation::onCreatedMediaSource()
    799 {
     831void MediaPlayerPrivateMediaFoundation::onCreatedMediaSource(COMPtr<IMFMediaSource>&& mediaSource, bool loadingProgress)
     832{
     833    m_loadingProgress = loadingProgress;
     834    m_mediaSource = WTFMove(mediaSource);
     835
    800836    if (!createTopologyFromSource())
    801837        return;
    … …  
    804840    HRESULT hr = m_mediaSession->SetTopology(0, m_topology.get());
    805841    ASSERT_UNUSED(hr, SUCCEEDED(hr));
     842}
     843
     844void MediaPlayerPrivateMediaFoundation::onNetworkStateChanged(MediaPlayer::NetworkState state)
     845{
     846    m_networkState = state;
     847    m_player->networkStateChanged();
    806848}
    807849
    … …  
    855897
    856898    m_player->timeChanged();
    857 }
    858 
    859 MediaPlayerPrivateMediaFoundation::AsyncCallback::AsyncCallback(MediaPlayerPrivateMediaFoundation* mediaPlayer, bool event)
    860     : m_refCount(0)
    861     , m_mediaPlayer(mediaPlayer)
    862     , m_event(event)
    863 {
    864     if (m_mediaPlayer)
    865         m_mediaPlayer->addListener(this);
    866 }
    867 
    868 MediaPlayerPrivateMediaFoundation::AsyncCallback::~AsyncCallback()
    869 {
    870     if (m_mediaPlayer)
    871         m_mediaPlayer->removeListener(this);
    872 }
    873 
    874 HRESULT MediaPlayerPrivateMediaFoundation::AsyncCallback::QueryInterface(_In_ REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
    875 {
    876     if (!ppvObject)
    877         return E_POINTER;
    878     if (!IsEqualGUID(riid, IID_IMFAsyncCallback)) {
    879         *ppvObject = nullptr;
    880         return E_NOINTERFACE;
    881     }
    882     *ppvObject = this;
    883     AddRef();
    884     return S_OK;
    885 }
    886 
    887 ULONG STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::AddRef()
    888 {
    889     m_refCount++;
    890     return m_refCount;
    891 }
    892 
    893 ULONG STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::Release()
    894 {
    895     m_refCount--;
    896     ULONG refCount = m_refCount;
    897     if (!refCount)
    898         delete this;
    899     return refCount;
    900 }
    901 
    902 HRESULT STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::GetParameters(__RPC__out DWORD *pdwFlags, __RPC__out DWORD *pdwQueue)
    903 {
    904     // Returning E_NOTIMPL gives default values.
    905     return E_NOTIMPL;
    906 }
    907 
    908 HRESULT STDMETHODCALLTYPE MediaPlayerPrivateMediaFoundation::AsyncCallback::Invoke(__RPC__in_opt IMFAsyncResult *pAsyncResult)
    909 {
    910     Locker locker { m_mutex };
    911 
    912     if (!m_mediaPlayer)
    913         return S_OK;
    914 
    915     if (m_event)
    916         m_mediaPlayer->endGetEvent(pAsyncResult);
    917     else
    918         m_mediaPlayer->endCreatedMediaSource(pAsyncResult);
    919 
    920     return S_OK;
    921 }
    922 
    923 void MediaPlayerPrivateMediaFoundation::AsyncCallback::onMediaPlayerDeleted()
    924 {
    925     Locker locker { m_mutex };
    926 
    927     m_mediaPlayer = nullptr;
    928899}
    929900
  • trunk/Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.h

    r287948 r293765  
    103103    DestinationColorSpace colorSpace() final;
    104104
     105protected:
     106    void onCreatedMediaSource(COMPtr<IMFMediaSource>&&, bool loadingProgress);
     107    void onNetworkStateChanged(MediaPlayer::NetworkState);
     108    void onTopologySet();
     109    void onBufferingStarted();
     110    void onBufferingStopped();
     111    void onSessionStarted();
     112    void onSessionEnded();
     113
     114    friend HRESULT beginGetEvent(WeakPtr<MediaPlayerPrivateMediaFoundation>, COMPtr<IMFMediaSession>);
     115
    105116private:
    106117    float maxTimeLoaded() const { return m_maxTimeLoaded; }
    … …  
    139150    bool endSession();
    140151    bool startCreateMediaSource(const String& url);
    141     bool endCreatedMediaSource(IMFAsyncResult*);
    142     bool endGetEvent(IMFAsyncResult*);
    143152    bool createTopologyFromSource();
    144153    bool addBranchToPartialTopology(int stream);
    … …  
    150159    COMPtr<IMFVideoDisplayControl> videoDisplay();
    151160
    152     void onCreatedMediaSource();
    153     void onTopologySet();
    154     void onBufferingStarted();
    155     void onBufferingStopped();
    156     void onSessionStarted();
    157     void onSessionEnded();
    158 
    159161    HWND hostWindow();
    160162    void invalidateVideoArea();
    … …  
    175177    };
    176178
    177     class AsyncCallback : public IMFAsyncCallback, public MediaPlayerListener {
    178         WTF_MAKE_FAST_ALLOCATED;
    179     public:
    180         AsyncCallback(MediaPlayerPrivateMediaFoundation*, bool event);
    181         ~AsyncCallback();
    182 
    183         HRESULT STDMETHODCALLTYPE QueryInterface(_In_ REFIID riid, __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject) override;
    184         ULONG STDMETHODCALLTYPE AddRef() override;
    185         ULONG STDMETHODCALLTYPE Release() override;
    186 
    187         HRESULT STDMETHODCALLTYPE GetParameters(__RPC__out DWORD *pdwFlags, __RPC__out DWORD *pdwQueue) override;
    188         HRESULT STDMETHODCALLTYPE Invoke(__RPC__in_opt IMFAsyncResult *pAsyncResult) override;
    189 
    190         void onMediaPlayerDeleted() override;
    191 
    192     private:
    193         ULONG m_refCount;
    194         MediaPlayerPrivateMediaFoundation* m_mediaPlayer;
    195         bool m_event;
    196         Lock m_mutex;
    197     };
     179    class AsyncCallback;
    198180
    199181    typedef Deque<COMPtr<IMFSample>> VideoSampleList;
Note: See TracChangeset for help on using the changeset viewer.