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