Changeset 293765 in webkit
- Timestamp:
- May 4, 2022, 1:31:55 AM (4 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 edited
-
ChangeLog (modified) (1 diff)
-
platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp (modified) (9 diffs)
-
platform/graphics/win/MediaPlayerPrivateMediaFoundation.h (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r293757 r293765 1 2022-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 1 43 2022-05-03 Yusuke Suzuki <ysuzuki@apple.com> 2 44 -
trunk/Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.cpp
r292696 r293765 28 28 #include "MediaPlayerPrivateMediaFoundation.h" 29 29 30 #if USE(MEDIA_FOUNDATION) 31 30 32 #include "CachedResourceLoader.h" 31 33 #include "FrameView.h" … … 34 36 #include "HostWindow.h" 35 37 #include "NotImplemented.h" 38 #include <shlwapi.h> 39 #include <wtf/MainThread.h> 40 #include <wtf/NeverDestroyed.h> 41 36 42 #if USE(CAIRO) 37 43 #include "CairoOperations.h" 38 44 #include <cairo.h> 39 45 #endif 40 41 #if USE(MEDIA_FOUNDATION)42 43 #include <wtf/MainThread.h>44 #include <wtf/NeverDestroyed.h>45 46 46 47 // MFSamplePresenterSampleCounter … … 56 57 57 58 namespace WebCore { 59 60 class MediaPlayerPrivateMediaFoundation::AsyncCallback : public IMFAsyncCallback { 61 WTF_MAKE_FAST_ALLOCATED; 62 public: 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 102 private: 103 ULONG m_refCount { 1 }; 104 Function<void(IMFAsyncResult*)> m_callback; 105 }; 58 106 59 107 MediaPlayerPrivateMediaFoundation::MediaPlayerPrivateMediaFoundation(MediaPlayer* player) … … 364 412 } 365 413 414 HRESULT 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 366 513 bool MediaPlayerPrivateMediaFoundation::createSession() 367 514 { … … 373 520 374 521 // 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); 377 523 ASSERT_UNUSED(hr, SUCCEEDED(hr)); 378 524 … … 418 564 Vector<wchar_t> urlSource = url.wideCharacters(); 419 565 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))) 423 596 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 else441 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 the557 // 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 }564 597 565 598 return true; … … 796 829 } 797 830 798 void MediaPlayerPrivateMediaFoundation::onCreatedMediaSource() 799 { 831 void MediaPlayerPrivateMediaFoundation::onCreatedMediaSource(COMPtr<IMFMediaSource>&& mediaSource, bool loadingProgress) 832 { 833 m_loadingProgress = loadingProgress; 834 m_mediaSource = WTFMove(mediaSource); 835 800 836 if (!createTopologyFromSource()) 801 837 return; … … 804 840 HRESULT hr = m_mediaSession->SetTopology(0, m_topology.get()); 805 841 ASSERT_UNUSED(hr, SUCCEEDED(hr)); 842 } 843 844 void MediaPlayerPrivateMediaFoundation::onNetworkStateChanged(MediaPlayer::NetworkState state) 845 { 846 m_networkState = state; 847 m_player->networkStateChanged(); 806 848 } 807 849 … … 855 897 856 898 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 else918 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;928 899 } 929 900 -
trunk/Source/WebCore/platform/graphics/win/MediaPlayerPrivateMediaFoundation.h
r287948 r293765 103 103 DestinationColorSpace colorSpace() final; 104 104 105 protected: 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 105 116 private: 106 117 float maxTimeLoaded() const { return m_maxTimeLoaded; } … … 139 150 bool endSession(); 140 151 bool startCreateMediaSource(const String& url); 141 bool endCreatedMediaSource(IMFAsyncResult*);142 bool endGetEvent(IMFAsyncResult*);143 152 bool createTopologyFromSource(); 144 153 bool addBranchToPartialTopology(int stream); … … 150 159 COMPtr<IMFVideoDisplayControl> videoDisplay(); 151 160 152 void onCreatedMediaSource();153 void onTopologySet();154 void onBufferingStarted();155 void onBufferingStopped();156 void onSessionStarted();157 void onSessionEnded();158 159 161 HWND hostWindow(); 160 162 void invalidateVideoArea(); … … 175 177 }; 176 178 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; 198 180 199 181 typedef Deque<COMPtr<IMFSample>> VideoSampleList;
Note:
See TracChangeset
for help on using the changeset viewer.