window 显示驱动开发-提供视频解码功能(三)
D3DDDICAPS_GETDECODERTFORMATCOUNT和D3DDDICAPS_GETDECODERTFORMATS请求类型
Direct3D 运行时指定D3DDDIARG_GETCAPSpInfo 成员指向的变量中特定 DirectX VA 解码类型的 GUID。 UMD 返回数字,然后返回它为特定 DirectX VA 解码类型支持的呈现目标格式列表。
查询流程概述
对于解码器渲染目标(RT)格式的查询,Direct3D运行时采用两级查询机制:
- 查询格式数量:首先获取特定解码器支持的RT格式总数
- 获取格式列表:然后获取具体的格式列表
数据结构与参数说明
关键数据结构
typedef struct _D3DDDIARG_GETCAPS {D3DDDICAPS_TYPE Type; // 请求类型VOID* pInfo; // 指向包含解码器GUID的结构体VOID* pData; // 指向返回数据的缓冲区UINT DataSize; // 缓冲区大小(输入)/返回数据大小(输出)
} D3DDDIARG_GETCAPS;typedef struct _DXVA2_DDI_GET_RT_FORMAT_COUNT {GUID DecodeGuid; // 要查询的解码器GUID
} DXVA2_DDI_GET_RT_FORMAT_COUNT;
详细查询流程
第一步:查询支持的RT格式数量 (D3DDDICAPS_GETDECODERTFORMATCOUNT)
运行时调用:
DXVA2_DDI_GET_RT_FORMAT_COUNT getRtCountInfo = {DXVA2_ModeH264_E // 示例:查询H264解码器
};D3DDDIARG_GETCAPS getCapsArgs = {};
getCapsArgs.Type = D3DDDICAPS_GETDECODERTFORMATCOUNT;
getCapsArgs.pInfo = &getRtCountInfo; // 包含解码器GUID
getCapsArgs.pData = &formatCount; // 指向UINT变量
getCapsArgs.DataSize = sizeof(UINT);pUMD->GetCaps(&getCapsArgs);
UMD响应要求:
- 解析pInfo指向的DXVA2_DDI_GET_RT_FORMAT_COUNT结构
- 返回指定解码器支持的RT格式数量
- 通过pData返回计数值
- 设置DataSize为实际写入的数据大小
第二步:查询RT格式列表 (D3DDDICAPS_GETDECODERTFORMATS)
运行时调用:
std::vector<D3DDDIFORMAT> formatList(formatCount);DXVA2_DDI_GET_RT_FORMAT_COUNT getRtFormatInfo = {DXVA2_ModeH264_E // 与上一步相同的GUID
};D3DDDIARG_GETCAPS getCapsArgs = {};
getCapsArgs.Type = D3DDDICAPS_GETDECODERTFORMATS;
getCapsArgs.pInfo = &getRtFormatInfo;
getCapsArgs.pData = formatList.data();
getCapsArgs.DataSize = formatCount * sizeof(D3DDDIFORMAT);pUMD->GetCaps(&getCapsArgs);
UMD响应要求:
- 验证pInfo中的GUID与之前查询一致
- 填充pData缓冲区所有支持的格式
- 格式按D3DDDIFORMAT枚举值排列
- 设置DataSize为实际写入的数据总字节数
常见渲染目标格式
UMD可能返回的典型D3DDDIFORMAT值:
格式值 | 描述 |
---|---|
D3DDDIFMT_NV12 | 最常用的YUV 4:2:0格式 |
D3DDDIFMT_YUY2 | 打包的YUV 4:2:2格式 |
D3DDDIFMT_A8R8G8B8 | 32位ARGB格式 |
D3DDDIFMT_P010 | 10位精度4:2:0格式 |
D3DDDIFMT_AYUV | 4:4:4格式带Alpha通道 |
错误处理规范
UMD应当正确处理以下情况:
无效GUID:
- 当pInfo包含不支持的GUID时
- 应返回0个格式或错误码
缓冲区不足:
if (pArgs->DataSize < requiredSize) {pArgs->DataSize = requiredSize; // 告知需要的大小return E_INVALIDARG;
}
参数验证:
- 检查pInfo是否为NULL
- 验证GUID结构完整性
实现示例代码
UMD侧实现伪代码
HRESULT UMD::GetCaps(D3DDDIARG_GETCAPS* pArgs) {if (!pArgs || !pArgs->pInfo) return E_INVALIDARG;auto* pGuidInfo = (DXVA2_DDI_GET_RT_FORMAT_COUNT*)pArgs->pInfo;switch (pArgs->Type) {case D3DDDICAPS_GETDECODERTFORMATCOUNT: {if (pArgs->DataSize < sizeof(UINT)) return E_INVALIDARG;UINT count = GetSupportedFormatCount(pGuidInfo->DecodeGuid);*(UINT*)pArgs->pData = count;pArgs->DataSize = sizeof(UINT);return S_OK;}case D3DDDICAPS_GETDECODERTFORMATS: {UINT count = GetSupportedFormatCount(pGuidInfo->DecodeGuid);size_t requiredSize = count * sizeof(D3DDDIFORMAT);if (pArgs->DataSize < requiredSize) {pArgs->DataSize = requiredSize;return E_INVALIDARG;}GetSupportedFormats(pGuidInfo->DecodeGuid, (D3DDDIFORMAT*)pArgs->pData);pArgs->DataSize = requiredSize;return S_OK;}// ...其他类型处理}
}
高级注意事项
格式优先级:
- 建议将最常用/性能最好的格式放在列表前面
- 运行时通常会选择列表中的第一个支持格式
动态能力:
- 某些驱动可能根据系统状态返回不同格式
- 如内存紧张时可能减少支持的格式
多适配器协调:
- 在混合GPU环境中,格式支持可能不同
- 需要针对每个适配器单独查询