我一直在为Nvidia的H.264编码器MFT造成的资源泄漏而苦苦挣扎。每次将框架提交给编码器时,我的D3D设备的参考计数都会以1递增,即使关闭MFT后,此引用也不会放弃。一堆线也泄漏了。 我几乎准备好与Nvidia一起提出这一点,但我首先要确保没有什么明显的我错过的。请在下面查看我的实现 - 我试图使其尽可能简洁明了。 aarguments为什么这可能是NVIDIA编码器的问题:

问题描述 投票:0回答:1

我尝试使用sindwriter以类似的方式将DXGI表面写入文件,但这里不存在泄漏。不幸的是,我无法访问SinkWriter的源代码。如果有人可以指向一些可以比较的工作示例代码,我会很高兴。

#pragma comment(lib, "D3D11.lib") #pragma comment(lib, "mfplat.lib") #pragma comment(lib, "mf.lib") #pragma comment(lib, "evr.lib") #pragma comment(lib, "mfuuid.lib") #pragma comment(lib, "Winmm.lib") // std #include <iostream> #include <string> // Windows #include <windows.h> #include <atlbase.h> // DirectX #include <d3d11.h> // Media Foundation #include <mfapi.h> #include <mfplay.h> #include <mfreadwrite.h> #include <mferror.h> #include <Codecapi.h> // Error handling #define CHECK(x) if (!(x)) { printf("%s(%d) %s was false\n", __FILE__, __LINE__, #x); throw std::exception(); } #define CHECK_HR(x) { HRESULT hr_ = (x); if (FAILED(hr_)) { printf("%s(%d) %s failed with 0x%x\n", __FILE__, __LINE__, #x, hr_); throw std::exception(); } } // Constants constexpr UINT ENCODE_WIDTH = 1920; constexpr UINT ENCODE_HEIGHT = 1080; constexpr UINT ENCODE_FRAMES = 120; void runEncode(); int main() { CHECK_HR(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)); CHECK_HR(MFStartup(MF_VERSION)); for (;;) { runEncode(); if (getchar() == 'q') break; } CHECK_HR(MFShutdown()); return 0; } void runEncode() { CComPtr<ID3D11Device> device; CComPtr<ID3D11DeviceContext> context; CComPtr<IMFDXGIDeviceManager> deviceManager; CComPtr<IMFVideoSampleAllocatorEx> allocator; CComPtr<IMFTransform> transform; CComPtr<IMFAttributes> transformAttrs; CComQIPtr<IMFMediaEventGenerator> eventGen; DWORD inputStreamID; DWORD outputStreamID; // ------------------------------------------------------------------------ // Initialize D3D11 // ------------------------------------------------------------------------ CHECK_HR(D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT | D3D11_CREATE_DEVICE_DEBUG, NULL, 0, D3D11_SDK_VERSION, &device, NULL, &context)); { // Probably not necessary in this application, but maybe the MFT requires it? CComQIPtr<ID3D10Multithread> mt(device); CHECK(mt); mt->SetMultithreadProtected(TRUE); } // Create device manager UINT resetToken; CHECK_HR(MFCreateDXGIDeviceManager(&resetToken, &deviceManager)); CHECK_HR(deviceManager->ResetDevice(device, resetToken)); // ------------------------------------------------------------------------ // Initialize hardware encoder MFT // ------------------------------------------------------------------------ { // Find the encoder CComHeapPtr<IMFActivate*> activateRaw; UINT32 activateCount = 0; // Input & output types MFT_REGISTER_TYPE_INFO inInfo = { MFMediaType_Video, MFVideoFormat_NV12 }; MFT_REGISTER_TYPE_INFO outInfo = { MFMediaType_Video, MFVideoFormat_H264 }; // Query for the adapter LUID to get a matching encoder for the device. CComQIPtr<IDXGIDevice> dxgiDevice(device); CHECK(dxgiDevice); CComPtr<IDXGIAdapter> adapter; CHECK_HR(dxgiDevice->GetAdapter(&adapter)); DXGI_ADAPTER_DESC adapterDesc; CHECK_HR(adapter->GetDesc(&adapterDesc)); CComPtr<IMFAttributes> enumAttrs; CHECK_HR(MFCreateAttributes(&enumAttrs, 1)); CHECK_HR(enumAttrs->SetBlob(MFT_ENUM_ADAPTER_LUID, (BYTE*)&adapterDesc.AdapterLuid, sizeof(LUID))); CHECK_HR(MFTEnum2(MFT_CATEGORY_VIDEO_ENCODER, MFT_ENUM_FLAG_HARDWARE | MFT_ENUM_FLAG_SORTANDFILTER, &inInfo, &outInfo, enumAttrs, &activateRaw, &activateCount)); CHECK(activateCount != 0); // Choose the first returned encoder CComPtr<IMFActivate> activate = activateRaw[0]; // Memory management for (UINT32 i = 0; i < activateCount; i++) activateRaw[i]->Release(); // Activate CHECK_HR(activate->ActivateObject(IID_PPV_ARGS(&transform))); // Get attributes CHECK_HR(transform->GetAttributes(&transformAttrs)); } // ------------------------------------------------------------------------ // Query encoder name (not necessary, but nice) and unlock for async use // ------------------------------------------------------------------------ { UINT32 nameLength = 0; std::wstring name; CHECK_HR(transformAttrs->GetStringLength(MFT_FRIENDLY_NAME_Attribute, &nameLength)); // IMFAttributes::GetString returns a null-terminated wide string name.resize((size_t)nameLength + 1); CHECK_HR(transformAttrs->GetString(MFT_FRIENDLY_NAME_Attribute, &name[0], (UINT32)name.size(), &nameLength)); name.resize(nameLength); printf("Using %ls\n", name.c_str()); // Unlock the transform for async use and get event generator CHECK_HR(transformAttrs->SetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, TRUE)); CHECK(eventGen = transform); } // Get stream IDs (expect 1 input and 1 output stream) { HRESULT hr = transform->GetStreamIDs(1, &inputStreamID, 1, &outputStreamID); if (hr == E_NOTIMPL) { inputStreamID = 0; outputStreamID = 0; hr = S_OK; } CHECK_HR(hr); } // ------------------------------------------------------------------------ // Configure hardware encoder MFT // ------------------------------------------------------------------------ // Set D3D manager CHECK_HR(transform->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, reinterpret_cast<ULONG_PTR>(deviceManager.p))); // Set output type CComPtr<IMFMediaType> outputType; CHECK_HR(MFCreateMediaType(&outputType)); CHECK_HR(outputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)); CHECK_HR(outputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_H264)); CHECK_HR(outputType->SetUINT32(MF_MT_AVG_BITRATE, 30000000)); CHECK_HR(MFSetAttributeSize(outputType, MF_MT_FRAME_SIZE, ENCODE_WIDTH, ENCODE_HEIGHT)); CHECK_HR(MFSetAttributeRatio(outputType, MF_MT_FRAME_RATE, 60, 1)); CHECK_HR(outputType->SetUINT32(MF_MT_INTERLACE_MODE, 2)); CHECK_HR(outputType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE)); CHECK_HR(transform->SetOutputType(outputStreamID, outputType, 0)); // Set input type CComPtr<IMFMediaType> inputType; CHECK_HR(transform->GetInputAvailableType(inputStreamID, 0, &inputType)); CHECK_HR(inputType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video)); CHECK_HR(inputType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_NV12)); CHECK_HR(MFSetAttributeSize(inputType, MF_MT_FRAME_SIZE, ENCODE_WIDTH, ENCODE_HEIGHT)); CHECK_HR(MFSetAttributeRatio(inputType, MF_MT_FRAME_RATE, 60, 1)); CHECK_HR(transform->SetInputType(inputStreamID, inputType, 0)); // ------------------------------------------------------------------------ // Create sample allocator // ------------------------------------------------------------------------ { MFCreateVideoSampleAllocatorEx(IID_PPV_ARGS(&allocator)); CHECK(allocator); CComPtr<IMFAttributes> allocAttrs; MFCreateAttributes(&allocAttrs, 2); CHECK_HR(allocAttrs->SetUINT32(MF_SA_D3D11_BINDFLAGS, D3D11_BIND_RENDER_TARGET)); CHECK_HR(allocAttrs->SetUINT32(MF_SA_D3D11_USAGE, D3D11_USAGE_DEFAULT)); CHECK_HR(allocator->SetDirectXManager(deviceManager)); CHECK_HR(allocator->InitializeSampleAllocatorEx(1, 2, allocAttrs, inputType)); } // ------------------------------------------------------------------------ // Start encoding // ------------------------------------------------------------------------ CHECK_HR(transform->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, NULL)); CHECK_HR(transform->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL)); CHECK_HR(transform->ProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, NULL)); // Encode loop for (int i = 0; i < ENCODE_FRAMES; i++) { // Get next event CComPtr<IMFMediaEvent> event; CHECK_HR(eventGen->GetEvent(0, &event)); MediaEventType eventType; CHECK_HR(event->GetType(&eventType)); switch (eventType) { case METransformNeedInput: { CComPtr<IMFSample> sample; CHECK_HR(allocator->AllocateSample(&sample)); CHECK_HR(transform->ProcessInput(inputStreamID, sample, 0)); // Dereferencing the device once after feeding each frame "fixes" the leak. //device.p->Release(); break; } case METransformHaveOutput: { DWORD status; MFT_OUTPUT_DATA_BUFFER outputBuffer = {}; outputBuffer.dwStreamID = outputStreamID; CHECK_HR(transform->ProcessOutput(0, 1, &outputBuffer, &status)); DWORD bufCount; DWORD bufLength; CHECK_HR(outputBuffer.pSample->GetBufferCount(&bufCount)); CComPtr<IMFMediaBuffer> outBuffer; CHECK_HR(outputBuffer.pSample->GetBufferByIndex(0, &outBuffer)); CHECK_HR(outBuffer->GetCurrentLength(&bufLength)); printf("METransformHaveOutput buffers=%d, bytes=%d\n", bufCount, bufLength); // Release the sample as it is not processed further. if (outputBuffer.pSample) outputBuffer.pSample->Release(); if (outputBuffer.pEvents) outputBuffer.pEvents->Release(); break; } } } // ------------------------------------------------------------------------ // Finish encoding // ------------------------------------------------------------------------ CHECK_HR(transform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, NULL)); CHECK_HR(transform->ProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, NULL)); CHECK_HR(transform->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, NULL)); // Shutdown printf("Finished encoding\n"); // I've tried all kinds of things... //CHECK_HR(transform->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, reinterpret_cast<ULONG_PTR>(nullptr))); //transform->SetInputType(inputStreamID, NULL, 0); //transform->SetOutputType(outputStreamID, NULL, 0); //transform->DeleteInputStream(inputStreamID); //deviceManager->ResetDevice(NULL, resetToken); CHECK_HR(MFShutdownObject(transform)); }

  • 我认为答案是“是”。
  • 我以前看到了问题:
可以关闭D3D设备吗?

    在进行下,我停止了重新创建D3D设备。相反,我正在使用全球
  • CAtlMap
  • 集合。键是从
uint64_t
场中包含GPU的LUID。这些值是具有2个字段的结构,
DXGI_ADAPTER_DESC::AdapterLuid
c++ memory-leaks directx nvidia ms-media-foundation
1个回答
1
投票
CComPtr<ID3D11Device>

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.