record_desktop_gdi.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #include "record_desktop_gdi.h"
  2. #include "error_define.h"
  3. #include "log_helper.h"
  4. namespace am {
  5. record_desktop_gdi::record_desktop_gdi()
  6. {
  7. _data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_BGRA;
  8. _buffer = NULL;
  9. _buffer_size = 0;
  10. _draw_cursor = true;
  11. _hdc = NULL;
  12. _bmp = NULL;
  13. _bmp_old = NULL;
  14. _ci = { 0 };
  15. }
  16. record_desktop_gdi::~record_desktop_gdi()
  17. {
  18. stop();
  19. clean_up();
  20. }
  21. int record_desktop_gdi::init(const RECORD_DESKTOP_RECT & rect, const int fps)
  22. {
  23. int error = AE_NO;
  24. if (_inited == true) {
  25. return error;
  26. }
  27. _fps = fps;
  28. _rect = rect;
  29. do {
  30. _width = rect.right - rect.left;
  31. _height = rect.bottom - rect.top;
  32. _buffer_size = (_width * 32 + 31) / 32 * _height * 4;
  33. _buffer = new uint8_t[_buffer_size];
  34. _start_time = av_gettime_relative();
  35. _time_base = { 1,AV_TIME_BASE };
  36. _pixel_fmt = AV_PIX_FMT_BGRA;
  37. _inited = true;
  38. } while (0);
  39. al_info("init gdi finished,error: %s %ld", err2str(error), GetLastError());
  40. return error;
  41. }
  42. int record_desktop_gdi::start()
  43. {
  44. if (_running == true) {
  45. al_warn("record desktop gdi is already running");
  46. return AE_NO;
  47. }
  48. if (_inited == false) {
  49. return AE_NEED_INIT;
  50. }
  51. _running = true;
  52. _thread = std::thread(std::bind(&record_desktop_gdi::record_func, this));
  53. return AE_NO;
  54. }
  55. int record_desktop_gdi::pause()
  56. {
  57. _paused = true;
  58. return AE_NO;
  59. }
  60. int record_desktop_gdi::resume()
  61. {
  62. _paused = false;
  63. return AE_NO;
  64. }
  65. int record_desktop_gdi::stop()
  66. {
  67. _running = false;
  68. if (_thread.joinable())
  69. _thread.join();
  70. return AE_NO;
  71. }
  72. void record_desktop_gdi::clean_up()
  73. {
  74. _inited = false;
  75. if (_buffer)
  76. delete[] _buffer;
  77. _buffer = nullptr;
  78. }
  79. void record_desktop_gdi::draw_cursor(HDC hdc)
  80. {
  81. if (!(_ci.flags & CURSOR_SHOWING))
  82. return;
  83. //is cursor in the tartet zone
  84. if (_ci.ptScreenPos.x < _rect.left ||
  85. _ci.ptScreenPos.x > _rect.right ||
  86. _ci.ptScreenPos.y < _rect.top ||
  87. _ci.ptScreenPos.y > _rect.bottom
  88. )
  89. return;
  90. HICON icon;
  91. ICONINFO ii;
  92. icon = CopyIcon(_ci.hCursor);
  93. if (!icon)
  94. return;
  95. int dstx = 0, dsty = 0;
  96. dstx = abs(_ci.ptScreenPos.x - _rect.left);
  97. dsty = abs(_ci.ptScreenPos.y - _rect.top);
  98. if (GetIconInfo(icon, &ii)) {
  99. POINT pos;
  100. DrawIconEx(hdc, dstx, dsty, icon, 0, 0, 0, NULL, DI_NORMAL);
  101. DeleteObject(ii.hbmColor);
  102. DeleteObject(ii.hbmMask);
  103. }
  104. DestroyIcon(icon);
  105. }
  106. int record_desktop_gdi::do_record()
  107. {
  108. //int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
  109. //int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
  110. HDC hdc_screen = NULL, hdc_mem = NULL;
  111. HBITMAP hbm_mem = NULL;
  112. int error = AE_ERROR;
  113. do {
  114. hdc_screen = GetWindowDC(NULL);
  115. if (!hdc_screen) {
  116. al_error("get window dc failed:%lu", GetLastError());
  117. error = AE_GDI_GET_DC_FAILED;
  118. break;
  119. }
  120. hdc_mem = CreateCompatibleDC(hdc_screen);
  121. if (!hdc_mem) {
  122. al_error("create compatible dc failed:%lu", GetLastError());
  123. error = AE_GDI_CREATE_DC_FAILED;
  124. break;
  125. }
  126. hbm_mem = CreateCompatibleBitmap(hdc_screen, _width, _height);
  127. if (!hbm_mem) {
  128. al_error("create compatible bitmap failed:%lu", GetLastError());
  129. error = AE_GDI_CREATE_BMP_FAILED;
  130. break;
  131. }
  132. SelectObject(hdc_mem, hbm_mem);
  133. //must have CAPTUREBLT falg,otherwise some layered window can not be captured
  134. if (!BitBlt(hdc_mem, 0, 0, _width, _height, hdc_screen, _rect.left, _rect.top, SRCCOPY | CAPTUREBLT)) {
  135. al_error("bitblt data failed:%lu", GetLastError());
  136. //error = AE_GDI_BITBLT_FAILED;
  137. //administrator UAC will trigger invalid handle error
  138. break;
  139. }
  140. memset(&_ci, 0, sizeof(CURSORINFO));
  141. _ci.cbSize = sizeof(CURSORINFO);
  142. if (GetCursorInfo(&_ci)) {
  143. draw_cursor(hdc_mem);
  144. }
  145. BITMAPINFOHEADER bi;
  146. bi.biSize = sizeof(BITMAPINFOHEADER);
  147. bi.biWidth = _width;
  148. bi.biHeight = _height * (-1);
  149. bi.biPlanes = 1;
  150. bi.biBitCount = 32;//should get from system color bits
  151. bi.biCompression = BI_RGB;
  152. bi.biSizeImage = 0;
  153. bi.biXPelsPerMeter = 0;
  154. bi.biYPelsPerMeter = 0;
  155. bi.biClrUsed = 0;
  156. bi.biClrImportant = 0;
  157. //scan colors by line order
  158. int ret = GetDIBits(hdc_mem, hbm_mem, 0, _height, _buffer, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
  159. if (ret <= 0 || ret == ERROR_INVALID_PARAMETER) {
  160. al_error("get dibits failed:%lu", GetLastError());
  161. error = AE_GDI_GET_DIBITS_FAILED;
  162. break;
  163. }
  164. #if 0
  165. //save bmp to test
  166. BITMAPFILEHEADER bf;
  167. bf.bfType = 0x4d42;
  168. bf.bfReserved1 = 0;
  169. bf.bfReserved2 = 0;
  170. bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
  171. bf.bfSize = bf.bfOffBits + _width * _height * 4;
  172. FILE *fp = fopen("..\\..\\save.bmp", "wb+");
  173. fwrite(&bf, 1, sizeof(bf), fp);
  174. fwrite(&bi, 1, sizeof(bi), fp);
  175. fwrite(_buffer, 1, _buffer_size, fp);
  176. fflush(fp);
  177. fclose(fp);
  178. #endif
  179. error = AE_NO;
  180. } while (0);
  181. if(hbm_mem)
  182. DeleteObject(hbm_mem);
  183. if(hdc_mem)
  184. DeleteObject(hdc_mem);
  185. if(hdc_screen)
  186. ReleaseDC(NULL, hdc_screen);
  187. return AE_NO;
  188. }
  189. void record_desktop_gdi::do_sleep(int64_t dur, int64_t pre, int64_t now)
  190. {
  191. int64_t delay = now - pre;
  192. dur = delay > dur ? max(0, dur - (delay - dur)) : (dur + dur - delay);
  193. //al_debug("%lld", delay);
  194. if(dur)
  195. av_usleep(dur);
  196. }
  197. void record_desktop_gdi::record_func()
  198. {
  199. AVFrame *frame = av_frame_alloc();
  200. int64_t pre_pts = 0;
  201. int64_t dur = AV_TIME_BASE / _fps;
  202. int ret = AE_NO;
  203. while (_running)
  204. {
  205. ret = do_record();
  206. if (ret != AE_NO) {
  207. if (_on_error) _on_error(ret);
  208. break;
  209. }
  210. frame->pts = av_gettime_relative();
  211. frame->pkt_dts = frame->pts;
  212. frame->width = _width;
  213. frame->height = _height;
  214. frame->format = AV_PIX_FMT_BGRA;
  215. frame->pict_type = AV_PICTURE_TYPE_I;
  216. frame->pkt_size = _width * _height * 4;
  217. av_image_fill_arrays(frame->data,
  218. frame->linesize,
  219. _buffer,
  220. AV_PIX_FMT_BGRA,
  221. _width,
  222. _height,
  223. 1
  224. );
  225. if (_on_data) _on_data(frame);
  226. do_sleep(dur, pre_pts, frame->pts);
  227. pre_pts = frame->pts;
  228. }
  229. av_frame_free(&frame);
  230. }
  231. }