21 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0A00
23 #define _WIN32_WINNT 0x0A00
52 #define TIMER_RES 1000000
53 #define TIMER_RES64 INT64_C(1000000)
109 #define OFFSET(x) offsetof(DdagrabContext, x)
110 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
119 {
"auto",
"let dda pick its preferred format", 0,
AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, INT_MAX,
FLAGS, .unit =
"output_fmt" },
122 {
"10bit",
"only output default 10 Bit format", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS, .unit =
"output_fmt" },
123 {
"x2bgr10",
"only output 10 Bit X2BGR10", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS, .unit =
"output_fmt" },
126 {
"allow_fallback",
"don't error on fallback to default 8 Bit format",
128 {
"force_fmt",
"exclude BGRA from format list (experimental, discouraged by Microsoft)",
130 {
"dup_frames",
"duplicate frames to maintain framerate",
139 IUnknown **resp = (IUnknown**)resource;
141 IUnknown_Release(*resp);
175 IDXGIDevice *dxgi_device =
NULL;
176 IDXGIAdapter *dxgi_adapter =
NULL;
177 IDXGIOutput *dxgi_output =
NULL;
178 IDXGIOutput1 *dxgi_output1 =
NULL;
179 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
180 IDXGIOutput5 *dxgi_output5 =
NULL;
182 typedef DPI_AWARENESS_CONTEXT (*set_thread_dpi_t)(DPI_AWARENESS_CONTEXT);
183 set_thread_dpi_t set_thread_dpi;
184 HMODULE user32_module;
189 hr = ID3D11Device_QueryInterface(dda->
device_hwctx->
device, &IID_IDXGIDevice, (
void**)&dxgi_device);
195 hr = IDXGIDevice_GetParent(dxgi_device, &IID_IDXGIAdapter, (
void**)&dxgi_adapter);
196 IDXGIDevice_Release(dxgi_device);
203 hr = IDXGIAdapter_EnumOutputs(dxgi_adapter, dda->
output_idx, &dxgi_output);
204 IDXGIAdapter_Release(dxgi_adapter);
211 hr = IDXGIOutput_GetDesc(dxgi_output, &dda->
output_desc);
213 IDXGIOutput_Release(dxgi_output);
218 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
219 user32_module = dlopen(
"user32.dll", 0);
220 if (!user32_module) {
225 set_thread_dpi = (set_thread_dpi_t)dlsym(user32_module,
"SetThreadDpiAwarenessContext");
228 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput5, (
void**)&dxgi_output5);
230 if (set_thread_dpi && SUCCEEDED(hr)) {
231 DPI_AWARENESS_CONTEXT prev_dpi_ctx;
234 DXGI_FORMAT_R10G10B10A2_UNORM,
248 IDXGIOutput_Release(dxgi_output);
251 prev_dpi_ctx = set_thread_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
255 hr = IDXGIOutput5_DuplicateOutput1(dxgi_output5,
261 IDXGIOutput5_Release(dxgi_output5);
265 set_thread_dpi(prev_dpi_ctx);
267 dlclose(user32_module);
268 user32_module =
NULL;
269 set_thread_dpi =
NULL;
273 dlclose(user32_module);
274 user32_module =
NULL;
275 set_thread_dpi =
NULL;
286 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput1, (
void**)&dxgi_output1);
287 IDXGIOutput_Release(dxgi_output);
294 hr = IDXGIOutput1_DuplicateOutput(dxgi_output1,
297 IDXGIOutput1_Release(dxgi_output1);
301 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
304 }
else if (hr == DXGI_ERROR_UNSUPPORTED) {
307 }
else if (hr == E_INVALIDARG) {
310 }
else if (hr == E_ACCESSDENIED) {
313 }
else if (FAILED(hr)) {
335 {
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
336 {
"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
343 D3D11_SAMPLER_DESC sampler_desc = { 0 };
344 D3D11_BLEND_DESC blend_desc = { 0 };
345 D3D11_BUFFER_DESC buffer_desc = { 0 };
350 hr = ID3D11Device_CreateVertexShader(dev,
360 hr = ID3D11Device_CreateInputLayout(dev,
371 hr = ID3D11Device_CreatePixelShader(dev,
384 buffer_desc.ByteWidth =
sizeof(const_data);
385 buffer_desc.Usage = D3D11_USAGE_IMMUTABLE;
386 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
387 hr = ID3D11Device_CreateBuffer(dev,
396 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
397 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
398 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
399 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
400 sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
401 hr = ID3D11Device_CreateSamplerState(dev,
409 blend_desc.AlphaToCoverageEnable = FALSE;
410 blend_desc.IndependentBlendEnable = FALSE;
411 blend_desc.RenderTarget[0].BlendEnable = TRUE;
412 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
413 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
414 blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
415 blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
416 blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
417 blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
418 blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
419 hr = ID3D11Device_CreateBlendState(dev,
427 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_INV_DEST_COLOR;
428 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_COLOR;
429 hr = ID3D11Device_CreateBlendState(dev,
456 DXGI_OUTDUPL_POINTER_SHAPE_INFO *shape_info,
457 ID3D11Texture2D **out_tex,
458 ID3D11ShaderResourceView **res_view)
461 D3D11_TEXTURE2D_DESC
desc = { 0 };
462 D3D11_SUBRESOURCE_DATA init_data = { 0 };
463 D3D11_SHADER_RESOURCE_VIEW_DESC resource_desc = { 0 };
469 desc.SampleDesc.Count = 1;
470 desc.SampleDesc.Quality = 0;
471 desc.Usage = D3D11_USAGE_IMMUTABLE;
472 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
474 desc.Width = shape_info->Width;
475 desc.Height = shape_info->Height;
477 init_data.pSysMem = buf;
478 init_data.SysMemPitch = shape_info->Pitch;
480 resource_desc.Format =
desc.Format;
481 resource_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
482 resource_desc.Texture2D.MostDetailedMip = 0;
483 resource_desc.Texture2D.MipLevels = 1;
495 (ID3D11Resource*)*out_tex,
509 int width = *_width,
height = *_height, pitch = *_pitch;
510 int real_height =
height / 2;
511 int size = real_height * pitch;
518 if (!
output || !output_xor) {
524 for (y = 0; y < real_height; y++) {
525 for (x = 0; x <
width; x++) {
526 int in_pos = (y * pitch) + (x / 8);
527 int out_pos = 4 * ((y *
width) + x);
528 int and_val = (
input[in_pos] >> (7 - (x % 8))) & 1;
529 int xor_val = (
input[in_pos +
size] >> (7 - (x % 8))) & 1;
531 if (!and_val && !xor_val) {
533 memset(&
output[out_pos], 0, 4);
534 output[out_pos + 3] = 0xFF;
537 memset(&output_xor[out_pos], 0, 4);
538 }
else if (and_val && !xor_val) {
540 memset(&
output[out_pos], 0, 4);
543 memset(&output_xor[out_pos], 0, 4);
544 }
else if (!and_val && xor_val) {
546 memset(&
output[out_pos], 0xFF, 4);
549 memset(&output_xor[out_pos], 0, 4);
550 }
else if (and_val && xor_val) {
552 memset(&
output[out_pos], 0, 4);
555 memset(&output_xor[out_pos], 0xFF, 4);
561 *_height = real_height;
563 *xor_out = output_xor;
575 if (!
output || !output_xor) {
584 for (y = 0; y <
height; y++) {
585 for (x = 0; x <
width; x++) {
586 int pos = (y*pitch) + (4*x) + 3;
593 *xor_out = output_xor;
604 if (frame_info->LastMouseUpdateTime.QuadPart == 0)
607 if (frame_info->PointerPosition.Visible) {
609 case DXGI_MODE_ROTATION_ROTATE90:
610 dda->
mouse_x = frame_info->PointerPosition.Position.y;
611 dda->
mouse_y = dda->
output_desc.DesktopCoordinates.right - dda->
output_desc.DesktopCoordinates.left - frame_info->PointerPosition.Position.x - 1;
613 case DXGI_MODE_ROTATION_ROTATE180:
614 dda->
mouse_x = dda->
output_desc.DesktopCoordinates.right - dda->
output_desc.DesktopCoordinates.left - frame_info->PointerPosition.Position.x - 1;
615 dda->
mouse_y = dda->
output_desc.DesktopCoordinates.bottom - dda->
output_desc.DesktopCoordinates.top - frame_info->PointerPosition.Position.y - 1;
617 case DXGI_MODE_ROTATION_ROTATE270:
618 dda->
mouse_x = dda->
output_desc.DesktopCoordinates.bottom - dda->
output_desc.DesktopCoordinates.top - frame_info->PointerPosition.Position.y - 1;
619 dda->
mouse_y = frame_info->PointerPosition.Position.x;
622 dda->
mouse_x = frame_info->PointerPosition.Position.x;
623 dda->
mouse_y = frame_info->PointerPosition.Position.y;
629 if (frame_info->PointerShapeBufferSize) {
630 UINT
size = frame_info->PointerShapeBufferSize;
631 DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info;
632 uint8_t *rgba_buf =
NULL, *rgb_xor_buf =
NULL;
637 hr = IDXGIOutputDuplication_GetFramePointerShape(dda->
dxgi_outdupl,
648 if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME) {
649 ret =
convert_mono_buffer(buf, &rgba_buf, &rgb_xor_buf, &shape_info.Width, &shape_info.Height, &shape_info.Pitch);
653 }
else if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR) {
654 ret =
fixup_color_mask(buf, &rgba_buf, &rgb_xor_buf, shape_info.Width, shape_info.Height, shape_info.Pitch);
658 }
else if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR) {
689 DXGI_OUTDUPL_FRAME_INFO frame_info;
691 IDXGIResource *desktop_resource =
NULL;
695 hr = IDXGIOutputDuplication_AcquireNextFrame(
700 if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
702 }
else if (FAILED(hr)) {
713 if (!frame_info.LastPresentTime.QuadPart || !frame_info.AccumulatedFrames) {
738 hr = IDXGIResource_QueryInterface(desktop_resource, &IID_ID3D11Texture2D, (
void**)desktop_texture);
747 D3D11_TEXTURE2D_DESC
desc;
748 ID3D11Texture2D_GetDesc(*desktop_texture, &
desc);
749 desc.Usage = D3D11_USAGE_DEFAULT;
751 desc.CPUAccessFlags = 0;
765 (ID3D11Resource*)*desktop_texture);
772 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
782 D3D11_TEXTURE2D_DESC
desc;
827 case DXGI_FORMAT_R10G10B10A2_UNORM:
935 ID3D11Texture2D *frame_tex = (ID3D11Texture2D*)
frame->data[0];
936 D3D11_RENDER_TARGET_VIEW_DESC target_desc = { 0 };
937 ID3D11RenderTargetView* target_view =
NULL;
938 ID3D11Buffer *mouse_vertex_buffer =
NULL;
939 D3D11_TEXTURE2D_DESC tex_desc;
940 int num_vertices = 0;
954 -x >= (
int)tex_desc.Width || -y >= (
int)tex_desc.Height)
958 target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
959 target_desc.Texture2D.MipSlice = 0;
962 (ID3D11Resource*)frame_tex,
971 ID3D11DeviceContext_ClearState(devctx);
974 D3D11_VIEWPORT viewport = { 0 };
975 viewport.Width = dda->
width;
976 viewport.Height = dda->
height;
977 viewport.MinDepth = 0.0f;
978 viewport.MaxDepth = 1.0f;
980 ID3D11DeviceContext_RSSetViewports(devctx, 1, &viewport);
986 x , y + tex_desc.Height, 0.0f, 0.0f, 1.0f,
987 x , y , 0.0f, 0.0f, 0.0f,
988 x + tex_desc.Width, y + tex_desc.Height, 0.0f, 1.0f, 1.0f,
989 x + tex_desc.Width, y , 0.0f, 1.0f, 0.0f,
994 D3D11_SUBRESOURCE_DATA init_data = { 0 };
995 D3D11_BUFFER_DESC buf_desc = { 0 };
998 case DXGI_MODE_ROTATION_ROTATE90:
999 vertices[ 0] = x; vertices[ 1] = y;
1000 vertices[ 5] = x; vertices[ 6] = y - tex_desc.Width;
1001 vertices[10] = x + tex_desc.Height; vertices[11] = y;
1002 vertices[15] = x + tex_desc.Height; vertices[16] = y - tex_desc.Width;
1003 vertices[ 3] = 0.0f; vertices[ 4] = 0.0f;
1004 vertices[ 8] = 1.0f; vertices[ 9] = 0.0f;
1005 vertices[13] = 0.0f; vertices[14] = 1.0f;
1006 vertices[18] = 1.0f; vertices[19] = 1.0f;
1008 case DXGI_MODE_ROTATION_ROTATE180:
1009 vertices[ 0] = x - tex_desc.Width; vertices[ 1] = y;
1010 vertices[ 5] = x - tex_desc.Width; vertices[ 6] = y - tex_desc.Height;
1011 vertices[10] = x; vertices[11] = y;
1012 vertices[15] = x; vertices[16] = y - tex_desc.Height;
1013 vertices[ 3] = 1.0f; vertices[ 4] = 0.0f;
1014 vertices[ 8] = 1.0f; vertices[ 9] = 1.0f;
1015 vertices[13] = 0.0f; vertices[14] = 0.0f;
1016 vertices[18] = 0.0f; vertices[19] = 1.0f;
1018 case DXGI_MODE_ROTATION_ROTATE270:
1019 vertices[ 0] = x - tex_desc.Height; vertices[ 1] = y + tex_desc.Width;
1020 vertices[ 5] = x - tex_desc.Height; vertices[ 6] = y;
1021 vertices[10] = x; vertices[11] = y + tex_desc.Width;
1022 vertices[15] = x; vertices[16] = y;
1023 vertices[ 3] = 1.0f; vertices[ 4] = 1.0f;
1024 vertices[ 8] = 0.0f; vertices[ 9] = 1.0f;
1025 vertices[13] = 1.0f; vertices[14] = 0.0f;
1026 vertices[18] = 0.0f; vertices[19] = 0.0f;
1032 num_vertices =
sizeof(vertices) / (
sizeof(
FLOAT) * 5);
1034 buf_desc.Usage = D3D11_USAGE_DEFAULT;
1035 buf_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1036 buf_desc.ByteWidth =
sizeof(vertices);
1037 init_data.pSysMem = vertices;
1042 &mouse_vertex_buffer);
1049 ID3D11DeviceContext_IASetVertexBuffers(devctx, 0, 1, &mouse_vertex_buffer, &
stride, &
offset);
1050 ID3D11DeviceContext_IASetInputLayout(devctx, dda->
input_layout);
1051 ID3D11DeviceContext_IASetPrimitiveTopology(devctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
1055 ID3D11DeviceContext_VSSetConstantBuffers(devctx, 0, 1, &dda->
const_buffer);
1056 ID3D11DeviceContext_PSSetSamplers(devctx, 0, 1, &dda->
sampler_state);
1060 ID3D11DeviceContext_OMSetBlendState(devctx, dda->
blend_state,
NULL, 0xFFFFFFFF);
1061 ID3D11DeviceContext_OMSetRenderTargets(devctx, 1, &target_view,
NULL);
1063 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1069 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1084 ID3D11Texture2D *cur_texture =
NULL;
1085 D3D11_TEXTURE2D_DESC
desc = { 0 };
1086 D3D11_BOX box = { 0 };
1144 }
else if (
ret < 0) {
1152 ID3D11Texture2D_GetDesc(cur_texture, &
desc);
1169 box.right = box.left + dda->
width;
1170 box.bottom = box.top + dda->
height;
1174 ID3D11DeviceContext_CopySubresourceRegion(
1176 (ID3D11Resource*)
frame->data[0], (UINT)(intptr_t)
frame->data[1],
1178 (ID3D11Resource*)cur_texture, 0,
1183 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1199 desc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) {
1231 IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1248 .description =
NULL_IF_CONFIG_SMALL(
"Grab Windows Desktop images using Desktop Duplication API"),
1250 .priv_class = &ddagrab_class,