21 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0A00
23 #define _WIN32_WINNT 0x0A00
51 #define TIMER_RES 1000000
52 #define TIMER_RES64 INT64_C(1000000)
108 #define OFFSET(x) offsetof(DdagrabContext, x)
109 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
118 {
"auto",
"let dda pick its preferred format", 0,
AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, INT_MAX,
FLAGS, .unit =
"output_fmt" },
121 {
"10bit",
"only output default 10 Bit format", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS, .unit =
"output_fmt" },
122 {
"x2bgr10",
"only output 10 Bit X2BGR10", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS, .unit =
"output_fmt" },
125 {
"allow_fallback",
"don't error on fallback to default 8 Bit format",
127 {
"force_fmt",
"exclude BGRA from format list (experimental, discouraged by Microsoft)",
129 {
"dup_frames",
"duplicate frames to maintain framerate",
138 IUnknown **resp = (IUnknown**)resource;
140 IUnknown_Release(*resp);
174 IDXGIDevice *dxgi_device =
NULL;
175 IDXGIAdapter *dxgi_adapter =
NULL;
176 IDXGIOutput *dxgi_output =
NULL;
177 IDXGIOutput1 *dxgi_output1 =
NULL;
178 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
179 IDXGIOutput5 *dxgi_output5 =
NULL;
181 typedef DPI_AWARENESS_CONTEXT (*set_thread_dpi_t)(DPI_AWARENESS_CONTEXT);
182 set_thread_dpi_t set_thread_dpi;
183 HMODULE user32_module;
188 hr = ID3D11Device_QueryInterface(dda->
device_hwctx->
device, &IID_IDXGIDevice, (
void**)&dxgi_device);
194 hr = IDXGIDevice_GetParent(dxgi_device, &IID_IDXGIAdapter, (
void**)&dxgi_adapter);
195 IDXGIDevice_Release(dxgi_device);
202 hr = IDXGIAdapter_EnumOutputs(dxgi_adapter, dda->
output_idx, &dxgi_output);
203 IDXGIAdapter_Release(dxgi_adapter);
210 hr = IDXGIOutput_GetDesc(dxgi_output, &dda->
output_desc);
212 IDXGIOutput_Release(dxgi_output);
217 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
218 user32_module = dlopen(
"user32.dll", 0);
219 if (!user32_module) {
224 set_thread_dpi = (set_thread_dpi_t)dlsym(user32_module,
"SetThreadDpiAwarenessContext");
227 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput5, (
void**)&dxgi_output5);
229 if (set_thread_dpi && SUCCEEDED(hr)) {
230 DPI_AWARENESS_CONTEXT prev_dpi_ctx;
233 DXGI_FORMAT_R10G10B10A2_UNORM,
247 IDXGIOutput_Release(dxgi_output);
250 prev_dpi_ctx = set_thread_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
254 hr = IDXGIOutput5_DuplicateOutput1(dxgi_output5,
260 IDXGIOutput5_Release(dxgi_output5);
264 set_thread_dpi(prev_dpi_ctx);
266 dlclose(user32_module);
267 user32_module =
NULL;
268 set_thread_dpi =
NULL;
272 dlclose(user32_module);
273 user32_module =
NULL;
274 set_thread_dpi =
NULL;
285 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput1, (
void**)&dxgi_output1);
286 IDXGIOutput_Release(dxgi_output);
293 hr = IDXGIOutput1_DuplicateOutput(dxgi_output1,
296 IDXGIOutput1_Release(dxgi_output1);
300 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
303 }
else if (hr == DXGI_ERROR_UNSUPPORTED) {
306 }
else if (hr == E_INVALIDARG) {
309 }
else if (hr == E_ACCESSDENIED) {
312 }
else if (FAILED(hr)) {
334 {
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
335 {
"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
342 D3D11_SAMPLER_DESC sampler_desc = { 0 };
343 D3D11_BLEND_DESC blend_desc = { 0 };
344 D3D11_BUFFER_DESC buffer_desc = { 0 };
349 hr = ID3D11Device_CreateVertexShader(dev,
359 hr = ID3D11Device_CreateInputLayout(dev,
370 hr = ID3D11Device_CreatePixelShader(dev,
383 buffer_desc.ByteWidth =
sizeof(const_data);
384 buffer_desc.Usage = D3D11_USAGE_IMMUTABLE;
385 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
386 hr = ID3D11Device_CreateBuffer(dev,
395 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
396 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
397 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
398 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
399 sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
400 hr = ID3D11Device_CreateSamplerState(dev,
408 blend_desc.AlphaToCoverageEnable = FALSE;
409 blend_desc.IndependentBlendEnable = FALSE;
410 blend_desc.RenderTarget[0].BlendEnable = TRUE;
411 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
412 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
413 blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
414 blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
415 blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
416 blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
417 blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
418 hr = ID3D11Device_CreateBlendState(dev,
426 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_DEST_COLOR;
427 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_COLOR;
428 hr = ID3D11Device_CreateBlendState(dev,
455 DXGI_OUTDUPL_POINTER_SHAPE_INFO *shape_info,
456 ID3D11Texture2D **out_tex,
457 ID3D11ShaderResourceView **res_view)
460 D3D11_TEXTURE2D_DESC
desc = { 0 };
461 D3D11_SUBRESOURCE_DATA init_data = { 0 };
462 D3D11_SHADER_RESOURCE_VIEW_DESC resource_desc = { 0 };
468 desc.SampleDesc.Count = 1;
469 desc.SampleDesc.Quality = 0;
470 desc.Usage = D3D11_USAGE_IMMUTABLE;
471 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
473 desc.Width = shape_info->Width;
474 desc.Height = shape_info->Height;
476 init_data.pSysMem = buf;
477 init_data.SysMemPitch = shape_info->Pitch;
479 resource_desc.Format =
desc.Format;
480 resource_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
481 resource_desc.Texture2D.MostDetailedMip = 0;
482 resource_desc.Texture2D.MipLevels = 1;
494 (ID3D11Resource*)*out_tex,
508 int width = *_width,
height = *_height, pitch = *_pitch;
509 int real_height =
height / 2;
510 int size = real_height * pitch;
517 if (!
output || !output_xor) {
523 for (y = 0; y < real_height; y++) {
524 for (x = 0; x <
width; x++) {
525 int in_pos = (y * pitch) + (x / 8);
526 int out_pos = 4 * ((y *
width) + x);
527 int and_val = (
input[in_pos] >> (7 - (x % 8))) & 1;
528 int xor_val = (
input[in_pos +
size] >> (7 - (x % 8))) & 1;
530 if (!and_val && !xor_val) {
532 memset(&
output[out_pos], 0, 4);
533 output[out_pos + 3] = 0xFF;
536 memset(&output_xor[out_pos], 0, 4);
537 }
else if (and_val && !xor_val) {
539 memset(&
output[out_pos], 0, 4);
542 memset(&output_xor[out_pos], 0, 4);
543 }
else if (!and_val && xor_val) {
545 memset(&
output[out_pos], 0xFF, 4);
548 memset(&output_xor[out_pos], 0, 4);
549 }
else if (and_val && xor_val) {
551 memset(&
output[out_pos], 0, 4);
554 memset(&output_xor[out_pos], 0xFF, 4);
560 *_height = real_height;
562 *xor_out = output_xor;
574 if (!
output || !output_xor) {
583 for (y = 0; y <
height; y++) {
584 for (x = 0; x <
width; x++) {
585 int pos = (y*pitch) + (4*x) + 3;
592 *xor_out = output_xor;
603 if (frame_info->LastMouseUpdateTime.QuadPart == 0)
606 if (frame_info->PointerPosition.Visible) {
608 case DXGI_MODE_ROTATION_ROTATE90:
609 dda->
mouse_x = frame_info->PointerPosition.Position.y;
610 dda->
mouse_y = dda->
output_desc.DesktopCoordinates.right - dda->
output_desc.DesktopCoordinates.left - frame_info->PointerPosition.Position.x - 1;
612 case DXGI_MODE_ROTATION_ROTATE180:
613 dda->
mouse_x = dda->
output_desc.DesktopCoordinates.right - dda->
output_desc.DesktopCoordinates.left - frame_info->PointerPosition.Position.x - 1;
614 dda->
mouse_y = dda->
output_desc.DesktopCoordinates.bottom - dda->
output_desc.DesktopCoordinates.top - frame_info->PointerPosition.Position.y - 1;
616 case DXGI_MODE_ROTATION_ROTATE270:
617 dda->
mouse_x = dda->
output_desc.DesktopCoordinates.bottom - dda->
output_desc.DesktopCoordinates.top - frame_info->PointerPosition.Position.y - 1;
618 dda->
mouse_y = frame_info->PointerPosition.Position.x;
621 dda->
mouse_x = frame_info->PointerPosition.Position.x;
622 dda->
mouse_y = frame_info->PointerPosition.Position.y;
628 if (frame_info->PointerShapeBufferSize) {
629 UINT
size = frame_info->PointerShapeBufferSize;
630 DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info;
631 uint8_t *rgba_buf =
NULL, *rgb_xor_buf =
NULL;
636 hr = IDXGIOutputDuplication_GetFramePointerShape(dda->
dxgi_outdupl,
647 if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME) {
648 ret =
convert_mono_buffer(buf, &rgba_buf, &rgb_xor_buf, &shape_info.Width, &shape_info.Height, &shape_info.Pitch);
652 }
else if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR) {
653 ret =
fixup_color_mask(buf, &rgba_buf, &rgb_xor_buf, shape_info.Width, shape_info.Height, shape_info.Pitch);
657 }
else if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR) {
688 DXGI_OUTDUPL_FRAME_INFO frame_info;
690 IDXGIResource *desktop_resource =
NULL;
694 hr = IDXGIOutputDuplication_AcquireNextFrame(
699 if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
701 }
else if (FAILED(hr)) {
712 if (!frame_info.LastPresentTime.QuadPart || !frame_info.AccumulatedFrames) {
737 hr = IDXGIResource_QueryInterface(desktop_resource, &IID_ID3D11Texture2D, (
void**)desktop_texture);
746 D3D11_TEXTURE2D_DESC
desc;
747 ID3D11Texture2D_GetDesc(*desktop_texture, &
desc);
748 desc.Usage = D3D11_USAGE_DEFAULT;
750 desc.CPUAccessFlags = 0;
764 (ID3D11Resource*)*desktop_texture);
771 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
781 D3D11_TEXTURE2D_DESC
desc;
826 case DXGI_FORMAT_R10G10B10A2_UNORM:
933 ID3D11Texture2D *frame_tex = (ID3D11Texture2D*)
frame->
data[0];
934 D3D11_RENDER_TARGET_VIEW_DESC target_desc = { 0 };
935 ID3D11RenderTargetView* target_view =
NULL;
936 ID3D11Buffer *mouse_vertex_buffer =
NULL;
937 D3D11_TEXTURE2D_DESC tex_desc;
938 int num_vertices = 0;
952 -x >= (
int)tex_desc.Width || -y >= (
int)tex_desc.Height)
956 target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
957 target_desc.Texture2D.MipSlice = 0;
960 (ID3D11Resource*)frame_tex,
969 ID3D11DeviceContext_ClearState(devctx);
972 D3D11_VIEWPORT viewport = { 0 };
973 viewport.Width = dda->
width;
974 viewport.Height = dda->
height;
975 viewport.MinDepth = 0.0f;
976 viewport.MaxDepth = 1.0f;
978 ID3D11DeviceContext_RSSetViewports(devctx, 1, &viewport);
984 x , y + tex_desc.Height, 0.0f, 0.0f, 1.0f,
985 x , y , 0.0f, 0.0f, 0.0f,
986 x + tex_desc.Width, y + tex_desc.Height, 0.0f, 1.0f, 1.0f,
987 x + tex_desc.Width, y , 0.0f, 1.0f, 0.0f,
992 D3D11_SUBRESOURCE_DATA init_data = { 0 };
993 D3D11_BUFFER_DESC buf_desc = { 0 };
996 case DXGI_MODE_ROTATION_ROTATE90:
997 vertices[ 0] = x; vertices[ 1] = y;
998 vertices[ 5] = x; vertices[ 6] = y - tex_desc.Width;
999 vertices[10] = x + tex_desc.Height; vertices[11] = y;
1000 vertices[15] = x + tex_desc.Height; vertices[16] = y - tex_desc.Width;
1001 vertices[ 3] = 0.0f; vertices[ 4] = 0.0f;
1002 vertices[ 8] = 1.0f; vertices[ 9] = 0.0f;
1003 vertices[13] = 0.0f; vertices[14] = 1.0f;
1004 vertices[18] = 1.0f; vertices[19] = 1.0f;
1006 case DXGI_MODE_ROTATION_ROTATE180:
1007 vertices[ 0] = x - tex_desc.Width; vertices[ 1] = y;
1008 vertices[ 5] = x - tex_desc.Width; vertices[ 6] = y - tex_desc.Height;
1009 vertices[10] = x; vertices[11] = y;
1010 vertices[15] = x; vertices[16] = y - tex_desc.Height;
1011 vertices[ 3] = 1.0f; vertices[ 4] = 0.0f;
1012 vertices[ 8] = 1.0f; vertices[ 9] = 1.0f;
1013 vertices[13] = 0.0f; vertices[14] = 0.0f;
1014 vertices[18] = 0.0f; vertices[19] = 1.0f;
1016 case DXGI_MODE_ROTATION_ROTATE270:
1017 vertices[ 0] = x - tex_desc.Height; vertices[ 1] = y + tex_desc.Width;
1018 vertices[ 5] = x - tex_desc.Height; vertices[ 6] = y;
1019 vertices[10] = x; vertices[11] = y + tex_desc.Width;
1020 vertices[15] = x; vertices[16] = y;
1021 vertices[ 3] = 1.0f; vertices[ 4] = 1.0f;
1022 vertices[ 8] = 0.0f; vertices[ 9] = 1.0f;
1023 vertices[13] = 1.0f; vertices[14] = 0.0f;
1024 vertices[18] = 0.0f; vertices[19] = 0.0f;
1030 num_vertices =
sizeof(vertices) / (
sizeof(
FLOAT) * 5);
1032 buf_desc.Usage = D3D11_USAGE_DEFAULT;
1033 buf_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1034 buf_desc.ByteWidth =
sizeof(vertices);
1035 init_data.pSysMem = vertices;
1040 &mouse_vertex_buffer);
1047 ID3D11DeviceContext_IASetVertexBuffers(devctx, 0, 1, &mouse_vertex_buffer, &
stride, &
offset);
1048 ID3D11DeviceContext_IASetInputLayout(devctx, dda->
input_layout);
1049 ID3D11DeviceContext_IASetPrimitiveTopology(devctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
1053 ID3D11DeviceContext_VSSetConstantBuffers(devctx, 0, 1, &dda->
const_buffer);
1054 ID3D11DeviceContext_PSSetSamplers(devctx, 0, 1, &dda->
sampler_state);
1058 ID3D11DeviceContext_OMSetBlendState(devctx, dda->
blend_state,
NULL, 0xFFFFFFFF);
1059 ID3D11DeviceContext_OMSetRenderTargets(devctx, 1, &target_view,
NULL);
1061 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1067 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1082 ID3D11Texture2D *cur_texture =
NULL;
1083 D3D11_TEXTURE2D_DESC
desc = { 0 };
1084 D3D11_BOX box = { 0 };
1142 }
else if (
ret < 0) {
1150 ID3D11Texture2D_GetDesc(cur_texture, &
desc);
1167 box.right = box.left + dda->
width;
1168 box.bottom = box.top + dda->
height;
1172 ID3D11DeviceContext_CopySubresourceRegion(
1176 (ID3D11Resource*)cur_texture, 0,
1181 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1197 desc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) {
1229 IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1246 .description =
NULL_IF_CONFIG_SMALL(
"Grab Windows Desktop images using Desktop Duplication API"),
1248 .priv_class = &ddagrab_class,