首先是一些必要的前言:
我想要实现的目标如下。我有一个应用程序,可以使用DirectX在窗口模式和全屏幕渲染。我需要能够在全屏模式下播放视频,并且在呈现应用程序和播放视频之间进行可见的转换是不可接受的(即踢出全屏并再次返回)。因此,我需要使用相同的DirectX设备来呈现应用程序和视频。
我已经通过根据DirectX SDK中的vmr9allocator示例组合自定义分配器/演示器来实现此目的(请参阅例如C:\ Program Files \ Microsoft SDKs \ Windows \ v7.1 \ Samples \ multimedia \ directshow \ VMR9 \ vmr9allocator)。我的版本有所不同,因为分配器类使用的DirectX设备不是由该类拥有,而是从应用程序的呈现部分传入(实际上是从角度GL层传递到精确,但这不是'与此讨论特别相关)。但是,过滤器的设置完全相同。
除了以下场景外,一切正常。如果应用程序失去焦点,则全屏DirectX设备将丢失。在这种情况下,我想停止视频并终止设备,进入窗口模式并创建一个新的DirectX设备,以便在窗口模式下渲染。我可以做到这一点,但我似乎让DirectShow处于某种不稳定状态。当我尝试随后以窗口模式呈现视频时,问题就会出现。我不是在这种情况下使用DX设备,而是通过创建DirectShow渲染到主窗口的子窗口来实现。因此,特别是对于DX渲染方法,我称之为
SetRenderingMode(VMR9Mode_Renderless)
对于我调用的窗口版本
SetRenderingMode(VMRMode_Windowless)
IVMRFilterConfig 界面上的。
我看到的(视频中全屏设备丢失后)是窗口视频无法呈现到我手动指定的窗口。相反,它坚持打开它自己的无父窗口,就像
一样SetRenderingMode(VMRMode_Windowed)
已被召唤。如果我调试代码然后我看到 SetRenderingMode(VMRMode_Windowless)返回"未知错误"!
我很难在这里获得有关我的代码有什么问题的建议,因为很多内容并且发布所有内容可能没什么帮助。所以我想知道的是在视频渲染过程中处理设备丢失的正确方法是什么。也许那时我可以确定我的代码出了什么问题。参考前面提到的DX示例,关键问题出现在 CAllocator :: PresentImage 函数中:
HRESULT CAllocator::PresentImage(
/* [in] */ DWORD_PTR dwUserID,
/* [in] */ VMR9PresentationInfo *lpPresInfo)
{
HRESULT hr;
CAutoLock Lock(&m_ObjectLock);
if( NeedToHandleDisplayChange() )
{}
hr = PresentHelper( lpPresInfo );
if( hr == D3DERR_DEVICELOST)
{
if (m_D3DDev->TestCooperativeLevel() == D3DERR_DEVICENOTRESET)
{
DeleteSurfaces();
FAIL_RET( CreateDevice() );
HMONITOR hMonitor = m_D3D->GetAdapterMonitor( D3DADAPTER_DEFAULT );
FAIL_RET( m_lpIVMRSurfAllocNotify->ChangeD3DDevice( m_D3DDev, hMonitor ) );
}
hr = S_OK;
}
return hr;
}
此功能在由DirectShow管理的线程上的每个帧上调用,并在播放视频时启动。示例代码表示您在此处重新创建设备。首先,这对我没有任何意义,因为你只应该在DX9的窗口消息线程上创建/重置/ TestCooperativeLevel,所以这打破了这个使用规则!其次,我无法实际执行此操作,因为DX设备是无关紧要的,因此我们无法重置它。但是,我无法找到任何合理的方法来告诉系统不要继续渲染。我无能为力并返回S_OK或一些失败代码,但问题仍然存在。
最后,这个问题!有谁知道处理这种情况的正确方法是什么,即设备丢失只是停止视频!
N.B。我不会在我的代码深处排除其他问题。但是,如果我至少知道正确的方法来做我想要的是什么,那么我希望能够排除/输出至少一部分代码。