无法在 HEVC 解码器 IMFTransform 上设置输出类型
Can't set the output type on an HEVC decoder IMFTransform
我编写了这个程序来设置基于 https://docs.microsoft.com/en-us/windows/win32/medfound/supporting-direct3d-11-video-decoding-in-media-foundation 的 HEVC 解码器。一切正常,直到最后我调用 result = decoder->SetOutputType(0, media_type, 0);
这个 returns 错误 MF_E_ATTRIBUTENOTFOUND
。我不确定出了什么问题,SetOutputType 文档中没有描述这个错误,我只找到了几个使用 MF 进行 HEVC 解码的示例,其中 none 描述了这样的错误。
// WindowsProject5.cpp : Defines the entry point for the application.
//
#include <iostream>
#include <initguid.h>
#include <mfapi.h>
#include <mftransform.h>
#include <combaseapi.h>
#include <d3d11.h>
#include <optional>
#include <Mferror.h>
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
auto result = CoInitialize(NULL);
if (result != S_OK) {
std::cout << "CoInitialize failed" << std::endl;
std::terminate();
}
MSG msg;
MFT_REGISTER_TYPE_INFO inputInfo{ MFMediaType_Video , MFVideoFormat_HEVC };
MFT_REGISTER_TYPE_INFO outputInfo{ MFMediaType_Video, MFVideoFormat_NV12 };
IMFActivate** activates;
unsigned int numActivates = 255;
result = MFTEnumEx(MFT_CATEGORY_VIDEO_DECODER, MFT_ENUM_FLAG_SYNCMFT, &inputInfo, nullptr, &activates, &numActivates);
if (result != S_OK) {
std::cout << "MFTEnum failed" << std::endl;
std::terminate();
}
std::cout << numActivates << std::endl;
if (!numActivates) {
std::cout << "No HEVC decoders found" << std::endl;
std::terminate();
}
IMFTransform* decoder;
result = activates[0]->ActivateObject(IID_PPV_ARGS(&decoder));
if (result != S_OK) {
std::cout << "ActivateObject failed" << std::endl;
std::terminate();
}
IMFAttributes* attributes;
result = decoder->GetAttributes(&attributes);
if (result != S_OK) {
std::cout << "GetAttributes failed" << std::endl;
std::terminate();
}
auto aware = 123456u;
result = attributes->GetUINT32(MF_SA_D3D11_AWARE, &aware);
if (result != S_OK) {
std::cout << "GetAttributes failed" << std::endl;
std::terminate();
}
std::cout << "MF_SA_D3D11_AWARE = " << aware << std::endl;
if (!aware) {
std::cout << "HEVC decoder is not DirectX aware" << std::endl;
std::terminate();
}
unsigned int resetToken;
IMFDXGIDeviceManager* deviceManager;
result = MFCreateDXGIDeviceManager(&resetToken, &deviceManager);
if (result != S_OK) {
std::cout << "MFCreateDXGIDeviceManager failed" << std::endl;
std::terminate();
}
result = decoder->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, reinterpret_cast<ULONG_PTR>(deviceManager));
if (result != S_OK) {
std::cout << "ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER) failed" << std::endl;
std::terminate();
}
ID3D11Device* device;
D3D_FEATURE_LEVEL featureLevel;
ID3D11DeviceContext* deviceContext;
result = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, nullptr, 0, D3D11_SDK_VERSION, &device, &featureLevel, &deviceContext);
if (result != S_OK) {
std::cout << "D3D11CreateDevice failed" << std::endl;
std::terminate();
}
result = deviceManager->ResetDevice(device, resetToken);
if (result != S_OK) {
std::cout << "ResetDevice failed" << std::endl;
std::terminate();
}
HANDLE deviceHandle;
result = deviceManager->OpenDeviceHandle(&deviceHandle);
if (result != S_OK) {
std::cout << "OpenDeviceHandle failed" << std::endl;
std::terminate();
}
ID3D11VideoDevice* videoDevice;
result = deviceManager->GetVideoService(deviceHandle, IID_PPV_ARGS(&videoDevice));
if (result != S_OK) {
std::cout << "GetVideoService failed" << std::endl;
std::terminate();
}
ID3D11VideoContext* videoContext;
result = deviceContext->QueryInterface(IID_PPV_ARGS(&videoContext));
if (result != S_OK) {
std::cout << "QueryInterface(videoContext) failed" << std::endl;
std::terminate();
}
ID3D10Multithread* multithreaded;
result = device->QueryInterface(IID_PPV_ARGS(&multithreaded));
if (result != S_OK) {
std::cout << "QueryInterface(multithreaded) failed" << std::endl;
std::terminate();
}
multithreaded->SetMultithreadProtected(true);
auto profileCount = videoDevice->GetVideoDecoderProfileCount();
std::optional<GUID> selectedProfile;
for (decltype(profileCount) i = 0; i < profileCount; ++i) {
GUID profile;
result = videoDevice->GetVideoDecoderProfile(i, &profile);
if (result != S_OK) {
std::cout << "GetVideoDecoderProfile(" << i << ") failed" << std::endl;
std::terminate();
}
if (profile == D3D11_DECODER_PROFILE_HEVC_VLD_MAIN) {
selectedProfile = profile;
std::cout << "D3D11_DECODER_PROFILE_HEVC_VLD_MAIN found" << std::endl;
}
else if (profile == D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10) {
std::cout << "D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10 found" << std::endl;
}
}
if (!selectedProfile.has_value()) {
std::cout << "No HEVC decoder profile found" << std::endl;
std::terminate();
}
BOOL supported;
result = videoDevice->CheckVideoDecoderFormat(&selectedProfile.value(), DXGI_FORMAT_NV12, &supported);
if (result != S_OK) {
std::cout << "CheckVideoDecoderFormat failed" << std::endl;
std::terminate();
}
if (!supported) {
std::cout << "Decoder format not supported" << std::endl;
std::terminate();
}
IMFMediaType* media_type;
result = MFCreateMediaType(&media_type);
if (result != S_OK) {
std::cout << "MFCreateMediaType failed" << std::endl;
std::terminate();
}
result = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
if (result != S_OK) {
std::cout << "SetGUID(MF_MT_MAJOR_TYPE) failed" << std::endl;
std::terminate();
}
result = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_HEVC);
if (result != S_OK) {
std::cout << "SetGUID(MF_MT_SUBTYPE) failed" << std::endl;
std::terminate();
}
result = decoder->SetInputType(0, media_type, 0); // No flags
if (result != S_OK) {
std::cout << "SetInputType failed" << std::endl;
std::terminate();
}
for (uint32_t i = 0;
SUCCEEDED(decoder->GetOutputAvailableType(0, i, &media_type)); ++i) {
GUID out_subtype = { 0 };
result = media_type->GetGUID(MF_MT_SUBTYPE, &out_subtype);
if (result != S_OK) {
std::cout << "GetGUID failed" << std::endl;
std::terminate();
}
if (out_subtype == MFVideoFormat_NV12) {
result = decoder->SetOutputType(0, media_type, 0); // No flags
if (result != S_OK) {
std::cout << "SetOutputType failed" << std::endl;
std::terminate();
}
return true;
}
}
return 0;
}
尽管 MSDN 没有在 H.265 / HEVC Video Decoder, you need to set them as well. See H.264 decoder article 中提及您需要哪些属性的其他输入媒体类型属性:MF_MT_FRAME_SIZE
和朋友。
您还可以使用 MFTrace SDK 工具来检查哪些属性被查询并报告为丢失,然后才会出现故障。
// Have this line added:
MFSetAttributeSize(media_type, MF_MT_FRAME_SIZE, 1280, 720);
result = decoder->SetInputType(0, media_type, 0); // No flags
我编写了这个程序来设置基于 https://docs.microsoft.com/en-us/windows/win32/medfound/supporting-direct3d-11-video-decoding-in-media-foundation 的 HEVC 解码器。一切正常,直到最后我调用 result = decoder->SetOutputType(0, media_type, 0);
这个 returns 错误 MF_E_ATTRIBUTENOTFOUND
。我不确定出了什么问题,SetOutputType 文档中没有描述这个错误,我只找到了几个使用 MF 进行 HEVC 解码的示例,其中 none 描述了这样的错误。
// WindowsProject5.cpp : Defines the entry point for the application.
//
#include <iostream>
#include <initguid.h>
#include <mfapi.h>
#include <mftransform.h>
#include <combaseapi.h>
#include <d3d11.h>
#include <optional>
#include <Mferror.h>
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
auto result = CoInitialize(NULL);
if (result != S_OK) {
std::cout << "CoInitialize failed" << std::endl;
std::terminate();
}
MSG msg;
MFT_REGISTER_TYPE_INFO inputInfo{ MFMediaType_Video , MFVideoFormat_HEVC };
MFT_REGISTER_TYPE_INFO outputInfo{ MFMediaType_Video, MFVideoFormat_NV12 };
IMFActivate** activates;
unsigned int numActivates = 255;
result = MFTEnumEx(MFT_CATEGORY_VIDEO_DECODER, MFT_ENUM_FLAG_SYNCMFT, &inputInfo, nullptr, &activates, &numActivates);
if (result != S_OK) {
std::cout << "MFTEnum failed" << std::endl;
std::terminate();
}
std::cout << numActivates << std::endl;
if (!numActivates) {
std::cout << "No HEVC decoders found" << std::endl;
std::terminate();
}
IMFTransform* decoder;
result = activates[0]->ActivateObject(IID_PPV_ARGS(&decoder));
if (result != S_OK) {
std::cout << "ActivateObject failed" << std::endl;
std::terminate();
}
IMFAttributes* attributes;
result = decoder->GetAttributes(&attributes);
if (result != S_OK) {
std::cout << "GetAttributes failed" << std::endl;
std::terminate();
}
auto aware = 123456u;
result = attributes->GetUINT32(MF_SA_D3D11_AWARE, &aware);
if (result != S_OK) {
std::cout << "GetAttributes failed" << std::endl;
std::terminate();
}
std::cout << "MF_SA_D3D11_AWARE = " << aware << std::endl;
if (!aware) {
std::cout << "HEVC decoder is not DirectX aware" << std::endl;
std::terminate();
}
unsigned int resetToken;
IMFDXGIDeviceManager* deviceManager;
result = MFCreateDXGIDeviceManager(&resetToken, &deviceManager);
if (result != S_OK) {
std::cout << "MFCreateDXGIDeviceManager failed" << std::endl;
std::terminate();
}
result = decoder->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, reinterpret_cast<ULONG_PTR>(deviceManager));
if (result != S_OK) {
std::cout << "ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER) failed" << std::endl;
std::terminate();
}
ID3D11Device* device;
D3D_FEATURE_LEVEL featureLevel;
ID3D11DeviceContext* deviceContext;
result = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, nullptr, 0, D3D11_SDK_VERSION, &device, &featureLevel, &deviceContext);
if (result != S_OK) {
std::cout << "D3D11CreateDevice failed" << std::endl;
std::terminate();
}
result = deviceManager->ResetDevice(device, resetToken);
if (result != S_OK) {
std::cout << "ResetDevice failed" << std::endl;
std::terminate();
}
HANDLE deviceHandle;
result = deviceManager->OpenDeviceHandle(&deviceHandle);
if (result != S_OK) {
std::cout << "OpenDeviceHandle failed" << std::endl;
std::terminate();
}
ID3D11VideoDevice* videoDevice;
result = deviceManager->GetVideoService(deviceHandle, IID_PPV_ARGS(&videoDevice));
if (result != S_OK) {
std::cout << "GetVideoService failed" << std::endl;
std::terminate();
}
ID3D11VideoContext* videoContext;
result = deviceContext->QueryInterface(IID_PPV_ARGS(&videoContext));
if (result != S_OK) {
std::cout << "QueryInterface(videoContext) failed" << std::endl;
std::terminate();
}
ID3D10Multithread* multithreaded;
result = device->QueryInterface(IID_PPV_ARGS(&multithreaded));
if (result != S_OK) {
std::cout << "QueryInterface(multithreaded) failed" << std::endl;
std::terminate();
}
multithreaded->SetMultithreadProtected(true);
auto profileCount = videoDevice->GetVideoDecoderProfileCount();
std::optional<GUID> selectedProfile;
for (decltype(profileCount) i = 0; i < profileCount; ++i) {
GUID profile;
result = videoDevice->GetVideoDecoderProfile(i, &profile);
if (result != S_OK) {
std::cout << "GetVideoDecoderProfile(" << i << ") failed" << std::endl;
std::terminate();
}
if (profile == D3D11_DECODER_PROFILE_HEVC_VLD_MAIN) {
selectedProfile = profile;
std::cout << "D3D11_DECODER_PROFILE_HEVC_VLD_MAIN found" << std::endl;
}
else if (profile == D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10) {
std::cout << "D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10 found" << std::endl;
}
}
if (!selectedProfile.has_value()) {
std::cout << "No HEVC decoder profile found" << std::endl;
std::terminate();
}
BOOL supported;
result = videoDevice->CheckVideoDecoderFormat(&selectedProfile.value(), DXGI_FORMAT_NV12, &supported);
if (result != S_OK) {
std::cout << "CheckVideoDecoderFormat failed" << std::endl;
std::terminate();
}
if (!supported) {
std::cout << "Decoder format not supported" << std::endl;
std::terminate();
}
IMFMediaType* media_type;
result = MFCreateMediaType(&media_type);
if (result != S_OK) {
std::cout << "MFCreateMediaType failed" << std::endl;
std::terminate();
}
result = media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
if (result != S_OK) {
std::cout << "SetGUID(MF_MT_MAJOR_TYPE) failed" << std::endl;
std::terminate();
}
result = media_type->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_HEVC);
if (result != S_OK) {
std::cout << "SetGUID(MF_MT_SUBTYPE) failed" << std::endl;
std::terminate();
}
result = decoder->SetInputType(0, media_type, 0); // No flags
if (result != S_OK) {
std::cout << "SetInputType failed" << std::endl;
std::terminate();
}
for (uint32_t i = 0;
SUCCEEDED(decoder->GetOutputAvailableType(0, i, &media_type)); ++i) {
GUID out_subtype = { 0 };
result = media_type->GetGUID(MF_MT_SUBTYPE, &out_subtype);
if (result != S_OK) {
std::cout << "GetGUID failed" << std::endl;
std::terminate();
}
if (out_subtype == MFVideoFormat_NV12) {
result = decoder->SetOutputType(0, media_type, 0); // No flags
if (result != S_OK) {
std::cout << "SetOutputType failed" << std::endl;
std::terminate();
}
return true;
}
}
return 0;
}
尽管 MSDN 没有在 H.265 / HEVC Video Decoder, you need to set them as well. See H.264 decoder article 中提及您需要哪些属性的其他输入媒体类型属性:MF_MT_FRAME_SIZE
和朋友。
您还可以使用 MFTrace SDK 工具来检查哪些属性被查询并报告为丢失,然后才会出现故障。
// Have this line added:
MFSetAttributeSize(media_type, MF_MT_FRAME_SIZE, 1280, 720);
result = decoder->SetInputType(0, media_type, 0); // No flags