Bug 1277626 - Create test DXVA decoders on the main thread so that we can protect them with a crash guard. r=jya,dvander
--- a/dom/media/platforms/wmf/DXVA2Manager.cpp
+++ b/dom/media/platforms/wmf/DXVA2Manager.cpp
@@ -186,16 +186,23 @@ static const GUID DXVA2_Intel_ModeH264_E
// This tests if a DXVA video decoder can be created for the given media type/resolution.
// It uses the same decoder device (DXVA2_ModeH264_E - DXVA2_ModeH264_VLD_NoFGT) as the H264
// decoder MFT provided by windows (CLSID_CMSH264DecoderMFT) uses, so we can use it to determine
// if the MFT will use software fallback or not.
bool
D3D9DXVA2Manager::SupportsConfig(IMFMediaType* aType, float aFramerate)
{
+ MOZ_ASSERT(NS_IsMainThread());
+ gfx::D3D9VideoCrashGuard crashGuard;
+ if (crashGuard.Crashed()) {
+ NS_WARNING("DXVA2D3D9 crash detected");
+ return false;
+ }
+
DXVA2_VideoDesc desc;
HRESULT hr = ConvertMFTypeToDXVAType(aType, &desc);
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
// AMD cards with UVD3 or earlier perform poorly trying to decode 1080p60 in hardware,
// so use software instead. Pick 45 as an arbitrary upper bound for the framerate we can
// handle.
if (mIsAMDPreUVD4 &&
@@ -537,16 +544,23 @@ private:
uint32_t mHeight;
UINT mDeviceManagerToken;
bool mIsAMDPreUVD4;
};
bool
D3D11DXVA2Manager::SupportsConfig(IMFMediaType* aType, float aFramerate)
{
+ MOZ_ASSERT(NS_IsMainThread());
+ gfx::D3D11VideoCrashGuard crashGuard;
+ if (crashGuard.Crashed()) {
+ NS_WARNING("DXVA2D3D9 crash detected");
+ return false;
+ }
+
RefPtr<ID3D11VideoDevice> videoDevice;
HRESULT hr = mDevice->QueryInterface(static_cast<ID3D11VideoDevice**>(getter_AddRefs(videoDevice)));
NS_ENSURE_TRUE(SUCCEEDED(hr), false);
D3D11_VIDEO_DECODER_DESC desc;
desc.Guid = mDecoderGUID;
UINT32 width = 0;
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -494,41 +494,76 @@ WMFVideoMFTManager::Input(MediaRawData*
NS_ENSURE_TRUE(SUCCEEDED(hr) && mLastInput != nullptr, hr);
mLastDuration = aSample->mDuration;
// Forward sample data to the decoder.
return mDecoder->Input(mLastInput);
}
+class SupportsConfigEvent : public Runnable {
+public:
+ SupportsConfigEvent(DXVA2Manager* aDXVA2Manager, IMFMediaType* aMediaType, float aFramerate)
+ : mDXVA2Manager(aDXVA2Manager)
+ , mMediaType(aMediaType)
+ , mFramerate(aFramerate)
+ , mSupportsConfig(false)
+ {}
+
+ NS_IMETHOD Run() {
+ MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
+ mSupportsConfig = mDXVA2Manager->SupportsConfig(mMediaType, mFramerate);
+ return NS_OK;
+ }
+ DXVA2Manager* mDXVA2Manager;
+ IMFMediaType* mMediaType;
+ float mFramerate;
+ bool mSupportsConfig;
+};
+
// The MFTransform we use for decoding h264 video will silently fall
// back to software decoding (even if we've negotiated DXVA) if the GPU
// doesn't support decoding the given resolution. It will then upload
// the software decoded frames into d3d textures to preserve behaviour.
//
// Unfortunately this seems to cause corruption (see bug 1193547) and is
// slow because the upload is done into a non-shareable texture and requires
// us to copy it.
//
// This code tests if the given resolution can be supported directly on the GPU,
// and makes sure we only ask the MFT for DXVA if it can be supported properly.
+//
+// Ideally we'd know the framerate during initialization and would also ensure
+// that new decoders are created if the resolution changes. Then we could move
+// this check into Init and consolidate the main thread blocking code.
bool
WMFVideoMFTManager::CanUseDXVA(IMFMediaType* aType)
{
MOZ_ASSERT(mDXVA2Manager);
// SupportsConfig only checks for valid h264 decoders currently.
if (mStreamType != H264) {
return true;
}
// Assume the current samples duration is representative for the
// entire video.
float framerate = 1000000.0 / mLastDuration;
- return mDXVA2Manager->SupportsConfig(aType, framerate);
+ // The supports config check must be done on the main thread since we have
+ // a crash guard protecting it.
+ RefPtr<SupportsConfigEvent> event =
+ new SupportsConfigEvent(mDXVA2Manager, aType, framerate);
+
+ if (NS_IsMainThread()) {
+ event->Run();
+ } else {
+ NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
+ }
+
+ return event->mSupportsConfig;
}
HRESULT
WMFVideoMFTManager::ConfigureVideoFrameGeometry()
{
RefPtr<IMFMediaType> mediaType;
HRESULT hr = mDecoder->GetOutputMediaType(mediaType);
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);