record_desktop_duplication.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932
  1. #include "record_desktop_duplication.h"
  2. #include "d3d_helper.h"
  3. #include "d3d_pixelshader.h"
  4. #include "d3d_vertexshader.h"
  5. #include "system_lib.h"
  6. #include "utils_string.h"
  7. #include "error_define.h"
  8. #include "log_helper.h"
  9. #include "system_error.h"
  10. namespace am {
  11. record_desktop_duplication::record_desktop_duplication()
  12. {
  13. _data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_BGRA;
  14. _buffer = NULL;
  15. _buffer_size = 0;
  16. _d3d11 = nullptr;
  17. _dxgi = nullptr;
  18. _d3d_device = nullptr;
  19. _d3d_ctx = nullptr;
  20. _d3d_vshader = nullptr;
  21. _d3d_pshader = nullptr;
  22. _d3d_inlayout = nullptr;
  23. _d3d_samplerlinear = nullptr;
  24. _duplication = nullptr;
  25. _image = nullptr;
  26. _output_des = {0};
  27. _output_index = 0;
  28. ZeroMemory(&_cursor_info, sizeof(_cursor_info));
  29. }
  30. record_desktop_duplication::~record_desktop_duplication()
  31. {
  32. stop();
  33. clean_up();
  34. }
  35. int record_desktop_duplication::init(const RECORD_DESKTOP_RECT &rect, const int fps)
  36. {
  37. int error = AE_NO;
  38. if (_inited == true) {
  39. return error;
  40. }
  41. _fps = fps;
  42. _rect = rect;
  43. do {
  44. _d3d11 = load_system_library("d3d11.dll");
  45. _dxgi = load_system_library("dxgi.dll");
  46. if (!_d3d11 || !_dxgi) {
  47. error = AE_D3D_LOAD_FAILED;
  48. break;
  49. }
  50. error = init_d3d11();
  51. if (error != AE_NO)
  52. break;
  53. _width = rect.right - rect.left;
  54. _height = rect.bottom - rect.top;
  55. _buffer_size = (_width * 32 + 31) / 32 * _height * 4;
  56. _buffer = new uint8_t[_buffer_size];
  57. _start_time = av_gettime_relative();
  58. _time_base = {1, AV_TIME_BASE};
  59. _pixel_fmt = AV_PIX_FMT_BGRA;
  60. error = init_duplication();
  61. if (error != AE_NO) {
  62. break;
  63. }
  64. _inited = true;
  65. } while (0);
  66. if (error != AE_NO) {
  67. al_debug("%s,last error:%s",
  68. err2str(error),
  69. system_error::error2str(GetLastError()).c_str());
  70. }
  71. return error;
  72. }
  73. int record_desktop_duplication::start()
  74. {
  75. if (_running == true) {
  76. al_warn("record desktop duplication is already running");
  77. return AE_NO;
  78. }
  79. if (_inited == false) {
  80. return AE_NEED_INIT;
  81. }
  82. _running = true;
  83. _thread = std::thread(std::bind(&record_desktop_duplication::record_func, this));
  84. return AE_NO;
  85. }
  86. int record_desktop_duplication::pause()
  87. {
  88. _paused = true;
  89. return AE_NO;
  90. }
  91. int record_desktop_duplication::resume()
  92. {
  93. _paused = false;
  94. return AE_NO;
  95. }
  96. int record_desktop_duplication::stop()
  97. {
  98. _running = false;
  99. if (_thread.joinable())
  100. _thread.join();
  101. return AE_NO;
  102. }
  103. void record_desktop_duplication::clean_up()
  104. {
  105. _inited = false;
  106. if (_buffer)
  107. delete[] _buffer;
  108. _buffer = nullptr;
  109. if (_cursor_info.buff) {
  110. delete[] _cursor_info.buff;
  111. _cursor_info.buff = nullptr;
  112. }
  113. ZeroMemory(&_cursor_info, sizeof(_cursor_info));
  114. //Clean up duplication interfaces
  115. clean_duplication();
  116. //Clean up d3d11 interfaces
  117. clean_d3d11();
  118. //finally free d3d11 & dxgi library
  119. if (_d3d11)
  120. free_system_library(_d3d11);
  121. _d3d11 = nullptr;
  122. if (_dxgi)
  123. free_system_library(_dxgi);
  124. _dxgi = nullptr;
  125. }
  126. int record_desktop_duplication::get_dst_adapter(IDXGIAdapter **adapter)
  127. {
  128. int error = AE_NO;
  129. do {
  130. auto adapters = d3d_helper::get_adapters(&error, true);
  131. if (error != AE_NO || adapters.size() == 0)
  132. break;
  133. for (std::list<IDXGIAdapter *>::iterator itr = adapters.begin(); itr != adapters.end();
  134. itr++) {
  135. IDXGIOutput *adapter_output = nullptr;
  136. DXGI_ADAPTER_DESC adapter_desc = {0};
  137. DXGI_OUTPUT_DESC adapter_output_desc = {0};
  138. (*itr)->GetDesc(&adapter_desc);
  139. al_debug("adaptor:%s", utils_string::unicode_ascii(adapter_desc.Description).c_str());
  140. unsigned int n = 0;
  141. RECT output_rect;
  142. while ((*itr)->EnumOutputs(n, &adapter_output) != DXGI_ERROR_NOT_FOUND) {
  143. HRESULT hr = adapter_output->GetDesc(&adapter_output_desc);
  144. if (FAILED(hr))
  145. continue;
  146. output_rect = adapter_output_desc.DesktopCoordinates;
  147. al_debug(" output:%s left:%d top:%d right:%d bottom:%d",
  148. utils_string::unicode_ascii(adapter_output_desc.DeviceName).c_str(),
  149. output_rect.left,
  150. output_rect.top,
  151. output_rect.right,
  152. output_rect.bottom);
  153. if (output_rect.left <= _rect.left && output_rect.top <= _rect.top
  154. && output_rect.right >= _rect.right && output_rect.bottom >= _rect.bottom) {
  155. error = AE_NO;
  156. break;
  157. }
  158. ++n;
  159. }
  160. if (error != AE_DXGI_FOUND_ADAPTER_FAILED) {
  161. *adapter = *itr;
  162. break;
  163. }
  164. }
  165. } while (0);
  166. return error;
  167. }
  168. int record_desktop_duplication::create_d3d_device(IDXGIAdapter *adapter, ID3D11Device **device)
  169. {
  170. int error = AE_NO;
  171. do {
  172. PFN_D3D11_CREATE_DEVICE create_device = (PFN_D3D11_CREATE_DEVICE)
  173. GetProcAddress(_d3d11, "D3D11CreateDevice");
  174. if (!create_device) {
  175. error = AE_D3D_GET_PROC_FAILED;
  176. break;
  177. }
  178. HRESULT hr = S_OK;
  179. // Driver types supported
  180. // If you set the pAdapter parameter to a non - NULL value,
  181. // you must also set the DriverType parameter to the D3D_DRIVER_TYPE_UNKNOWN value.
  182. D3D_DRIVER_TYPE driver_types[] = {
  183. D3D_DRIVER_TYPE_UNKNOWN,
  184. D3D_DRIVER_TYPE_HARDWARE,
  185. D3D_DRIVER_TYPE_WARP,
  186. D3D_DRIVER_TYPE_REFERENCE,
  187. };
  188. UINT n_driver_types = ARRAYSIZE(driver_types);
  189. // Feature levels supported
  190. D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_0,
  191. D3D_FEATURE_LEVEL_10_1,
  192. D3D_FEATURE_LEVEL_10_0,
  193. D3D_FEATURE_LEVEL_9_1};
  194. UINT n_feature_levels = ARRAYSIZE(feature_levels);
  195. D3D_FEATURE_LEVEL feature_level;
  196. // Create device
  197. for (UINT driver_index = 0; driver_index < n_driver_types; ++driver_index) {
  198. hr = create_device(adapter,
  199. driver_types[driver_index],
  200. nullptr,
  201. 0,
  202. feature_levels,
  203. n_feature_levels,
  204. D3D11_SDK_VERSION,
  205. device,
  206. &feature_level,
  207. &_d3d_ctx);
  208. if (SUCCEEDED(hr))
  209. break;
  210. }
  211. if (FAILED(hr)) {
  212. error = AE_D3D_CREATE_DEVICE_FAILED;
  213. break;
  214. }
  215. } while (0);
  216. return error;
  217. }
  218. int record_desktop_duplication::init_d3d11()
  219. {
  220. int error = AE_NO;
  221. do {
  222. IDXGIAdapter *adapter = nullptr;
  223. error = get_dst_adapter(&adapter);
  224. if (error != AE_NO)
  225. break;
  226. error = create_d3d_device(adapter, &_d3d_device);
  227. if (error != AE_NO)
  228. break;
  229. //No need for grab full screen,but in move & dirty rects copy
  230. #if 0
  231. // VERTEX shader
  232. UINT Size = ARRAYSIZE(g_VS);
  233. HRESULT hr = _d3d_device->CreateVertexShader(g_VS, Size, nullptr, &_d3d_vshader);
  234. if (FAILED(hr))
  235. {
  236. error = AE_D3D_CREATE_VERTEX_SHADER_FAILED;
  237. break;
  238. }
  239. // Input layout
  240. D3D11_INPUT_ELEMENT_DESC layouts[] =
  241. {
  242. { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
  243. { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
  244. };
  245. UINT n_layouts = ARRAYSIZE(layouts);
  246. hr = _d3d_device->CreateInputLayout(layouts, n_layouts, g_VS, Size, &_d3d_inlayout);
  247. if (FAILED(hr))
  248. {
  249. error = AE_D3D_CREATE_INLAYOUT_FAILED;
  250. break;
  251. }
  252. _d3d_ctx->IASetInputLayout(_d3d_inlayout);
  253. // Pixel shader
  254. Size = ARRAYSIZE(g_PS);
  255. hr = _d3d_device->CreatePixelShader(g_PS, Size, nullptr, &_d3d_pshader);
  256. if (FAILED(hr))
  257. {
  258. error = AE_D3D_CREATE_PIXEL_SHADER_FAILED;
  259. break;
  260. }
  261. // Set up sampler
  262. D3D11_SAMPLER_DESC sampler_desc;
  263. RtlZeroMemory(&sampler_desc, sizeof(sampler_desc));
  264. sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
  265. sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
  266. sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
  267. sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
  268. sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
  269. sampler_desc.MinLOD = 0;
  270. sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
  271. hr = _d3d_device->CreateSamplerState(&sampler_desc, &_d3d_samplerlinear);
  272. if (FAILED(hr))
  273. {
  274. error = AE_D3D_CREATE_SAMPLERSTATE_FAILED;
  275. break;
  276. }
  277. #endif
  278. } while (0);
  279. return error;
  280. }
  281. void record_desktop_duplication::clean_d3d11()
  282. {
  283. if (_d3d_device)
  284. _d3d_device->Release();
  285. _d3d_device = nullptr;
  286. if (_d3d_ctx)
  287. _d3d_ctx->Release();
  288. _d3d_ctx = nullptr;
  289. if (_d3d_vshader)
  290. _d3d_vshader->Release();
  291. _d3d_vshader = nullptr;
  292. if (_d3d_pshader)
  293. _d3d_pshader->Release();
  294. _d3d_pshader = nullptr;
  295. if (_d3d_inlayout)
  296. _d3d_inlayout->Release();
  297. _d3d_inlayout = nullptr;
  298. if (_d3d_samplerlinear)
  299. _d3d_samplerlinear->Release();
  300. _d3d_samplerlinear = nullptr;
  301. }
  302. int record_desktop_duplication::init_duplication()
  303. {
  304. int error = AE_NO;
  305. do {
  306. // Get DXGI device
  307. IDXGIDevice *dxgi_device = nullptr;
  308. HRESULT hr = _d3d_device->QueryInterface(__uuidof(IDXGIDevice),
  309. reinterpret_cast<void **>(&dxgi_device));
  310. if (FAILED(hr)) {
  311. error = AE_D3D_QUERYINTERFACE_FAILED;
  312. break;
  313. }
  314. // Get DXGI adapter
  315. IDXGIAdapter *dxgi_adapter = nullptr;
  316. hr = dxgi_device->GetParent(__uuidof(IDXGIAdapter),
  317. reinterpret_cast<void **>(&dxgi_adapter));
  318. dxgi_device->Release();
  319. dxgi_device = nullptr;
  320. if (FAILED(hr)) {
  321. error = AE_DUP_GET_PARENT_FAILED;
  322. break;
  323. }
  324. // Get output
  325. IDXGIOutput *dxgi_output = nullptr;
  326. hr = dxgi_adapter->EnumOutputs(_output_index, &dxgi_output);
  327. dxgi_adapter->Release();
  328. dxgi_adapter = nullptr;
  329. if (FAILED(hr)) {
  330. error = AE_DUP_ENUM_OUTPUT_FAILED;
  331. break;
  332. }
  333. dxgi_output->GetDesc(&_output_des);
  334. // QI for Output 1
  335. IDXGIOutput1 *dxgi_output1 = nullptr;
  336. hr = dxgi_output->QueryInterface(__uuidof(dxgi_output1),
  337. reinterpret_cast<void **>(&dxgi_output1));
  338. dxgi_output->Release();
  339. dxgi_output = nullptr;
  340. if (FAILED(hr)) {
  341. error = AE_DUP_QI_FAILED;
  342. break;
  343. }
  344. // Create desktop duplication
  345. hr = dxgi_output1->DuplicateOutput(_d3d_device, &_duplication);
  346. dxgi_output1->Release();
  347. dxgi_output1 = nullptr;
  348. if (FAILED(hr)) {
  349. error = AE_DUP_DUPLICATE_FAILED;
  350. if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
  351. error = AE_DUP_DUPLICATE_MAX_FAILED;
  352. }
  353. al_error("duplicate output failed,%lld", hr);
  354. break;
  355. }
  356. } while (0);
  357. return error;
  358. }
  359. int record_desktop_duplication::free_duplicated_frame()
  360. {
  361. HRESULT hr = _duplication->ReleaseFrame();
  362. if (FAILED(hr)) {
  363. return AE_DUP_RELEASE_FRAME_FAILED;
  364. }
  365. if (_image) {
  366. _image->Release();
  367. _image = nullptr;
  368. }
  369. return AE_DUP_RELEASE_FRAME_FAILED;
  370. }
  371. void record_desktop_duplication::clean_duplication()
  372. {
  373. if (_duplication)
  374. _duplication->Release();
  375. if (_image)
  376. _image->Release();
  377. _duplication = nullptr;
  378. _image = nullptr;
  379. }
  380. bool record_desktop_duplication::attatch_desktop()
  381. {
  382. HDESK desktop = nullptr;
  383. desktop = OpenInputDesktop(0, FALSE, GENERIC_ALL);
  384. if (!desktop) {
  385. // We do not have access to the desktop so request a retry
  386. return false;
  387. }
  388. // Attach desktop to this thread
  389. bool battached = SetThreadDesktop(desktop) != 0;
  390. CloseDesktop(desktop);
  391. if (!battached) {
  392. // We do not have access to the desktop so request a retry
  393. return false;
  394. }
  395. return true;
  396. }
  397. int record_desktop_duplication::get_desktop_image(DXGI_OUTDUPL_FRAME_INFO *frame_info)
  398. {
  399. IDXGIResource *dxgi_res = nullptr;
  400. // Get new frame (adaptive low-latency timeout)
  401. int timeout_ms = 10;
  402. if (_fps > 0) {
  403. timeout_ms = 1000 / _fps / 2;
  404. if (timeout_ms < 1) timeout_ms = 1;
  405. }
  406. HRESULT hr = _duplication->AcquireNextFrame(timeout_ms, frame_info, &dxgi_res);
  407. // Timeout will return when desktop has no chane
  408. if (hr == DXGI_ERROR_WAIT_TIMEOUT)
  409. return AE_TIMEOUT;
  410. if (FAILED(hr))
  411. return AE_DUP_ACQUIRE_FRAME_FAILED;
  412. // QI for IDXGIResource
  413. hr = dxgi_res->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&_image));
  414. dxgi_res->Release();
  415. dxgi_res = nullptr;
  416. if (FAILED(hr))
  417. return AE_DUP_QI_FRAME_FAILED;
  418. // Copy old description
  419. D3D11_TEXTURE2D_DESC frame_desc;
  420. _image->GetDesc(&frame_desc);
  421. // Create a new staging buffer for fill frame image
  422. ID3D11Texture2D *new_image = NULL;
  423. frame_desc.Usage = D3D11_USAGE_STAGING;
  424. frame_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
  425. frame_desc.BindFlags = 0;
  426. frame_desc.MiscFlags = 0;
  427. frame_desc.MipLevels = 1;
  428. frame_desc.ArraySize = 1;
  429. frame_desc.SampleDesc.Count = 1;
  430. frame_desc.SampleDesc.Quality = 0;
  431. hr = _d3d_device->CreateTexture2D(&frame_desc, NULL, &new_image);
  432. if (FAILED(hr))
  433. return AE_DUP_CREATE_TEXTURE_FAILED;
  434. // Copy next staging buffer to new staging buffer
  435. _d3d_ctx->CopyResource(new_image, _image);
  436. #if 1
  437. // Should calc the row pitch ,and compare dst row pitch with frame row pitch
  438. // Create staging buffer for map bits
  439. IDXGISurface *dxgi_surface = NULL;
  440. hr = new_image->QueryInterface(__uuidof(IDXGISurface), (void **) (&dxgi_surface));
  441. new_image->Release();
  442. if (FAILED(hr))
  443. return AE_DUP_QI_DXGI_FAILED;
  444. // Map buff to mapped rect structure
  445. DXGI_MAPPED_RECT mapped_rect;
  446. hr = dxgi_surface->Map(&mapped_rect, DXGI_MAP_READ);
  447. if (FAILED(hr))
  448. return AE_DUP_MAP_FAILED;
  449. int dst_offset_x = _rect.left - _output_des.DesktopCoordinates.left;
  450. int dst_offset_y = _rect.top - _output_des.DesktopCoordinates.top;
  451. int dst_rowpitch = min(frame_desc.Width, _rect.right - _rect.left) * 4;
  452. int dst_colpitch = min(_height,
  453. _output_des.DesktopCoordinates.bottom
  454. - _output_des.DesktopCoordinates.top - dst_offset_y);
  455. for (int h = 0; h < dst_colpitch; h++) {
  456. memcpy_s(_buffer + h * dst_rowpitch,
  457. dst_rowpitch,
  458. (BYTE *) mapped_rect.pBits + (h + dst_offset_y) * mapped_rect.Pitch
  459. + dst_offset_x * 4,
  460. min(mapped_rect.Pitch, dst_rowpitch));
  461. }
  462. dxgi_surface->Unmap();
  463. dxgi_surface->Release();
  464. dxgi_surface = nullptr;
  465. #else
  466. D3D11_MAPPED_SUBRESOURCE resource;
  467. UINT subresource = D3D11CalcSubresource(0, 0, 0);
  468. hr = _d3d_ctx->Map(new_image, subresource, D3D11_MAP_READ_WRITE, 0, &resource);
  469. new_image->Release();
  470. if (FAILED(hr))
  471. return AE_DUP_MAP_FAILED;
  472. int dst_rowpitch = frame_desc.Width * 4;
  473. for (int h = 0; h < frame_desc.Height; h++) {
  474. memcpy_s(_buffer + h * dst_rowpitch,
  475. dst_rowpitch,
  476. (BYTE *) resource.pData + h * resource.RowPitch,
  477. min(resource.RowPitch, dst_rowpitch));
  478. }
  479. #endif
  480. return AE_NO;
  481. }
  482. int record_desktop_duplication::get_desktop_cursor(const DXGI_OUTDUPL_FRAME_INFO *frame_info)
  483. {
  484. // A non-zero mouse update timestamp indicates that there is a mouse position update and optionally a shape change
  485. if (frame_info->LastMouseUpdateTime.QuadPart == 0)
  486. return AE_NO;
  487. bool b_updated = true;
  488. // Make sure we don't update pointer position wrongly
  489. // If pointer is invisible, make sure we did not get an update from another output that the last time that said pointer
  490. // was visible, if so, don't set it to invisible or update.
  491. if (!frame_info->PointerPosition.Visible && (_cursor_info.output_index != _output_index))
  492. b_updated = false;
  493. // If two outputs both say they have a visible, only update if new update has newer timestamp
  494. if (frame_info->PointerPosition.Visible && _cursor_info.visible
  495. && (_cursor_info.output_index != _output_index)
  496. && (_cursor_info.pre_timestamp.QuadPart > frame_info->LastMouseUpdateTime.QuadPart))
  497. b_updated = false;
  498. // Update position
  499. if (b_updated) {
  500. _cursor_info.position.x = frame_info->PointerPosition.Position.x
  501. + _output_des.DesktopCoordinates.left;
  502. _cursor_info.position.y = frame_info->PointerPosition.Position.y
  503. + _output_des.DesktopCoordinates.top;
  504. _cursor_info.output_index = _output_index;
  505. _cursor_info.pre_timestamp = frame_info->LastMouseUpdateTime;
  506. _cursor_info.visible = frame_info->PointerPosition.Visible != 0;
  507. }
  508. // No new shape only update cursor positions & visible state
  509. if (frame_info->PointerShapeBufferSize == 0) {
  510. return AE_NO;
  511. }
  512. // Old buffer too small
  513. if (frame_info->PointerShapeBufferSize > _cursor_info.size) {
  514. if (_cursor_info.buff) {
  515. delete[] _cursor_info.buff;
  516. _cursor_info.buff = nullptr;
  517. }
  518. _cursor_info.buff = new (std::nothrow) BYTE[frame_info->PointerShapeBufferSize];
  519. if (!_cursor_info.buff) {
  520. _cursor_info.size = 0;
  521. return AE_ALLOCATE_FAILED;
  522. }
  523. // Update buffer size
  524. _cursor_info.size = frame_info->PointerShapeBufferSize;
  525. }
  526. // Get shape
  527. UINT BufferSizeRequired;
  528. HRESULT hr = _duplication->GetFramePointerShape(frame_info->PointerShapeBufferSize,
  529. reinterpret_cast<VOID *>(_cursor_info.buff),
  530. &BufferSizeRequired,
  531. &(_cursor_info.shape));
  532. if (FAILED(hr)) {
  533. delete[] _cursor_info.buff;
  534. _cursor_info.buff = nullptr;
  535. _cursor_info.size = 0;
  536. return AE_DUP_GET_CURSORSHAPE_FAILED;
  537. }
  538. return AE_NO;
  539. }
  540. static unsigned int bit_reverse(unsigned int n)
  541. {
  542. n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa);
  543. n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc);
  544. n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0);
  545. n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
  546. n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
  547. return n;
  548. }
  549. void record_desktop_duplication::draw_cursor()
  550. {
  551. if (_cursor_info.visible == false)
  552. return;
  553. int cursor_width = 0, cursor_height = 0, left = 0, top = 0;
  554. cursor_width = _cursor_info.shape.Width;
  555. cursor_height = _cursor_info.shape.Height;
  556. // In case that,the value of position is negative value
  557. left = abs(_cursor_info.position.x - _rect.left);
  558. top = abs(_cursor_info.position.y - _rect.top);
  559. // Notice here
  560. if (_cursor_info.shape.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME)
  561. cursor_height = cursor_height / 2;
  562. //Skip invisible pixel
  563. cursor_width = min(_width - left, cursor_width);
  564. cursor_height = min(_height - top, cursor_height);
  565. //al_debug("left:%d top:%d width:%d height:%d type:%d", left, top, cursor_width, height, _cursor_info.shape.Type);
  566. switch (_cursor_info.shape.Type) {
  567. // The pointer type is a color mouse pointer,
  568. // which is a color bitmap. The bitmap's size
  569. // is specified by width and height in a 32 bpp
  570. // ARGB DIB format.
  571. // should trans cursor to BGRA?
  572. case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR: {
  573. unsigned int *cursor_32 = reinterpret_cast<unsigned int *>(_cursor_info.buff);
  574. unsigned int *screen_32 = reinterpret_cast<unsigned int *>(_buffer);
  575. for (int row = 0; row < cursor_height; row++) {
  576. for (int col = 0; col < cursor_width; col++) {
  577. unsigned int cur_cursor_val
  578. = cursor_32[col + (row * (_cursor_info.shape.Pitch / sizeof(UINT)))];
  579. //Skip black or empty value
  580. if (cur_cursor_val == 0x00000000)
  581. continue;
  582. else
  583. screen_32[(abs(top) + row) * _width + abs(left) + col]
  584. = cur_cursor_val; //bit_reverse(cur_cursor_val);
  585. }
  586. }
  587. break;
  588. }
  589. // The pointer type is a monochrome mouse pointer,
  590. // which is a monochrome bitmap. The bitmap's size
  591. // is specified by width and height in a 1 bits per
  592. // pixel (bpp) device independent bitmap (DIB) format
  593. // AND mask that is followed by another 1 bpp DIB format
  594. // XOR mask of the same size.
  595. case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME: {
  596. unsigned int *cursor_32 = reinterpret_cast<unsigned int *>(_cursor_info.buff);
  597. unsigned int *screen_32 = reinterpret_cast<unsigned int *>(_buffer);
  598. for (int row = 0; row < cursor_height; row++) {
  599. BYTE MASK = 0x80;
  600. for (int col = 0; col < cursor_width; col++) {
  601. // Get masks using appropriate offsets
  602. BYTE AndMask = _cursor_info.buff[(col / 8) + (row * (_cursor_info.shape.Pitch))]
  603. & MASK;
  604. BYTE XorMask
  605. = _cursor_info.buff[(col / 8)
  606. + ((row + cursor_height) * (_cursor_info.shape.Pitch))]
  607. & MASK;
  608. UINT AndMask32 = (AndMask) ? 0xFFFFFFFF : 0xFF000000;
  609. UINT XorMask32 = (XorMask) ? 0x00FFFFFF : 0x00000000;
  610. // Set new pixel
  611. screen_32[(abs(top) + row) * _width + abs(left) + col]
  612. = (screen_32[(abs(top) + row) * _width + abs(left) + col] & AndMask32)
  613. ^ XorMask32;
  614. // Adjust mask
  615. if (MASK == 0x01) {
  616. MASK = 0x80;
  617. } else {
  618. MASK = MASK >> 1;
  619. }
  620. }
  621. }
  622. break;
  623. }
  624. // The pointer type is a masked color mouse pointer.
  625. // A masked color mouse pointer is a 32 bpp ARGB format
  626. // bitmap with the mask value in the alpha bits. The only
  627. // allowed mask values are 0 and 0xFF. When the mask value
  628. // is 0, the RGB value should replace the screen pixel.
  629. // When the mask value is 0xFF, an XOR operation is performed
  630. // on the RGB value and the screen pixel; the result replaces the screen pixel.
  631. case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: {
  632. unsigned int *cursor_32 = reinterpret_cast<unsigned int *>(_cursor_info.buff);
  633. unsigned int *screen_32 = reinterpret_cast<unsigned int *>(_buffer);
  634. for (int row = 0; row < cursor_height; row++) {
  635. for (int col = 0; col < cursor_width; col++) {
  636. unsigned int cur_cursor_val
  637. = cursor_32[col + (row * (_cursor_info.shape.Pitch / sizeof(UINT)))];
  638. unsigned int cur_screen_val = screen_32[(abs(top) + row) * _width + abs(left) + col];
  639. unsigned int mask_val = 0xFF000000 & cur_cursor_val;
  640. if (mask_val) {
  641. //0xFF: XOR operation is performed on the RGB value and the screen pixel
  642. cur_screen_val = (cur_screen_val ^ cur_cursor_val) | 0xFF000000;
  643. } else {
  644. //0x00: the RGB value should replace the screen pixel
  645. cur_screen_val = cur_cursor_val | 0xFF000000;
  646. }
  647. }
  648. }
  649. break;
  650. }
  651. default:
  652. break;
  653. }
  654. }
  655. void record_desktop_duplication::do_sleep(int64_t dur, int64_t pre, int64_t now)
  656. {
  657. int64_t delay = now - pre;
  658. dur = delay > dur ? max(0, dur - (delay - dur)) : (dur + dur - delay);
  659. //al_debug("%lld", delay);
  660. if (dur)
  661. av_usleep(dur);
  662. }
  663. void record_desktop_duplication::record_func()
  664. {
  665. AVFrame *frame = av_frame_alloc();
  666. int64_t pre_pts = 0, dur = AV_TIME_BASE / _fps;
  667. int error = AE_NO;
  668. #if 0
  669. if (attatch_desktop() != true) {
  670. al_fatal("duplication attach desktop failed :%s",
  671. system_error::error2str(GetLastError()).c_str());
  672. if (_on_error) _on_error(AE_DUP_ATTATCH_FAILED);
  673. return;
  674. }
  675. #endif
  676. DXGI_OUTDUPL_FRAME_INFO frame_info;
  677. while (_running) {
  678. //Timeout is no new picture,no need to update
  679. if ((error = get_desktop_image(&frame_info)) == AE_TIMEOUT) {
  680. // Push duplicate frame to keep steady cadence and avoid buffer growth
  681. frame->pts = av_gettime_relative();
  682. frame->pkt_dts = frame->pts;
  683. frame->width = _width;
  684. frame->height = _height;
  685. frame->format = AV_PIX_FMT_BGRA;
  686. frame->pict_type = AV_PICTURE_TYPE_NONE;
  687. frame->pkt_size = _width * _height * 4;
  688. av_image_fill_arrays(frame->data,
  689. frame->linesize,
  690. _buffer,
  691. AV_PIX_FMT_BGRA,
  692. _width,
  693. _height,
  694. 1);
  695. if (_on_data)
  696. _on_data(frame);
  697. do_sleep(dur, pre_pts, frame->pts);
  698. pre_pts = frame->pts;
  699. continue;
  700. }
  701. if (error != AE_NO) {
  702. while (_running) {
  703. Sleep(50);
  704. clean_duplication();
  705. if ((error = init_duplication()) != AE_NO) {
  706. if (_on_error)
  707. _on_error(error);
  708. } else
  709. break;
  710. }
  711. continue;
  712. }
  713. if ((error = get_desktop_cursor(&frame_info)) == AE_NO)
  714. draw_cursor();
  715. free_duplicated_frame();
  716. // 使用相对时间戳,与muxer的_base_time保持一致
  717. frame->pts = av_gettime_relative();
  718. frame->pkt_dts = frame->pts;
  719. // frame->pkt_pts = frame->pts;
  720. frame->width = _width;
  721. frame->height = _height;
  722. frame->format = AV_PIX_FMT_BGRA;
  723. frame->pict_type = AV_PICTURE_TYPE_NONE;
  724. frame->pkt_size = _width * _height * 4;
  725. av_image_fill_arrays(frame->data,
  726. frame->linesize,
  727. _buffer,
  728. AV_PIX_FMT_BGRA,
  729. _width,
  730. _height,
  731. 1);
  732. #if 0
  733. //save bmp to test
  734. BITMAPINFOHEADER bi;
  735. bi.biSize = sizeof(BITMAPINFOHEADER);
  736. bi.biWidth = _width;
  737. bi.biHeight = _height * (-1);
  738. bi.biPlanes = 1;
  739. bi.biBitCount = 32;//should get from system color bits
  740. bi.biCompression = BI_RGB;
  741. bi.biSizeImage = 0;
  742. bi.biXPelsPerMeter = 0;
  743. bi.biYPelsPerMeter = 0;
  744. bi.biClrUsed = 0;
  745. bi.biClrImportant = 0;
  746. BITMAPFILEHEADER bf;
  747. bf.bfType = 0x4d42;
  748. bf.bfReserved1 = 0;
  749. bf.bfReserved2 = 0;
  750. bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
  751. bf.bfSize = bf.bfOffBits + _width * _height * 4;
  752. FILE *fp = fopen("..\\..\\save.bmp", "wb+");
  753. fwrite(&bf, 1, sizeof(bf), fp);
  754. fwrite(&bi, 1, sizeof(bi), fp);
  755. fwrite(_buffer, 1, _buffer_size, fp);
  756. fflush(fp);
  757. fclose(fp);
  758. #endif
  759. if (_on_data)
  760. _on_data(frame);
  761. do_sleep(dur, pre_pts, frame->pts);
  762. pre_pts = frame->pts;
  763. }
  764. av_frame_free(&frame);
  765. }
  766. } // namespace am