使用Sink Writer写入桌面复制采样时成功1-3次后异常终止求助
桌面复制采样写入Sink Writer时仅成功1-3次后程序终止/报错问题
我用Sink Writer写入通过Desktop Duplication获取的采样,但成功写入1-3次后程序就会终止或报错,相关代码如下:
while(true){ hr = dxgiOutputDuplication->AcquireNextFrame(0, &frame_info, &resource); if (SUCCEEDED(hr)) { ID3D11Texture2D* texture = NULL; hr = resource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&texture); if (SUCCEEDED(hr)) { IDXGISurface* dxgiSurface = NULL; hr = texture->QueryInterface(__uuidof(IDXGISurface), (void**)&dxgiSurface); if (SUCCEEDED(hr)) { IMFSample* sample = NULL; hr = MFCreateSample(&sample); if (SUCCEEDED(hr)) { IMFMediaBuffer* buffer = NULL; hr = MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), dxgiSurface, 0, FALSE, &buffer); if (SUCCEEDED(hr)) { hr = sample->AddBuffer(buffer); hr = sample->SetSampleDuration(duration); hr = presentation->GetTime(&sampleTime); hr = sample->SetSampleTime(sampleTime); //sampleTime += duration * 10; DWORD length = 0; IMF2DBuffer* imf_buffer = NULL; hr = buffer->QueryInterface(__uuidof(IMF2DBuffer), (void**)&imf_buffer); if (SUCCEEDED(hr)) { hr = imf_buffer->GetContiguousLength(&length); hr = buffer->SetCurrentLength(length); hr = writer->WriteSample(0, sample); if (FAILED(hr)) { OutputDebugString(L"FAILED WRITE SAMPLE\n"); } o++; if (o > 1920) { writer->Finalize(); OutputDebugString(L"OOOOOOOOOO"); break; } imf_buffer->Release(); imf_buffer = NULL; } buffer->Release(); buffer = NULL; } sample->Release(); sample = NULL; } dxgiSurface->Release(); dxgiSurface = NULL; } texture->Release(); texture = NULL; } resource->Release(); resource = NULL; } dxgiOutputDuplication->ReleaseFrame(); }
注:当前使用嵌套if仅为测试,正式场景应使用THROW_IF_ERROR。
问题排查与修复方案
- AcquireNextFrame超时参数错误:原代码超时设为0,无新帧时会立即返回失败,后续可能触发无效资源操作。应设置合理超时(如100000,即10ms),并在超时失败时继续循环,其他错误则退出:
hr = dxgiOutputDuplication->AcquireNextFrame(100000, &frame_info, &resource); // ... } else { if (hr != DXGI_ERROR_WAIT_TIMEOUT) { break; } } - 时间戳未累加:注释掉的
sampleTime += duration必须恢复,否则会出现时间戳重复,Sink Writer会拒绝写入。同时要确保duration单位为Media Foundation标准的100纳秒(如30帧/秒对应3333333)。 - 错误检查缺失:所有HRESULT调用(如
sample->AddBuffer、SetSampleDuration)都要检查返回值,忽略失败会导致后续操作基于无效状态执行,直接引发崩溃。 - 异步写入的资源生命周期问题:Sink Writer的
WriteSample默认异步执行,若在调用后立即释放DXGI Surface等资源,可能导致异步写入时资源已被销毁。可通过等待IMFAsyncResult确保写入完成,或配置Sink Writer为同步模式。 - 设备一致性问题:确保Desktop Duplication使用的D3D设备与Sink Writer的设备完全一致,跨设备传递DXGI Surface会直接失败。
修改后的核心代码片段
while(true){ hr = dxgiOutputDuplication->AcquireNextFrame(100000, &frame_info, &resource); if (SUCCEEDED(hr)) { ID3D11Texture2D* texture = NULL; hr = resource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&texture); if (SUCCEEDED(hr)) { IDXGISurface* dxgiSurface = NULL; hr = texture->QueryInterface(__uuidof(IDXGISurface), (void**)&dxgiSurface); if (SUCCEEDED(hr)) { IMFSample* sample = NULL; hr = MFCreateSample(&sample); if (SUCCEEDED(hr)) { IMFMediaBuffer* buffer = NULL; hr = MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), dxgiSurface, 0, FALSE, &buffer); if (SUCCEEDED(hr)) { if (SUCCEEDED(sample->AddBuffer(buffer))) { if (SUCCEEDED(sample->SetSampleDuration(duration))) { if (SUCCEEDED(presentation->GetTime(&sampleTime))) { if (SUCCEEDED(sample->SetSampleTime(sampleTime))) { sampleTime += duration; DWORD length = 0; IMF2DBuffer* imf_buffer = NULL; if (SUCCEEDED(buffer->QueryInterface(__uuidof(IMF2DBuffer), (void**)&imf_buffer))) { if (SUCCEEDED(imf_buffer->GetContiguousLength(&length)) && SUCCEEDED(buffer->SetCurrentLength(length))) { hr = writer->WriteSample(0, sample); if (FAILED(hr)) { OutputDebugString(L"FAILED WRITE SAMPLE\n"); // 可通过FormatMessage将hr转换为具体错误信息打印 } else { o++; if (o > 1920) { if (SUCCEEDED(writer->Finalize())) { OutputDebugString(L"OOOOOOOOOO\n"); } break; } } } imf_buffer->Release(); } } } } } buffer->Release(); } sample->Release(); } dxgiSurface->Release(); } texture->Release(); } resource->Release(); } else { if (hr != DXGI_ERROR_WAIT_TIMEOUT) { break; } } dxgiOutputDuplication->ReleaseFrame(); }
内容的提问来源于stack exchange,提问作者Angella Yu
相关产品推荐
相关产品推荐

