| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- #include "record_desktop_gdi.h"
- #include "error_define.h"
- #include "log_helper.h"
- namespace am {
- record_desktop_gdi::record_desktop_gdi()
- {
- _data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_BGRA;
- _buffer = NULL;
- _buffer_size = 0;
- _draw_cursor = true;
- _hdc = NULL;
- _bmp = NULL;
- _bmp_old = NULL;
- _ci = {0};
- }
- record_desktop_gdi::~record_desktop_gdi()
- {
- stop();
- clean_up();
- }
- int record_desktop_gdi::init(const RECORD_DESKTOP_RECT &rect, const int fps)
- {
- int error = AE_NO;
- if (_inited == true) {
- return error;
- }
- _fps = fps;
- _rect = rect;
- do {
- _width = rect.right - rect.left;
- _height = rect.bottom - rect.top;
- _buffer_size = (_width * 32 + 31) / 32 * _height * 4;
- _buffer = new uint8_t[_buffer_size];
- _start_time = av_gettime_relative();
- _time_base = {1, AV_TIME_BASE};
- _pixel_fmt = AV_PIX_FMT_BGRA;
- _inited = true;
- } while (0);
- al_info("init gdi finished,error: %s %ld", err2str(error), GetLastError());
- return error;
- }
- int record_desktop_gdi::start()
- {
- if (_running == true) {
- al_warn("record desktop gdi is already running");
- return AE_NO;
- }
- if (_inited == false) {
- return AE_NEED_INIT;
- }
- _running = true;
- _thread = std::thread(std::bind(&record_desktop_gdi::record_func, this));
- return AE_NO;
- }
- int record_desktop_gdi::pause()
- {
- _paused = true;
- return AE_NO;
- }
- int record_desktop_gdi::resume()
- {
- _paused = false;
- return AE_NO;
- }
- int record_desktop_gdi::stop()
- {
- _running = false;
- if (_thread.joinable())
- _thread.join();
- return AE_NO;
- }
- void record_desktop_gdi::clean_up()
- {
- _inited = false;
- if (_buffer)
- delete[] _buffer;
- _buffer = nullptr;
- }
- void record_desktop_gdi::draw_cursor(HDC hdc)
- {
- if (!(_ci.flags & CURSOR_SHOWING))
- return;
- //is cursor in the tartet zone
- if (_ci.ptScreenPos.x < _rect.left || _ci.ptScreenPos.x > _rect.right
- || _ci.ptScreenPos.y < _rect.top || _ci.ptScreenPos.y > _rect.bottom)
- return;
- HICON icon;
- ICONINFO ii;
- icon = CopyIcon(_ci.hCursor);
- if (!icon)
- return;
- int dstx = 0, dsty = 0;
- dstx = abs(_ci.ptScreenPos.x - _rect.left);
- dsty = abs(_ci.ptScreenPos.y - _rect.top);
- if (GetIconInfo(icon, &ii)) {
- POINT pos;
- DrawIconEx(hdc, dstx, dsty, icon, 0, 0, 0, NULL, DI_NORMAL);
- DeleteObject(ii.hbmColor);
- DeleteObject(ii.hbmMask);
- }
- DestroyIcon(icon);
- }
- int record_desktop_gdi::do_record()
- {
- //int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
- //int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
- HDC hdc_screen = NULL, hdc_mem = NULL;
- HBITMAP hbm_mem = NULL;
- int error = AE_ERROR;
- do {
- hdc_screen = GetWindowDC(NULL);
- if (!hdc_screen) {
- al_error("get window dc failed:%lu", GetLastError());
- error = AE_GDI_GET_DC_FAILED;
- break;
- }
- hdc_mem = CreateCompatibleDC(hdc_screen);
- if (!hdc_mem) {
- al_error("create compatible dc failed:%lu", GetLastError());
- error = AE_GDI_CREATE_DC_FAILED;
- break;
- }
- hbm_mem = CreateCompatibleBitmap(hdc_screen, _width, _height);
- if (!hbm_mem) {
- al_error("create compatible bitmap failed:%lu", GetLastError());
- error = AE_GDI_CREATE_BMP_FAILED;
- break;
- }
- SelectObject(hdc_mem, hbm_mem);
- //must have CAPTUREBLT falg,otherwise some layered window can not be captured
- if (!BitBlt(hdc_mem,
- 0,
- 0,
- _width,
- _height,
- hdc_screen,
- _rect.left,
- _rect.top,
- SRCCOPY | CAPTUREBLT)) {
- al_error("bitblt data failed:%lu", GetLastError());
- //error = AE_GDI_BITBLT_FAILED;
- //administrator UAC will trigger invalid handle error
- break;
- }
- memset(&_ci, 0, sizeof(CURSORINFO));
- _ci.cbSize = sizeof(CURSORINFO);
- if (GetCursorInfo(&_ci)) {
- draw_cursor(hdc_mem);
- }
- BITMAPINFOHEADER bi;
- bi.biSize = sizeof(BITMAPINFOHEADER);
- bi.biWidth = _width;
- bi.biHeight = _height * (-1);
- bi.biPlanes = 1;
- bi.biBitCount = 32; //should get from system color bits
- bi.biCompression = BI_RGB;
- bi.biSizeImage = 0;
- bi.biXPelsPerMeter = 0;
- bi.biYPelsPerMeter = 0;
- bi.biClrUsed = 0;
- bi.biClrImportant = 0;
- //scan colors by line order
- int ret
- = GetDIBits(hdc_mem, hbm_mem, 0, _height, _buffer, (BITMAPINFO *) &bi, DIB_RGB_COLORS);
- if (ret <= 0 || ret == ERROR_INVALID_PARAMETER) {
- al_error("get dibits failed:%lu", GetLastError());
- error = AE_GDI_GET_DIBITS_FAILED;
- break;
- }
- #if 0
- //save bmp to test
- BITMAPFILEHEADER bf;
- bf.bfType = 0x4d42;
- bf.bfReserved1 = 0;
- bf.bfReserved2 = 0;
- bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
- bf.bfSize = bf.bfOffBits + _width * _height * 4;
- FILE *fp = fopen("..\\..\\save.bmp", "wb+");
- fwrite(&bf, 1, sizeof(bf), fp);
- fwrite(&bi, 1, sizeof(bi), fp);
- fwrite(_buffer, 1, _buffer_size, fp);
- fflush(fp);
- fclose(fp);
- #endif
- error = AE_NO;
- } while (0);
- if (hbm_mem)
- DeleteObject(hbm_mem);
- if (hdc_mem)
- DeleteObject(hdc_mem);
- if (hdc_screen)
- ReleaseDC(NULL, hdc_screen);
- return AE_NO;
- }
- void record_desktop_gdi::do_sleep(int64_t dur, int64_t pre, int64_t now)
- {
- int64_t delay = now - pre;
- dur = delay > dur ? max(0, dur - (delay - dur)) : (dur + dur - delay);
- //al_debug("%lld", delay);
- if (dur)
- av_usleep(dur);
- }
- void record_desktop_gdi::record_func()
- {
- AVFrame *frame = av_frame_alloc();
- int64_t pre_pts = 0;
- int64_t dur = AV_TIME_BASE / _fps;
- int ret = AE_NO;
- while (_running) {
- ret = do_record();
- if (ret != AE_NO) {
- if (_on_error)
- _on_error(ret);
- break;
- }
- // 使用相对时间戳,与muxer的_base_time保持一致
- int64_t dur = av_rescale_q(1, av_inv_q(_time_base), _time_base);
- frame->pts = av_gettime_relative();
- frame->pkt_dts = frame->pts;
- frame->width = _width;
- frame->height = _height;
- frame->format = AV_PIX_FMT_BGRA;
- frame->pict_type = AV_PICTURE_TYPE_I;
- frame->pkt_size = _width * _height * 4;
- av_image_fill_arrays(frame->data,
- frame->linesize,
- _buffer,
- AV_PIX_FMT_BGRA,
- _width,
- _height,
- 1);
- if (_on_data)
- _on_data(frame);
- do_sleep(dur, pre_pts, frame->pts);
- pre_pts = frame->pts;
- }
- av_frame_free(&frame);
- }
- } // namespace am
|