FFmpeg
gdigrab.c
Go to the documentation of this file.
1 /*
2  * GDI video grab interface
3  *
4  * This file is part of FFmpeg.
5  *
6  * Copyright (C) 2013 Calvin Walton <calvin.walton@kepstin.ca>
7  * Copyright (C) 2007-2010 Christophe Gisquet <word1.word2@gmail.com>
8  *
9  * FFmpeg is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * FFmpeg is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with FFmpeg; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  */
23 
24 /**
25  * @file
26  * GDI frame device demuxer
27  * @author Calvin Walton <calvin.walton@kepstin.ca>
28  * @author Christophe Gisquet <word1.word2@gmail.com>
29  */
30 
31 #include "config.h"
32 #include "libavformat/internal.h"
33 #include "libavutil/opt.h"
34 #include "libavutil/time.h"
36 #include <windows.h>
37 
38 /**
39  * GDI Device Demuxer context
40  */
41 struct gdigrab {
42  const AVClass *class; /**< Class for private options */
43 
44  int frame_size; /**< Size in bytes of the frame pixel data */
45  int header_size; /**< Size in bytes of the DIB header */
46  AVRational time_base; /**< Time base */
47  int64_t time_frame; /**< Current time */
48 
49  int draw_mouse; /**< Draw mouse cursor (private option) */
50  int show_region; /**< Draw border (private option) */
51  AVRational framerate; /**< Capture framerate (private option) */
52  int width; /**< Width of the grab frame (private option) */
53  int height; /**< Height of the grab frame (private option) */
54  int offset_x; /**< Capture x offset (private option) */
55  int offset_y; /**< Capture y offset (private option) */
56 
57  HWND hwnd; /**< Handle of the window for the grab */
58  HDC source_hdc; /**< Source device context */
59  HDC dest_hdc; /**< Destination, source-compatible DC */
60  BITMAPINFO bmi; /**< Information describing DIB format */
61  HBITMAP hbmp; /**< Information on the bitmap captured */
62  void *buffer; /**< The buffer containing the bitmap image data */
63  RECT clip_rect; /**< The subarea of the screen or window to clip */
64 
65  HWND region_hwnd; /**< Handle of the region border window */
66 
68 };
69 
70 #define WIN32_API_ERROR(str) \
71  av_log(s1, AV_LOG_ERROR, str " (error %li)\n", GetLastError())
72 
73 #define REGION_WND_BORDER 3
74 
75 /**
76  * Callback to handle Windows messages for the region outline window.
77  *
78  * In particular, this handles painting the frame rectangle.
79  *
80  * @param hwnd The region outline window handle.
81  * @param msg The Windows message.
82  * @param wparam First Windows message parameter.
83  * @param lparam Second Windows message parameter.
84  * @return 0 success, !0 failure
85  */
86 static LRESULT CALLBACK
87 gdigrab_region_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
88 {
89  PAINTSTRUCT ps;
90  HDC hdc;
91  RECT rect;
92 
93  switch (msg) {
94  case WM_PAINT:
95  hdc = BeginPaint(hwnd, &ps);
96 
97  GetClientRect(hwnd, &rect);
98  FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
99 
100  rect.left++; rect.top++; rect.right--; rect.bottom--;
101  FrameRect(hdc, &rect, GetStockObject(WHITE_BRUSH));
102 
103  rect.left++; rect.top++; rect.right--; rect.bottom--;
104  FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
105 
106  EndPaint(hwnd, &ps);
107  break;
108  default:
109  return DefWindowProc(hwnd, msg, wparam, lparam);
110  }
111  return 0;
112 }
113 
114 /**
115  * Initialize the region outline window.
116  *
117  * @param s1 The format context.
118  * @param gdigrab gdigrab context.
119  * @return 0 success, !0 failure
120  */
121 static int
123 {
124  HWND hwnd;
125  RECT rect = gdigrab->clip_rect;
126  HRGN region = NULL;
127  HRGN region_interior = NULL;
128 
129  DWORD style = WS_POPUP | WS_VISIBLE;
130  DWORD ex = WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_TRANSPARENT;
131 
133  rect.right += REGION_WND_BORDER; rect.bottom += REGION_WND_BORDER;
134 
135  AdjustWindowRectEx(&rect, style, FALSE, ex);
136 
137  // Create a window with no owner; use WC_DIALOG instead of writing a custom
138  // window class
139  hwnd = CreateWindowEx(ex, WC_DIALOG, NULL, style, rect.left, rect.top,
140  rect.right - rect.left, rect.bottom - rect.top,
141  NULL, NULL, NULL, NULL);
142  if (!hwnd) {
143  WIN32_API_ERROR("Could not create region display window");
144  goto error;
145  }
146 
147  // Set the window shape to only include the border area
148  GetClientRect(hwnd, &rect);
149  region = CreateRectRgn(0, 0,
150  rect.right - rect.left, rect.bottom - rect.top);
151  region_interior = CreateRectRgn(REGION_WND_BORDER, REGION_WND_BORDER,
152  rect.right - rect.left - REGION_WND_BORDER,
153  rect.bottom - rect.top - REGION_WND_BORDER);
154  CombineRgn(region, region, region_interior, RGN_DIFF);
155  if (!SetWindowRgn(hwnd, region, FALSE)) {
156  WIN32_API_ERROR("Could not set window region");
157  goto error;
158  }
159  // The "region" memory is now owned by the window
160  region = NULL;
161  DeleteObject(region_interior);
162 
163  SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) gdigrab_region_wnd_proc);
164 
165  ShowWindow(hwnd, SW_SHOW);
166 
167  gdigrab->region_hwnd = hwnd;
168 
169  return 0;
170 
171 error:
172  if (region)
173  DeleteObject(region);
174  if (region_interior)
175  DeleteObject(region_interior);
176  if (hwnd)
177  DestroyWindow(hwnd);
178  return 1;
179 }
180 
181 /**
182  * Cleanup/free the region outline window.
183  *
184  * @param s1 The format context.
185  * @param gdigrab gdigrab context.
186  */
187 static void
189 {
190  if (gdigrab->region_hwnd)
191  DestroyWindow(gdigrab->region_hwnd);
193 }
194 
195 /**
196  * Process the Windows message queue.
197  *
198  * This is important to prevent Windows from thinking the window has become
199  * unresponsive. As well, things like WM_PAINT (to actually draw the window
200  * contents) are handled from the message queue context.
201  *
202  * @param s1 The format context.
203  * @param gdigrab gdigrab context.
204  */
205 static void
207 {
208  HWND hwnd = gdigrab->region_hwnd;
209  MSG msg;
210 
211  while (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) {
212  DispatchMessage(&msg);
213  }
214 }
215 
216 /**
217  * Initializes the gdi grab device demuxer (public device demuxer API).
218  *
219  * @param s1 Context from avformat core
220  * @return AVERROR_IO error, 0 success
221  */
222 static int
224 {
225  struct gdigrab *gdigrab = s1->priv_data;
226 
227  HWND hwnd;
228  HDC source_hdc = NULL;
229  HDC dest_hdc = NULL;
230  BITMAPINFO bmi;
231  HBITMAP hbmp = NULL;
232  void *buffer = NULL;
233 
234  const char *filename = s1->url;
235  const char *name = NULL;
236  AVStream *st = NULL;
237 
238  int bpp;
239  int horzres;
240  int vertres;
241  int desktophorzres;
242  int desktopvertres;
243  RECT virtual_rect;
244  RECT clip_rect;
245  BITMAP bmp;
246  int ret;
247 
248  if (!strncmp(filename, "title=", 6)) {
249  wchar_t *name_w = NULL;
250  name = filename + 6;
251 
252  if(utf8towchar(name, &name_w)) {
253  ret = AVERROR(errno);
254  goto error;
255  }
256  if(!name_w) {
257  ret = AVERROR(EINVAL);
258  goto error;
259  }
260 
261  hwnd = FindWindowW(NULL, name_w);
262  av_freep(&name_w);
263  if (!hwnd) {
265  "Can't find window '%s', aborting.\n", name);
266  ret = AVERROR(EIO);
267  goto error;
268  }
269  if (gdigrab->show_region) {
271  "Can't show region when grabbing a window.\n");
272  gdigrab->show_region = 0;
273  }
274  } else if (!strcmp(filename, "desktop")) {
275  hwnd = NULL;
276  } else {
278  "Please use \"desktop\" or \"title=<windowname>\" to specify your target.\n");
279  ret = AVERROR(EIO);
280  goto error;
281  }
282 
283  /* This will get the device context for the selected window, or if
284  * none, the primary screen */
285  source_hdc = GetDC(hwnd);
286  if (!source_hdc) {
287  WIN32_API_ERROR("Couldn't get window device context");
288  ret = AVERROR(EIO);
289  goto error;
290  }
291  bpp = GetDeviceCaps(source_hdc, BITSPIXEL);
292 
293  horzres = GetDeviceCaps(source_hdc, HORZRES);
294  vertres = GetDeviceCaps(source_hdc, VERTRES);
295  desktophorzres = GetDeviceCaps(source_hdc, DESKTOPHORZRES);
296  desktopvertres = GetDeviceCaps(source_hdc, DESKTOPVERTRES);
297 
298  if (hwnd) {
299  GetClientRect(hwnd, &virtual_rect);
300  /* window -- get the right height and width for scaling DPI */
301  virtual_rect.left = virtual_rect.left * desktophorzres / horzres;
302  virtual_rect.right = virtual_rect.right * desktophorzres / horzres;
303  virtual_rect.top = virtual_rect.top * desktopvertres / vertres;
304  virtual_rect.bottom = virtual_rect.bottom * desktopvertres / vertres;
305  } else {
306  /* desktop -- get the right height and width for scaling DPI */
307  virtual_rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
308  virtual_rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
309  virtual_rect.right = (virtual_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN)) * desktophorzres / horzres;
310  virtual_rect.bottom = (virtual_rect.top + GetSystemMetrics(SM_CYVIRTUALSCREEN)) * desktopvertres / vertres;
311  }
312 
313  /* If no width or height set, use full screen/window area */
314  if (!gdigrab->width || !gdigrab->height) {
315  clip_rect.left = virtual_rect.left;
316  clip_rect.top = virtual_rect.top;
317  clip_rect.right = virtual_rect.right;
318  clip_rect.bottom = virtual_rect.bottom;
319  } else {
320  clip_rect.left = gdigrab->offset_x;
321  clip_rect.top = gdigrab->offset_y;
322  clip_rect.right = gdigrab->width + gdigrab->offset_x;
323  clip_rect.bottom = gdigrab->height + gdigrab->offset_y;
324  }
325 
326  if (clip_rect.left < virtual_rect.left ||
327  clip_rect.top < virtual_rect.top ||
328  clip_rect.right > virtual_rect.right ||
329  clip_rect.bottom > virtual_rect.bottom) {
331  "Capture area (%li,%li),(%li,%li) extends outside window area (%li,%li),(%li,%li)",
332  clip_rect.left, clip_rect.top,
333  clip_rect.right, clip_rect.bottom,
334  virtual_rect.left, virtual_rect.top,
335  virtual_rect.right, virtual_rect.bottom);
336  ret = AVERROR(EIO);
337  goto error;
338  }
339 
340 
341  if (name) {
343  "Found window %s, capturing %lix%lix%i at (%li,%li)\n",
344  name,
345  clip_rect.right - clip_rect.left,
346  clip_rect.bottom - clip_rect.top,
347  bpp, clip_rect.left, clip_rect.top);
348  } else {
350  "Capturing whole desktop as %lix%lix%i at (%li,%li)\n",
351  clip_rect.right - clip_rect.left,
352  clip_rect.bottom - clip_rect.top,
353  bpp, clip_rect.left, clip_rect.top);
354  }
355 
356  if (clip_rect.right - clip_rect.left <= 0 ||
357  clip_rect.bottom - clip_rect.top <= 0 || bpp%8) {
358  av_log(s1, AV_LOG_ERROR, "Invalid properties, aborting\n");
359  ret = AVERROR(EIO);
360  goto error;
361  }
362 
363  dest_hdc = CreateCompatibleDC(source_hdc);
364  if (!dest_hdc) {
365  WIN32_API_ERROR("Screen DC CreateCompatibleDC");
366  ret = AVERROR(EIO);
367  goto error;
368  }
369 
370  /* Create a DIB and select it into the dest_hdc */
371  bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
372  bmi.bmiHeader.biWidth = clip_rect.right - clip_rect.left;
373  bmi.bmiHeader.biHeight = -(clip_rect.bottom - clip_rect.top);
374  bmi.bmiHeader.biPlanes = 1;
375  bmi.bmiHeader.biBitCount = bpp;
376  bmi.bmiHeader.biCompression = BI_RGB;
377  bmi.bmiHeader.biSizeImage = 0;
378  bmi.bmiHeader.biXPelsPerMeter = 0;
379  bmi.bmiHeader.biYPelsPerMeter = 0;
380  bmi.bmiHeader.biClrUsed = 0;
381  bmi.bmiHeader.biClrImportant = 0;
382  hbmp = CreateDIBSection(dest_hdc, &bmi, DIB_RGB_COLORS,
383  &buffer, NULL, 0);
384  if (!hbmp) {
385  WIN32_API_ERROR("Creating DIB Section");
386  ret = AVERROR(EIO);
387  goto error;
388  }
389 
390  if (!SelectObject(dest_hdc, hbmp)) {
391  WIN32_API_ERROR("SelectObject");
392  ret = AVERROR(EIO);
393  goto error;
394  }
395 
396  /* Get info from the bitmap */
397  GetObject(hbmp, sizeof(BITMAP), &bmp);
398 
399  st = avformat_new_stream(s1, NULL);
400  if (!st) {
401  ret = AVERROR(ENOMEM);
402  goto error;
403  }
404  avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */
405 
406  gdigrab->frame_size = bmp.bmWidthBytes * bmp.bmHeight * bmp.bmPlanes;
407  gdigrab->header_size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
408  (bpp <= 8 ? (1 << bpp) : 0) * sizeof(RGBQUAD) /* palette size */;
411 
412  gdigrab->hwnd = hwnd;
415  gdigrab->hbmp = hbmp;
416  gdigrab->bmi = bmi;
417  gdigrab->buffer = buffer;
419 
421 
422  if (gdigrab->show_region) {
424  ret = AVERROR(EIO);
425  goto error;
426  }
427  }
428 
430 
434 
435  return 0;
436 
437 error:
438  if (source_hdc)
439  ReleaseDC(hwnd, source_hdc);
440  if (dest_hdc)
441  DeleteDC(dest_hdc);
442  if (hbmp)
443  DeleteObject(hbmp);
444  if (source_hdc)
445  DeleteDC(source_hdc);
446  return ret;
447 }
448 
449 /**
450  * Paints a mouse pointer in a Win32 image.
451  *
452  * @param s1 Context of the log information
453  * @param s Current grad structure
454  */
456 {
457  CURSORINFO ci = {0};
458 
459 #define CURSOR_ERROR(str) \
460  if (!gdigrab->cursor_error_printed) { \
461  WIN32_API_ERROR(str); \
462  gdigrab->cursor_error_printed = 1; \
463  }
464 
465  ci.cbSize = sizeof(ci);
466 
467  if (GetCursorInfo(&ci)) {
468  HCURSOR icon = CopyCursor(ci.hCursor);
469  ICONINFO info;
470  POINT pos;
471  RECT clip_rect = gdigrab->clip_rect;
472  HWND hwnd = gdigrab->hwnd;
473  int horzres = GetDeviceCaps(gdigrab->source_hdc, HORZRES);
474  int vertres = GetDeviceCaps(gdigrab->source_hdc, VERTRES);
475  int desktophorzres = GetDeviceCaps(gdigrab->source_hdc, DESKTOPHORZRES);
476  int desktopvertres = GetDeviceCaps(gdigrab->source_hdc, DESKTOPVERTRES);
477  info.hbmMask = NULL;
478  info.hbmColor = NULL;
479 
480  if (ci.flags != CURSOR_SHOWING)
481  return;
482 
483  if (!icon) {
484  /* Use the standard arrow cursor as a fallback.
485  * You'll probably only hit this in Wine, which can't fetch
486  * the current system cursor. */
487  icon = CopyCursor(LoadCursor(NULL, IDC_ARROW));
488  }
489 
490  if (!GetIconInfo(icon, &info)) {
491  CURSOR_ERROR("Could not get icon info");
492  goto icon_error;
493  }
494 
495  if (hwnd) {
496  RECT rect;
497 
498  if (GetWindowRect(hwnd, &rect)) {
499  pos.x = ci.ptScreenPos.x - clip_rect.left - info.xHotspot - rect.left;
500  pos.y = ci.ptScreenPos.y - clip_rect.top - info.yHotspot - rect.top;
501 
502  //that would keep the correct location of mouse with hidpi screens
503  pos.x = pos.x * desktophorzres / horzres;
504  pos.y = pos.y * desktopvertres / vertres;
505  } else {
506  CURSOR_ERROR("Couldn't get window rectangle");
507  goto icon_error;
508  }
509  } else {
510  //that would keep the correct location of mouse with hidpi screens
511  pos.x = ci.ptScreenPos.x * desktophorzres / horzres - clip_rect.left - info.xHotspot;
512  pos.y = ci.ptScreenPos.y * desktopvertres / vertres - clip_rect.top - info.yHotspot;
513  }
514 
515  av_log(s1, AV_LOG_DEBUG, "Cursor pos (%li,%li) -> (%li,%li)\n",
516  ci.ptScreenPos.x, ci.ptScreenPos.y, pos.x, pos.y);
517 
518  if (pos.x >= 0 && pos.x <= clip_rect.right - clip_rect.left &&
519  pos.y >= 0 && pos.y <= clip_rect.bottom - clip_rect.top) {
520  if (!DrawIcon(gdigrab->dest_hdc, pos.x, pos.y, icon))
521  CURSOR_ERROR("Couldn't draw icon");
522  }
523 
524 icon_error:
525  if (info.hbmMask)
526  DeleteObject(info.hbmMask);
527  if (info.hbmColor)
528  DeleteObject(info.hbmColor);
529  if (icon)
530  DestroyCursor(icon);
531  } else {
532  CURSOR_ERROR("Couldn't get cursor info");
533  }
534 }
535 
536 /**
537  * Grabs a frame from gdi (public device demuxer API).
538  *
539  * @param s1 Context from avformat core
540  * @param pkt Packet holding the grabbed frame
541  * @return frame size in bytes
542  */
544 {
545  struct gdigrab *gdigrab = s1->priv_data;
546 
547  HDC dest_hdc = gdigrab->dest_hdc;
549  RECT clip_rect = gdigrab->clip_rect;
551  int64_t time_frame = gdigrab->time_frame;
552 
553  BITMAPFILEHEADER bfh;
554  int file_size = gdigrab->header_size + gdigrab->frame_size;
555 
556  int64_t curtime, delay;
557 
558  /* Calculate the time of the next frame */
559  time_frame += INT64_C(1000000);
560 
561  /* Run Window message processing queue */
562  if (gdigrab->show_region)
564 
565  /* wait based on the frame rate */
566  for (;;) {
567  curtime = av_gettime_relative();
568  delay = time_frame * av_q2d(time_base) - curtime;
569  if (delay <= 0) {
570  if (delay < INT64_C(-1000000) * av_q2d(time_base)) {
571  time_frame += INT64_C(1000000);
572  }
573  break;
574  }
575  if (s1->flags & AVFMT_FLAG_NONBLOCK) {
576  return AVERROR(EAGAIN);
577  } else {
578  av_usleep(delay);
579  }
580  }
581 
582  if (av_new_packet(pkt, file_size) < 0)
583  return AVERROR(ENOMEM);
584  pkt->pts = av_gettime();
585 
586  /* Blit screen grab */
587  if (!BitBlt(dest_hdc, 0, 0,
588  clip_rect.right - clip_rect.left,
589  clip_rect.bottom - clip_rect.top,
590  source_hdc,
591  clip_rect.left, clip_rect.top, SRCCOPY | CAPTUREBLT)) {
592  WIN32_API_ERROR("Failed to capture image");
593  return AVERROR(EIO);
594  }
595  if (gdigrab->draw_mouse)
597 
598  /* Copy bits to packet data */
599 
600  bfh.bfType = 0x4d42; /* "BM" in little-endian */
601  bfh.bfSize = file_size;
602  bfh.bfReserved1 = 0;
603  bfh.bfReserved2 = 0;
604  bfh.bfOffBits = gdigrab->header_size;
605 
606  memcpy(pkt->data, &bfh, sizeof(bfh));
607 
608  memcpy(pkt->data + sizeof(bfh), &gdigrab->bmi.bmiHeader, sizeof(gdigrab->bmi.bmiHeader));
609 
610  if (gdigrab->bmi.bmiHeader.biBitCount <= 8)
611  GetDIBColorTable(dest_hdc, 0, 1 << gdigrab->bmi.bmiHeader.biBitCount,
612  (RGBQUAD *) (pkt->data + sizeof(bfh) + sizeof(gdigrab->bmi.bmiHeader)));
613 
615 
617 
619 }
620 
621 /**
622  * Closes gdi frame grabber (public device demuxer API).
623  *
624  * @param s1 Context from avformat core
625  * @return 0 success, !0 failure
626  */
628 {
629  struct gdigrab *s = s1->priv_data;
630 
631  if (s->show_region)
633 
634  if (s->source_hdc)
635  ReleaseDC(s->hwnd, s->source_hdc);
636  if (s->dest_hdc)
637  DeleteDC(s->dest_hdc);
638  if (s->hbmp)
639  DeleteObject(s->hbmp);
640  if (s->source_hdc)
641  DeleteDC(s->source_hdc);
642 
643  return 0;
644 }
645 
646 #define OFFSET(x) offsetof(struct gdigrab, x)
647 #define DEC AV_OPT_FLAG_DECODING_PARAM
648 static const AVOption options[] = {
649  { "draw_mouse", "draw the mouse pointer", OFFSET(draw_mouse), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, DEC },
650  { "show_region", "draw border around capture area", OFFSET(show_region), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
651  { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "ntsc"}, 0, INT_MAX, DEC },
652  { "video_size", "set video frame size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
653  { "offset_x", "capture area x offset", OFFSET(offset_x), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
654  { "offset_y", "capture area y offset", OFFSET(offset_y), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC },
655  { NULL },
656 };
657 
658 static const AVClass gdigrab_class = {
659  .class_name = "GDIgrab indev",
660  .item_name = av_default_item_name,
661  .option = options,
662  .version = LIBAVUTIL_VERSION_INT,
664 };
665 
666 /** gdi grabber device demuxer declaration */
668  .name = "gdigrab",
669  .long_name = NULL_IF_CONFIG_SMALL("GDI API Windows frame grabber"),
670  .priv_data_size = sizeof(struct gdigrab),
672  .read_packet = gdigrab_read_packet,
673  .read_close = gdigrab_read_close,
674  .flags = AVFMT_NOFILE,
675  .priv_class = &gdigrab_class,
676 };
error
static void error(const char *err)
Definition: target_bsf_fuzzer.c:31
wchar_filename.h
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
name
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 default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
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
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:768
AVCodecParameters::codec_type
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:56
gdigrab_region_wnd_destroy
static void gdigrab_region_wnd_destroy(AVFormatContext *s1, struct gdigrab *gdigrab)
Cleanup/free the region outline window.
Definition: gdigrab.c:188
ff_gdigrab_demuxer
const AVInputFormat ff_gdigrab_demuxer
gdi grabber device demuxer declaration
Definition: gdigrab.c:667
gdigrab_read_packet
static int gdigrab_read_packet(AVFormatContext *s1, AVPacket *pkt)
Grabs a frame from gdi (public device demuxer API).
Definition: gdigrab.c:543
gdigrab::dest_hdc
HDC dest_hdc
Destination, source-compatible DC.
Definition: gdigrab.c:59
AV_OPT_TYPE_VIDEO_RATE
@ AV_OPT_TYPE_VIDEO_RATE
offset must point to AVRational
Definition: opt.h:237
rect
Definition: f_ebur128.c:77
gdigrab::offset_y
int offset_y
Capture y offset (private option)
Definition: gdigrab.c:55
AVPacket::data
uint8_t * data
Definition: packet.h:373
AVOption
AVOption.
Definition: opt.h:247
AVStream::avg_frame_rate
AVRational avg_frame_rate
Average framerate.
Definition: avformat.h:1015
gdigrab::time_frame
int64_t time_frame
Current time.
Definition: gdigrab.c:47
gdigrab::region_hwnd
HWND region_hwnd
Handle of the region border window.
Definition: gdigrab.c:65
OFFSET
#define OFFSET(x)
Definition: gdigrab.c:646
gdigrab::cursor_error_printed
int cursor_error_printed
Definition: gdigrab.c:67
DEC
#define DEC
Definition: gdigrab.c:647
framerate
int framerate
Definition: h264_levels.c:65
gdigrab::frame_size
int frame_size
Size in bytes of the frame pixel data.
Definition: gdigrab.c:44
pkt
AVPacket * pkt
Definition: movenc.c:59
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
AVInputFormat
Definition: avformat.h:650
gdigrab::height
int height
Height of the grab frame (private option)
Definition: gdigrab.c:53
width
#define width
gdigrab_read_close
static int gdigrab_read_close(AVFormatContext *s1)
Closes gdi frame grabber (public device demuxer API).
Definition: gdigrab.c:627
s
#define s(width, name)
Definition: cbs_vp9.c:257
av_new_packet
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:99
AV_CODEC_ID_BMP
@ AV_CODEC_ID_BMP
Definition: codec_id.h:128
AVInputFormat::name
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:655
s1
#define s1
Definition: regdef.h:38
av_q2d
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
info
MIPS optimizations info
Definition: mips.txt:2
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
av_usleep
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition: time.c:84
WIN32_API_ERROR
#define WIN32_API_ERROR(str)
Definition: gdigrab.c:70
AVFormatContext
Format I/O context.
Definition: avformat.h:1200
internal.h
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1095
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
read_header
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:527
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
gdigrab_region_wnd_proc
static LRESULT CALLBACK gdigrab_region_wnd_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
Callback to handle Windows messages for the region outline window.
Definition: gdigrab.c:87
NULL
#define NULL
Definition: coverity.c:32
gdigrab::bmi
BITMAPINFO bmi
Information describing DIB format.
Definition: gdigrab.c:60
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:234
REGION_WND_BORDER
#define REGION_WND_BORDER
Definition: gdigrab.c:73
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
gdigrab::time_base
AVRational time_base
Time base.
Definition: gdigrab.c:46
gdigrab::header_size
int header_size
Size in bytes of the DIB header.
Definition: gdigrab.c:45
gdigrab::clip_rect
RECT clip_rect
The subarea of the screen or window to clip.
Definition: gdigrab.c:63
time.h
AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT
@ AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT
Definition: log.h:41
paint_mouse_pointer
static void paint_mouse_pointer(AVFormatContext *s1, struct gdigrab *gdigrab)
Paints a mouse pointer in a Win32 image.
Definition: gdigrab.c:455
gdigrab::framerate
AVRational framerate
Capture framerate (private option)
Definition: gdigrab.c:51
gdigrab::hbmp
HBITMAP hbmp
Information on the bitmap captured.
Definition: gdigrab.c:61
gdigrab_read_header
static int gdigrab_read_header(AVFormatContext *s1)
Initializes the gdi grab device demuxer (public device demuxer API).
Definition: gdigrab.c:223
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:117
gdigrab::offset_x
int offset_x
Capture x offset (private option)
Definition: gdigrab.c:54
gdigrab::show_region
int show_region
Draw border (private option)
Definition: gdigrab.c:50
gdigrab::source_hdc
HDC source_hdc
Source device context.
Definition: gdigrab.c:58
gdigrab_class
static const AVClass gdigrab_class
Definition: gdigrab.c:658
AVFMT_NOFILE
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:464
gdigrab::hwnd
HWND hwnd
Handle of the window for the grab.
Definition: gdigrab.c:57
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:366
av_inv_q
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition: rational.h:159
AVFMT_FLAG_NONBLOCK
#define AVFMT_FLAG_NONBLOCK
Do not block when reading packets from input.
Definition: avformat.h:1321
ret
ret
Definition: filter_design.txt:187
AVStream
Stream structure.
Definition: avformat.h:935
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:71
pos
unsigned int pos
Definition: spdifenc.c:412
gdigrab::buffer
void * buffer
The buffer containing the bitmap image data.
Definition: gdigrab.c:62
gdigrab::draw_mouse
int draw_mouse
Draw mouse cursor (private option)
Definition: gdigrab.c:49
gdigrab_region_wnd_init
static int gdigrab_region_wnd_init(AVFormatContext *s1, struct gdigrab *gdigrab)
Initialize the region outline window.
Definition: gdigrab.c:122
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:224
gdigrab
GDI Device Demuxer context.
Definition: gdigrab.c:41
gdigrab_region_wnd_update
static void gdigrab_region_wnd_update(AVFormatContext *s1, struct gdigrab *gdigrab)
Process the Windows message queue.
Definition: gdigrab.c:206
avpriv_set_pts_info
void avpriv_set_pts_info(AVStream *st, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:1196
av_gettime
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:39
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
AVPacket
This structure stores compressed data.
Definition: packet.h:350
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
AVCodecParameters::bit_rate
int64_t bit_rate
The average bitrate of the encoded data (in bits per second).
Definition: codec_par.h:89
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:28
options
static const AVOption options[]
Definition: gdigrab.c:648
gdigrab::width
int width
Width of the grab frame (private option)
Definition: gdigrab.c:52
CURSOR_ERROR
#define CURSOR_ERROR(str)