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)
103 #define OFFSET(x) offsetof(DdagrabContext, x)
104 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
113 {
"auto",
"let dda pick its preferred format", 0,
AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, INT_MAX,
FLAGS,
"output_fmt" },
116 {
"10bit",
"only output default 10 Bit format", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS,
"output_fmt" },
117 {
"x2bgr10",
"only output 10 Bit X2BGR10", 0,
AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R10G10B10A2_UNORM }, 0, INT_MAX,
FLAGS,
"output_fmt" },
120 {
"allow_fallback",
"don't error on fallback to default 8 Bit format",
122 {
"force_fmt",
"exclude BGRA from format list (experimental, discouraged by Microsoft)",
131 IUnknown **resp = (IUnknown**)resource;
133 IUnknown_Release(*resp);
163 IDXGIDevice *dxgi_device =
NULL;
164 IDXGIAdapter *dxgi_adapter =
NULL;
165 IDXGIOutput *dxgi_output =
NULL;
166 IDXGIOutput1 *dxgi_output1 =
NULL;
167 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
168 IDXGIOutput5 *dxgi_output5 =
NULL;
170 typedef DPI_AWARENESS_CONTEXT (*set_thread_dpi_t)(DPI_AWARENESS_CONTEXT);
171 set_thread_dpi_t set_thread_dpi;
172 HMODULE user32_module;
177 hr = ID3D11Device_QueryInterface(dda->
device_hwctx->
device, &IID_IDXGIDevice, (
void**)&dxgi_device);
183 hr = IDXGIDevice_GetParent(dxgi_device, &IID_IDXGIAdapter, (
void**)&dxgi_adapter);
184 IDXGIDevice_Release(dxgi_device);
191 hr = IDXGIAdapter_EnumOutputs(dxgi_adapter, dda->
output_idx, &dxgi_output);
192 IDXGIAdapter_Release(dxgi_adapter);
199 hr = IDXGIOutput_GetDesc(dxgi_output, &dda->
output_desc);
201 IDXGIOutput_Release(dxgi_output);
206 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
207 user32_module = dlopen(
"user32.dll", 0);
208 if (!user32_module) {
213 set_thread_dpi = (set_thread_dpi_t)dlsym(user32_module,
"SetThreadDpiAwarenessContext");
216 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput5, (
void**)&dxgi_output5);
218 if (set_thread_dpi && SUCCEEDED(hr)) {
219 DPI_AWARENESS_CONTEXT prev_dpi_ctx;
222 DXGI_FORMAT_R10G10B10A2_UNORM,
236 IDXGIOutput_Release(dxgi_output);
239 prev_dpi_ctx = set_thread_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
243 hr = IDXGIOutput5_DuplicateOutput1(dxgi_output5,
249 IDXGIOutput5_Release(dxgi_output5);
253 set_thread_dpi(prev_dpi_ctx);
255 dlclose(user32_module);
256 user32_module =
NULL;
257 set_thread_dpi =
NULL;
261 dlclose(user32_module);
262 user32_module =
NULL;
263 set_thread_dpi =
NULL;
274 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput1, (
void**)&dxgi_output1);
275 IDXGIOutput_Release(dxgi_output);
282 hr = IDXGIOutput1_DuplicateOutput(dxgi_output1,
285 IDXGIOutput1_Release(dxgi_output1);
289 if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
292 }
else if (hr == DXGI_ERROR_UNSUPPORTED) {
295 }
else if (hr == E_INVALIDARG) {
298 }
else if (hr == E_ACCESSDENIED) {
301 }
else if (FAILED(hr)) {
323 {
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
324 {
"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
331 D3D11_SAMPLER_DESC sampler_desc = { 0 };
332 D3D11_BLEND_DESC blend_desc = { 0 };
333 D3D11_BUFFER_DESC buffer_desc = { 0 };
338 hr = ID3D11Device_CreateVertexShader(dev,
348 hr = ID3D11Device_CreateInputLayout(dev,
359 hr = ID3D11Device_CreatePixelShader(dev,
372 buffer_desc.ByteWidth =
sizeof(const_data);
373 buffer_desc.Usage = D3D11_USAGE_IMMUTABLE;
374 buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
375 hr = ID3D11Device_CreateBuffer(dev,
384 sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
385 sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
386 sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
387 sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
388 sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
389 hr = ID3D11Device_CreateSamplerState(dev,
397 blend_desc.AlphaToCoverageEnable = FALSE;
398 blend_desc.IndependentBlendEnable = FALSE;
399 blend_desc.RenderTarget[0].BlendEnable = TRUE;
400 blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
401 blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
402 blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
403 blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
404 blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
405 blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
406 blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
407 hr = ID3D11Device_CreateBlendState(dev,
434 DXGI_OUTDUPL_POINTER_SHAPE_INFO *shape_info,
435 ID3D11Texture2D **out_tex,
436 ID3D11ShaderResourceView **res_view)
439 D3D11_TEXTURE2D_DESC
desc = { 0 };
440 D3D11_SUBRESOURCE_DATA init_data = { 0 };
441 D3D11_SHADER_RESOURCE_VIEW_DESC resource_desc = { 0 };
447 desc.SampleDesc.Count = 1;
448 desc.SampleDesc.Quality = 0;
449 desc.Usage = D3D11_USAGE_IMMUTABLE;
450 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
452 desc.Width = shape_info->Width;
453 desc.Height = shape_info->Height;
455 init_data.pSysMem = buf;
456 init_data.SysMemPitch = shape_info->Pitch;
458 resource_desc.Format =
desc.Format;
459 resource_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
460 resource_desc.Texture2D.MostDetailedMip = 0;
461 resource_desc.Texture2D.MipLevels = 1;
487 int width = *_width,
height = *_height, pitch = *_pitch;
488 int real_height =
height / 2;
497 for (y = 0; y < real_height; y++) {
498 for (x = 0; x <
width; x++) {
499 int v =
input[(real_height + y) * pitch + (x / 8)];
500 v = (v >> (7 - (x % 8))) & 1;
501 memset(&
output[4 * ((y*
width) + x)], v ? 0xFF : 0, 4);
506 *_height = real_height;
516 for (y = 0; y <
height; y++) {
517 for (x = 0; x <
width; x++) {
518 int pos = (y*pitch) + (4*x) + 3;
519 buf[
pos] = buf[
pos] ? 0 : 0xFF;
530 if (frame_info->LastMouseUpdateTime.QuadPart == 0)
533 if (frame_info->PointerPosition.Visible) {
535 case DXGI_MODE_ROTATION_ROTATE90:
536 dda->
mouse_x = frame_info->PointerPosition.Position.y;
537 dda->
mouse_y = dda->
output_desc.DesktopCoordinates.right - dda->
output_desc.DesktopCoordinates.left - frame_info->PointerPosition.Position.x - 1;
539 case DXGI_MODE_ROTATION_ROTATE180:
540 dda->
mouse_x = dda->
output_desc.DesktopCoordinates.right - dda->
output_desc.DesktopCoordinates.left - frame_info->PointerPosition.Position.x - 1;
541 dda->
mouse_y = dda->
output_desc.DesktopCoordinates.bottom - dda->
output_desc.DesktopCoordinates.top - frame_info->PointerPosition.Position.y - 1;
543 case DXGI_MODE_ROTATION_ROTATE270:
544 dda->
mouse_x = dda->
output_desc.DesktopCoordinates.bottom - dda->
output_desc.DesktopCoordinates.top - frame_info->PointerPosition.Position.y - 1;
545 dda->
mouse_y = frame_info->PointerPosition.Position.x;
548 dda->
mouse_x = frame_info->PointerPosition.Position.x;
549 dda->
mouse_y = frame_info->PointerPosition.Position.y;
555 if (frame_info->PointerShapeBufferSize) {
556 UINT
size = frame_info->PointerShapeBufferSize;
557 DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info;
562 hr = IDXGIOutputDuplication_GetFramePointerShape(dda->
dxgi_outdupl,
573 if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME) {
574 uint8_t *new_buf =
convert_mono_buffer(buf, &shape_info.Width, &shape_info.Height, &shape_info.Pitch);
579 }
else if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR) {
580 fixup_color_mask(buf, shape_info.Width, shape_info.Height, shape_info.Pitch);
581 }
else if (shape_info.Type != DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR) {
603 DXGI_OUTDUPL_FRAME_INFO frame_info;
605 IDXGIResource *desktop_resource =
NULL;
609 hr = IDXGIOutputDuplication_AcquireNextFrame(
614 if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
616 }
else if (FAILED(hr)) {
627 if (need_frame && (!frame_info.LastPresentTime.QuadPart || !frame_info.AccumulatedFrames)) {
632 hr = IDXGIResource_QueryInterface(desktop_resource, &IID_ID3D11Texture2D, (
void**)desktop_texture);
645 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
655 D3D11_TEXTURE2D_DESC
desc;
700 case DXGI_FORMAT_R10G10B10A2_UNORM:
807 ID3D11Texture2D *frame_tex = (ID3D11Texture2D*)
frame->data[0];
808 D3D11_RENDER_TARGET_VIEW_DESC target_desc = { 0 };
809 ID3D11RenderTargetView* target_view =
NULL;
810 ID3D11Buffer *mouse_vertex_buffer =
NULL;
811 D3D11_TEXTURE2D_DESC tex_desc;
812 int num_vertices = 0;
826 -x >= (
int)tex_desc.Width || -y >= (
int)tex_desc.Height)
830 target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
831 target_desc.Texture2D.MipSlice = 0;
834 (ID3D11Resource*)frame_tex,
843 ID3D11DeviceContext_ClearState(devctx);
846 D3D11_VIEWPORT viewport = { 0 };
847 viewport.Width = dda->
width;
848 viewport.Height = dda->
height;
849 viewport.MinDepth = 0.0f;
850 viewport.MaxDepth = 1.0f;
852 ID3D11DeviceContext_RSSetViewports(devctx, 1, &viewport);
858 x , y + tex_desc.Height, 0.0f, 0.0f, 1.0f,
859 x , y , 0.0f, 0.0f, 0.0f,
860 x + tex_desc.Width, y + tex_desc.Height, 0.0f, 1.0f, 1.0f,
861 x + tex_desc.Width, y , 0.0f, 1.0f, 0.0f,
866 D3D11_SUBRESOURCE_DATA init_data = { 0 };
867 D3D11_BUFFER_DESC buf_desc = { 0 };
870 case DXGI_MODE_ROTATION_ROTATE90:
871 vertices[ 0] = x; vertices[ 1] = y;
872 vertices[ 5] = x; vertices[ 6] = y - tex_desc.Width;
873 vertices[10] = x + tex_desc.Height; vertices[11] = y;
874 vertices[15] = x + tex_desc.Height; vertices[16] = y - tex_desc.Width;
875 vertices[ 3] = 0.0f; vertices[ 4] = 0.0f;
876 vertices[ 8] = 1.0f; vertices[ 9] = 0.0f;
877 vertices[13] = 0.0f; vertices[14] = 1.0f;
878 vertices[18] = 1.0f; vertices[19] = 1.0f;
880 case DXGI_MODE_ROTATION_ROTATE180:
881 vertices[ 0] = x - tex_desc.Width; vertices[ 1] = y;
882 vertices[ 5] = x - tex_desc.Width; vertices[ 6] = y - tex_desc.Height;
883 vertices[10] = x; vertices[11] = y;
884 vertices[15] = x; vertices[16] = y - tex_desc.Height;
885 vertices[ 3] = 1.0f; vertices[ 4] = 0.0f;
886 vertices[ 8] = 1.0f; vertices[ 9] = 1.0f;
887 vertices[13] = 0.0f; vertices[14] = 0.0f;
888 vertices[18] = 0.0f; vertices[19] = 1.0f;
890 case DXGI_MODE_ROTATION_ROTATE270:
891 vertices[ 0] = x - tex_desc.Height; vertices[ 1] = y + tex_desc.Width;
892 vertices[ 5] = x - tex_desc.Height; vertices[ 6] = y;
893 vertices[10] = x; vertices[11] = y + tex_desc.Width;
894 vertices[15] = x; vertices[16] = y;
895 vertices[ 3] = 1.0f; vertices[ 4] = 1.0f;
896 vertices[ 8] = 0.0f; vertices[ 9] = 1.0f;
897 vertices[13] = 1.0f; vertices[14] = 0.0f;
898 vertices[18] = 0.0f; vertices[19] = 0.0f;
904 num_vertices =
sizeof(vertices) / (
sizeof(
FLOAT) * 5);
906 buf_desc.Usage = D3D11_USAGE_DEFAULT;
907 buf_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
908 buf_desc.ByteWidth =
sizeof(vertices);
909 init_data.pSysMem = vertices;
914 &mouse_vertex_buffer);
921 ID3D11DeviceContext_IASetVertexBuffers(devctx, 0, 1, &mouse_vertex_buffer, &
stride, &
offset);
922 ID3D11DeviceContext_IASetInputLayout(devctx, dda->
input_layout);
923 ID3D11DeviceContext_IASetPrimitiveTopology(devctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
927 ID3D11DeviceContext_VSSetConstantBuffers(devctx, 0, 1, &dda->
const_buffer);
928 ID3D11DeviceContext_PSSetSamplers(devctx, 0, 1, &dda->
sampler_state);
932 ID3D11DeviceContext_OMSetBlendState(devctx, dda->
blend_state,
NULL, 0xFFFFFFFF);
933 ID3D11DeviceContext_OMSetRenderTargets(devctx, 1, &target_view,
NULL);
935 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
949 ID3D11Texture2D *cur_texture =
NULL;
950 D3D11_TEXTURE2D_DESC
desc = { 0 };
951 D3D11_BOX box = { 0 };
1007 }
else if (
ret < 0) {
1015 ID3D11Texture2D_GetDesc(cur_texture, &
desc);
1032 box.right = box.left + dda->
width;
1033 box.bottom = box.top + dda->
height;
1037 ID3D11DeviceContext_CopySubresourceRegion(
1039 (ID3D11Resource*)
frame->data[0], (UINT)(intptr_t)
frame->data[1],
1041 (ID3D11Resource*)cur_texture, 0,
1046 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1062 desc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) {
1094 IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1111 .description =
NULL_IF_CONFIG_SMALL(
"Grab Windows Desktop images using Desktop Duplication API"),
1113 .priv_class = &ddagrab_class,