obs-amf-test.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #include <AMF/core/Factory.h>
  2. #include <AMF/core/Trace.h>
  3. #include <AMF/components/VideoEncoderVCE.h>
  4. #include <AMF/components/VideoEncoderHEVC.h>
  5. #include <AMF/components/VideoEncoderAV1.h>
  6. #include <util/windows/ComPtr.hpp>
  7. #include <dxgi.h>
  8. #include <d3d11.h>
  9. #include <d3d11_1.h>
  10. #include <vector>
  11. #include <string>
  12. #include <map>
  13. using namespace amf;
  14. #ifdef _MSC_VER
  15. extern "C" __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
  16. #endif
  17. #define AMD_VENDOR_ID 0x1002
  18. struct adapter_caps {
  19. bool is_amd = false;
  20. bool supports_avc = false;
  21. bool supports_hevc = false;
  22. bool supports_av1 = false;
  23. };
  24. static AMFFactory *amf_factory = nullptr;
  25. static std::vector<uint64_t> luid_order;
  26. static std::map<uint32_t, adapter_caps> adapter_info;
  27. static bool has_encoder(AMFContextPtr &amf_context, const wchar_t *encoder_name)
  28. {
  29. AMFComponentPtr encoder;
  30. AMF_RESULT res = amf_factory->CreateComponent(amf_context, encoder_name, &encoder);
  31. return res == AMF_OK;
  32. }
  33. static inline uint32_t get_adapter_idx(uint32_t adapter_idx, LUID luid)
  34. {
  35. for (size_t i = 0; i < luid_order.size(); i++) {
  36. if (luid_order[i] == *(uint64_t *)&luid) {
  37. return (uint32_t)i;
  38. }
  39. }
  40. return adapter_idx;
  41. }
  42. static bool get_adapter_caps(IDXGIFactory *factory, uint32_t adapter_idx)
  43. {
  44. AMF_RESULT res;
  45. HRESULT hr;
  46. ComPtr<IDXGIAdapter> adapter;
  47. hr = factory->EnumAdapters(adapter_idx, &adapter);
  48. if (FAILED(hr))
  49. return false;
  50. DXGI_ADAPTER_DESC desc;
  51. adapter->GetDesc(&desc);
  52. uint32_t luid_idx = get_adapter_idx(adapter_idx, desc.AdapterLuid);
  53. adapter_caps &caps = adapter_info[luid_idx];
  54. if (desc.VendorId != AMD_VENDOR_ID)
  55. return true;
  56. caps.is_amd = true;
  57. ComPtr<ID3D11Device> device;
  58. ComPtr<ID3D11DeviceContext> context;
  59. hr = D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0, nullptr, 0, D3D11_SDK_VERSION, &device,
  60. nullptr, &context);
  61. if (FAILED(hr))
  62. return true;
  63. AMFContextPtr amf_context;
  64. res = amf_factory->CreateContext(&amf_context);
  65. if (res != AMF_OK)
  66. return true;
  67. res = amf_context->InitDX11(device);
  68. if (res != AMF_OK)
  69. return true;
  70. caps.supports_avc = has_encoder(amf_context, AMFVideoEncoderVCE_AVC);
  71. caps.supports_hevc = has_encoder(amf_context, AMFVideoEncoder_HEVC);
  72. caps.supports_av1 = has_encoder(amf_context, AMFVideoEncoder_AV1);
  73. return true;
  74. }
  75. DWORD WINAPI TimeoutThread(LPVOID param)
  76. {
  77. HANDLE hMainThread = (HANDLE)param;
  78. DWORD ret = WaitForSingleObject(hMainThread, 2500);
  79. if (ret == WAIT_TIMEOUT)
  80. TerminateProcess(GetCurrentProcess(), STATUS_TIMEOUT);
  81. CloseHandle(hMainThread);
  82. return 0;
  83. }
  84. int main(int argc, char *argv[])
  85. try {
  86. ComPtr<IDXGIFactory> factory;
  87. AMF_RESULT res;
  88. HRESULT hr;
  89. HANDLE hMainThread;
  90. DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, 0, FALSE,
  91. DUPLICATE_SAME_ACCESS);
  92. DWORD threadId;
  93. HANDLE hThread;
  94. hThread = CreateThread(NULL, 0, TimeoutThread, hMainThread, 0, &threadId);
  95. CloseHandle(hThread);
  96. /* --------------------------------------------------------- */
  97. /* try initializing amf, I guess */
  98. HMODULE amf_module = LoadLibraryW(AMF_DLL_NAME);
  99. if (!amf_module)
  100. throw "Failed to load AMF lib";
  101. auto init = (AMFInit_Fn)GetProcAddress(amf_module, AMF_INIT_FUNCTION_NAME);
  102. if (!init)
  103. throw "Failed to get init func";
  104. res = init(AMF_FULL_VERSION, &amf_factory);
  105. if (res != AMF_OK)
  106. throw "AMFInit failed";
  107. /* --------------------------------------------------------- */
  108. /* parse expected LUID order */
  109. for (int i = 1; i < argc; i++) {
  110. luid_order.push_back(strtoull(argv[i], NULL, 16));
  111. }
  112. /* --------------------------------------------------------- */
  113. /* obtain adapter compatibility information */
  114. hr = CreateDXGIFactory1(__uuidof(IDXGIFactory), (void **)&factory);
  115. if (FAILED(hr))
  116. throw "CreateDXGIFactory1 failed";
  117. uint32_t idx = 0;
  118. while (get_adapter_caps(factory, idx++))
  119. ;
  120. for (auto &[idx, caps] : adapter_info) {
  121. printf("[%u]\n", idx);
  122. printf("is_amd=%s\n", caps.is_amd ? "true" : "false");
  123. printf("supports_avc=%s\n", caps.supports_avc ? "true" : "false");
  124. printf("supports_hevc=%s\n", caps.supports_hevc ? "true" : "false");
  125. printf("supports_av1=%s\n", caps.supports_av1 ? "true" : "false");
  126. }
  127. return 0;
  128. } catch (const char *text) {
  129. printf("[error]\nstring=%s\n", text);
  130. return 0;
  131. }