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)
106 #define OFFSET(x) offsetof(DdagrabContext, x)
107 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
116 {
"auto",
"let dda pick its preferred format", 0,
AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, INT_MAX,
FLAGS,
"output_fmt" },
119 {
"10bit",
"only output default 10 Bit format", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS,
"output_fmt" },
120 {
"x2bgr10",
"only output 10 Bit X2BGR10", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS,
"output_fmt" },
123 {
"allow_fallback",
"don't error on fallback to default 8 Bit format",
125 {
"force_fmt",
"exclude BGRA from format list (experimental, discouraged by Microsoft)",
134 IUnknown **resp = (IUnknown**)resource;
136 IUnknown_Release(*resp);
169 IDXGIDevice *dxgi_device =
NULL;
170 IDXGIAdapter *dxgi_adapter =
NULL;
171 IDXGIOutput *dxgi_output =
NULL;
172 IDXGIOutput1 *dxgi_output1 =
NULL;
173 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
174 IDXGIOutput5 *dxgi_output5 =
NULL;
176 typedef DPI_AWARENESS_CONTEXT (*set_thread_dpi_t)(DPI_AWARENESS_CONTEXT);
177 set_thread_dpi_t set_thread_dpi;
178 HMODULE user32_module;
183 hr = ID3D11Device_QueryInterface(dda->
device_hwctx->
device, &IID_IDXGIDevice, (
void**)&dxgi_device);
189 hr = IDXGIDevice_GetParent(dxgi_device, &IID_IDXGIAdapter, (
void**)&dxgi_adapter);
190 IDXGIDevice_Release(dxgi_device);
197 hr = IDXGIAdapter_EnumOutputs(dxgi_adapter, dda->
output_idx, &dxgi_output);
198 IDXGIAdapter_Release(dxgi_adapter);
205 hr = IDXGIOutput_GetDesc(dxgi_output, &dda->
output_desc);
207 IDXGIOutput_Release(dxgi_output);
212 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
213 user32_module = dlopen(
"user32.dll", 0);
214 if (!user32_module) {
219 set_thread_dpi = (set_thread_dpi_t)dlsym(user32_module,
"SetThreadDpiAwarenessContext");
222 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput5, (
void**)&dxgi_output5);
224 if (set_thread_dpi && SUCCEEDED(hr)) {
225 DPI_AWARENESS_CONTEXT prev_dpi_ctx;
228 DXGI_FORMAT_R10G10B10A2_UNORM,
242 IDXGIOutput_Release(dxgi_output);
245 prev_dpi_ctx = set_thread_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
249 hr = IDXGIOutput5_DuplicateOutput1(dxgi_output5,
255 IDXGIOutput5_Release(dxgi_output5);
259 set_thread_dpi(prev_dpi_ctx);
261 dlclose(user32_module);
262 user32_module =
NULL;
263 set_thread_dpi =
NULL;
267 dlclose(user32_module);
268 user32_module =
NULL;
269 set_thread_dpi =
NULL;
280 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput1, (
void**)&dxgi_output1);
281 IDXGIOutput_Release(dxgi_output);
288 hr = IDXGIOutput1_DuplicateOutput(dxgi_output1,
291 IDXGIOutput1_Release(dxgi_output1);
295 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
298 }
else if (hr == DXGI_ERROR_UNSUPPORTED) {
301 }
else if (hr == E_INVALIDARG) {
304 }
else if (hr == E_ACCESSDENIED) {
307 }
else if (FAILED(hr)) {
329 {
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
330 {
"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
337 D3D11_SAMPLER_DESC sampler_desc = { 0 };
338 D3D11_BLEND_DESC blend_desc = { 0 };
339 D3D11_BUFFER_DESC buffer_desc = { 0 };
344 hr = ID3D11Device_CreateVertexShader(dev,
354 hr = ID3D11Device_CreateInputLayout(dev,
365 hr = ID3D11Device_CreatePixelShader(dev,
378 buffer_desc.ByteWidth =
sizeof(const_data);
379 buffer_desc.Usage = D3D11_USAGE_IMMUTABLE;
380 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
381 hr = ID3D11Device_CreateBuffer(dev,
390 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
391 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
392 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
393 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
394 sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
395 hr = ID3D11Device_CreateSamplerState(dev,
403 blend_desc.AlphaToCoverageEnable = FALSE;
404 blend_desc.IndependentBlendEnable = FALSE;
405 blend_desc.RenderTarget[0].BlendEnable = TRUE;
406 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
407 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
408 blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
409 blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
410 blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
411 blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
412 blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
413 hr = ID3D11Device_CreateBlendState(dev,
421 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_DEST_COLOR;
422 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_COLOR;
423 hr = ID3D11Device_CreateBlendState(dev,
450 DXGI_OUTDUPL_POINTER_SHAPE_INFO *shape_info,
451 ID3D11Texture2D **out_tex,
452 ID3D11ShaderResourceView **res_view)
455 D3D11_TEXTURE2D_DESC
desc = { 0 };
456 D3D11_SUBRESOURCE_DATA init_data = { 0 };
457 D3D11_SHADER_RESOURCE_VIEW_DESC resource_desc = { 0 };
463 desc.SampleDesc.Count = 1;
464 desc.SampleDesc.Quality = 0;
465 desc.Usage = D3D11_USAGE_IMMUTABLE;
466 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
468 desc.Width = shape_info->Width;
469 desc.Height = shape_info->Height;
471 init_data.pSysMem = buf;
472 init_data.SysMemPitch = shape_info->Pitch;
474 resource_desc.Format =
desc.Format;
475 resource_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
476 resource_desc.Texture2D.MostDetailedMip = 0;
477 resource_desc.Texture2D.MipLevels = 1;
489 (ID3D11Resource*)*out_tex,
503 int width = *_width,
height = *_height, pitch = *_pitch;
504 int real_height =
height / 2;
505 int size = real_height * pitch;
512 if (!
output || !output_xor) {
518 for (y = 0; y < real_height; y++) {
519 for (x = 0; x <
width; x++) {
520 int in_pos = (y * pitch) + (x / 8);
521 int out_pos = 4 * ((y *
width) + x);
522 int and_val = (
input[in_pos] >> (7 - (x % 8))) & 1;
523 int xor_val = (
input[in_pos +
size] >> (7 - (x % 8))) & 1;
525 if (!and_val && !xor_val) {
527 memset(&
output[out_pos], 0, 4);
528 output[out_pos + 3] = 0xFF;
531 memset(&output_xor[out_pos], 0, 4);
532 }
else if (and_val && !xor_val) {
534 memset(&
output[out_pos], 0, 4);
537 memset(&output_xor[out_pos], 0, 4);
538 }
else if (!and_val && xor_val) {
540 memset(&
output[out_pos], 0xFF, 4);
543 memset(&output_xor[out_pos], 0, 4);
544 }
else if (and_val && xor_val) {
546 memset(&
output[out_pos], 0, 4);
549 memset(&output_xor[out_pos], 0xFF, 4);
555 *_height = real_height;
557 *xor_out = output_xor;
569 if (!
output || !output_xor) {
578 for (y = 0; y <
height; y++) {
579 for (x = 0; x <
width; x++) {
580 int pos = (y*pitch) + (4*x) + 3;
587 *xor_out = output_xor;
598 if (frame_info->LastMouseUpdateTime.QuadPart == 0)
601 if (frame_info->PointerPosition.Visible) {
603 case DXGI_MODE_ROTATION_ROTATE90:
604 dda->
mouse_x = frame_info->PointerPosition.Position.y;
605 dda->
mouse_y = dda->
output_desc.DesktopCoordinates.right - dda->
output_desc.DesktopCoordinates.left - frame_info->PointerPosition.Position.x - 1;
607 case DXGI_MODE_ROTATION_ROTATE180:
608 dda->
mouse_x = dda->
output_desc.DesktopCoordinates.right - dda->
output_desc.DesktopCoordinates.left - frame_info->PointerPosition.Position.x - 1;
609 dda->
mouse_y = dda->
output_desc.DesktopCoordinates.bottom - dda->
output_desc.DesktopCoordinates.top - frame_info->PointerPosition.Position.y - 1;
611 case DXGI_MODE_ROTATION_ROTATE270:
612 dda->
mouse_x = dda->
output_desc.DesktopCoordinates.bottom - dda->
output_desc.DesktopCoordinates.top - frame_info->PointerPosition.Position.y - 1;
613 dda->
mouse_y = frame_info->PointerPosition.Position.x;
616 dda->
mouse_x = frame_info->PointerPosition.Position.x;
617 dda->
mouse_y = frame_info->PointerPosition.Position.y;
623 if (frame_info->PointerShapeBufferSize) {
624 UINT
size = frame_info->PointerShapeBufferSize;
625 DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info;
626 uint8_t *rgba_buf =
NULL, *rgb_xor_buf =
NULL;
631 hr = IDXGIOutputDuplication_GetFramePointerShape(dda->
dxgi_outdupl,
642 if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME) {
643 ret =
convert_mono_buffer(buf, &rgba_buf, &rgb_xor_buf, &shape_info.Width, &shape_info.Height, &shape_info.Pitch);
647 }
else if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR) {
648 ret =
fixup_color_mask(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_COLOR) {
683 DXGI_OUTDUPL_FRAME_INFO frame_info;
685 IDXGIResource *desktop_resource =
NULL;
689 hr = IDXGIOutputDuplication_AcquireNextFrame(
694 if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
696 }
else if (FAILED(hr)) {
707 if (need_frame && (!frame_info.LastPresentTime.QuadPart || !frame_info.AccumulatedFrames)) {
712 hr = IDXGIResource_QueryInterface(desktop_resource, &IID_ID3D11Texture2D, (
void**)desktop_texture);
725 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
735 D3D11_TEXTURE2D_DESC
desc;
780 case DXGI_FORMAT_R10G10B10A2_UNORM:
887 ID3D11Texture2D *frame_tex = (ID3D11Texture2D*)
frame->
data[0];
888 D3D11_RENDER_TARGET_VIEW_DESC target_desc = { 0 };
889 ID3D11RenderTargetView* target_view =
NULL;
890 ID3D11Buffer *mouse_vertex_buffer =
NULL;
891 D3D11_TEXTURE2D_DESC tex_desc;
892 int num_vertices = 0;
906 -x >= (
int)tex_desc.Width || -y >= (
int)tex_desc.Height)
910 target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
911 target_desc.Texture2D.MipSlice = 0;
914 (ID3D11Resource*)frame_tex,
923 ID3D11DeviceContext_ClearState(devctx);
926 D3D11_VIEWPORT viewport = { 0 };
927 viewport.Width = dda->
width;
928 viewport.Height = dda->
height;
929 viewport.MinDepth = 0.0f;
930 viewport.MaxDepth = 1.0f;
932 ID3D11DeviceContext_RSSetViewports(devctx, 1, &viewport);
938 x , y + tex_desc.Height, 0.0f, 0.0f, 1.0f,
939 x , y , 0.0f, 0.0f, 0.0f,
940 x + tex_desc.Width, y + tex_desc.Height, 0.0f, 1.0f, 1.0f,
941 x + tex_desc.Width, y , 0.0f, 1.0f, 0.0f,
946 D3D11_SUBRESOURCE_DATA init_data = { 0 };
947 D3D11_BUFFER_DESC buf_desc = { 0 };
950 case DXGI_MODE_ROTATION_ROTATE90:
951 vertices[ 0] = x; vertices[ 1] = y;
952 vertices[ 5] = x; vertices[ 6] = y - tex_desc.Width;
953 vertices[10] = x + tex_desc.Height; vertices[11] = y;
954 vertices[15] = x + tex_desc.Height; vertices[16] = y - tex_desc.Width;
955 vertices[ 3] = 0.0f; vertices[ 4] = 0.0f;
956 vertices[ 8] = 1.0f; vertices[ 9] = 0.0f;
957 vertices[13] = 0.0f; vertices[14] = 1.0f;
958 vertices[18] = 1.0f; vertices[19] = 1.0f;
960 case DXGI_MODE_ROTATION_ROTATE180:
961 vertices[ 0] = x - tex_desc.Width; vertices[ 1] = y;
962 vertices[ 5] = x - tex_desc.Width; vertices[ 6] = y - tex_desc.Height;
963 vertices[10] = x; vertices[11] = y;
964 vertices[15] = x; vertices[16] = y - tex_desc.Height;
965 vertices[ 3] = 1.0f; vertices[ 4] = 0.0f;
966 vertices[ 8] = 1.0f; vertices[ 9] = 1.0f;
967 vertices[13] = 0.0f; vertices[14] = 0.0f;
968 vertices[18] = 0.0f; vertices[19] = 1.0f;
970 case DXGI_MODE_ROTATION_ROTATE270:
971 vertices[ 0] = x - tex_desc.Height; vertices[ 1] = y + tex_desc.Width;
972 vertices[ 5] = x - tex_desc.Height; vertices[ 6] = y;
973 vertices[10] = x; vertices[11] = y + tex_desc.Width;
974 vertices[15] = x; vertices[16] = y;
975 vertices[ 3] = 1.0f; vertices[ 4] = 1.0f;
976 vertices[ 8] = 0.0f; vertices[ 9] = 1.0f;
977 vertices[13] = 1.0f; vertices[14] = 0.0f;
978 vertices[18] = 0.0f; vertices[19] = 0.0f;
984 num_vertices =
sizeof(vertices) / (
sizeof(
FLOAT) * 5);
986 buf_desc.Usage = D3D11_USAGE_DEFAULT;
987 buf_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
988 buf_desc.ByteWidth =
sizeof(vertices);
989 init_data.pSysMem = vertices;
994 &mouse_vertex_buffer);
1001 ID3D11DeviceContext_IASetVertexBuffers(devctx, 0, 1, &mouse_vertex_buffer, &
stride, &
offset);
1002 ID3D11DeviceContext_IASetInputLayout(devctx, dda->
input_layout);
1003 ID3D11DeviceContext_IASetPrimitiveTopology(devctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
1007 ID3D11DeviceContext_VSSetConstantBuffers(devctx, 0, 1, &dda->
const_buffer);
1008 ID3D11DeviceContext_PSSetSamplers(devctx, 0, 1, &dda->
sampler_state);
1012 ID3D11DeviceContext_OMSetBlendState(devctx, dda->
blend_state,
NULL, 0xFFFFFFFF);
1013 ID3D11DeviceContext_OMSetRenderTargets(devctx, 1, &target_view,
NULL);
1015 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1021 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1036 ID3D11Texture2D *cur_texture =
NULL;
1037 D3D11_TEXTURE2D_DESC
desc = { 0 };
1038 D3D11_BOX box = { 0 };
1094 }
else if (
ret < 0) {
1102 ID3D11Texture2D_GetDesc(cur_texture, &
desc);
1119 box.right = box.left + dda->
width;
1120 box.bottom = box.top + dda->
height;
1124 ID3D11DeviceContext_CopySubresourceRegion(
1128 (ID3D11Resource*)cur_texture, 0,
1133 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1149 desc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) {
1181 IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1198 .description =
NULL_IF_CONFIG_SMALL(
"Grab Windows Desktop images using Desktop Duplication API"),
1200 .priv_class = &ddagrab_class,