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 
74  int64_t time_frame;
75  int64_t time_timeout;
76  int64_t first_pts;
77 
78  DXGI_FORMAT raw_format;
79  int raw_width;
81 
82  ID3D11Texture2D *probed_texture;
83 
84  ID3D11VertexShader *vertex_shader;
85  ID3D11InputLayout *input_layout;
86  ID3D11PixelShader *pixel_shader;
87  ID3D11Buffer *const_buffer;
88  ID3D11SamplerState *sampler_state;
89  ID3D11BlendState *blend_state;
90 
94  int width;
95  int height;
96  int offset_x;
97  int offset_y;
98  int out_fmt;
102 
103 #define OFFSET(x) offsetof(DdagrabContext, x)
104 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
105 static const AVOption ddagrab_options[] = {
106  { "output_idx", "dda output index to capture", OFFSET(output_idx), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
107  { "draw_mouse", "draw the mouse pointer", OFFSET(draw_mouse), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
108  { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, { .str = "30" }, 0, INT_MAX, FLAGS },
109  { "video_size", "set video frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS },
110  { "offset_x", "capture area x offset", OFFSET(offset_x), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
111  { "offset_y", "capture area y offset", OFFSET(offset_y), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS },
112  { "output_fmt", "desired output format", OFFSET(out_fmt), AV_OPT_TYPE_INT, { .i64 = DXGI_FORMAT_B8G8R8A8_UNORM }, 0, INT_MAX, FLAGS, "output_fmt" },
113  { "auto", "let dda pick its preferred format", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, INT_MAX, FLAGS, "output_fmt" },
114  { "8bit", "only output default 8 Bit format", 0, AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_B8G8R8A8_UNORM }, 0, INT_MAX, FLAGS, "output_fmt" },
115  { "bgra", "only output 8 Bit BGRA", 0, AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_B8G8R8A8_UNORM }, 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" },
118  { "16bit", "only output default 16 Bit format", 0, AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R16G16B16A16_FLOAT },0, INT_MAX, FLAGS, "output_fmt" },
119  { "rgbaf16", "only output 16 Bit RGBAF16", 0, AV_OPT_TYPE_CONST, { .i64 = DXGI_FORMAT_R16G16B16A16_FLOAT },0, INT_MAX, FLAGS, "output_fmt" },
120  { "allow_fallback", "don't error on fallback to default 8 Bit format",
121  OFFSET(allow_fallback), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
122  { "force_fmt", "exclude BGRA from format list (experimental, discouraged by Microsoft)",
123  OFFSET(force_fmt), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
124  { NULL }
125 };
126 
127 AVFILTER_DEFINE_CLASS(ddagrab);
128 
129 static inline void release_resource(void *resource)
130 {
131  IUnknown **resp = (IUnknown**)resource;
132  if (*resp) {
133  IUnknown_Release(*resp);
134  *resp = NULL;
135  }
136 }
137 
139 {
140  DdagrabContext *dda = avctx->priv;
141 
148 
150 
154 
155  av_frame_free(&dda->last_frame);
158 }
159 
161 {
162  DdagrabContext *dda = avctx->priv;
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;
169 
170  typedef DPI_AWARENESS_CONTEXT (*set_thread_dpi_t)(DPI_AWARENESS_CONTEXT);
171  set_thread_dpi_t set_thread_dpi;
172  HMODULE user32_module;
173 #endif
174  int w, h;
175  HRESULT hr;
176 
177  hr = ID3D11Device_QueryInterface(dda->device_hwctx->device, &IID_IDXGIDevice, (void**)&dxgi_device);
178  if (FAILED(hr)) {
179  av_log(avctx, AV_LOG_ERROR, "Failed querying IDXGIDevice\n");
180  return AVERROR_EXTERNAL;
181  }
182 
183  hr = IDXGIDevice_GetParent(dxgi_device, &IID_IDXGIAdapter, (void**)&dxgi_adapter);
184  IDXGIDevice_Release(dxgi_device);
185  dxgi_device = NULL;
186  if (FAILED(hr)) {
187  av_log(avctx, AV_LOG_ERROR, "Failed getting parent IDXGIAdapter\n");
188  return AVERROR_EXTERNAL;
189  }
190 
191  hr = IDXGIAdapter_EnumOutputs(dxgi_adapter, dda->output_idx, &dxgi_output);
192  IDXGIAdapter_Release(dxgi_adapter);
193  dxgi_adapter = NULL;
194  if (FAILED(hr)) {
195  av_log(avctx, AV_LOG_ERROR, "Failed to enumerate DXGI output %d\n", dda->output_idx);
196  return AVERROR_EXTERNAL;
197  }
198 
199  hr = IDXGIOutput_GetDesc(dxgi_output, &dda->output_desc);
200  if (FAILED(hr)) {
201  IDXGIOutput_Release(dxgi_output);
202  av_log(avctx, AV_LOG_ERROR, "Failed getting output description\n");
203  return AVERROR_EXTERNAL;
204  }
205 
206 #if HAVE_IDXGIOUTPUT5 && HAVE_DPI_AWARENESS_CONTEXT
207  user32_module = dlopen("user32.dll", 0);
208  if (!user32_module) {
209  av_log(avctx, AV_LOG_ERROR, "Failed loading user32.dll\n");
210  return AVERROR_EXTERNAL;
211  }
212 
213  set_thread_dpi = (set_thread_dpi_t)dlsym(user32_module, "SetThreadDpiAwarenessContext");
214 
215  if (set_thread_dpi)
216  hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput5, (void**)&dxgi_output5);
217 
218  if (set_thread_dpi && SUCCEEDED(hr)) {
219  DPI_AWARENESS_CONTEXT prev_dpi_ctx;
220  DXGI_FORMAT formats[] = {
222  DXGI_FORMAT_R10G10B10A2_UNORM,
224  };
225  int nb_formats = FF_ARRAY_ELEMS(formats);
226 
227  if(dda->out_fmt == DXGI_FORMAT_B8G8R8A8_UNORM) {
229  nb_formats = 1;
230  } else if (dda->out_fmt) {
231  formats[0] = dda->out_fmt;
233  nb_formats = dda->force_fmt ? 1 : 2;
234  }
235 
236  IDXGIOutput_Release(dxgi_output);
237  dxgi_output = NULL;
238 
239  prev_dpi_ctx = set_thread_dpi(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
240  if (!prev_dpi_ctx)
241  av_log(avctx, AV_LOG_WARNING, "Failed enabling DPI awareness for DDA\n");
242 
243  hr = IDXGIOutput5_DuplicateOutput1(dxgi_output5,
244  (IUnknown*)dda->device_hwctx->device,
245  0,
246  nb_formats,
247  formats,
248  &dda->dxgi_outdupl);
249  IDXGIOutput5_Release(dxgi_output5);
250  dxgi_output5 = NULL;
251 
252  if (prev_dpi_ctx)
253  set_thread_dpi(prev_dpi_ctx);
254 
255  dlclose(user32_module);
256  user32_module = NULL;
257  set_thread_dpi = NULL;
258 
259  av_log(avctx, AV_LOG_DEBUG, "Using IDXGIOutput5 interface\n");
260  } else {
261  dlclose(user32_module);
262  user32_module = NULL;
263  set_thread_dpi = NULL;
264 
265  av_log(avctx, AV_LOG_DEBUG, "Falling back to IDXGIOutput1\n");
266 #else
267  {
268 #endif
269  if (dda->out_fmt && dda->out_fmt != DXGI_FORMAT_B8G8R8A8_UNORM && (!dda->allow_fallback || dda->force_fmt)) {
270  av_log(avctx, AV_LOG_ERROR, "Only 8 bit output supported with legacy API\n");
271  return AVERROR(ENOTSUP);
272  }
273 
274  hr = IDXGIOutput_QueryInterface(dxgi_output, &IID_IDXGIOutput1, (void**)&dxgi_output1);
275  IDXGIOutput_Release(dxgi_output);
276  dxgi_output = NULL;
277  if (FAILED(hr)) {
278  av_log(avctx, AV_LOG_ERROR, "Failed querying IDXGIOutput1\n");
279  return AVERROR_EXTERNAL;
280  }
281 
282  hr = IDXGIOutput1_DuplicateOutput(dxgi_output1,
283  (IUnknown*)dda->device_hwctx->device,
284  &dda->dxgi_outdupl);
285  IDXGIOutput1_Release(dxgi_output1);
286  dxgi_output1 = NULL;
287  }
288 
289  if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
290  av_log(avctx, AV_LOG_ERROR, "Too many open duplication sessions\n");
291  return AVERROR(EBUSY);
292  } else if (hr == DXGI_ERROR_UNSUPPORTED) {
293  av_log(avctx, AV_LOG_ERROR, "Selected output not supported\n");
294  return AVERROR_EXTERNAL;
295  } else if (hr == E_INVALIDARG) {
296  av_log(avctx, AV_LOG_ERROR, "Invalid output duplication argument\n");
297  return AVERROR(EINVAL);
298  } else if (hr == E_ACCESSDENIED) {
299  av_log(avctx, AV_LOG_ERROR, "Desktop duplication access denied\n");
300  return AVERROR(EPERM);
301  } else if (FAILED(hr)) {
302  av_log(avctx, AV_LOG_ERROR, "Failed duplicating output\n");
303  return AVERROR_EXTERNAL;
304  }
305 
306  w = dda->output_desc.DesktopCoordinates.right - dda->output_desc.DesktopCoordinates.left;
307  h = dda->output_desc.DesktopCoordinates.bottom - dda->output_desc.DesktopCoordinates.top;
308  av_log(avctx, AV_LOG_VERBOSE, "Opened dxgi output %d with dimensions %dx%d\n", dda->output_idx, w, h);
309 
310  return 0;
311 }
312 
313 typedef struct ConstBufferData
314 {
315  float width;
316  float height;
317 
318  uint64_t padding;
320 
321 static const D3D11_INPUT_ELEMENT_DESC vertex_shader_input_layout[] =
322 {
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 }
325 };
326 
328 {
329  DdagrabContext *dda = avctx->priv;
330  ID3D11Device *dev = dda->device_hwctx->device;
331  D3D11_SAMPLER_DESC sampler_desc = { 0 };
332  D3D11_BLEND_DESC blend_desc = { 0 };
333  D3D11_BUFFER_DESC buffer_desc = { 0 };
334  D3D11_SUBRESOURCE_DATA buffer_data = { 0 };
335  ConstBufferData const_data = { 0 };
336  HRESULT hr;
337 
338  hr = ID3D11Device_CreateVertexShader(dev,
341  NULL,
342  &dda->vertex_shader);
343  if (FAILED(hr)) {
344  av_log(avctx, AV_LOG_ERROR, "CreateVertexShader failed: %lx\n", hr);
345  return AVERROR_EXTERNAL;
346  }
347 
348  hr = ID3D11Device_CreateInputLayout(dev,
353  &dda->input_layout);
354  if (FAILED(hr)) {
355  av_log(avctx, AV_LOG_ERROR, "CreateInputLayout failed: %lx\n", hr);
356  return AVERROR_EXTERNAL;
357  }
358 
359  hr = ID3D11Device_CreatePixelShader(dev,
362  NULL,
363  &dda->pixel_shader);
364  if (FAILED(hr)) {
365  av_log(avctx, AV_LOG_ERROR, "CreatePixelShader failed: %lx\n", hr);
366  return AVERROR_EXTERNAL;
367  }
368 
369  const_data = (ConstBufferData){ dda->width, dda->height };
370 
371  buffer_data.pSysMem = &const_data;
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,
376  &buffer_desc,
377  &buffer_data,
378  &dda->const_buffer);
379  if (FAILED(hr)) {
380  av_log(avctx, AV_LOG_ERROR, "CreateBuffer const buffer failed: %lx\n", hr);
381  return AVERROR_EXTERNAL;
382  }
383 
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,
390  &sampler_desc,
391  &dda->sampler_state);
392  if (FAILED(hr)) {
393  av_log(avctx, AV_LOG_ERROR, "CreateSamplerState failed: %lx\n", hr);
394  return AVERROR_EXTERNAL;
395  }
396 
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,
408  &blend_desc,
409  &dda->blend_state);
410  if (FAILED(hr)) {
411  av_log(avctx, AV_LOG_ERROR, "CreateBlendState failed: %lx\n", hr);
412  return AVERROR_EXTERNAL;
413  }
414 
415  return 0;
416 }
417 
419 {
420  DdagrabContext *dda = avctx->priv;
421 
422  dda->last_frame = av_frame_alloc();
423  if (!dda->last_frame)
424  return AVERROR(ENOMEM);
425 
426  dda->mouse_x = -1;
427  dda->mouse_y = -1;
428 
429  return 0;
430 }
431 
433  uint8_t *buf,
434  DXGI_OUTDUPL_POINTER_SHAPE_INFO *shape_info,
435  ID3D11Texture2D **out_tex,
436  ID3D11ShaderResourceView **res_view)
437 {
438  DdagrabContext *dda = avctx->priv;
439  D3D11_TEXTURE2D_DESC desc = { 0 };
440  D3D11_SUBRESOURCE_DATA init_data = { 0 };
441  D3D11_SHADER_RESOURCE_VIEW_DESC resource_desc = { 0 };
442  HRESULT hr;
443 
444  desc.MipLevels = 1;
445  desc.ArraySize = 1;
447  desc.SampleDesc.Count = 1;
448  desc.SampleDesc.Quality = 0;
449  desc.Usage = D3D11_USAGE_IMMUTABLE;
450  desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
451 
452  desc.Width = shape_info->Width;
453  desc.Height = shape_info->Height;
454 
455  init_data.pSysMem = buf;
456  init_data.SysMemPitch = shape_info->Pitch;
457 
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;
462 
463  hr = ID3D11Device_CreateTexture2D(dda->device_hwctx->device,
464  &desc,
465  &init_data,
466  out_tex);
467  if (FAILED(hr)) {
468  av_log(avctx, AV_LOG_ERROR, "Failed creating pointer texture\n");
469  return AVERROR_EXTERNAL;
470  }
471 
472  hr = ID3D11Device_CreateShaderResourceView(dda->device_hwctx->device,
473  (ID3D11Resource*)dda->mouse_texture,
474  &resource_desc,
475  res_view);
476  if (FAILED(hr)) {
477  release_resource(out_tex);
478  av_log(avctx, AV_LOG_ERROR, "CreateShaderResourceView for mouse failed: %lx\n", hr);
479  return AVERROR_EXTERNAL;
480  }
481 
482  return 0;
483 }
484 
485 static uint8_t *convert_mono_buffer(uint8_t *input, int *_width, int *_height, int *_pitch)
486 {
487  int width = *_width, height = *_height, pitch = *_pitch;
488  int real_height = height / 2;
489  uint8_t *output = av_malloc(real_height * width * 4);
490  int y, x;
491 
492  if (!output)
493  return NULL;
494 
495  // This simulates drawing the cursor on a full black surface
496  // i.e. ignore the AND mask, turn XOR mask into all 4 color channels
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);
502  }
503  }
504 
505  *_pitch = width * 4;
506  *_height = real_height;
507 
508  return output;
509 }
510 
511 static void fixup_color_mask(uint8_t *buf, int width, int height, int pitch)
512 {
513  int x, y;
514  // There is no good way to replicate XOR'ig parts of the texture with the screen
515  // best effort is rendering the non-masked parts, and make the rest transparent
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;
520  }
521  }
522 }
523 
524 static int update_mouse_pointer(AVFilterContext *avctx, DXGI_OUTDUPL_FRAME_INFO *frame_info)
525 {
526  DdagrabContext *dda = avctx->priv;
527  HRESULT hr;
528  int ret;
529 
530  if (frame_info->LastMouseUpdateTime.QuadPart == 0)
531  return 0;
532 
533  if (frame_info->PointerPosition.Visible) {
534  switch (dda->output_desc.Rotation) {
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;
538  break;
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;
542  break;
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;
546  break;
547  default:
548  dda->mouse_x = frame_info->PointerPosition.Position.x;
549  dda->mouse_y = frame_info->PointerPosition.Position.y;
550  }
551  } else {
552  dda->mouse_x = dda->mouse_y = -1;
553  }
554 
555  if (frame_info->PointerShapeBufferSize) {
556  UINT size = frame_info->PointerShapeBufferSize;
557  DXGI_OUTDUPL_POINTER_SHAPE_INFO shape_info;
558  uint8_t *buf = av_malloc(size);
559  if (!buf)
560  return AVERROR(ENOMEM);
561 
562  hr = IDXGIOutputDuplication_GetFramePointerShape(dda->dxgi_outdupl,
563  size,
564  buf,
565  &size,
566  &shape_info);
567  if (FAILED(hr)) {
568  av_free(buf);
569  av_log(avctx, AV_LOG_ERROR, "Failed getting pointer shape: %lx\n", hr);
570  return AVERROR_EXTERNAL;
571  }
572 
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);
575  av_free(buf);
576  if (!new_buf)
577  return AVERROR(ENOMEM);
578  buf = new_buf;
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) {
582  av_log(avctx, AV_LOG_WARNING, "Unsupported pointer shape type: %d\n", (int)shape_info.Type);
583  av_free(buf);
584  return 0;
585  }
586 
589 
590  ret = create_d3d11_pointer_tex(avctx, buf, &shape_info, &dda->mouse_texture, &dda->mouse_resource_view);
591  av_freep(&buf);
592  if (ret < 0)
593  return ret;
594 
595  av_log(avctx, AV_LOG_VERBOSE, "Updated pointer shape texture\n");
596  }
597 
598  return 0;
599 }
600 
601 static int next_frame_internal(AVFilterContext *avctx, ID3D11Texture2D **desktop_texture, int need_frame)
602 {
603  DXGI_OUTDUPL_FRAME_INFO frame_info;
604  DdagrabContext *dda = avctx->priv;
605  IDXGIResource *desktop_resource = NULL;
606  HRESULT hr;
607  int ret;
608 
609  hr = IDXGIOutputDuplication_AcquireNextFrame(
610  dda->dxgi_outdupl,
611  dda->time_timeout,
612  &frame_info,
613  &desktop_resource);
614  if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
615  return AVERROR(EAGAIN);
616  } else if (FAILED(hr)) {
617  av_log(avctx, AV_LOG_ERROR, "AcquireNextFrame failed: %lx\n", hr);
618  return AVERROR_EXTERNAL;
619  }
620 
621  if (dda->draw_mouse) {
622  ret = update_mouse_pointer(avctx, &frame_info);
623  if (ret < 0)
624  goto error;
625  }
626 
627  if (need_frame && (!frame_info.LastPresentTime.QuadPart || !frame_info.AccumulatedFrames)) {
628  ret = AVERROR(EAGAIN);
629  goto error;
630  }
631 
632  hr = IDXGIResource_QueryInterface(desktop_resource, &IID_ID3D11Texture2D, (void**)desktop_texture);
633  release_resource(&desktop_resource);
634  if (FAILED(hr)) {
635  av_log(avctx, AV_LOG_ERROR, "DXGIResource QueryInterface failed\n");
637  goto error;
638  }
639 
640  return 0;
641 
642 error:
643  release_resource(&desktop_resource);
644 
645  hr = IDXGIOutputDuplication_ReleaseFrame(dda->dxgi_outdupl);
646  if (FAILED(hr))
647  av_log(avctx, AV_LOG_ERROR, "DDA error ReleaseFrame failed!\n");
648 
649  return ret;
650 }
651 
653 {
654  DdagrabContext *dda = avctx->priv;
655  D3D11_TEXTURE2D_DESC desc;
656  int ret;
657 
658  av_assert1(!dda->probed_texture);
659 
660  do {
661  ret = next_frame_internal(avctx, &dda->probed_texture, 1);
662  } while(ret == AVERROR(EAGAIN));
663  if (ret < 0)
664  return ret;
665 
666  ID3D11Texture2D_GetDesc(dda->probed_texture, &desc);
667 
668  dda->raw_format = desc.Format;
669  dda->raw_width = desc.Width;
670  dda->raw_height = desc.Height;
671 
672  if (dda->width <= 0)
673  dda->width = dda->raw_width;
674  if (dda->height <= 0)
675  dda->height = dda->raw_height;
676 
677  return 0;
678 }
679 
681 {
682  DdagrabContext *dda = avctx->priv;
683  int ret = 0;
684 
686  if (!dda->frames_ref)
687  return AVERROR(ENOMEM);
690 
692  dda->frames_ctx->width = dda->width;
693  dda->frames_ctx->height = dda->height;
694 
695  switch (dda->raw_format) {
697  av_log(avctx, AV_LOG_VERBOSE, "Probed 8 bit RGB frame format\n");
699  break;
700  case DXGI_FORMAT_R10G10B10A2_UNORM:
701  av_log(avctx, AV_LOG_VERBOSE, "Probed 10 bit RGB frame format\n");
703  break;
705  av_log(avctx, AV_LOG_VERBOSE, "Probed 16 bit float RGB frame format\n");
707  break;
708  default:
709  av_log(avctx, AV_LOG_ERROR, "Unexpected texture output format!\n");
710  return AVERROR_BUG;
711  }
712 
713  if (dda->draw_mouse)
714  dda->frames_hwctx->BindFlags |= D3D11_BIND_RENDER_TARGET;
715 
717  if (ret < 0) {
718  av_log(avctx, AV_LOG_ERROR, "Failed to initialise hardware frames context: %d.\n", ret);
719  goto fail;
720  }
721 
722  return 0;
723 fail:
725  return ret;
726 }
727 
728 static int ddagrab_config_props(AVFilterLink *outlink)
729 {
730  AVFilterContext *avctx = outlink->src;
731  DdagrabContext *dda = avctx->priv;
732  int ret;
733 
734  if (avctx->hw_device_ctx) {
736 
738  av_log(avctx, AV_LOG_ERROR, "Non-D3D11VA input hw_device_ctx\n");
739  return AVERROR(EINVAL);
740  }
741 
742  dda->device_ref = av_buffer_ref(avctx->hw_device_ctx);
743  if (!dda->device_ref)
744  return AVERROR(ENOMEM);
745 
746  av_log(avctx, AV_LOG_VERBOSE, "Using provided hw_device_ctx\n");
747  } else {
749  if (ret < 0) {
750  av_log(avctx, AV_LOG_ERROR, "Failed to create D3D11VA device.\n");
751  return ret;
752  }
753 
755 
756  av_log(avctx, AV_LOG_VERBOSE, "Created internal hw_device_ctx\n");
757  }
758 
760 
761  ret = init_dxgi_dda(avctx);
762  if (ret < 0)
763  return ret;
764 
765  ret = probe_output_format(avctx);
766  if (ret < 0)
767  return ret;
768 
769  if (dda->out_fmt && dda->raw_format != dda->out_fmt && (!dda->allow_fallback || dda->force_fmt)) {
770  av_log(avctx, AV_LOG_ERROR, "Requested output format unavailable.\n");
771  return AVERROR(ENOTSUP);
772  }
773 
774  dda->width -= FFMAX(dda->width - dda->raw_width + dda->offset_x, 0);
775  dda->height -= FFMAX(dda->height - dda->raw_height + dda->offset_y, 0);
776 
777  dda->time_base = av_inv_q(dda->framerate);
779  dda->time_timeout = av_rescale_q(1, dda->time_base, (AVRational) { 1, 1000 }) / 2;
780 
781  if (dda->draw_mouse) {
782  ret = init_render_resources(avctx);
783  if (ret < 0)
784  return ret;
785  }
786 
787  ret = init_hwframes_ctx(avctx);
788  if (ret < 0)
789  return ret;
790 
791  outlink->hw_frames_ctx = av_buffer_ref(dda->frames_ref);
792  if (!outlink->hw_frames_ctx)
793  return AVERROR(ENOMEM);
794 
795  outlink->w = dda->width;
796  outlink->h = dda->height;
797  outlink->time_base = (AVRational){1, TIMER_RES};
798  outlink->frame_rate = dda->framerate;
799 
800  return 0;
801 }
802 
804 {
805  DdagrabContext *dda = avctx->priv;
806  ID3D11DeviceContext *devctx = dda->device_hwctx->device_context;
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;
813  int x, y;
814  HRESULT hr;
815  int ret = 0;
816 
817  if (!dda->mouse_texture || dda->mouse_x < 0 || dda->mouse_y < 0)
818  return 0;
819 
820  ID3D11Texture2D_GetDesc(dda->mouse_texture, &tex_desc);
821 
822  x = dda->mouse_x - dda->offset_x;
823  y = dda->mouse_y - dda->offset_y;
824 
825  if (x >= dda->width || y >= dda->height ||
826  -x >= (int)tex_desc.Width || -y >= (int)tex_desc.Height)
827  return 0;
828 
829  target_desc.Format = dda->raw_format;
830  target_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
831  target_desc.Texture2D.MipSlice = 0;
832 
833  hr = ID3D11Device_CreateRenderTargetView(dda->device_hwctx->device,
834  (ID3D11Resource*)frame_tex,
835  &target_desc,
836  &target_view);
837  if (FAILED(hr)) {
838  av_log(avctx, AV_LOG_ERROR, "CreateRenderTargetView failed: %lx\n", hr);
840  goto end;
841  }
842 
843  ID3D11DeviceContext_ClearState(devctx);
844 
845  {
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;
851 
852  ID3D11DeviceContext_RSSetViewports(devctx, 1, &viewport);
853  }
854 
855  {
856  FLOAT vertices[] = {
857  // x, y, z, u, v
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,
862  };
863  UINT stride = sizeof(FLOAT) * 5;
864  UINT offset = 0;
865 
866  D3D11_SUBRESOURCE_DATA init_data = { 0 };
867  D3D11_BUFFER_DESC buf_desc = { 0 };
868 
869  switch (dda->output_desc.Rotation) {
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;
879  break;
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;
889  break;
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;
899  break;
900  default:
901  break;
902  }
903 
904  num_vertices = sizeof(vertices) / (sizeof(FLOAT) * 5);
905 
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;
910 
911  hr = ID3D11Device_CreateBuffer(dda->device_hwctx->device,
912  &buf_desc,
913  &init_data,
914  &mouse_vertex_buffer);
915  if (FAILED(hr)) {
916  av_log(avctx, AV_LOG_ERROR, "CreateBuffer failed: %lx\n", hr);
918  goto end;
919  }
920 
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);
924  }
925 
926  ID3D11DeviceContext_VSSetShader(devctx, dda->vertex_shader, NULL, 0);
927  ID3D11DeviceContext_VSSetConstantBuffers(devctx, 0, 1, &dda->const_buffer);
928  ID3D11DeviceContext_PSSetSamplers(devctx, 0, 1, &dda->sampler_state);
929  ID3D11DeviceContext_PSSetShaderResources(devctx, 0, 1, &dda->mouse_resource_view);
930  ID3D11DeviceContext_PSSetShader(devctx, dda->pixel_shader, NULL, 0);
931 
932  ID3D11DeviceContext_OMSetBlendState(devctx, dda->blend_state, NULL, 0xFFFFFFFF);
933  ID3D11DeviceContext_OMSetRenderTargets(devctx, 1, &target_view, NULL);
934 
935  ID3D11DeviceContext_Draw(devctx, num_vertices, 0);
936 
937 end:
938  release_resource(&mouse_vertex_buffer);
939  release_resource(&target_view);
940 
941  return ret;
942 }
943 
945 {
946  AVFilterContext *avctx = outlink->src;
947  DdagrabContext *dda = avctx->priv;
948 
949  ID3D11Texture2D *cur_texture = NULL;
950  D3D11_TEXTURE2D_DESC desc = { 0 };
951  D3D11_BOX box = { 0 };
952 
953  int64_t time_frame = dda->time_frame;
954  int64_t now, delay;
955  AVFrame *frame = NULL;
956  HRESULT hr;
957  int ret;
958 
959  /* time_frame is in units of microseconds divided by the time_base.
960  * This means that adding a clean 1M to it is the equivalent of adding
961  * 1M*time_base microseconds to it, except it avoids all rounding error.
962  * The only time rounding error occurs is when multiplying to calculate
963  * the delay. So any rounding error there corrects itself over time.
964  */
965  time_frame += TIMER_RES64;
966  for (;;) {
967  now = av_gettime_relative();
968  delay = time_frame * av_q2d(dda->time_base) - now;
969  if (delay <= 0) {
970  if (delay < -TIMER_RES64 * av_q2d(dda->time_base)) {
971  time_frame += TIMER_RES64;
972  }
973  break;
974  }
975  av_usleep(delay);
976  }
977 
978  if (!dda->first_pts)
979  dda->first_pts = now;
980  now -= dda->first_pts;
981 
982  if (!dda->probed_texture) {
983  ret = next_frame_internal(avctx, &cur_texture, 0);
984  } else {
985  cur_texture = dda->probed_texture;
986  dda->probed_texture = NULL;
987  ret = 0;
988  }
989 
990  if (ret == AVERROR(EAGAIN) && dda->last_frame->buf[0]) {
991  frame = av_frame_alloc();
992  if (!frame)
993  return AVERROR(ENOMEM);
994 
995  ret = av_frame_ref(frame, dda->last_frame);
996  if (ret < 0) {
998  return ret;
999  }
1000 
1001  av_log(avctx, AV_LOG_DEBUG, "Duplicated output frame\n");
1002 
1003  goto frame_done;
1004  } else if (ret == AVERROR(EAGAIN)) {
1005  av_log(avctx, AV_LOG_VERBOSE, "Initial DDA AcquireNextFrame timeout!\n");
1006  return AVERROR(EAGAIN);
1007  } else if (ret < 0) {
1008  return ret;
1009  }
1010 
1011  // AcquireNextFrame sometimes has bursts of delay.
1012  // This increases accuracy of the timestamp, but might upset consumers due to more jittery framerate?
1013  now = av_gettime_relative() - dda->first_pts;
1014 
1015  ID3D11Texture2D_GetDesc(cur_texture, &desc);
1016  if (desc.Format != dda->raw_format ||
1017  (int)desc.Width != dda->raw_width ||
1018  (int)desc.Height != dda->raw_height) {
1019  av_log(avctx, AV_LOG_ERROR, "Output parameters changed!");
1021  goto fail;
1022  }
1023 
1024  frame = ff_get_video_buffer(outlink, dda->width, dda->height);
1025  if (!frame) {
1026  ret = AVERROR(ENOMEM);
1027  goto fail;
1028  }
1029 
1030  box.left = dda->offset_x;
1031  box.top = dda->offset_y;
1032  box.right = box.left + dda->width;
1033  box.bottom = box.top + dda->height;
1034  box.front = 0;
1035  box.back = 1;
1036 
1037  ID3D11DeviceContext_CopySubresourceRegion(
1039  (ID3D11Resource*)frame->data[0], (UINT)(intptr_t)frame->data[1],
1040  0, 0, 0,
1041  (ID3D11Resource*)cur_texture, 0,
1042  &box);
1043 
1044  release_resource(&cur_texture);
1045 
1046  hr = IDXGIOutputDuplication_ReleaseFrame(dda->dxgi_outdupl);
1047  if (FAILED(hr)) {
1048  av_log(avctx, AV_LOG_ERROR, "DDA ReleaseFrame failed!\n");
1050  goto fail;
1051  }
1052 
1053  if (dda->draw_mouse) {
1054  ret = draw_mouse_pointer(avctx, frame);
1055  if (ret < 0)
1056  goto fail;
1057  }
1058 
1059  frame->sample_aspect_ratio = (AVRational){1, 1};
1060 
1061  if (desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM ||
1062  desc.Format == DXGI_FORMAT_R10G10B10A2_UNORM) {
1063  // According to MSDN, all integer formats contain sRGB image data
1064  frame->color_range = AVCOL_RANGE_JPEG;
1065  frame->color_primaries = AVCOL_PRI_BT709;
1066  frame->color_trc = AVCOL_TRC_IEC61966_2_1;
1067  frame->colorspace = AVCOL_SPC_RGB;
1068  } else if(desc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT) {
1069  // According to MSDN, all floating point formats contain sRGB image data with linear 1.0 gamma.
1070  frame->color_range = AVCOL_RANGE_JPEG;
1071  frame->color_primaries = AVCOL_PRI_BT709;
1072  frame->color_trc = AVCOL_TRC_LINEAR;
1073  frame->colorspace = AVCOL_SPC_RGB;
1074  } else {
1075  ret = AVERROR_BUG;
1076  goto fail;
1077  }
1078 
1080  if (ret < 0)
1081  return ret;
1082 
1083 frame_done:
1084  frame->pts = now;
1085  dda->time_frame = time_frame;
1086 
1087  return ff_filter_frame(outlink, frame);
1088 
1089 fail:
1090  if (frame)
1091  av_frame_free(&frame);
1092 
1093  if (cur_texture)
1094  IDXGIOutputDuplication_ReleaseFrame(dda->dxgi_outdupl);
1095 
1096  release_resource(&cur_texture);
1097  return ret;
1098 }
1099 
1100 static const AVFilterPad ddagrab_outputs[] = {
1101  {
1102  .name = "default",
1103  .type = AVMEDIA_TYPE_VIDEO,
1104  .request_frame = ddagrab_request_frame,
1105  .config_props = ddagrab_config_props,
1106  },
1107 };
1108 
1110  .name = "ddagrab",
1111  .description = NULL_IF_CONFIG_SMALL("Grab Windows Desktop images using Desktop Duplication API"),
1112  .priv_size = sizeof(DdagrabContext),
1113  .priv_class = &ddagrab_class,
1114  .init = ddagrab_init,
1116  .inputs = NULL,
1119  .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE,
1120  .flags = AVFILTER_FLAG_HWDEVICE,
1121 };
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
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:80
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
TIMER_RES
#define TIMER_RES
Definition: vsrc_ddagrab.c:51
DdagrabContext::force_fmt
int force_fmt
Definition: vsrc_ddagrab.c:100
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:803
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:327
ConstBufferData::width
float width
Definition: vsrc_ddagrab.c:315
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
AVCOL_TRC_LINEAR
@ AVCOL_TRC_LINEAR
"Linear transfer characteristics"
Definition: pixfmt.h:575
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:601
DdagrabContext::blend_state
ID3D11BlendState * blend_state
Definition: vsrc_ddagrab.c:89
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
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
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
w
uint8_t w
Definition: llviddspenc.c:38
AVCOL_RANGE_JPEG
@ AVCOL_RANGE_JPEG
Full range content.
Definition: pixfmt.h:669
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:944
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:596
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:94
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:76
AVFilter::name
const char * name
Filter name.
Definition: avfilter.h:170
ff_vsrc_ddagrab
const AVFilter ff_vsrc_ddagrab
Definition: vsrc_ddagrab.c:1109
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
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:580
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:86
AV_HWDEVICE_TYPE_D3D11VA
@ AV_HWDEVICE_TYPE_D3D11VA
Definition: hwcontext.h:35
DdagrabContext::framerate
AVRational framerate
Definition: vsrc_ddagrab.c:93
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:105
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:79
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:432
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:321
ConstBufferData
Definition: vsrc_ddagrab.c:313
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
if
if(ret)
Definition: filter_design.txt:179
ConstBufferData::height
float height
Definition: vsrc_ddagrab.c:316
fixup_color_mask
static void fixup_color_mask(uint8_t *buf, int width, int height, int pitch)
Definition: vsrc_ddagrab.c:511
DdagrabContext::vertex_shader
ID3D11VertexShader * vertex_shader
Definition: vsrc_ddagrab.c:84
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:728
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:87
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:543
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:138
AV_PIX_FMT_X2BGR10
#define AV_PIX_FMT_X2BGR10
Definition: pixfmt.h:523
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:129
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:98
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:73
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:104
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:78
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
convert_mono_buffer
static uint8_t * convert_mono_buffer(uint8_t *input, int *_width, int *_height, int *_pitch)
Definition: vsrc_ddagrab.c:485
DdagrabContext::draw_mouse
int draw_mouse
Definition: vsrc_ddagrab.c:92
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:99
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:97
stride
#define stride
Definition: h264pred_template.c:537
DdagrabContext::time_timeout
int64_t time_timeout
Definition: vsrc_ddagrab.c:75
AVFilter
Filter definition.
Definition: avfilter.h:166
DdagrabContext::output_idx
int output_idx
Definition: vsrc_ddagrab.c:91
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
frame
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 the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
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:160
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:85
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:74
DdagrabContext::height
int height
Definition: vsrc_ddagrab.c:95
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:680
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:524
AV_PIX_FMT_RGBAF16
#define AV_PIX_FMT_RGBAF16
Definition: pixfmt.h:532
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:88
ddagrab_outputs
static const AVFilterPad ddagrab_outputs[]
Definition: vsrc_ddagrab.c:1100
DdagrabContext::offset_x
int offset_x
Definition: vsrc_ddagrab.c:96
DdagrabContext::probed_texture
ID3D11Texture2D * probed_texture
Definition: vsrc_ddagrab.c:82
ddagrab_init
static av_cold int ddagrab_init(AVFilterContext *avctx)
Definition: vsrc_ddagrab.c:418
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:318
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
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Definition: opt.h:234
hwcontext_d3d11va.h
OFFSET
#define OFFSET(x)
Definition: vsrc_ddagrab.c:103
probe_output_format
static int probe_output_format(AVFilterContext *avctx)
Definition: vsrc_ddagrab.c:652
w32dlfcn.h