我正在使用Media Foundation的Source Reader编写硬件加速的h264解码器,但遇到了问题。我跟着this tutorial,并支持自己的Windows SDK媒体基础示例。如何正确使用硬件加速的Media Foundation Source Reader来解码视频?
当硬件加速关闭时,我的应用程序似乎工作正常,但它不提供我需要的性能。当我通过传递一个IMFDXGIDeviceManager
到IMFAttributes
用于创建阅读器来打开加速时,事情变得复杂。
如果我使用D3D_DRIVER_TYPE_NULL
驱动程序创建ID3D11Device
,应用程序工作正常,帧被处理速度更快,在软件的模式,而是由CPU和GPU使用率判断它仍然没有大部分处理上的CPU。
另一方面,当我使用D3D_DRIVER_TYPE_HARDWARE
驱动程序创建ID3D11Device
驱动程序并运行该应用程序时,可能会发生以下四种情况之一。
我仅前
IMFMediaBuffer::Lock
函数返回其被描述为0x887a0005获得帧的不可预测的数(通常为1-3)“的GPU设备实例已经暂停。使用GetDeviceRemovedReason
以确定适当的行动”。当我打电话给ID3D11Device::GetDeviceRemovedReason
时,我得到0x887a0020,它被描述为“驱动程序遇到问题并且被置于设备移除状态”,这没有我希望的那样有帮助。该应用程序崩溃在
IMFMediaBuffer::Lock
调用外部DLL。看来,DLL取决于使用的GPU。对于Intel集成GPU,它是igd10iumd32.dll,对于Nvidia移动GPU,它是mfplat.dll。此特定崩溃的消息如下所示:“decode_ tester.exe中0x53C6DB8C(mfplat.dll)引发的异常:0xC0000005:访问冲突读取位置0x00000024”。地址在执行过程中有所不同,有时涉及阅读,有时写作。图形驱动器停止响应,则系统挂起的时间很短,然后应用程序崩溃等在点2或涂饰等在点1
该应用工作正常,并处理所有与硬件的帧加速。
大多数是1或2,很少3或4
这里的时间是在CPU/GPU的使用是什么样的,当没有我的机器在不同的模式节流(英特尔酷睿处理带有HD Graphics 530,Windows 10 Pro的i5-6500)。
- NULL - CPU:〜90%,GPU:〜15%
- HARDWARE - CPU:〜15%,GPU:〜60%
- SOFTWARE - CPU:〜40%,GPU:〜7 %
我在三台机器上测试了应用程序。他们都有英特尔集成GPU(HD 4400,HD 4600,HD 530)。其中一个也有可切换的Nvidia专用GPU(GF 840M)。它在所有这些方面都有相同的地方,唯一的区别是当它使用Nvidia的GPU时,它会在另一个dll中崩溃。
我有一个COM或DirectX没有以往的经验,但所有这一切是不一致的和不可预测的,所以它看起来像一个内存破坏我。不过,我不知道我犯了什么错误。你能帮我找到我做错了什么吗?
最小的代码示例,我可以拿出来与如下。我使用Visual Studio Professional 2015将其编译为C++项目。我准备了定义以启用硬件加速并选择硬件驱动程序。评论他们改变行为。此外,代码预计this video file将出现在项目目录中。
#include <iostream>
#include <string>
#include <atlbase.h>
#include <d3d11.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <windows.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "mf.lib")
#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mfreadwrite.lib")
#pragma comment(lib, "mfuuid.lib")
#define ENABLE_HW_ACCELERATION
#define ENABLE_HW_DRIVER
void handle_result(HRESULT hr)
{
if (SUCCEEDED(hr))
return;
WCHAR message[512];
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), message, ARRAYSIZE(message), nullptr);
printf("%ls", message);
abort();
}
int main(int argc, char** argv)
{
handle_result(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE));
handle_result(MFStartup(MF_VERSION));
{
CComPtr<IMFAttributes> attributes;
handle_result(MFCreateAttributes(&attributes, 3));
#if defined(ENABLE_HW_ACCELERATION)
CComPtr<ID3D11Device> device;
D3D_FEATURE_LEVEL levels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0 };
#if defined(ENABLE_HW_DRIVER)
handle_result(D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_VIDEO_SUPPORT,
levels, ARRAYSIZE(levels), D3D11_SDK_VERSION, &device, nullptr, nullptr));
#else
handle_result(D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_NULL, nullptr, D3D11_CREATE_DEVICE_SINGLETHREADED,
levels, ARRAYSIZE(levels), D3D11_SDK_VERSION, &device, nullptr, nullptr));
#endif
UINT token;
CComPtr<IMFDXGIDeviceManager> manager;
handle_result(MFCreateDXGIDeviceManager(&token, &manager));
handle_result(manager->ResetDevice(device, token));
handle_result(attributes->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, manager));
handle_result(attributes->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, TRUE));
handle_result(attributes->SetUINT32(MF_SOURCE_READER_ENABLE_ADVANCED_VIDEO_PROCESSING, TRUE));
#else
handle_result(attributes->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING, TRUE));
#endif
CComPtr<IMFSourceReader> reader;
handle_result(MFCreateSourceReaderFromURL(L"Rogue One - A Star Wars Story - Trailer.mp4", attributes, &reader));
CComPtr<IMFMediaType> output_type;
handle_result(MFCreateMediaType(&output_type));
handle_result(output_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video));
handle_result(output_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32));
handle_result(reader->SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, nullptr, output_type));
unsigned int frame_count{};
std::cout << "Started processing frames" << std::endl;
while (true)
{
CComPtr<IMFSample> sample;
DWORD flags;
handle_result(reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM,
0, nullptr, &flags, nullptr, &sample));
if (flags & MF_SOURCE_READERF_ENDOFSTREAM || sample == nullptr)
break;
std::cout << "Frame " << frame_count++ << std::endl;
CComPtr<IMFMediaBuffer> buffer;
BYTE* data;
handle_result(sample->ConvertToContiguousBuffer(&buffer));
handle_result(buffer->Lock(&data, nullptr, nullptr));
// Use the frame here.
buffer->Unlock();
}
std::cout << "Finished processing frames" << std::endl;
}
MFShutdown();
CoUninitialize();
return 0;
}
您可以尝试使用MF_MT_SUBTYPE,MFVideoFormat_NV12。 – VuVirt
感谢您的提示!事实上,当我将MFVideoFormat_NV12设置为输出子类型时,它开始工作。我使用DXVAChecker为我使用的解码器(或者我认为)列出了[可能的输出格式](https://i.imgsafe.org/12d5643c00.png),并且没有RGB32。这是否意味着我无法使用此解码器将H264直接解码为RGB32?那么为什么它有时会像我的问题的第4点所描述的那样正常工作?或者为什么没有“不支持输出格式”的错误信息?奇怪的是,NV12似乎是使代码正常工作的唯一格式。 – Vennor
请检查我的具体答案 – VuVirt