21 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0A00
23 #define _WIN32_WINNT 0x0A00
25 #define WIN32_LEAN_AND_MEAN
53 #define TIMER_RES 1000000
54 #define TIMER_RES64 INT64_C(1000000)
105 #define OFFSET(x) offsetof(DdagrabContext, x)
106 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
115 {
"auto",
"let dda pick its preferred format", 0,
AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, INT_MAX,
FLAGS,
"output_fmt" },
118 {
"10bit",
"only output default 10 Bit format", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS,
"output_fmt" },
119 {
"x2bgr10",
"only output 10 Bit X2BGR10", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS,
"output_fmt" },
122 {
"allow_fallback",
"don't error on fallback to default 8 Bit format",
124 {
"force_fmt",
"exclude BGRA from format list (experimental, discouraged by Microsoft)",
133 IUnknown **resp = (IUnknown**)resource;
135 IUnknown_Release(*resp);
165 IDXGIDevice *dxgi_device =
NULL;
166 IDXGIAdapter *dxgi_adapter =
NULL;
167 IDXGIOutput *dxgi_output =
NULL;
168 IDXGIOutput1 *dxgi_output1 =
NULL;
169 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
170 IDXGIOutput5 *dxgi_output5 =
NULL;
172 typedef DPI_AWARENESS_CONTEXT (*set_thread_dpi_t)(DPI_AWARENESS_CONTEXT);
173 set_thread_dpi_t set_thread_dpi;
174 HMODULE user32_module;
179 hr = ID3D11Device_QueryInterface(dda->
device_hwctx->
device, &IID_IDXGIDevice, (
void**)&dxgi_device);
185 hr = IDXGIDevice_GetParent(dxgi_device, &IID_IDXGIAdapter, (
void**)&dxgi_adapter);
186 IDXGIDevice_Release(dxgi_device);
193 hr = IDXGIAdapter_EnumOutputs(dxgi_adapter, dda->
output_idx, &dxgi_output);
194 IDXGIAdapter_Release(dxgi_adapter);
201 hr = IDXGIOutput_GetDesc(dxgi_output, &dda->
output_desc);
203 IDXGIOutput_Release(dxgi_output);
208 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
209 user32_module = dlopen(
"user32.dll", 0);
210 if (!user32_module) {
215 set_thread_dpi = (set_thread_dpi_t)dlsym(user32_module,
"SetThreadDpiAwarenessContext");
218 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput5, (
void**)&dxgi_output5);
220 if (set_thread_dpi && SUCCEEDED(hr)) {
221 DPI_AWARENESS_CONTEXT prev_dpi_ctx;
224 DXGI_FORMAT_R10G10B10A2_UNORM,
238 IDXGIOutput_Release(dxgi_output);
241 prev_dpi_ctx = set_thread_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
245 hr = IDXGIOutput5_DuplicateOutput1(dxgi_output5,
251 IDXGIOutput5_Release(dxgi_output5);
255 set_thread_dpi(prev_dpi_ctx);
257 dlclose(user32_module);
258 user32_module =
NULL;
259 set_thread_dpi =
NULL;
263 dlclose(user32_module);
264 user32_module =
NULL;
265 set_thread_dpi =
NULL;
276 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput1, (
void**)&dxgi_output1);
277 IDXGIOutput_Release(dxgi_output);
284 hr = IDXGIOutput1_DuplicateOutput(dxgi_output1,
287 IDXGIOutput1_Release(dxgi_output1);
291 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
294 }
else if (hr == DXGI_ERROR_UNSUPPORTED) {
297 }
else if (hr == E_INVALIDARG) {
300 }
else if (hr == E_ACCESSDENIED) {
303 }
else if (FAILED(hr)) {
325 {
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
326 {
"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
333 D3D11_SAMPLER_DESC sampler_desc = { 0 };
334 D3D11_BLEND_DESC blend_desc = { 0 };
335 D3D11_BUFFER_DESC buffer_desc = { 0 };
340 hr = ID3D11Device_CreateVertexShader(dev,
350 hr = ID3D11Device_CreateInputLayout(dev,
361 hr = ID3D11Device_CreatePixelShader(dev,
374 buffer_desc.ByteWidth =
sizeof(const_data);
375 buffer_desc.Usage = D3D11_USAGE_IMMUTABLE;
376 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
377 hr = ID3D11Device_CreateBuffer(dev,
386 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
387 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
388 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
389 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
390 sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
391 hr = ID3D11Device_CreateSamplerState(dev,
399 blend_desc.AlphaToCoverageEnable = FALSE;
400 blend_desc.IndependentBlendEnable = FALSE;
401 blend_desc.RenderTarget[0].BlendEnable = TRUE;
402 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
403 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
404 blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
405 blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
406 blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
407 blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
408 blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
409 hr = ID3D11Device_CreateBlendState(dev,
436 DXGI_OUTDUPL_POINTER_SHAPE_INFO *shape_info,
437 ID3D11Texture2D **out_tex,
438 ID3D11ShaderResourceView **res_view)
441 D3D11_TEXTURE2D_DESC
desc = { 0 };
442 D3D11_SUBRESOURCE_DATA init_data = { 0 };
443 D3D11_SHADER_RESOURCE_VIEW_DESC resource_desc = { 0 };
449 desc.SampleDesc.Count = 1;
450 desc.SampleDesc.Quality = 0;
451 desc.Usage = D3D11_USAGE_IMMUTABLE;
452 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
454 desc.Width = shape_info->Width;
455 desc.Height = shape_info->Height;
457 init_data.pSysMem = buf;
458 init_data.SysMemPitch = shape_info->Pitch;
460 resource_desc.Format =
desc.Format;
461 resource_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
462 resource_desc.Texture2D.MostDetailedMip = 0;
463 resource_desc.Texture2D.MipLevels = 1;
489 int width = *_width,
height = *_height, pitch = *_pitch;
490 int real_height =
height / 2;
499 for (y = 0; y < real_height; y++) {
500 for (x = 0; x <
width; x++) {
501 int v =
input[(real_height + y) * pitch + (x / 8)];
502 v = (v >> (7 - (x % 8))) & 1;
503 memset(&
output[4 * ((y*
width) + x)], v ? 0xFF : 0, 4);
508 *_height = real_height;
518 for (y = 0; y <
height; y++) {
519 for (x = 0; x <
width; x++) {
520 int pos = (y*pitch) + (4*x) + 3;
521 buf[
pos] = buf[
pos] ? 0 : 0xFF;
532 if (frame_info->LastMouseUpdateTime.QuadPart == 0)
535 if (frame_info->PointerPosition.Visible) {
536 dda->
mouse_x = frame_info->PointerPosition.Position.x;
537 dda->
mouse_y = frame_info->PointerPosition.Position.y;
542 if (frame_info->PointerShapeBufferSize) {
543 UINT
size = frame_info->PointerShapeBufferSize;
544 DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info;
549 hr = IDXGIOutputDuplication_GetFramePointerShape(dda->
dxgi_outdupl,
560 if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME) {
561 uint8_t *new_buf =
convert_mono_buffer(buf, &shape_info.Width, &shape_info.Height, &shape_info.Pitch);
566 }
else if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR) {
567 fixup_color_mask(buf, shape_info.Width, shape_info.Height, shape_info.Pitch);
568 }
else if (shape_info.Type != DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR) {
590 DXGI_OUTDUPL_FRAME_INFO frame_info;
592 IDXGIResource *desktop_resource =
NULL;
596 hr = IDXGIOutputDuplication_AcquireNextFrame(
601 if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
603 }
else if (FAILED(hr)) {
614 hr = IDXGIResource_QueryInterface(desktop_resource, &IID_ID3D11Texture2D, (
void**)desktop_texture);
615 IDXGIResource_Release(desktop_resource);
616 desktop_resource =
NULL;
628 D3D11_TEXTURE2D_DESC
desc;
673 case DXGI_FORMAT_R10G10B10A2_UNORM:
780 ID3D11Texture2D *frame_tex = (ID3D11Texture2D*)
frame->data[0];
781 D3D11_RENDER_TARGET_VIEW_DESC target_desc = { 0 };
782 ID3D11RenderTargetView* target_view =
NULL;
783 ID3D11Buffer *mouse_vertex_buffer =
NULL;
784 D3D11_TEXTURE2D_DESC tex_desc;
785 int num_vertices = 0;
799 -x >= (
int)tex_desc.Width || -y >= (
int)tex_desc.Height)
803 target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
804 target_desc.Texture2D.MipSlice = 0;
807 (ID3D11Resource*)frame_tex,
816 ID3D11DeviceContext_ClearState(devctx);
819 D3D11_VIEWPORT viewport = { 0 };
820 viewport.Width = dda->
width;
821 viewport.Height = dda->
height;
822 viewport.MinDepth = 0.0f;
823 viewport.MaxDepth = 1.0f;
825 ID3D11DeviceContext_RSSetViewports(devctx, 1, &viewport);
831 x , y + tex_desc.Height, 0.0f, 0.0f, 1.0f,
832 x , y , 0.0f, 0.0f, 0.0f,
833 x + tex_desc.Width, y + tex_desc.Height, 0.0f, 1.0f, 1.0f,
834 x + tex_desc.Width, y , 0.0f, 1.0f, 0.0f,
839 D3D11_SUBRESOURCE_DATA init_data = { 0 };
840 D3D11_BUFFER_DESC buf_desc = { 0 };
842 num_vertices =
sizeof(vertices) / (
sizeof(
FLOAT) * 5);
844 buf_desc.Usage = D3D11_USAGE_DEFAULT;
845 buf_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
846 buf_desc.ByteWidth =
sizeof(vertices);
847 init_data.pSysMem = vertices;
852 &mouse_vertex_buffer);
859 ID3D11DeviceContext_IASetVertexBuffers(devctx, 0, 1, &mouse_vertex_buffer, &
stride, &
offset);
860 ID3D11DeviceContext_IASetInputLayout(devctx, dda->
input_layout);
861 ID3D11DeviceContext_IASetPrimitiveTopology(devctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
865 ID3D11DeviceContext_VSSetConstantBuffers(devctx, 0, 1, &dda->
const_buffer);
866 ID3D11DeviceContext_PSSetSamplers(devctx, 0, 1, &dda->
sampler_state);
870 ID3D11DeviceContext_OMSetBlendState(devctx, dda->
blend_state,
NULL, 0xFFFFFFFF);
871 ID3D11DeviceContext_OMSetRenderTargets(devctx, 1, &target_view,
NULL);
873 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
887 ID3D11Texture2D *cur_texture =
NULL;
888 D3D11_TEXTURE2D_DESC
desc = { 0 };
889 D3D11_BOX box = { 0 };
945 }
else if (
ret < 0) {
953 ID3D11Texture2D_GetDesc(cur_texture, &
desc);
970 box.right = box.left + dda->
width;
971 box.bottom = box.top + dda->
height;
975 ID3D11DeviceContext_CopySubresourceRegion(
977 (ID3D11Resource*)
frame->data[0], (UINT)(intptr_t)
frame->data[1],
979 (ID3D11Resource*)cur_texture, 0,
984 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1000 desc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) {
1033 IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1050 .description =
NULL_IF_CONFIG_SMALL(
"Grab Windows Desktop images using Desktop Duplication API"),
1052 .priv_class = &ddagrab_class,