Windows::Graphics::Capture对接IMFSinkWriter返回0x80070057错误排查
错误原因与解决方案
0x80070057是E_INVALIDARG错误,即传入WriteSample的参数或前置配置存在无效值,代码的核心问题如下:
核心错误点
- 像素格式不匹配
你创建Direct3D11CaptureFramePool时指定的是R16G16B16A16Float浮点格式,但给IMFSinkWriter配置的输入格式是MFVideoFormat_ARGB32(对应B8G8R8A8_UNORM整数格式),两者完全不兼容,编码器无法识别输入纹理。 - 时间参数单位错误
SetSampleTime和SetSampleDuration要求的时间单位是100纳秒,你现在的duration直接传入毫秒值,单位偏差了10000倍,第一帧duration=0也是无效值。 - D3D设备缺少视频支持标志
创建D3D11设备时没有添加D3D11_CREATE_DEVICE_VIDEO_SUPPORT标志,硬件编码器无法访问捕获到的GPU纹理。 - 冗余逻辑干扰(非直接报错原因)
你创建的交换链全程未使用,属于冗余代码,可直接删除。
关键修改步骤
- 统一像素格式
创建帧池时改用B8G8R8A8UIntNormalized格式:
auto framepool = winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::CreateFreeThreaded( device, winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized, 2, item.Size() );
- 修正时间参数单位
把帧时长转换为100纳秒单位:
if (!recordedFirstFrame) { recordedFirstFrame = true; firstFrameTime = frameTime; frametime100ns = 0; duration = 333333; // 首帧默认给30fps的帧间隔:333333 * 100ns ≈ 33ms } else { frametime100ns = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - firstFrameTime).count() / 100; // 时长统一转换为100纳秒单位 duration = std::chrono::duration_cast<std::chrono::nanoseconds>(frameTime - lastFrameTime).count() / 100; }
- 修改D3D设备创建参数,添加视频支持标志
winrt::check_hresult(D3D11CreateDevice( nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_VIDEO_SUPPORT, nullptr, 0, D3D11_SDK_VERSION, d3dDevice.put(), nullptr, nullptr ));
- 补充COM资源释放,避免内存泄漏
每次处理完帧后释放IMFMediaBuffer和IMFSample:
// WriteSample调用完成后添加 sample->Release(); buffer->Release();
- 删除冗余的交换链创建代码,该对象全程没有被调用,不影响核心逻辑
补充注意事项
- 如果显示器分辨率是奇数,部分H264编码器不支持非2的倍数的宽高,可提前把捕获尺寸对齐到16的倍数
- 捕获窗口/显示器如果有系统缩放,需要用
GetDpiForMonitor获取缩放比例调整实际输出分辨率,避免画面模糊 - 程序退出前需要调用
MFShutdown释放Media Foundation资源
内容的提问来源于stack exchange,提问作者Roger Jacobson
相关产品推荐
相关产品推荐

