1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "config.h"
20
21 #if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0A00
22 #undef _WIN32_WINNT
23 #define _WIN32_WINNT 0x0A00
24 #endif
25
26 #include <windows.h>
27
29
30 #include <initguid.h>
31 #include <d3d11.h>
32 #include <dxgi1_2.h>
33 #if HAVE_IDXGIOUTPUT5
34 #include <dxgi1_5.h>
35 #endif
36
47
49
50 // avutil/time.h takes and returns time in microseconds
51 #define TIMER_RES 1000000
52 #define TIMER_RES64 INT64_C(1000000)
53
56
60
64
68
74
79
83
86
94
107
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",
132 };
133
135
137 {
138 IUnknown **resp = (IUnknown**)resource;
139 if (*resp) {
140 IUnknown_Release(*resp);
142 }
143 }
144
146 {
148
156
159
165
169 }
170
172 {
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;
180
181 typedef DPI_AWARENESS_CONTEXT (*set_thread_dpi_t)(DPI_AWARENESS_CONTEXT);
182 set_thread_dpi_t set_thread_dpi;
183 HMODULE user32_module;
184 #endif
186 HRESULT hr;
187
188 hr = ID3D11Device_QueryInterface(dda->
device_hwctx->
device, &IID_IDXGIDevice, (
void**)&dxgi_device);
189 if (FAILED(hr)) {
192 }
193
194 hr = IDXGIDevice_GetParent(dxgi_device, &IID_IDXGIAdapter, (void**)&dxgi_adapter);
195 IDXGIDevice_Release(dxgi_device);
197 if (FAILED(hr)) {
200 }
201
202 hr = IDXGIAdapter_EnumOutputs(dxgi_adapter, dda->
output_idx, &dxgi_output);
203 IDXGIAdapter_Release(dxgi_adapter);
205 if (FAILED(hr)) {
208 }
209
210 hr = IDXGIOutput_GetDesc(dxgi_output, &dda->
output_desc);
211 if (FAILED(hr)) {
212 IDXGIOutput_Release(dxgi_output);
215 }
216
217 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
218 user32_module = dlopen("user32.dll", 0);
219 if (!user32_module) {
222 }
223
224 set_thread_dpi = (set_thread_dpi_t)dlsym(user32_module, "SetThreadDpiAwarenessContext");
225
226 if (set_thread_dpi)
227 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput5, (void**)&dxgi_output5);
228
229 if (set_thread_dpi && SUCCEEDED(hr)) {
230 DPI_AWARENESS_CONTEXT prev_dpi_ctx;
233 DXGI_FORMAT_R10G10B10A2_UNORM,
235 };
237
240 nb_formats = 1;
245 }
246
247 IDXGIOutput_Release(dxgi_output);
249
250 prev_dpi_ctx = set_thread_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
251 if (!prev_dpi_ctx)
253
254 hr = IDXGIOutput5_DuplicateOutput1(dxgi_output5,
256 0,
257 nb_formats,
260 IDXGIOutput5_Release(dxgi_output5);
262
263 if (prev_dpi_ctx)
264 set_thread_dpi(prev_dpi_ctx);
265
266 dlclose(user32_module);
267 user32_module =
NULL;
268 set_thread_dpi =
NULL;
269
271 } else {
272 dlclose(user32_module);
273 user32_module =
NULL;
274 set_thread_dpi =
NULL;
275
277 #else
278 {
279 #endif
283 }
284
285 hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput1, (void**)&dxgi_output1);
286 IDXGIOutput_Release(dxgi_output);
288 if (FAILED(hr)) {
291 }
292
293 hr = IDXGIOutput1_DuplicateOutput(dxgi_output1,
296 IDXGIOutput1_Release(dxgi_output1);
298 }
299
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)) {
315 }
316
320
321 return 0;
322 }
323
325 {
328
331
333 {
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 }
336 };
337
339 {
342 D3D11_SAMPLER_DESC sampler_desc = { 0 };
343 D3D11_BLEND_DESC blend_desc = { 0 };
344 D3D11_BUFFER_DESC buffer_desc = { 0 };
347 HRESULT hr;
348
349 hr = ID3D11Device_CreateVertexShader(dev,
354 if (FAILED(hr)) {
357 }
358
359 hr = ID3D11Device_CreateInputLayout(dev,
365 if (FAILED(hr)) {
368 }
369
370 hr = ID3D11Device_CreatePixelShader(dev,
375 if (FAILED(hr)) {
378 }
379
381
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,
387 &buffer_desc,
390 if (FAILED(hr)) {
393 }
394
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,
401 &sampler_desc,
403 if (FAILED(hr)) {
406 }
407
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,
419 &blend_desc,
421 if (FAILED(hr)) {
424 }
425
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,
429 &blend_desc,
431 if (FAILED(hr)) {
434 }
435
436 return 0;
437 }
438
440 {
442
446
449
450 return 0;
451 }
452
454 uint8_t *buf,
455 DXGI_OUTDUPL_POINTER_SHAPE_INFO *shape_info,
456 ID3D11Texture2D **out_tex,
457 ID3D11ShaderResourceView **res_view)
458 {
460 D3D11_TEXTURE2D_DESC
desc = { 0 };
461 D3D11_SUBRESOURCE_DATA init_data = { 0 };
462 D3D11_SHADER_RESOURCE_VIEW_DESC resource_desc = { 0 };
463 HRESULT hr;
464
468 desc.SampleDesc.Count = 1;
469 desc.SampleDesc.Quality = 0;
470 desc.Usage = D3D11_USAGE_IMMUTABLE;
471 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
472
473 desc.Width = shape_info->Width;
474 desc.Height = shape_info->Height;
475
476 init_data.pSysMem = buf;
477 init_data.SysMemPitch = shape_info->Pitch;
478
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;
483
486 &init_data,
487 out_tex);
488 if (FAILED(hr)) {
491 }
492
494 (ID3D11Resource*)*out_tex,
495 &resource_desc,
496 res_view);
497 if (FAILED(hr)) {
501 }
502
503 return 0;
504 }
505
507 {
508 int width = *_width,
height = *_height, pitch = *_pitch;
509 int real_height =
height / 2;
510 int size = real_height * pitch;
511
514
515 int y, x;
516
517 if (!
output || !output_xor) {
521 }
522
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;
529
530 if (!and_val && !xor_val) {
531 // solid black
532 memset(&
output[out_pos], 0, 4);
533 output[out_pos + 3] = 0xFF;
534
535 // transparent
536 memset(&output_xor[out_pos], 0, 4);
537 } else if (and_val && !xor_val) {
538 // transparent
539 memset(&
output[out_pos], 0, 4);
540
541 // transparent
542 memset(&output_xor[out_pos], 0, 4);
543 } else if (!and_val && xor_val) {
544 // solid white
545 memset(&
output[out_pos], 0xFF, 4);
546
547 // transparent
548 memset(&output_xor[out_pos], 0, 4);
549 } else if (and_val && xor_val) {
550 // transparent
551 memset(&
output[out_pos], 0, 4);
552
553 // solid white -> invert color
554 memset(&output_xor[out_pos], 0xFF, 4);
555 }
556 }
557 }
558
560 *_height = real_height;
562 *xor_out = output_xor;
563
564 return 0;
565 }
566
568 {
572 int x, y;
573
574 if (!
output || !output_xor) {
578 }
579
582
583 for (y = 0; y <
height; y++) {
584 for (x = 0; x <
width; x++) {
585 int pos = (y*pitch) + (4*x) + 3;
588 }
589 }
590
592 *xor_out = output_xor;
593
594 return 0;
595 }
596
598 {
600 HRESULT hr;
602
603 if (frame_info->LastMouseUpdateTime.QuadPart == 0)
604 return 0;
605
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;
611 break;
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;
615 break;
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;
619 break;
620 default:
621 dda->
mouse_x = frame_info->PointerPosition.Position.x;
622 dda->
mouse_y = frame_info->PointerPosition.Position.y;
623 }
624 } else {
626 }
627
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;
633 if (!buf)
635
636 hr = IDXGIOutputDuplication_GetFramePointerShape(dda->
dxgi_outdupl,
638 buf,
640 &shape_info);
641 if (FAILED(hr)) {
645 }
646
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) {
658 rgba_buf = buf;
660 } else {
663 return 0;
664 }
665
670
677 if (ret2 < 0)
678 return ret2;
679
681 }
682
683 return 0;
684 }
685
687 {
688 DXGI_OUTDUPL_FRAME_INFO frame_info;
690 IDXGIResource *desktop_resource =
NULL;
691 HRESULT hr;
693
694 hr = IDXGIOutputDuplication_AcquireNextFrame(
697 &frame_info,
698 &desktop_resource);
699 if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
701 } else if (FAILED(hr)) {
704 }
705
710 }
711
712 if (!frame_info.LastPresentTime.QuadPart || !frame_info.AccumulatedFrames) {
713 if (need_frame) {
716 }
717
718 // Unforunately, we can't rely on the desktop_resource's format in this case.
719 // The API might even return it in with a format that was not in the initial
720 // list of supported formats, and it can change/flicker randomly.
721 // To work around this, return an internal copy of the last valid texture we got.
723
724 // The initial probing should make this impossible.
729 }
730
734 return 0;
735 }
736
737 hr = IDXGIResource_QueryInterface(desktop_resource, &IID_ID3D11Texture2D, (void**)desktop_texture);
739 if (FAILED(hr)) {
743 }
744
746 D3D11_TEXTURE2D_DESC
desc;
747 ID3D11Texture2D_GetDesc(*desktop_texture, &
desc);
748 desc.Usage = D3D11_USAGE_DEFAULT;
750 desc.CPUAccessFlags = 0;
752
754 if (FAILED(hr)) {
759 }
760 }
761
764 (ID3D11Resource*)*desktop_texture);
765
766 return 0;
767
770
771 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
772 if (FAILED(hr))
774
776 }
777
779 {
781 D3D11_TEXTURE2D_DESC
desc;
783
785
786 do {
791
793
797
802
803 return 0;
804 }
805
807 {
810
816
820
825 break;
826 case DXGI_FORMAT_R10G10B10A2_UNORM:
829 break;
833 break;
834 default:
837 }
838
841
846 }
847
848 return 0;
852 }
853
855 {
859
862
866 }
867
871
873 } else {
878 }
879
881
883 }
884
886
890
894
898 }
899
902
906
911 }
912
916
920
925
926 return 0;
927 }
928
930 {
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;
939 int x, y;
940 HRESULT hr;
942
944 return 0;
945
947
950
952 -x >= (int)tex_desc.Width || -y >= (int)tex_desc.Height)
953 return 0;
954
956 target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
957 target_desc.Texture2D.MipSlice = 0;
958
960 (ID3D11Resource*)frame_tex,
961 &target_desc,
962 &target_view);
963 if (FAILED(hr)) {
966 goto end;
967 }
968
969 ID3D11DeviceContext_ClearState(devctx);
970
971 {
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;
977
978 ID3D11DeviceContext_RSSetViewports(devctx, 1, &viewport);
979 }
980
981 {
983 // x, y, z, u, v
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,
988 };
991
992 D3D11_SUBRESOURCE_DATA init_data = { 0 };
993 D3D11_BUFFER_DESC buf_desc = { 0 };
994
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;
1005 break;
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;
1015 break;
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;
1025 break;
1026 default:
1027 break;
1028 }
1029
1030 num_vertices =
sizeof(vertices) / (
sizeof(
FLOAT) * 5);
1031
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;
1036
1038 &buf_desc,
1039 &init_data,
1040 &mouse_vertex_buffer);
1041 if (FAILED(hr)) {
1044 goto end;
1045 }
1046
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);
1050 }
1051
1053 ID3D11DeviceContext_VSSetConstantBuffers(devctx, 0, 1, &dda->
const_buffer);
1054 ID3D11DeviceContext_PSSetSamplers(devctx, 0, 1, &dda->
sampler_state);
1057
1058 ID3D11DeviceContext_OMSetBlendState(devctx, dda->
blend_state,
NULL, 0xFFFFFFFF);
1059 ID3D11DeviceContext_OMSetRenderTargets(devctx, 1, &target_view,
NULL);
1060
1061 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1062
1066
1067 ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1068 }
1069
1070 end:
1073
1075 }
1076
1078 {
1081
1082 ID3D11Texture2D *cur_texture =
NULL;
1083 D3D11_TEXTURE2D_DESC
desc = { 0 };
1084 D3D11_BOX box = { 0 };
1085
1089 HRESULT hr;
1091
1092 /* time_frame is in units of microseconds divided by the time_base.
1093 * This means that adding a clean 1M to it is the equivalent of adding
1094 * 1M*time_base microseconds to it, except it avoids all rounding error.
1095 * The only time rounding error occurs is when multiplying to calculate
1096 * the delay. So any rounding error there corrects itself over time.
1097 */
1099 for (;;) {
1102 if (delay <= 0) {
1105 }
1106 break;
1107 }
1109 }
1110
1114
1116 do {
1119 } else {
1123 }
1124
1129
1134 }
1135
1137
1138 goto frame_done;
1142 }
else if (
ret < 0) {
1144 }
1145
1146 // AcquireNextFrame sometimes has bursts of delay.
1147 // This increases accuracy of the timestamp, but might upset consumers due to more jittery framerate?
1149
1150 ID3D11Texture2D_GetDesc(cur_texture, &
desc);
1157 }
1158
1163 }
1164
1167 box.right = box.left + dda->
width;
1168 box.bottom = box.top + dda->
height;
1169 box.front = 0;
1170 box.back = 1;
1171
1172 ID3D11DeviceContext_CopySubresourceRegion(
1175 0, 0, 0,
1176 (ID3D11Resource*)cur_texture, 0,
1177 &box);
1178
1180
1181 hr = IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1182 if (FAILED(hr)) {
1186 }
1187
1192 }
1193
1195
1197 desc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) {
1198 // According to MSDN, all integer formats contain sRGB image data
1204 // According to MSDN, all floating point formats contain sRGB image data with linear 1.0 gamma.
1209 } else {
1212 }
1213
1217
1218 frame_done:
1221
1223
1227
1228 if (cur_texture)
1229 IDXGIOutputDuplication_ReleaseFrame(dda->
dxgi_outdupl);
1230
1233 }
1234
1236 {
1241 },
1242 };
1243
1246 .description =
NULL_IF_CONFIG_SMALL(
"Grab Windows Desktop images using Desktop Duplication API"),
1248 .priv_class = &ddagrab_class,
1256 };