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 SampleおよびSink Writer Tutorialから直接取得されます。ビデオ形式の定義も Sink Writer チュートリアルから取られ、フレーム解像度とVIDEO_INPUT_FORMAT = MFVideoFormat_ARGB32
.
ただし、このループを ~20 回 (場合によってはもう少し、場合によっては少し) 通過した後、次の HRESULT メッセージで失敗しmSinkWriter->WriteSample()
ます。mDeskDupl->AcquireNextFrame()
アプリケーションが無効な呼び出しを行いました。呼び出しのパラメーターまたは一部のオブジェクトの状態が正しくありませんでした。デバッグ メッセージで詳細を表示するには、D3D デバッグ レイヤーを有効にします。
D3D デバッグ レイヤーを有効にすると、フレーム (これらのオブジェクトは私のフレームだと思います) が何らかの理由で解放されず、積み上げられ続けることがわかります。
D3D11 警告: 0x0000006504FFC290 のライブ オブジェクト、参照カウント: 17。[ STATE_CREATION 警告 #0: 不明]
HRESULT の失敗は、GPU がメモリ不足になっていることが原因であると確信しています (GPU-Z ユーティリティを介して GPU メモリの使用状況を監視することでも確認されています)。ただし、割り当てているすべてのリソースを解放しているため ( SafeRelease 実装)、このメモリ リークの原因はわかりません。
編集:ポインターをスマート ポインターに変更し、マクロ定義を追加しました。