| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932 |
- #include "record_desktop_duplication.h"
- #include "d3d_helper.h"
- #include "d3d_pixelshader.h"
- #include "d3d_vertexshader.h"
- #include "system_lib.h"
- #include "utils_string.h"
- #include "error_define.h"
- #include "log_helper.h"
- #include "system_error.h"
- namespace am {
- record_desktop_duplication::record_desktop_duplication()
- {
- _data_type = RECORD_DESKTOP_DATA_TYPES::AT_DESKTOP_BGRA;
- _buffer = NULL;
- _buffer_size = 0;
- _d3d11 = nullptr;
- _dxgi = nullptr;
- _d3d_device = nullptr;
- _d3d_ctx = nullptr;
- _d3d_vshader = nullptr;
- _d3d_pshader = nullptr;
- _d3d_inlayout = nullptr;
- _d3d_samplerlinear = nullptr;
- _duplication = nullptr;
- _image = nullptr;
- _output_des = {0};
- _output_index = 0;
- ZeroMemory(&_cursor_info, sizeof(_cursor_info));
- }
- record_desktop_duplication::~record_desktop_duplication()
- {
- stop();
- clean_up();
- }
- int record_desktop_duplication::init(const RECORD_DESKTOP_RECT &rect, const int fps)
- {
- int error = AE_NO;
- if (_inited == true) {
- return error;
- }
- _fps = fps;
- _rect = rect;
- do {
- _d3d11 = load_system_library("d3d11.dll");
- _dxgi = load_system_library("dxgi.dll");
- if (!_d3d11 || !_dxgi) {
- error = AE_D3D_LOAD_FAILED;
- break;
- }
- error = init_d3d11();
- if (error != AE_NO)
- break;
- _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;
- error = init_duplication();
- if (error != AE_NO) {
- break;
- }
- _inited = true;
- } while (0);
- if (error != AE_NO) {
- al_debug("%s,last error:%s",
- err2str(error),
- system_error::error2str(GetLastError()).c_str());
- }
- return error;
- }
- int record_desktop_duplication::start()
- {
- if (_running == true) {
- al_warn("record desktop duplication is already running");
- return AE_NO;
- }
- if (_inited == false) {
- return AE_NEED_INIT;
- }
- _running = true;
- _thread = std::thread(std::bind(&record_desktop_duplication::record_func, this));
- return AE_NO;
- }
- int record_desktop_duplication::pause()
- {
- _paused = true;
- return AE_NO;
- }
- int record_desktop_duplication::resume()
- {
- _paused = false;
- return AE_NO;
- }
- int record_desktop_duplication::stop()
- {
- _running = false;
- if (_thread.joinable())
- _thread.join();
- return AE_NO;
- }
- void record_desktop_duplication::clean_up()
- {
- _inited = false;
- if (_buffer)
- delete[] _buffer;
- _buffer = nullptr;
- if (_cursor_info.buff) {
- delete[] _cursor_info.buff;
- _cursor_info.buff = nullptr;
- }
- ZeroMemory(&_cursor_info, sizeof(_cursor_info));
- //Clean up duplication interfaces
- clean_duplication();
- //Clean up d3d11 interfaces
- clean_d3d11();
- //finally free d3d11 & dxgi library
- if (_d3d11)
- free_system_library(_d3d11);
- _d3d11 = nullptr;
- if (_dxgi)
- free_system_library(_dxgi);
- _dxgi = nullptr;
- }
- int record_desktop_duplication::get_dst_adapter(IDXGIAdapter **adapter)
- {
- int error = AE_NO;
- do {
- auto adapters = d3d_helper::get_adapters(&error, true);
- if (error != AE_NO || adapters.size() == 0)
- break;
- for (std::list<IDXGIAdapter *>::iterator itr = adapters.begin(); itr != adapters.end();
- itr++) {
- IDXGIOutput *adapter_output = nullptr;
- DXGI_ADAPTER_DESC adapter_desc = {0};
- DXGI_OUTPUT_DESC adapter_output_desc = {0};
- (*itr)->GetDesc(&adapter_desc);
- al_debug("adaptor:%s", utils_string::unicode_ascii(adapter_desc.Description).c_str());
- unsigned int n = 0;
- RECT output_rect;
- while ((*itr)->EnumOutputs(n, &adapter_output) != DXGI_ERROR_NOT_FOUND) {
- HRESULT hr = adapter_output->GetDesc(&adapter_output_desc);
- if (FAILED(hr))
- continue;
- output_rect = adapter_output_desc.DesktopCoordinates;
- al_debug(" output:%s left:%d top:%d right:%d bottom:%d",
- utils_string::unicode_ascii(adapter_output_desc.DeviceName).c_str(),
- output_rect.left,
- output_rect.top,
- output_rect.right,
- output_rect.bottom);
- if (output_rect.left <= _rect.left && output_rect.top <= _rect.top
- && output_rect.right >= _rect.right && output_rect.bottom >= _rect.bottom) {
- error = AE_NO;
- break;
- }
- ++n;
- }
- if (error != AE_DXGI_FOUND_ADAPTER_FAILED) {
- *adapter = *itr;
- break;
- }
- }
- } while (0);
- return error;
- }
- int record_desktop_duplication::create_d3d_device(IDXGIAdapter *adapter, ID3D11Device **device)
- {
- int error = AE_NO;
- do {
- PFN_D3D11_CREATE_DEVICE create_device = (PFN_D3D11_CREATE_DEVICE)
- GetProcAddress(_d3d11, "D3D11CreateDevice");
- if (!create_device) {
- error = AE_D3D_GET_PROC_FAILED;
- break;
- }
- HRESULT hr = S_OK;
- // Driver types supported
- // If you set the pAdapter parameter to a non - NULL value,
- // you must also set the DriverType parameter to the D3D_DRIVER_TYPE_UNKNOWN value.
- D3D_DRIVER_TYPE driver_types[] = {
- D3D_DRIVER_TYPE_UNKNOWN,
- D3D_DRIVER_TYPE_HARDWARE,
- D3D_DRIVER_TYPE_WARP,
- D3D_DRIVER_TYPE_REFERENCE,
- };
- UINT n_driver_types = ARRAYSIZE(driver_types);
- // Feature levels supported
- D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_0,
- D3D_FEATURE_LEVEL_10_1,
- D3D_FEATURE_LEVEL_10_0,
- D3D_FEATURE_LEVEL_9_1};
- UINT n_feature_levels = ARRAYSIZE(feature_levels);
- D3D_FEATURE_LEVEL feature_level;
- // Create device
- for (UINT driver_index = 0; driver_index < n_driver_types; ++driver_index) {
- hr = create_device(adapter,
- driver_types[driver_index],
- nullptr,
- 0,
- feature_levels,
- n_feature_levels,
- D3D11_SDK_VERSION,
- device,
- &feature_level,
- &_d3d_ctx);
- if (SUCCEEDED(hr))
- break;
- }
- if (FAILED(hr)) {
- error = AE_D3D_CREATE_DEVICE_FAILED;
- break;
- }
- } while (0);
- return error;
- }
- int record_desktop_duplication::init_d3d11()
- {
- int error = AE_NO;
- do {
- IDXGIAdapter *adapter = nullptr;
- error = get_dst_adapter(&adapter);
- if (error != AE_NO)
- break;
- error = create_d3d_device(adapter, &_d3d_device);
- if (error != AE_NO)
- break;
- //No need for grab full screen,but in move & dirty rects copy
- #if 0
- // VERTEX shader
- UINT Size = ARRAYSIZE(g_VS);
- HRESULT hr = _d3d_device->CreateVertexShader(g_VS, Size, nullptr, &_d3d_vshader);
- if (FAILED(hr))
- {
- error = AE_D3D_CREATE_VERTEX_SHADER_FAILED;
- break;
- }
- // Input layout
- D3D11_INPUT_ELEMENT_DESC layouts[] =
- {
- { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
- { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
- };
- UINT n_layouts = ARRAYSIZE(layouts);
- hr = _d3d_device->CreateInputLayout(layouts, n_layouts, g_VS, Size, &_d3d_inlayout);
- if (FAILED(hr))
- {
- error = AE_D3D_CREATE_INLAYOUT_FAILED;
- break;
- }
- _d3d_ctx->IASetInputLayout(_d3d_inlayout);
- // Pixel shader
- Size = ARRAYSIZE(g_PS);
- hr = _d3d_device->CreatePixelShader(g_PS, Size, nullptr, &_d3d_pshader);
- if (FAILED(hr))
- {
- error = AE_D3D_CREATE_PIXEL_SHADER_FAILED;
- break;
- }
- // Set up sampler
- D3D11_SAMPLER_DESC sampler_desc;
- RtlZeroMemory(&sampler_desc, sizeof(sampler_desc));
- sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
- sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
- sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
- sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
- sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
- sampler_desc.MinLOD = 0;
- sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
- hr = _d3d_device->CreateSamplerState(&sampler_desc, &_d3d_samplerlinear);
- if (FAILED(hr))
- {
- error = AE_D3D_CREATE_SAMPLERSTATE_FAILED;
- break;
- }
- #endif
- } while (0);
- return error;
- }
- void record_desktop_duplication::clean_d3d11()
- {
- if (_d3d_device)
- _d3d_device->Release();
- _d3d_device = nullptr;
- if (_d3d_ctx)
- _d3d_ctx->Release();
- _d3d_ctx = nullptr;
- if (_d3d_vshader)
- _d3d_vshader->Release();
- _d3d_vshader = nullptr;
- if (_d3d_pshader)
- _d3d_pshader->Release();
- _d3d_pshader = nullptr;
- if (_d3d_inlayout)
- _d3d_inlayout->Release();
- _d3d_inlayout = nullptr;
- if (_d3d_samplerlinear)
- _d3d_samplerlinear->Release();
- _d3d_samplerlinear = nullptr;
- }
- int record_desktop_duplication::init_duplication()
- {
- int error = AE_NO;
- do {
- // Get DXGI device
- IDXGIDevice *dxgi_device = nullptr;
- HRESULT hr = _d3d_device->QueryInterface(__uuidof(IDXGIDevice),
- reinterpret_cast<void **>(&dxgi_device));
- if (FAILED(hr)) {
- error = AE_D3D_QUERYINTERFACE_FAILED;
- break;
- }
- // Get DXGI adapter
- IDXGIAdapter *dxgi_adapter = nullptr;
- hr = dxgi_device->GetParent(__uuidof(IDXGIAdapter),
- reinterpret_cast<void **>(&dxgi_adapter));
- dxgi_device->Release();
- dxgi_device = nullptr;
- if (FAILED(hr)) {
- error = AE_DUP_GET_PARENT_FAILED;
- break;
- }
- // Get output
- IDXGIOutput *dxgi_output = nullptr;
- hr = dxgi_adapter->EnumOutputs(_output_index, &dxgi_output);
- dxgi_adapter->Release();
- dxgi_adapter = nullptr;
- if (FAILED(hr)) {
- error = AE_DUP_ENUM_OUTPUT_FAILED;
- break;
- }
- dxgi_output->GetDesc(&_output_des);
- // QI for Output 1
- IDXGIOutput1 *dxgi_output1 = nullptr;
- hr = dxgi_output->QueryInterface(__uuidof(dxgi_output1),
- reinterpret_cast<void **>(&dxgi_output1));
- dxgi_output->Release();
- dxgi_output = nullptr;
- if (FAILED(hr)) {
- error = AE_DUP_QI_FAILED;
- break;
- }
- // Create desktop duplication
- hr = dxgi_output1->DuplicateOutput(_d3d_device, &_duplication);
- dxgi_output1->Release();
- dxgi_output1 = nullptr;
- if (FAILED(hr)) {
- error = AE_DUP_DUPLICATE_FAILED;
- if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
- error = AE_DUP_DUPLICATE_MAX_FAILED;
- }
- al_error("duplicate output failed,%lld", hr);
- break;
- }
- } while (0);
- return error;
- }
- int record_desktop_duplication::free_duplicated_frame()
- {
- HRESULT hr = _duplication->ReleaseFrame();
- if (FAILED(hr)) {
- return AE_DUP_RELEASE_FRAME_FAILED;
- }
- if (_image) {
- _image->Release();
- _image = nullptr;
- }
- return AE_DUP_RELEASE_FRAME_FAILED;
- }
- void record_desktop_duplication::clean_duplication()
- {
- if (_duplication)
- _duplication->Release();
- if (_image)
- _image->Release();
- _duplication = nullptr;
- _image = nullptr;
- }
- bool record_desktop_duplication::attatch_desktop()
- {
- HDESK desktop = nullptr;
- desktop = OpenInputDesktop(0, FALSE, GENERIC_ALL);
- if (!desktop) {
- // We do not have access to the desktop so request a retry
- return false;
- }
- // Attach desktop to this thread
- bool battached = SetThreadDesktop(desktop) != 0;
- CloseDesktop(desktop);
- if (!battached) {
- // We do not have access to the desktop so request a retry
- return false;
- }
- return true;
- }
- int record_desktop_duplication::get_desktop_image(DXGI_OUTDUPL_FRAME_INFO *frame_info)
- {
- IDXGIResource *dxgi_res = nullptr;
- // Get new frame (adaptive low-latency timeout)
- int timeout_ms = 10;
- if (_fps > 0) {
- timeout_ms = 1000 / _fps / 2;
- if (timeout_ms < 1) timeout_ms = 1;
- }
- HRESULT hr = _duplication->AcquireNextFrame(timeout_ms, frame_info, &dxgi_res);
- // Timeout will return when desktop has no chane
- if (hr == DXGI_ERROR_WAIT_TIMEOUT)
- return AE_TIMEOUT;
- if (FAILED(hr))
- return AE_DUP_ACQUIRE_FRAME_FAILED;
- // QI for IDXGIResource
- hr = dxgi_res->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&_image));
- dxgi_res->Release();
- dxgi_res = nullptr;
- if (FAILED(hr))
- return AE_DUP_QI_FRAME_FAILED;
- // Copy old description
- D3D11_TEXTURE2D_DESC frame_desc;
- _image->GetDesc(&frame_desc);
- // Create a new staging buffer for fill frame image
- ID3D11Texture2D *new_image = NULL;
- frame_desc.Usage = D3D11_USAGE_STAGING;
- frame_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
- frame_desc.BindFlags = 0;
- frame_desc.MiscFlags = 0;
- frame_desc.MipLevels = 1;
- frame_desc.ArraySize = 1;
- frame_desc.SampleDesc.Count = 1;
- frame_desc.SampleDesc.Quality = 0;
- hr = _d3d_device->CreateTexture2D(&frame_desc, NULL, &new_image);
- if (FAILED(hr))
- return AE_DUP_CREATE_TEXTURE_FAILED;
- // Copy next staging buffer to new staging buffer
- _d3d_ctx->CopyResource(new_image, _image);
- #if 1
- // Should calc the row pitch ,and compare dst row pitch with frame row pitch
- // Create staging buffer for map bits
- IDXGISurface *dxgi_surface = NULL;
- hr = new_image->QueryInterface(__uuidof(IDXGISurface), (void **) (&dxgi_surface));
- new_image->Release();
- if (FAILED(hr))
- return AE_DUP_QI_DXGI_FAILED;
- // Map buff to mapped rect structure
- DXGI_MAPPED_RECT mapped_rect;
- hr = dxgi_surface->Map(&mapped_rect, DXGI_MAP_READ);
- if (FAILED(hr))
- return AE_DUP_MAP_FAILED;
- int dst_offset_x = _rect.left - _output_des.DesktopCoordinates.left;
- int dst_offset_y = _rect.top - _output_des.DesktopCoordinates.top;
- int dst_rowpitch = min(frame_desc.Width, _rect.right - _rect.left) * 4;
- int dst_colpitch = min(_height,
- _output_des.DesktopCoordinates.bottom
- - _output_des.DesktopCoordinates.top - dst_offset_y);
- for (int h = 0; h < dst_colpitch; h++) {
- memcpy_s(_buffer + h * dst_rowpitch,
- dst_rowpitch,
- (BYTE *) mapped_rect.pBits + (h + dst_offset_y) * mapped_rect.Pitch
- + dst_offset_x * 4,
- min(mapped_rect.Pitch, dst_rowpitch));
- }
- dxgi_surface->Unmap();
- dxgi_surface->Release();
- dxgi_surface = nullptr;
- #else
- D3D11_MAPPED_SUBRESOURCE resource;
- UINT subresource = D3D11CalcSubresource(0, 0, 0);
- hr = _d3d_ctx->Map(new_image, subresource, D3D11_MAP_READ_WRITE, 0, &resource);
- new_image->Release();
- if (FAILED(hr))
- return AE_DUP_MAP_FAILED;
- int dst_rowpitch = frame_desc.Width * 4;
- for (int h = 0; h < frame_desc.Height; h++) {
- memcpy_s(_buffer + h * dst_rowpitch,
- dst_rowpitch,
- (BYTE *) resource.pData + h * resource.RowPitch,
- min(resource.RowPitch, dst_rowpitch));
- }
- #endif
- return AE_NO;
- }
- int record_desktop_duplication::get_desktop_cursor(const DXGI_OUTDUPL_FRAME_INFO *frame_info)
- {
- // A non-zero mouse update timestamp indicates that there is a mouse position update and optionally a shape change
- if (frame_info->LastMouseUpdateTime.QuadPart == 0)
- return AE_NO;
- bool b_updated = true;
- // Make sure we don't update pointer position wrongly
- // If pointer is invisible, make sure we did not get an update from another output that the last time that said pointer
- // was visible, if so, don't set it to invisible or update.
- if (!frame_info->PointerPosition.Visible && (_cursor_info.output_index != _output_index))
- b_updated = false;
- // If two outputs both say they have a visible, only update if new update has newer timestamp
- if (frame_info->PointerPosition.Visible && _cursor_info.visible
- && (_cursor_info.output_index != _output_index)
- && (_cursor_info.pre_timestamp.QuadPart > frame_info->LastMouseUpdateTime.QuadPart))
- b_updated = false;
- // Update position
- if (b_updated) {
- _cursor_info.position.x = frame_info->PointerPosition.Position.x
- + _output_des.DesktopCoordinates.left;
- _cursor_info.position.y = frame_info->PointerPosition.Position.y
- + _output_des.DesktopCoordinates.top;
- _cursor_info.output_index = _output_index;
- _cursor_info.pre_timestamp = frame_info->LastMouseUpdateTime;
- _cursor_info.visible = frame_info->PointerPosition.Visible != 0;
- }
- // No new shape only update cursor positions & visible state
- if (frame_info->PointerShapeBufferSize == 0) {
- return AE_NO;
- }
- // Old buffer too small
- if (frame_info->PointerShapeBufferSize > _cursor_info.size) {
- if (_cursor_info.buff) {
- delete[] _cursor_info.buff;
- _cursor_info.buff = nullptr;
- }
- _cursor_info.buff = new (std::nothrow) BYTE[frame_info->PointerShapeBufferSize];
- if (!_cursor_info.buff) {
- _cursor_info.size = 0;
- return AE_ALLOCATE_FAILED;
- }
- // Update buffer size
- _cursor_info.size = frame_info->PointerShapeBufferSize;
- }
- // Get shape
- UINT BufferSizeRequired;
- HRESULT hr = _duplication->GetFramePointerShape(frame_info->PointerShapeBufferSize,
- reinterpret_cast<VOID *>(_cursor_info.buff),
- &BufferSizeRequired,
- &(_cursor_info.shape));
- if (FAILED(hr)) {
- delete[] _cursor_info.buff;
- _cursor_info.buff = nullptr;
- _cursor_info.size = 0;
- return AE_DUP_GET_CURSORSHAPE_FAILED;
- }
- return AE_NO;
- }
- static unsigned int bit_reverse(unsigned int n)
- {
- n = ((n >> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa);
- n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc);
- n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0);
- n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00);
- n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000);
- return n;
- }
- void record_desktop_duplication::draw_cursor()
- {
- if (_cursor_info.visible == false)
- return;
- int cursor_width = 0, cursor_height = 0, left = 0, top = 0;
- cursor_width = _cursor_info.shape.Width;
- cursor_height = _cursor_info.shape.Height;
- // In case that,the value of position is negative value
- left = abs(_cursor_info.position.x - _rect.left);
- top = abs(_cursor_info.position.y - _rect.top);
- // Notice here
- if (_cursor_info.shape.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME)
- cursor_height = cursor_height / 2;
- //Skip invisible pixel
- cursor_width = min(_width - left, cursor_width);
- cursor_height = min(_height - top, cursor_height);
- //al_debug("left:%d top:%d width:%d height:%d type:%d", left, top, cursor_width, height, _cursor_info.shape.Type);
- switch (_cursor_info.shape.Type) {
- // The pointer type is a color mouse pointer,
- // which is a color bitmap. The bitmap's size
- // is specified by width and height in a 32 bpp
- // ARGB DIB format.
- // should trans cursor to BGRA?
- case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR: {
- unsigned int *cursor_32 = reinterpret_cast<unsigned int *>(_cursor_info.buff);
- unsigned int *screen_32 = reinterpret_cast<unsigned int *>(_buffer);
- for (int row = 0; row < cursor_height; row++) {
- for (int col = 0; col < cursor_width; col++) {
- unsigned int cur_cursor_val
- = cursor_32[col + (row * (_cursor_info.shape.Pitch / sizeof(UINT)))];
- //Skip black or empty value
- if (cur_cursor_val == 0x00000000)
- continue;
- else
- screen_32[(abs(top) + row) * _width + abs(left) + col]
- = cur_cursor_val; //bit_reverse(cur_cursor_val);
- }
- }
- break;
- }
- // The pointer type is a monochrome mouse pointer,
- // which is a monochrome bitmap. The bitmap's size
- // is specified by width and height in a 1 bits per
- // pixel (bpp) device independent bitmap (DIB) format
- // AND mask that is followed by another 1 bpp DIB format
- // XOR mask of the same size.
- case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME: {
- unsigned int *cursor_32 = reinterpret_cast<unsigned int *>(_cursor_info.buff);
- unsigned int *screen_32 = reinterpret_cast<unsigned int *>(_buffer);
- for (int row = 0; row < cursor_height; row++) {
- BYTE MASK = 0x80;
- for (int col = 0; col < cursor_width; col++) {
- // Get masks using appropriate offsets
- BYTE AndMask = _cursor_info.buff[(col / 8) + (row * (_cursor_info.shape.Pitch))]
- & MASK;
- BYTE XorMask
- = _cursor_info.buff[(col / 8)
- + ((row + cursor_height) * (_cursor_info.shape.Pitch))]
- & MASK;
- UINT AndMask32 = (AndMask) ? 0xFFFFFFFF : 0xFF000000;
- UINT XorMask32 = (XorMask) ? 0x00FFFFFF : 0x00000000;
- // Set new pixel
- screen_32[(abs(top) + row) * _width + abs(left) + col]
- = (screen_32[(abs(top) + row) * _width + abs(left) + col] & AndMask32)
- ^ XorMask32;
- // Adjust mask
- if (MASK == 0x01) {
- MASK = 0x80;
- } else {
- MASK = MASK >> 1;
- }
- }
- }
- break;
- }
- // The pointer type is a masked color mouse pointer.
- // A masked color mouse pointer is a 32 bpp ARGB format
- // bitmap with the mask value in the alpha bits. The only
- // allowed mask values are 0 and 0xFF. When the mask value
- // is 0, the RGB value should replace the screen pixel.
- // When the mask value is 0xFF, an XOR operation is performed
- // on the RGB value and the screen pixel; the result replaces the screen pixel.
- case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR: {
- unsigned int *cursor_32 = reinterpret_cast<unsigned int *>(_cursor_info.buff);
- unsigned int *screen_32 = reinterpret_cast<unsigned int *>(_buffer);
- for (int row = 0; row < cursor_height; row++) {
- for (int col = 0; col < cursor_width; col++) {
- unsigned int cur_cursor_val
- = cursor_32[col + (row * (_cursor_info.shape.Pitch / sizeof(UINT)))];
- unsigned int cur_screen_val = screen_32[(abs(top) + row) * _width + abs(left) + col];
- unsigned int mask_val = 0xFF000000 & cur_cursor_val;
- if (mask_val) {
- //0xFF: XOR operation is performed on the RGB value and the screen pixel
- cur_screen_val = (cur_screen_val ^ cur_cursor_val) | 0xFF000000;
- } else {
- //0x00: the RGB value should replace the screen pixel
- cur_screen_val = cur_cursor_val | 0xFF000000;
- }
- }
- }
- break;
- }
- default:
- break;
- }
- }
- void record_desktop_duplication::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_duplication::record_func()
- {
- AVFrame *frame = av_frame_alloc();
- int64_t pre_pts = 0, dur = AV_TIME_BASE / _fps;
- int error = AE_NO;
- #if 0
- if (attatch_desktop() != true) {
- al_fatal("duplication attach desktop failed :%s",
- system_error::error2str(GetLastError()).c_str());
- if (_on_error) _on_error(AE_DUP_ATTATCH_FAILED);
- return;
- }
- #endif
- DXGI_OUTDUPL_FRAME_INFO frame_info;
- while (_running) {
- //Timeout is no new picture,no need to update
- if ((error = get_desktop_image(&frame_info)) == AE_TIMEOUT) {
- // Push duplicate frame to keep steady cadence and avoid buffer growth
- 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_NONE;
- 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;
- continue;
- }
- if (error != AE_NO) {
- while (_running) {
- Sleep(50);
- clean_duplication();
- if ((error = init_duplication()) != AE_NO) {
- if (_on_error)
- _on_error(error);
- } else
- break;
- }
- continue;
- }
- if ((error = get_desktop_cursor(&frame_info)) == AE_NO)
- draw_cursor();
- free_duplicated_frame();
- // 使用相对时间戳,与muxer的_base_time保持一致
- frame->pts = av_gettime_relative();
- frame->pkt_dts = frame->pts;
- // frame->pkt_pts = frame->pts;
- frame->width = _width;
- frame->height = _height;
- frame->format = AV_PIX_FMT_BGRA;
- frame->pict_type = AV_PICTURE_TYPE_NONE;
- frame->pkt_size = _width * _height * 4;
- av_image_fill_arrays(frame->data,
- frame->linesize,
- _buffer,
- AV_PIX_FMT_BGRA,
- _width,
- _height,
- 1);
- #if 0
- //save bmp to test
- 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;
- 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
- if (_on_data)
- _on_data(frame);
- do_sleep(dur, pre_pts, frame->pts);
- pre_pts = frame->pts;
- }
- av_frame_free(&frame);
- }
- } // namespace am
|