MF SinkWriter内存问题

时间:2016-01-18 14:56:13

标签: c++ windows com ms-media-foundation dxgi

我尝试使用DXGI Desktop Duplication API和MF Sink Writer将我的桌面图像(1920x1080)编码为视频文件。我的编码线程如下所示:

#define RETURN_ON_BAD_HR(expr) \
{ \
    HRESULT _hr_ = (expr); \
    if (FAILED(_hr_)) { \
        qDebug() << "Error encountered with message from HRESULT: " << \
                    getMessageFromHR(_hr_); \
        MFShutdown(); \
        CoUninitialize(); \
        return; \
    } \
}

void DuplicationThread::run() {
    if (CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) != S_OK) {
        qDebug() << "Failed to initialize COM.";
        return;
    }

    if (MFStartup(MF_VERSION) != S_OK) {
        qDebug() << "Failed to initialize Media Foundation.";
        CoUninitialize();
        return;
    }

    CComPtr<ID3D11Device> pDevice;
    RETURN_ON_BAD_HR(InitializeDx(&pDevice));

    CComPtr<IDXGIOutputDuplication> pDeskDupl;
    RETURN_ON_BAD_HR(InitiateDupl(pDevice, &pDeskDupl));

    CComPtr<IMFSinkWriter> pSinkWriter;
    DWORD streamIndex;
    RETURN_ON_BAD_HR(InitSinkWriter(&pSinkWriter, &streamIndex));

    LONGLONG rtStart = 0;

    while (!isInterruptionRequested()) {
        DXGI_OUTDUPL_FRAME_INFO frameInfo;
        CComPtr<IDXGIResource> pDesktopResource;
        RETURN_ON_BAD_HR(pDeskDupl->AcquireNextFrame(500, &frameInfo, &pDesktopResource));

        CComPtr<ID3D11Texture2D> pAcquiredDesktopImage;
        RETURN_ON_BAD_HR(pDesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&pAcquiredDesktopImage)));

        CComPtr<IMFMediaBuffer> pMediaBuffer;
        RETURN_ON_BAD_HR(MFCreateDXGISurfaceBuffer(__uuidof(ID3D11Texture2D), pAcquiredDesktopImage, 0, FALSE, &pMediaBuffer));

        CComPtr<IMF2DBuffer> p2DBuffer;
        DWORD length;
        RETURN_ON_BAD_HR(pMediaBuffer->QueryInterface(__uuidof(IMF2DBuffer), reinterpret_cast<void **>(&p2DBuffer)));
        RETURN_ON_BAD_HR(p2DBuffer->GetContiguousLength(&length));
        RETURN_ON_BAD_HR(pMediaBuffer->SetCurrentLength(length));

        CComPtr<IMFSample> pSample;
        RETURN_ON_BAD_HR(MFCreateVideoSampleFromSurface(NULL, &pSample));
        RETURN_ON_BAD_HR(pSample->AddBuffer(pMediaBuffer));
        RETURN_ON_BAD_HR(pSample->SetSampleTime(rtStart));
        RETURN_ON_BAD_HR(pSample->SetSampleDuration(VIDEO_FRAME_DURATION));

        RETURN_ON_BAD_HR(pSinkWriter->WriteSample(streamIndex, pSample));
        RETURN_ON_BAD_HR(pDeskDupl->ReleaseFrame());
        rtStart += VIDEO_FRAME_DURATION;

        // successful iterations 
        static int count = 0;
        qDebug() << "count: " << count++;
    }

    RETURN_ON_BAD_HR(pSinkWriter->Finalize());

    MFShutdown();
    CoUninitialize();
}

初始化例程直接来自Desktop Duplication SampleSink Writer Tutorial。视频格式定义也取自Sink Writer教程,更改了帧分辨率和VIDEO_INPUT_FORMAT = MFVideoFormat_ARGB32

然而,经过这个循环~20次(有时多一点,有时少一点),它在mSinkWriter->WriteSample()mDeskDupl->AcquireNextFrame()上失败并带有以下HRESULT消息:

  

该应用程序拨打的电话无效。调用的参数或某个对象的状态是不正确的。启用D3D调试层以通过调试消息查看详细信息。

启用D3D调试层后,我发现我的帧(我认为这些对象是我的帧)由于某种原因没有被释放,只是继续堆积:

  

D3D11警告:活动对象位于0x0000006504FFC290,Refcount:17。[STATE_CREATION WARNING#0:UNKNOWN]

我相当肯定HRESULT失败来自我的GPU耗尽内存(也通过GPU-Z实用程序观察GPU内存使用情况确认)。但是,我不知道导致内存泄漏的原因是什么,因为我发布了我分配的所有资源(SafeRelease implementation)。

编辑:更改了指向智能指针的指针并添加了宏定义。

0 个答案:

没有答案