FFmpeg
vsrc_ddagrab.c
Go to the documentation of this file.
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 
28 #define COBJMACROS
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 
37 #include "libavutil/opt.h"
38 #include "libavutil/time.h"
39 #include "libavutil/avstring.h"
40 #include "libavutil/avassert.h"
41 #include "libavutil/hwcontext.h"
43 #include "compat/w32dlfcn.h"
44 #include "avfilter.h"
45 #include "internal.h"
46 #include "video.h"
47 
48 #include "vsrc_ddagrab_shaders.h"
49 
50 // avutil/time.h takes and returns time in microseconds
51 #define TIMER_RES 1000000
52 #define TIMER_RES64 INT64_C(1000000)
53 
54 typedef struct DdagrabContext {
55  const AVClass *class;
56 
60 
64 
65  DXGI_OUTPUT_DESC output_desc;
66  IDXGIOutputDuplication *dxgi_outdupl;
68 
70  ID3D11Texture2D *mouse_texture;
71  ID3D11ShaderResourceView* mouse_resource_view;
72  ID3D11Texture2D *mouse_xor_texture;
73  ID3D11ShaderResourceView* mouse_xor_resource_view;
74 
76  int64_t time_frame;
77  int64_t time_timeout;
78  int64_t first_pts;
79 
80  DXGI_FORMAT raw_format;
81  int raw_width;
83 
84  ID3D11Texture2D *probed_texture;
85 
86  ID3D11VertexShader *vertex_shader;
87  ID3D11InputLayout *input_layout;
88  ID3D11PixelShader *pixel_shader;
89  ID3D11Buffer *const_buffer;
90  ID3D11SamplerState *sampler_state;
91  ID3D11BlendState *blend_state;
92  ID3D11BlendState *blend_state_xor;
93 
97  int width;
98  int height;
99  int offset_x;
100  int offset_y;
101  int out_fmt;
105 
106 #define OFFSET(x) offsetof(DdagrabContext, x)
107 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
108 static const AVOption ddagrab_options[] = {
109  { "output_idx", "dda output index to capture", OFFSET(output_idx), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
110  { "draw_mouse", "draw the mouse pointer", OFFSET(draw_mouse), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
111  { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, { .str = "30" }, 0, INT_MAX, FLAGS },
112  { "video_size", "set video frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS },
113  { "offset_x", "capture area x offset", OFFSET(offset_x), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
114  { "offset_y", "capture area y offset", OFFSET(offset_y), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
115  { "output_fmt", "desired output format", OFFSET(out_fmt), AV_OPT_TYPE_INT, { .i64 = DXGI_FORMAT_B8G8R8A8_UNORM }, 0, INT_MAX, FLAGS, "output_fmt" },
116  { "auto", "let dda pick its preferred format", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, INT_MAX, FLAGS, "output_fmt" },
117  { "8bit", "only output default 8 Bit format", 0, AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_B8G8R8A8_UNORM }, 0, INT_MAX, FLAGS, "output_fmt" },
118  { "bgra", "only output 8 Bit BGRA", 0, AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_B8G8R8A8_UNORM }, 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" },
121  { "16bit", "only output default 16 Bit format", 0, AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R16G16B16A16_FLOAT },0, INT_MAX, FLAGS, "output_fmt" },
122  { "rgbaf16", "only output 16 Bit RGBAF16", 0, AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R16G16B16A16_FLOAT },0, INT_MAX, FLAGS, "output_fmt" },
123  { "allow_fallback", "don't error on fallback to default 8 Bit format",
124  OFFSET(allow_fallback), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
125  { "force_fmt", "exclude BGRA from format list (experimental, discouraged by Microsoft)",
126  OFFSET(force_fmt), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
127  { NULL }
128 };
129 
130 AVFILTER_DEFINE_CLASS(ddagrab);
131 
132 static inline void release_resource(void *resource)
133 {
134  IUnknown **resp = (IUnknown**)resource;
135  if (*resp) {
136  IUnknown_Release(*resp);
137  *resp = NULL;
138  }
139 }
140 
142 {
143  DdagrabContext *dda = avctx->priv;
144 
152 
154 
160 
161  av_frame_free(&dda->last_frame);
164 }
165 
167 {
168  DdagrabContext *dda = avctx->priv;
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;
175 
176  typedef DPI_AWARENESS_CONTEXT (*set_thread_dpi_t)(DPI_AWARENESS_CONTEXT);
177  set_thread_dpi_t set_thread_dpi;
178  HMODULE user32_module;
179 #endif
180  int w, h;
181  HRESULT hr;
182 
183  hr = ID3D11Device_QueryInterface(dda->device_hwctx->device, &IID_IDXGIDevice, (void**)&dxgi_device);
184  if (FAILED(hr)) {
185  av_log(avctx, AV_LOG_ERROR, "Failed querying IDXGIDevice\n");
186  return AVERROR_EXTERNAL;
187  }
188 
189  hr = IDXGIDevice_GetParent(dxgi_device, &IID_IDXGIAdapter, (void**)&dxgi_adapter);
190  IDXGIDevice_Release(dxgi_device);
191  dxgi_device = NULL;
192  if (FAILED(hr)) {
193  av_log(avctx, AV_LOG_ERROR, "Failed getting parent IDXGIAdapter\n");
194  return AVERROR_EXTERNAL;
195  }
196 
197  hr = IDXGIAdapter_EnumOutputs(dxgi_adapter, dda->output_idx, &dxgi_output);
198  IDXGIAdapter_Release(dxgi_adapter);
199  dxgi_adapter = NULL;
200  if (FAILED(hr)) {
201  av_log(avctx, AV_LOG_ERROR, "Failed to enumerate DXGI output %d\n", dda->output_idx);
202  return AVERROR_EXTERNAL;
203  }
204 
205  hr = IDXGIOutput_GetDesc(dxgi_output, &dda->output_desc);
206  if (FAILED(hr)) {
207  IDXGIOutput_Release(dxgi_output);
208  av_log(avctx, AV_LOG_ERROR, "Failed getting output description\n");
209  return AVERROR_EXTERNAL;
210  }
211 
212 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
213  user32_module = dlopen("user32.dll", 0);
214  if (!user32_module) {
215  av_log(avctx, AV_LOG_ERROR, "Failed loading user32.dll\n");
216  return AVERROR_EXTERNAL;
217  }
218 
219  set_thread_dpi = (set_thread_dpi_t)dlsym(user32_module, "SetThreadDpiAwarenessContext");
220 
221  if (set_thread_dpi)
222  hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput5, (void**)&dxgi_output5);
223 
224  if (set_thread_dpi && SUCCEEDED(hr)) {
225  DPI_AWARENESS_CONTEXT prev_dpi_ctx;
226  DXGI_FORMAT formats[] = {
228  DXGI_FORMAT_R10G10B10A2_UNORM,
230  };
231  int nb_formats = FF_ARRAY_ELEMS(formats);
232 
233  if(dda->out_fmt == DXGI_FORMAT_B8G8R8A8_UNORM) {
235  nb_formats = 1;
236  } else if (dda->out_fmt) {
237  formats[0] = dda->out_fmt;
239  nb_formats = dda->force_fmt ? 1 : 2;
240  }
241 
242  IDXGIOutput_Release(dxgi_output);
243  dxgi_output = NULL;
244 
245  prev_dpi_ctx = set_thread_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
246  if (!prev_dpi_ctx)
247  av_log(avctx, AV_LOG_WARNING, "Failed enabling DPI awareness for DDA\n");
248 
249  hr = IDXGIOutput5_DuplicateOutput1(dxgi_output5,
250  (IUnknown*)dda->device_hwctx->device,
251  0,
252  nb_formats,
253  formats,
254  &dda->dxgi_outdupl);
255  IDXGIOutput5_Release(dxgi_output5);
256  dxgi_output5 = NULL;
257 
258  if (prev_dpi_ctx)
259  set_thread_dpi(prev_dpi_ctx);
260 
261  dlclose(user32_module);
262  user32_module = NULL;
263  set_thread_dpi = NULL;
264 
265  av_log(avctx, AV_LOG_DEBUG, "Using IDXGIOutput5 interface\n");
266  } else {
267  dlclose(user32_module);
268  user32_module = NULL;
269  set_thread_dpi = NULL;
270 
271  av_log(avctx, AV_LOG_DEBUG, "Falling back to IDXGIOutput1\n");
272 #else
273  {
274 #endif
275  if (dda->out_fmt && dda->out_fmt != DXGI_FORMAT_B8G8R8A8_UNORM && (!dda->allow_fallback || dda->force_fmt)) {
276  av_log(avctx, AV_LOG_ERROR, "Only 8 bit output supported with legacy API\n");
277  return AVERROR(ENOTSUP);
278  }
279 
280  hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput1, (void**)&dxgi_output1);
281  IDXGIOutput_Release(dxgi_output);
282  dxgi_output = NULL;
283  if (FAILED(hr)) {
284  av_log(avctx, AV_LOG_ERROR, "Failed querying IDXGIOutput1\n");
285  return AVERROR_EXTERNAL;
286  }
287 
288  hr = IDXGIOutput1_DuplicateOutput(dxgi_output1,
289  (IUnknown*)dda->device_hwctx->device,
290  &dda->dxgi_outdupl);
291  IDXGIOutput1_Release(dxgi_output1);
292  dxgi_output1 = NULL;
293  }
294 
295  if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
296  av_log(avctx, AV_LOG_ERROR, "Too many open duplication sessions\n");
297  return AVERROR(EBUSY);
298  } else if (hr == DXGI_ERROR_UNSUPPORTED) {
299  av_log(avctx, AV_LOG_ERROR, "Selected output not supported\n");
300  return AVERROR_EXTERNAL;
301  } else if (hr == E_INVALIDARG) {
302  av_log(avctx, AV_LOG_ERROR, "Invalid output duplication argument\n");
303  return AVERROR(EINVAL);
304  } else if (hr == E_ACCESSDENIED) {
305  av_log(avctx, AV_LOG_ERROR, "Desktop duplication access denied\n");
306  return AVERROR(EPERM);
307  } else if (FAILED(hr)) {
308  av_log(avctx, AV_LOG_ERROR, "Failed duplicating output\n");
309  return AVERROR_EXTERNAL;
310  }
311 
312  w = dda->output_desc.DesktopCoordinates.right - dda->output_desc.DesktopCoordinates.left;
313  h = dda->output_desc.DesktopCoordinates.bottom - dda->output_desc.DesktopCoordinates.top;
314  av_log(avctx, AV_LOG_VERBOSE, "Opened dxgi output %d with dimensions %dx%d\n", dda->output_idx, w, h);
315 
316  return 0;
317 }
318 
319 typedef struct ConstBufferData
320 {
321  float width;
322  float height;
323 
324  uint64_t padding;
326 
327 static const D3D11_INPUT_ELEMENT_DESC vertex_shader_input_layout[] =
328 {
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 }
331 };
332 
334 {
335  DdagrabContext *dda = avctx->priv;
336  ID3D11Device *dev = dda->device_hwctx->device;
337  D3D11_SAMPLER_DESC sampler_desc = { 0 };
338  D3D11_BLEND_DESC blend_desc = { 0 };
339  D3D11_BUFFER_DESC buffer_desc = { 0 };
340  D3D11_SUBRESOURCE_DATA buffer_data = { 0 };
341  ConstBufferData const_data = { 0 };
342  HRESULT hr;
343 
344  hr = ID3D11Device_CreateVertexShader(dev,
347  NULL,
348  &dda->vertex_shader);
349  if (FAILED(hr)) {
350  av_log(avctx, AV_LOG_ERROR, "CreateVertexShader failed: %lx\n", hr);
351  return AVERROR_EXTERNAL;
352  }
353 
354  hr = ID3D11Device_CreateInputLayout(dev,
359  &dda->input_layout);
360  if (FAILED(hr)) {
361  av_log(avctx, AV_LOG_ERROR, "CreateInputLayout failed: %lx\n", hr);
362  return AVERROR_EXTERNAL;
363  }
364 
365  hr = ID3D11Device_CreatePixelShader(dev,
368  NULL,
369  &dda->pixel_shader);
370  if (FAILED(hr)) {
371  av_log(avctx, AV_LOG_ERROR, "CreatePixelShader failed: %lx\n", hr);
372  return AVERROR_EXTERNAL;
373  }
374 
375  const_data = (ConstBufferData){ dda->width, dda->height };
376 
377  buffer_data.pSysMem = &const_data;
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,
382  &buffer_desc,
383  &buffer_data,
384  &dda->const_buffer);
385  if (FAILED(hr)) {
386  av_log(avctx, AV_LOG_ERROR, "CreateBuffer const buffer failed: %lx\n", hr);
387  return AVERROR_EXTERNAL;
388  }
389 
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,
396  &sampler_desc,
397  &dda->sampler_state);
398  if (FAILED(hr)) {
399  av_log(avctx, AV_LOG_ERROR, "CreateSamplerState failed: %lx\n", hr);
400  return AVERROR_EXTERNAL;
401  }
402 
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,
414  &blend_desc,
415  &dda->blend_state);
416  if (FAILED(hr)) {
417  av_log(avctx, AV_LOG_ERROR, "CreateBlendState failed: %lx\n", hr);
418  return AVERROR_EXTERNAL;
419  }
420 
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,
424  &blend_desc,
425  &dda->blend_state_xor);
426  if (FAILED(hr)) {
427  av_log(avctx, AV_LOG_ERROR, "CreateBlendState (xor) failed: %lx\n", hr);
428  return AVERROR_EXTERNAL;
429  }
430 
431  return 0;
432 }
433 
435 {
436  DdagrabContext *dda = avctx->priv;
437 
438  dda->last_frame = av_frame_alloc();
439  if (!dda->last_frame)
440  return AVERROR(ENOMEM);
441 
442  dda->mouse_x = -1;
443  dda->mouse_y = -1;
444 
445  return 0;
446 }
447 
449  uint8_t *buf,
450  DXGI_OUTDUPL_POINTER_SHAPE_INFO *shape_info,
451  ID3D11Texture2D **out_tex,
452  ID3D11ShaderResourceView **res_view)
453 {
454  DdagrabContext *dda = avctx->priv;
455  D3D11_TEXTURE2D_DESC desc = { 0 };
456  D3D11_SUBRESOURCE_DATA init_data = { 0 };
457  D3D11_SHADER_RESOURCE_VIEW_DESC resource_desc = { 0 };
458  HRESULT hr;
459 
460  desc.MipLevels = 1;
461  desc.ArraySize = 1;
463  desc.SampleDesc.Count = 1;
464  desc.SampleDesc.Quality = 0;
465  desc.Usage = D3D11_USAGE_IMMUTABLE;
466  desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
467 
468  desc.Width = shape_info->Width;
469  desc.Height = shape_info->Height;
470 
471  init_data.pSysMem = buf;
472  init_data.SysMemPitch = shape_info->Pitch;
473 
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;
478 
479  hr = ID3D11Device_CreateTexture2D(dda->device_hwctx->device,
480  &desc,
481  &init_data,
482  out_tex);
483  if (FAILED(hr)) {
484  av_log(avctx, AV_LOG_ERROR, "Failed creating pointer texture\n");
485  return AVERROR_EXTERNAL;
486  }
487 
488  hr = ID3D11Device_CreateShaderResourceView(dda->device_hwctx->device,
489  (ID3D11Resource*)*out_tex,
490  &resource_desc,
491  res_view);
492  if (FAILED(hr)) {
493  release_resource(out_tex);
494  av_log(avctx, AV_LOG_ERROR, "CreateShaderResourceView for mouse failed: %lx\n", hr);
495  return AVERROR_EXTERNAL;
496  }
497 
498  return 0;
499 }
500 
501 static int convert_mono_buffer(uint8_t *input, uint8_t **rgba_out, uint8_t **xor_out, int *_width, int *_height, int *_pitch)
502 {
503  int width = *_width, height = *_height, pitch = *_pitch;
504  int real_height = height / 2;
505  int size = real_height * pitch;
506 
507  uint8_t *output = av_malloc(real_height * width * 4);
508  uint8_t *output_xor = av_malloc(real_height * width * 4);
509 
510  int y, x;
511 
512  if (!output || !output_xor) {
513  av_free(output);
514  av_free(output_xor);
515  return AVERROR(ENOMEM);
516  }
517 
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;
524 
525  if (!and_val && !xor_val) {
526  // solid black
527  memset(&output[out_pos], 0, 4);
528  output[out_pos + 3] = 0xFF;
529 
530  // transparent
531  memset(&output_xor[out_pos], 0, 4);
532  } else if (and_val && !xor_val) {
533  // transparent
534  memset(&output[out_pos], 0, 4);
535 
536  // transparent
537  memset(&output_xor[out_pos], 0, 4);
538  } else if (!and_val && xor_val) {
539  // solid white
540  memset(&output[out_pos], 0xFF, 4);
541 
542  // transparent
543  memset(&output_xor[out_pos], 0, 4);
544  } else if (and_val && xor_val) {
545  // transparent
546  memset(&output[out_pos], 0, 4);
547 
548  // solid white -> invert color
549  memset(&output_xor[out_pos], 0xFF, 4);
550  }
551  }
552  }
553 
554  *_pitch = width * 4;
555  *_height = real_height;
556  *rgba_out = output;
557  *xor_out = output_xor;
558 
559  return 0;
560 }
561 
562 static int fixup_color_mask(uint8_t *input, uint8_t **rgba_out, uint8_t **xor_out, int width, int height, int pitch)
563 {
564  int size = height * pitch;
565  uint8_t *output = av_malloc(size);
566  uint8_t *output_xor = av_malloc(size);
567  int x, y;
568 
569  if (!output || !output_xor) {
570  av_free(output);
571  av_free(output_xor);
572  return AVERROR(ENOMEM);
573  }
574 
575  memcpy(output, input, size);
576  memcpy(output_xor, input, size);
577 
578  for (y = 0; y < height; y++) {
579  for (x = 0; x < width; x++) {
580  int pos = (y*pitch) + (4*x) + 3;
581  output[pos] = input[pos] ? 0 : 0xFF;
582  output_xor[pos] = input[pos] ? 0xFF : 0;
583  }
584  }
585 
586  *rgba_out = output;
587  *xor_out = output_xor;
588 
589  return 0;
590 }
591 
592 static int update_mouse_pointer(AVFilterContext *avctx, DXGI_OUTDUPL_FRAME_INFO *frame_info)
593 {
594  DdagrabContext *dda = avctx->priv;
595  HRESULT hr;
596  int ret, ret2;
597 
598  if (frame_info->LastMouseUpdateTime.QuadPart == 0)
599  return 0;
600 
601  if (frame_info->PointerPosition.Visible) {
602  switch (dda->output_desc.Rotation) {
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;
606  break;
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;
610  break;
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;
614  break;
615  default:
616  dda->mouse_x = frame_info->PointerPosition.Position.x;
617  dda->mouse_y = frame_info->PointerPosition.Position.y;
618  }
619  } else {
620  dda->mouse_x = dda->mouse_y = -1;
621  }
622 
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;
627  uint8_t *buf = av_malloc(size);
628  if (!buf)
629  return AVERROR(ENOMEM);
630 
631  hr = IDXGIOutputDuplication_GetFramePointerShape(dda->dxgi_outdupl,
632  size,
633  buf,
634  &size,
635  &shape_info);
636  if (FAILED(hr)) {
637  av_free(buf);
638  av_log(avctx, AV_LOG_ERROR, "Failed getting pointer shape: %lx\n", hr);
639  return AVERROR_EXTERNAL;
640  }
641 
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);
644  av_freep(&buf);
645  if (ret < 0)
646  return ret;
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);
649  av_freep(&buf);
650  if (ret < 0)
651  return ret;
652  } else if (shape_info.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR) {
653  rgba_buf = buf;
654  buf = NULL;
655  } else {
656  av_log(avctx, AV_LOG_WARNING, "Unsupported pointer shape type: %d\n", (int)shape_info.Type);
657  av_freep(&buf);
658  return 0;
659  }
660 
665 
666  ret = create_d3d11_pointer_tex(avctx, rgba_buf, &shape_info, &dda->mouse_texture, &dda->mouse_resource_view);
667  ret2 = rgb_xor_buf ? create_d3d11_pointer_tex(avctx, rgb_xor_buf, &shape_info, &dda->mouse_xor_texture, &dda->mouse_xor_resource_view) : 0;
668  av_freep(&rgba_buf);
669  av_freep(&rgb_xor_buf);
670  if (ret < 0)
671  return ret;
672  if (ret2 < 0)
673  return ret2;
674 
675  av_log(avctx, AV_LOG_VERBOSE, "Updated pointer shape texture\n");
676  }
677 
678  return 0;
679 }
680 
681 static int next_frame_internal(AVFilterContext *avctx, ID3D11Texture2D **desktop_texture, int need_frame)
682 {
683  DXGI_OUTDUPL_FRAME_INFO frame_info;
684  DdagrabContext *dda = avctx->priv;
685  IDXGIResource *desktop_resource = NULL;
686  HRESULT hr;
687  int ret;
688 
689  hr = IDXGIOutputDuplication_AcquireNextFrame(
690  dda->dxgi_outdupl,
691  dda->time_timeout,
692  &frame_info,
693  &desktop_resource);
694  if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
695  return AVERROR(EAGAIN);
696  } else if (FAILED(hr)) {
697  av_log(avctx, AV_LOG_ERROR, "AcquireNextFrame failed: %lx\n", hr);
698  return AVERROR_EXTERNAL;
699  }
700 
701  if (dda->draw_mouse) {
702  ret = update_mouse_pointer(avctx, &frame_info);
703  if (ret < 0)
704  goto error;
705  }
706 
707  if (need_frame && (!frame_info.LastPresentTime.QuadPart || !frame_info.AccumulatedFrames)) {
708  ret = AVERROR(EAGAIN);
709  goto error;
710  }
711 
712  hr = IDXGIResource_QueryInterface(desktop_resource, &IID_ID3D11Texture2D, (void**)desktop_texture);
713  release_resource(&desktop_resource);
714  if (FAILED(hr)) {
715  av_log(avctx, AV_LOG_ERROR, "DXGIResource QueryInterface failed\n");
717  goto error;
718  }
719 
720  return 0;
721 
722 error:
723  release_resource(&desktop_resource);
724 
725  hr = IDXGIOutputDuplication_ReleaseFrame(dda->dxgi_outdupl);
726  if (FAILED(hr))
727  av_log(avctx, AV_LOG_ERROR, "DDA error ReleaseFrame failed!\n");
728 
729  return ret;
730 }
731 
733 {
734  DdagrabContext *dda = avctx->priv;
735  D3D11_TEXTURE2D_DESC desc;
736  int ret;
737 
738  av_assert1(!dda->probed_texture);
739 
740  do {
741  ret = next_frame_internal(avctx, &dda->probed_texture, 1);
742  } while(ret == AVERROR(EAGAIN));
743  if (ret < 0)
744  return ret;
745 
746  ID3D11Texture2D_GetDesc(dda->probed_texture, &desc);
747 
748  dda->raw_format = desc.Format;
749  dda->raw_width = desc.Width;
750  dda->raw_height = desc.Height;
751 
752  if (dda->width <= 0)
753  dda->width = dda->raw_width;
754  if (dda->height <= 0)
755  dda->height = dda->raw_height;
756 
757  return 0;
758 }
759 
761 {
762  DdagrabContext *dda = avctx->priv;
763  int ret = 0;
764 
766  if (!dda->frames_ref)
767  return AVERROR(ENOMEM);
770 
772  dda->frames_ctx->width = dda->width;
773  dda->frames_ctx->height = dda->height;
774 
775  switch (dda->raw_format) {
777  av_log(avctx, AV_LOG_VERBOSE, "Probed 8 bit RGB frame format\n");
779  break;
780  case DXGI_FORMAT_R10G10B10A2_UNORM:
781  av_log(avctx, AV_LOG_VERBOSE, "Probed 10 bit RGB frame format\n");
783  break;
785  av_log(avctx, AV_LOG_VERBOSE, "Probed 16 bit float RGB frame format\n");
787  break;
788  default:
789  av_log(avctx, AV_LOG_ERROR, "Unexpected texture output format!\n");
790  return AVERROR_BUG;
791  }
792 
793  if (dda->draw_mouse)
794  dda->frames_hwctx->BindFlags |= D3D11_BIND_RENDER_TARGET;
795 
797  if (ret < 0) {
798  av_log(avctx, AV_LOG_ERROR, "Failed to initialise hardware frames context: %d.\n", ret);
799  goto fail;
800  }
801 
802  return 0;
803 fail:
805  return ret;
806 }
807 
808 static int ddagrab_config_props(AVFilterLink *outlink)
809 {
810  AVFilterContext *avctx = outlink->src;
811  DdagrabContext *dda = avctx->priv;
812  int ret;
813 
814  if (avctx->hw_device_ctx) {
816 
818  av_log(avctx, AV_LOG_ERROR, "Non-D3D11VA input hw_device_ctx\n");
819  return AVERROR(EINVAL);
820  }
821 
822  dda->device_ref = av_buffer_ref(avctx->hw_device_ctx);
823  if (!dda->device_ref)
824  return AVERROR(ENOMEM);
825 
826  av_log(avctx, AV_LOG_VERBOSE, "Using provided hw_device_ctx\n");
827  } else {
829  if (ret < 0) {
830  av_log(avctx, AV_LOG_ERROR, "Failed to create D3D11VA device.\n");
831  return ret;
832  }
833 
835 
836  av_log(avctx, AV_LOG_VERBOSE, "Created internal hw_device_ctx\n");
837  }
838 
840 
841  ret = init_dxgi_dda(avctx);
842  if (ret < 0)
843  return ret;
844 
845  ret = probe_output_format(avctx);
846  if (ret < 0)
847  return ret;
848 
849  if (dda->out_fmt && dda->raw_format != dda->out_fmt && (!dda->allow_fallback || dda->force_fmt)) {
850  av_log(avctx, AV_LOG_ERROR, "Requested output format unavailable.\n");
851  return AVERROR(ENOTSUP);
852  }
853 
854  dda->width -= FFMAX(dda->width - dda->raw_width + dda->offset_x, 0);
855  dda->height -= FFMAX(dda->height - dda->raw_height + dda->offset_y, 0);
856 
857  dda->time_base = av_inv_q(dda->framerate);
859  dda->time_timeout = av_rescale_q(1, dda->time_base, (AVRational) { 1, 1000 }) / 2;
860 
861  if (dda->draw_mouse) {
862  ret = init_render_resources(avctx);
863  if (ret < 0)
864  return ret;
865  }
866 
867  ret = init_hwframes_ctx(avctx);
868  if (ret < 0)
869  return ret;
870 
871  outlink->hw_frames_ctx = av_buffer_ref(dda->frames_ref);
872  if (!outlink->hw_frames_ctx)
873  return AVERROR(ENOMEM);
874 
875  outlink->w = dda->width;
876  outlink->h = dda->height;
877  outlink->time_base = (AVRational){1, TIMER_RES};
878  outlink->frame_rate = dda->framerate;
879 
880  return 0;
881 }
882 
884 {
885  DdagrabContext *dda = avctx->priv;
886  ID3D11DeviceContext *devctx = dda->device_hwctx->device_context;
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;
893  int x, y;
894  HRESULT hr;
895  int ret = 0;
896 
897  if (!dda->mouse_texture || dda->mouse_x < 0 || dda->mouse_y < 0)
898  return 0;
899 
900  ID3D11Texture2D_GetDesc(dda->mouse_texture, &tex_desc);
901 
902  x = dda->mouse_x - dda->offset_x;
903  y = dda->mouse_y - dda->offset_y;
904 
905  if (x >= dda->width || y >= dda->height ||
906  -x >= (int)tex_desc.Width || -y >= (int)tex_desc.Height)
907  return 0;
908 
909  target_desc.Format = dda->raw_format;
910  target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
911  target_desc.Texture2D.MipSlice = 0;
912 
913  hr = ID3D11Device_CreateRenderTargetView(dda->device_hwctx->device,
914  (ID3D11Resource*)frame_tex,
915  &target_desc,
916  &target_view);
917  if (FAILED(hr)) {
918  av_log(avctx, AV_LOG_ERROR, "CreateRenderTargetView failed: %lx\n", hr);
920  goto end;
921  }
922 
923  ID3D11DeviceContext_ClearState(devctx);
924 
925  {
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;
931 
932  ID3D11DeviceContext_RSSetViewports(devctx, 1, &viewport);
933  }
934 
935  {
936  FLOAT vertices[] = {
937  // x, y, z, u, v
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,
942  };
943  UINT stride = sizeof(FLOAT) * 5;
944  UINT offset = 0;
945 
946  D3D11_SUBRESOURCE_DATA init_data = { 0 };
947  D3D11_BUFFER_DESC buf_desc = { 0 };
948 
949  switch (dda->output_desc.Rotation) {
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;
959  break;
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;
969  break;
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;
979  break;
980  default:
981  break;
982  }
983 
984  num_vertices = sizeof(vertices) / (sizeof(FLOAT) * 5);
985 
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;
990 
991  hr = ID3D11Device_CreateBuffer(dda->device_hwctx->device,
992  &buf_desc,
993  &init_data,
994  &mouse_vertex_buffer);
995  if (FAILED(hr)) {
996  av_log(avctx, AV_LOG_ERROR, "CreateBuffer failed: %lx\n", hr);
998  goto end;
999  }
1000 
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);
1004  }
1005 
1006  ID3D11DeviceContext_VSSetShader(devctx, dda->vertex_shader, NULL, 0);
1007  ID3D11DeviceContext_VSSetConstantBuffers(devctx, 0, 1, &dda->const_buffer);
1008  ID3D11DeviceContext_PSSetSamplers(devctx, 0, 1, &dda->sampler_state);
1009  ID3D11DeviceContext_PSSetShaderResources(devctx, 0, 1, &dda->mouse_resource_view);
1010  ID3D11DeviceContext_PSSetShader(devctx, dda->pixel_shader, NULL, 0);
1011 
1012  ID3D11DeviceContext_OMSetBlendState(devctx, dda->blend_state, NULL, 0xFFFFFFFF);
1013  ID3D11DeviceContext_OMSetRenderTargets(devctx, 1, &target_view, NULL);
1014 
1015  ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1016 
1017  if (dda->mouse_xor_resource_view) {
1018  ID3D11DeviceContext_PSSetShaderResources(devctx, 0, 1, &dda->mouse_xor_resource_view);
1019  ID3D11DeviceContext_OMSetBlendState(devctx, dda->blend_state_xor, NULL, 0xFFFFFFFF);
1020 
1021  ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
1022  }
1023 
1024 end:
1025  release_resource(&mouse_vertex_buffer);
1026  release_resource(&target_view);
1027 
1028  return ret;
1029 }
1030 
1032 {
1033  AVFilterContext *avctx = outlink->src;
1034  DdagrabContext *dda = avctx->priv;
1035 
1036  ID3D11Texture2D *cur_texture = NULL;
1037  D3D11_TEXTURE2D_DESC desc = { 0 };
1038  D3D11_BOX box = { 0 };
1039 
1040  int64_t time_frame = dda->time_frame;
1041  int64_t now, delay;
1042  AVFrame *frame = NULL;
1043  HRESULT hr;
1044  int ret;
1045 
1046  /* time_frame is in units of microseconds divided by the time_base.
1047  * This means that adding a clean 1M to it is the equivalent of adding
1048  * 1M*time_base microseconds to it, except it avoids all rounding error.
1049  * The only time rounding error occurs is when multiplying to calculate
1050  * the delay. So any rounding error there corrects itself over time.
1051  */
1052  time_frame += TIMER_RES64;
1053  for (;;) {
1054  now = av_gettime_relative();
1055  delay = time_frame * av_q2d(dda->time_base) - now;
1056  if (delay <= 0) {
1057  if (delay < -TIMER_RES64 * av_q2d(dda->time_base)) {
1058  time_frame += TIMER_RES64;
1059  }
1060  break;
1061  }
1062  av_usleep(delay);
1063  }
1064 
1065  if (!dda->first_pts)
1066  dda->first_pts = now;
1067  now -= dda->first_pts;
1068 
1069  if (!dda->probed_texture) {
1070  ret = next_frame_internal(avctx, &cur_texture, 0);
1071  } else {
1072  cur_texture = dda->probed_texture;
1073  dda->probed_texture = NULL;
1074  ret = 0;
1075  }
1076 
1077  if (ret == AVERROR(EAGAIN) && dda->last_frame->buf[0]) {
1078  frame = av_frame_alloc();
1079  if (!frame)
1080  return AVERROR(ENOMEM);
1081 
1082  ret = av_frame_ref(frame, dda->last_frame);
1083  if (ret < 0) {
1084  av_frame_free(&frame);
1085  return ret;
1086  }
1087 
1088  av_log(avctx, AV_LOG_DEBUG, "Duplicated output frame\n");
1089 
1090  goto frame_done;
1091  } else if (ret == AVERROR(EAGAIN)) {
1092  av_log(avctx, AV_LOG_VERBOSE, "Initial DDA AcquireNextFrame timeout!\n");
1093  return AVERROR(EAGAIN);
1094  } else if (ret < 0) {
1095  return ret;
1096  }
1097 
1098  // AcquireNextFrame sometimes has bursts of delay.
1099  // This increases accuracy of the timestamp, but might upset consumers due to more jittery framerate?
1100  now = av_gettime_relative() - dda->first_pts;
1101 
1102  ID3D11Texture2D_GetDesc(cur_texture, &desc);
1103  if (desc.Format != dda->raw_format ||
1104  (int)desc.Width != dda->raw_width ||
1105  (int)desc.Height != dda->raw_height) {
1106  av_log(avctx, AV_LOG_ERROR, "Output parameters changed!");
1108  goto fail;
1109  }
1110 
1111  frame = ff_get_video_buffer(outlink, dda->width, dda->height);
1112  if (!frame) {
1113  ret = AVERROR(ENOMEM);
1114  goto fail;
1115  }
1116 
1117  box.left = dda->offset_x;
1118  box.top = dda->offset_y;
1119  box.right = box.left + dda->width;
1120  box.bottom = box.top + dda->height;
1121  box.front = 0;
1122  box.back = 1;
1123 
1124  ID3D11DeviceContext_CopySubresourceRegion(
1126  (ID3D11Resource*)frame->data[0], (UINT)(intptr_t)frame->data[1],
1127  0, 0, 0,
1128  (ID3D11Resource*)cur_texture, 0,
1129  &box);
1130 
1131  release_resource(&cur_texture);
1132 
1133  hr = IDXGIOutputDuplication_ReleaseFrame(dda->dxgi_outdupl);
1134  if (FAILED(hr)) {
1135  av_log(avctx, AV_LOG_ERROR, "DDA ReleaseFrame failed!\n");
1137  goto fail;
1138  }
1139 
1140  if (dda->draw_mouse) {
1141  ret = draw_mouse_pointer(avctx, frame);
1142  if (ret < 0)
1143  goto fail;
1144  }
1145 
1147 
1148  if (desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM ||
1149  desc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) {
1150  // According to MSDN, all integer formats contain sRGB image data
1155  } else if(desc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT) {
1156  // According to MSDN, all floating point formats contain sRGB image data with linear 1.0 gamma.
1161  } else {
1162  ret = AVERROR_BUG;
1163  goto fail;
1164  }
1165 
1167  if (ret < 0)
1168  return ret;
1169 
1170 frame_done:
1171  frame->pts = now;
1172  dda->time_frame = time_frame;
1173 
1174  return ff_filter_frame(outlink, frame);
1175 
1176 fail:
1177  if (frame)
1178  av_frame_free(&frame);
1179 
1180  if (cur_texture)
1181  IDXGIOutputDuplication_ReleaseFrame(dda->dxgi_outdupl);
1182 
1183  release_resource(&cur_texture);
1184  return ret;
1185 }
1186 
1187 static const AVFilterPad ddagrab_outputs[] = {
1188  {
1189  .name = "default",
1190  .type = AVMEDIA_TYPE_VIDEO,
1191  .request_frame = ddagrab_request_frame,
1192  .config_props = ddagrab_config_props,
1193  },
1194 };
1195 
1197  .name = "ddagrab",
1198  .description = NULL_IF_CONFIG_SMALL("Grab Windows Desktop images using Desktop Duplication API"),
1199  .priv_size = sizeof(DdagrabContext),
1200  .priv_class = &ddagrab_class,
1201  .init = ddagrab_init,
1203  .inputs = NULL,
1206  .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
1207  .flags = AVFILTER_FLAG_HWDEVICE,
1208 };
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:31
formats
formats
Definition: signature.h:48
ff_get_video_buffer
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:108
AVFrame::color_trc
enum AVColorTransferCharacteristic color_trc
Definition: frame.h:660
AVHWDeviceContext::hwctx
void * hwctx
The format-specific data, allocated and freed by libavutil along with this context.
Definition: hwcontext.h:92
DdagrabContext::raw_height
int raw_height
Definition: vsrc_ddagrab.c:82
av_gettime_relative
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
Definition: time.c:56
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVFrame::color_range
enum AVColorRange color_range
MPEG vs JPEG YUV range.
Definition: frame.h:656
TIMER_RES
#define TIMER_RES
Definition: vsrc_ddagrab.c:51
DdagrabContext::force_fmt
int force_fmt
Definition: vsrc_ddagrab.c:103
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
opt.h
draw_mouse_pointer
static int draw_mouse_pointer(AVFilterContext *avctx, AVFrame *frame)
Definition: vsrc_ddagrab.c:883
FF_FILTER_FLAG_HWFRAME_AWARE
#define FF_FILTER_FLAG_HWFRAME_AWARE
The filter is aware of hardware frames, and any hardware frame context should not be automatically pr...
Definition: internal.h:364
init_render_resources
static av_cold int init_render_resources(AVFilterContext *avctx)
Definition: vsrc_ddagrab.c:333
ConstBufferData::width
float width
Definition: vsrc_ddagrab.c:321
ff_filter_frame
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:978
DXGI_FORMAT_B8G8R8A8_UNORM
@ DXGI_FORMAT_B8G8R8A8_UNORM
Definition: dds.c:91
AVBufferRef::data
uint8_t * data
The data buffer.
Definition: buffer.h:90
fixup_color_mask
static int fixup_color_mask(uint8_t *input, uint8_t **rgba_out, uint8_t **xor_out, int width, int height, int pitch)
Definition: vsrc_ddagrab.c:562
AVCOL_TRC_LINEAR
@ AVCOL_TRC_LINEAR
"Linear transfer characteristics"
Definition: pixfmt.h:579
AV_OPT_TYPE_VIDEO_RATE
@ AV_OPT_TYPE_VIDEO_RATE
offset must point to AVRational
Definition: opt.h:238
DdagrabContext::frames_ctx
AVHWFramesContext * frames_ctx
Definition: vsrc_ddagrab.c:62
AVHWFramesContext::format
enum AVPixelFormat format
The pixel format identifying the underlying HW surface type.
Definition: hwcontext.h:209
next_frame_internal
static int next_frame_internal(AVFilterContext *avctx, ID3D11Texture2D **desktop_texture, int need_frame)
Definition: vsrc_ddagrab.c:681
DdagrabContext::blend_state
ID3D11BlendState * blend_state
Definition: vsrc_ddagrab.c:91
output
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce output
Definition: filter_design.txt:225
AVFrame::color_primaries
enum AVColorPrimaries color_primaries
Definition: frame.h:658
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:100
DdagrabContext::device_ctx
AVHWDeviceContext * device_ctx
Definition: vsrc_ddagrab.c:58
AVFrame::colorspace
enum AVColorSpace colorspace
YUV colorspace type.
Definition: frame.h:667
av_hwframe_ctx_init
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:334
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:340
AVFrame::pts
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:452
w
uint8_t w
Definition: llviddspenc.c:38
AVCOL_RANGE_JPEG
@ AVCOL_RANGE_JPEG
Full range content.
Definition: pixfmt.h:673
av_hwframe_ctx_alloc
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:248
AVOption
AVOption.
Definition: opt.h:251
DdagrabContext::frames_hwctx
AVD3D11VAFramesContext * frames_hwctx
Definition: vsrc_ddagrab.c:63
ddagrab_request_frame
static int ddagrab_request_frame(AVFilterLink *outlink)
Definition: vsrc_ddagrab.c:1031
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:196
AVCOL_SPC_RGB
@ AVCOL_SPC_RGB
order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB), YZX and ST 428-1
Definition: pixfmt.h:600
AVFilterContext::hw_device_ctx
AVBufferRef * hw_device_ctx
For filters which will create hardware frames, sets the device the filter should create them in.
Definition: avfilter.h:457
AV_PIX_FMT_BGRA
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
DdagrabContext::width
int width
Definition: vsrc_ddagrab.c:97
FFMAX
#define FFMAX(a, b)
Definition: macros.h:47
av_buffer_ref
AVBufferRef * av_buffer_ref(const AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:103
DdagrabContext::first_pts
int64_t first_pts
Definition: vsrc_ddagrab.c:78
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:170
ff_vsrc_ddagrab
const AVFilter ff_vsrc_ddagrab
Definition: vsrc_ddagrab.c:1196
AVHWFramesContext::width
int width
The allocated dimensions of the frames in this pool.
Definition: hwcontext.h:229
video.h
AVFrame::buf
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition: frame.h:590
AVFrame::data
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:361
DdagrabContext::last_frame
AVFrame * last_frame
Definition: vsrc_ddagrab.c:67
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:30
AVFILTER_DEFINE_CLASS
AVFILTER_DEFINE_CLASS(ddagrab)
AVD3D11VAFramesContext::BindFlags
UINT BindFlags
D3D11_TEXTURE2D_DESC.BindFlags used for texture creation.
Definition: hwcontext_d3d11va.h:160
vsrc_ddagrab_shaders.h
AVCOL_TRC_IEC61966_2_1
@ AVCOL_TRC_IEC61966_2_1
IEC 61966-2-1 (sRGB or sYCC)
Definition: pixfmt.h:584
AVFilterContext::priv
void * priv
private data for use by the filter
Definition: avfilter.h:412
fail
#define fail()
Definition: checkasm.h:138
DdagrabContext::pixel_shader
ID3D11PixelShader * pixel_shader
Definition: vsrc_ddagrab.c:88
AV_HWDEVICE_TYPE_D3D11VA
@ AV_HWDEVICE_TYPE_D3D11VA
Definition: hwcontext.h:35
DdagrabContext::framerate
AVRational framerate
Definition: vsrc_ddagrab.c:96
DdagrabContext::mouse_xor_resource_view
ID3D11ShaderResourceView * mouse_xor_resource_view
Definition: vsrc_ddagrab.c:73
AVFilterPad
A filter pad used for either input or output.
Definition: internal.h:47
AVHWDeviceContext
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:88
avassert.h
DdagrabContext::device_hwctx
AVD3D11VADeviceContext * device_hwctx
Definition: vsrc_ddagrab.c:59
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
ddagrab_options
static const AVOption ddagrab_options[]
Definition: vsrc_ddagrab.c:108
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
av_cold
#define av_cold
Definition: attributes.h:90
AVHWFramesContext::height
int height
Definition: hwcontext.h:229
width
#define width
AVD3D11VADeviceContext::device
ID3D11Device * device
Device used for texture creation and access.
Definition: hwcontext_d3d11va.h:56
DdagrabContext::raw_width
int raw_width
Definition: vsrc_ddagrab.c:81
av_q2d
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:365
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
create_d3d11_pointer_tex
static int create_d3d11_pointer_tex(AVFilterContext *avctx, uint8_t *buf, DXGI_OUTDUPL_POINTER_SHAPE_INFO *shape_info, ID3D11Texture2D **out_tex, ID3D11ShaderResourceView **res_view)
Definition: vsrc_ddagrab.c:448
DdagrabContext::dxgi_outdupl
IDXGIOutputDuplication * dxgi_outdupl
Definition: vsrc_ddagrab.c:66
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
vertex_shader_input_layout
static const D3D11_INPUT_ELEMENT_DESC vertex_shader_input_layout[]
Definition: vsrc_ddagrab.c:327
ConstBufferData
Definition: vsrc_ddagrab.c:319
DdagrabContext::mouse_x
int mouse_x
Definition: vsrc_ddagrab.c:69
av_usleep
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition: time.c:84
frame
static AVFrame * frame
Definition: demux_decode.c:54
if
if(ret)
Definition: filter_design.txt:179
ConstBufferData::height
float height
Definition: vsrc_ddagrab.c:322
DdagrabContext::vertex_shader
ID3D11VertexShader * vertex_shader
Definition: vsrc_ddagrab.c:86
framerate
float framerate
Definition: av1_levels.c:29
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
ddagrab_config_props
static int ddagrab_config_props(AVFilterLink *outlink)
Definition: vsrc_ddagrab.c:808
AVHWFramesContext::sw_format
enum AVPixelFormat sw_format
The pixel format identifying the actual data layout of the hardware frames.
Definition: hwcontext.h:222
DdagrabContext::mouse_texture
ID3D11Texture2D * mouse_texture
Definition: vsrc_ddagrab.c:70
av_buffer_unref
void av_buffer_unref(AVBufferRef **buf)
Free a given reference and automatically free the buffer if there are no more references to it.
Definition: buffer.c:139
DdagrabContext::const_buffer
ID3D11Buffer * const_buffer
Definition: vsrc_ddagrab.c:89
AVRational
Rational number (pair of numerator and denominator).
Definition: rational.h:58
AV_OPT_TYPE_IMAGE_SIZE
@ AV_OPT_TYPE_IMAGE_SIZE
offset must point to two consecutive integers
Definition: opt.h:235
AVCOL_PRI_BT709
@ AVCOL_PRI_BT709
also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP 177 Annex B
Definition: pixfmt.h:547
time.h
inputs
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
Definition: filter_design.txt:243
AVD3D11VAFramesContext
This struct is allocated as AVHWFramesContext.hwctx.
Definition: hwcontext_d3d11va.h:131
ddagrab_uninit
static av_cold void ddagrab_uninit(AVFilterContext *avctx)
Definition: vsrc_ddagrab.c:141
AV_PIX_FMT_X2BGR10
#define AV_PIX_FMT_X2BGR10
Definition: pixfmt.h:527
DdagrabContext::mouse_y
int mouse_y
Definition: vsrc_ddagrab.c:69
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:106
av_frame_ref
int av_frame_ref(AVFrame *dst, const AVFrame *src)
Set up a new reference to the data described by the source frame.
Definition: frame.c:361
release_resource
static void release_resource(void *resource)
Definition: vsrc_ddagrab.c:132
AVFILTER_FLAG_HWDEVICE
#define AVFILTER_FLAG_HWDEVICE
The filter can create hardware frames using AVFilterContext.hw_device_ctx.
Definition: avfilter.h:138
DdagrabContext::out_fmt
int out_fmt
Definition: vsrc_ddagrab.c:101
size
int size
Definition: twinvq_data.h:10344
AVERROR_OUTPUT_CHANGED
#define AVERROR_OUTPUT_CHANGED
Output changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_INPUT_CHANGED)
Definition: error.h:76
TIMER_RES64
#define TIMER_RES64
Definition: vsrc_ddagrab.c:52
height
#define height
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
AV_PIX_FMT_D3D11
@ AV_PIX_FMT_D3D11
Hardware surfaces for Direct3D11.
Definition: pixfmt.h:333
DdagrabContext::time_base
AVRational time_base
Definition: vsrc_ddagrab.c:75
input
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some input
Definition: filter_design.txt:172
FLAGS
#define FLAGS
Definition: vsrc_ddagrab.c:107
internal.h
FILTER_SINGLE_PIXFMT
#define FILTER_SINGLE_PIXFMT(pix_fmt_)
Definition: internal.h:182
DdagrabContext::raw_format
DXGI_FORMAT raw_format
Definition: vsrc_ddagrab.c:80
buffer_data
Definition: avio_read_callback.c:36
DXGI_FORMAT_R16G16B16A16_FLOAT
@ DXGI_FORMAT_R16G16B16A16_FLOAT
Definition: dds.c:62
DdagrabContext::mouse_resource_view
ID3D11ShaderResourceView * mouse_resource_view
Definition: vsrc_ddagrab.c:71
AVD3D11VADeviceContext
This struct is allocated as AVHWDeviceContext.hwctx.
Definition: hwcontext_d3d11va.h:45
av_assert1
#define av_assert1(cond)
assert() equivalent, that does not lie in speed critical code.
Definition: avassert.h:56
DdagrabContext::draw_mouse
int draw_mouse
Definition: vsrc_ddagrab.c:95
av_inv_q
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition: rational.h:159
DdagrabContext::allow_fallback
int allow_fallback
Definition: vsrc_ddagrab.c:102
FLOAT
float FLOAT
Definition: faandct.c:33
AVFilterPad::name
const char * name
Pad name.
Definition: internal.h:53
DdagrabContext::offset_y
int offset_y
Definition: vsrc_ddagrab.c:100
stride
#define stride
Definition: h264pred_template.c:537
DdagrabContext::time_timeout
int64_t time_timeout
Definition: vsrc_ddagrab.c:77
AVFilter
Filter definition.
Definition: avfilter.h:166
convert_mono_buffer
static int convert_mono_buffer(uint8_t *input, uint8_t **rgba_out, uint8_t **xor_out, int *_width, int *_height, int *_pitch)
Definition: vsrc_ddagrab.c:501
DdagrabContext::output_idx
int output_idx
Definition: vsrc_ddagrab.c:94
AVHWFramesContext
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:124
ret
ret
Definition: filter_design.txt:187
AVHWDeviceContext::type
enum AVHWDeviceType type
This field identifies the underlying API used for hardware access.
Definition: hwcontext.h:79
AVHWFramesContext::hwctx
void * hwctx
The format-specific data, allocated and freed automatically along with this context.
Definition: hwcontext.h:162
init_dxgi_dda
static av_cold int init_dxgi_dda(AVFilterContext *avctx)
Definition: vsrc_ddagrab.c:166
av_hwdevice_ctx_create
int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type, const char *device, AVDictionary *opts, int flags)
Open a device of the specified type and create an AVHWDeviceContext for it.
Definition: hwcontext.c:615
pos
unsigned int pos
Definition: spdifenc.c:413
DdagrabContext::input_layout
ID3D11InputLayout * input_layout
Definition: vsrc_ddagrab.c:87
AVFrame::sample_aspect_ratio
AVRational sample_aspect_ratio
Sample aspect ratio for the video frame, 0/1 if unknown/unspecified.
Definition: frame.h:447
av_frame_replace
int av_frame_replace(AVFrame *dst, const AVFrame *src)
Ensure the destination frame refers to the same data described by the source frame,...
Definition: frame.c:482
DdagrabContext::frames_ref
AVBufferRef * frames_ref
Definition: vsrc_ddagrab.c:61
DdagrabContext::time_frame
int64_t time_frame
Definition: vsrc_ddagrab.c:76
DdagrabContext::height
int height
Definition: vsrc_ddagrab.c:98
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:225
avfilter.h
AVFilterContext
An instance of a filter.
Definition: avfilter.h:397
desc
const char * desc
Definition: libsvtav1.c:83
pixel_shader_bytes
static const uint8_t pixel_shader_bytes[]
Definition: vsrc_ddagrab_shaders.h:101
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AVBufferRef
A reference to a data buffer.
Definition: buffer.h:82
vertex_shader_bytes
static const uint8_t vertex_shader_bytes[]
Definition: vsrc_ddagrab_shaders.h:63
init_hwframes_ctx
static av_cold int init_hwframes_ctx(AVFilterContext *avctx)
Definition: vsrc_ddagrab.c:760
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
update_mouse_pointer
static int update_mouse_pointer(AVFilterContext *avctx, DXGI_OUTDUPL_FRAME_INFO *frame_info)
Definition: vsrc_ddagrab.c:592
AV_PIX_FMT_RGBAF16
#define AV_PIX_FMT_RGBAF16
Definition: pixfmt.h:536
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Definition: opt.h:244
FILTER_OUTPUTS
#define FILTER_OUTPUTS(array)
Definition: internal.h:193
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
DdagrabContext::sampler_state
ID3D11SamplerState * sampler_state
Definition: vsrc_ddagrab.c:90
ddagrab_outputs
static const AVFilterPad ddagrab_outputs[]
Definition: vsrc_ddagrab.c:1187
DdagrabContext::offset_x
int offset_x
Definition: vsrc_ddagrab.c:99
DdagrabContext::probed_texture
ID3D11Texture2D * probed_texture
Definition: vsrc_ddagrab.c:84
ddagrab_init
static av_cold int ddagrab_init(AVFilterContext *avctx)
Definition: vsrc_ddagrab.c:434
DdagrabContext::output_desc
DXGI_OUTPUT_DESC output_desc
Definition: vsrc_ddagrab.c:65
hwcontext.h
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:52
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
DdagrabContext::device_ref
AVBufferRef * device_ref
Definition: vsrc_ddagrab.c:57
ConstBufferData::padding
uint64_t padding
Definition: vsrc_ddagrab.c:324
AVD3D11VADeviceContext::device_context
ID3D11DeviceContext * device_context
If unset, this will be set from the device field on init.
Definition: hwcontext_d3d11va.h:64
ID3D11Device
void ID3D11Device
Definition: nvenc.h:28
uninit
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:285
h
h
Definition: vp9dsp_template.c:2038
DdagrabContext
Definition: vsrc_ddagrab.c:54
avstring.h
DdagrabContext::mouse_xor_texture
ID3D11Texture2D * mouse_xor_texture
Definition: vsrc_ddagrab.c:72
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:234
hwcontext_d3d11va.h
OFFSET
#define OFFSET(x)
Definition: vsrc_ddagrab.c:106
probe_output_format
static int probe_output_format(AVFilterContext *avctx)
Definition: vsrc_ddagrab.c:732
w32dlfcn.h
DdagrabContext::blend_state_xor
ID3D11BlendState * blend_state_xor
Definition: vsrc_ddagrab.c:92