You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 04:27:25