obs-amf-test.cpp 4.4 KB

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