FFmpeg
xcbgrab.c
Go to the documentation of this file.
1 /*
2  * XCB input grabber
3  * Copyright (C) 2014 Luca Barbato <lu_zero@gentoo.org>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "config.h"
23 
24 #include <stdlib.h>
25 #include <string.h>
26 #include <xcb/xcb.h>
27 
28 #if CONFIG_LIBXCB_XFIXES
29 #include <xcb/xfixes.h>
30 #endif
31 
32 #if CONFIG_LIBXCB_SHM
33 #include <sys/shm.h>
34 #include <xcb/shm.h>
35 #endif
36 
37 #if CONFIG_LIBXCB_SHAPE
38 #include <xcb/shape.h>
39 #endif
40 
41 #include "libavutil/internal.h"
42 #include "libavutil/mathematics.h"
43 #include "libavutil/opt.h"
44 #include "libavutil/parseutils.h"
45 #include "libavutil/time.h"
46 
47 #include "libavformat/avformat.h"
48 #include "libavformat/internal.h"
49 
50 typedef struct XCBGrabContext {
51  const AVClass *class;
52 
53  xcb_connection_t *conn;
54  xcb_screen_t *screen;
55  xcb_window_t window;
56 #if CONFIG_LIBXCB_SHM
57  AVBufferPool *shm_pool;
58 #endif
59  int64_t time_frame;
61  int64_t frame_duration;
62 
63  int x, y;
64  int width, height;
66  int bpp;
67 
72  int centered;
74 
75  const char *framerate;
76 
77  int has_shm;
79 
80 #define FOLLOW_CENTER -1
81 
82 #define OFFSET(x) offsetof(XCBGrabContext, x)
83 #define D AV_OPT_FLAG_DECODING_PARAM
84 static const AVOption options[] = {
85  { "x", "Initial x coordinate.", OFFSET(x), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D },
86  { "y", "Initial y coordinate.", OFFSET(y), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D },
87  { "grab_x", "Initial x coordinate.", OFFSET(x), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D },
88  { "grab_y", "Initial y coordinate.", OFFSET(y), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, D },
89  { "video_size", "A string describing frame size, such as 640x480 or hd720.", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL }, 0, 0, D },
90  { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "ntsc" }, 0, 0, D },
91  { "draw_mouse", "Draw the mouse pointer.", OFFSET(draw_mouse), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, D },
92  { "follow_mouse", "Move the grabbing region when the mouse pointer reaches within specified amount of pixels to the edge of region.",
93  OFFSET(follow_mouse), AV_OPT_TYPE_INT, { .i64 = 0 }, FOLLOW_CENTER, INT_MAX, D, "follow_mouse" },
94  { "centered", "Keep the mouse pointer at the center of grabbing region when following.", 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, INT_MIN, INT_MAX, D, "follow_mouse" },
95  { "show_region", "Show the grabbing region.", OFFSET(show_region), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D },
96  { "region_border", "Set the region border thickness.", OFFSET(region_border), AV_OPT_TYPE_INT, { .i64 = 3 }, 1, 128, D },
97  { "select_region", "Select the grabbing region graphically using the pointer.", OFFSET(select_region), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D },
98  { NULL },
99 };
100 
101 static const AVClass xcbgrab_class = {
102  .class_name = "xcbgrab indev",
103  .item_name = av_default_item_name,
104  .option = options,
105  .version = LIBAVUTIL_VERSION_INT,
107 };
108 
110  xcb_query_pointer_reply_t *p,
111  xcb_get_geometry_reply_t *geo)
112 {
113  XCBGrabContext *c = s->priv_data;
114  int x = c->x, y = c->y;
115  int w = c->width, h = c->height, f = c->follow_mouse;
116  int p_x, p_y;
117 
118  if (!p || !geo)
119  return AVERROR(EIO);
120 
121  p_x = p->win_x;
122  p_y = p->win_y;
123 
124  if (f == FOLLOW_CENTER) {
125  x = p_x - w / 2;
126  y = p_y - h / 2;
127  } else {
128  int left = x + f;
129  int right = x + w - f;
130  int top = y + f;
131  int bottom = y + h - f;
132  if (p_x > right) {
133  x += p_x - right;
134  } else if (p_x < left) {
135  x -= left - p_x;
136  }
137  if (p_y > bottom) {
138  y += p_y - bottom;
139  } else if (p_y < top) {
140  y -= top - p_y;
141  }
142  }
143 
144  c->x = FFMIN(FFMAX(0, x), geo->width - w);
145  c->y = FFMIN(FFMAX(0, y), geo->height - h);
146 
147  return 0;
148 }
149 
150 static void xcbgrab_image_reply_free(void *opaque, uint8_t *data)
151 {
152  free(opaque);
153 }
154 
156 {
157  XCBGrabContext *c = s->priv_data;
158  xcb_get_image_cookie_t iq;
159  xcb_get_image_reply_t *img;
160  xcb_drawable_t drawable = c->screen->root;
161  xcb_generic_error_t *e = NULL;
162  uint8_t *data;
163  int length;
164 
165  iq = xcb_get_image(c->conn, XCB_IMAGE_FORMAT_Z_PIXMAP, drawable,
166  c->x, c->y, c->width, c->height, ~0);
167 
168  img = xcb_get_image_reply(c->conn, iq, &e);
169 
170  if (e) {
171  av_log(s, AV_LOG_ERROR,
172  "Cannot get the image data "
173  "event_error: response_type:%u error_code:%u "
174  "sequence:%u resource_id:%u minor_code:%u major_code:%u.\n",
175  e->response_type, e->error_code,
176  e->sequence, e->resource_id, e->minor_code, e->major_code);
177  free(e);
178  return AVERROR(EACCES);
179  }
180 
181  if (!img)
182  return AVERROR(EAGAIN);
183 
184  data = xcb_get_image_data(img);
185  length = xcb_get_image_data_length(img);
186 
187  av_init_packet(pkt);
188 
189  pkt->buf = av_buffer_create(data, length, xcbgrab_image_reply_free, img, 0);
190  if (!pkt->buf) {
191  free(img);
192  return AVERROR(ENOMEM);
193  }
194 
195  pkt->data = data;
196  pkt->size = length;
197 
198  return 0;
199 }
200 
202 {
203  XCBGrabContext *c = s->priv_data;
204  int64_t curtime, delay;
205 
206  c->time_frame += c->frame_duration;
207 
208  for (;;) {
209  curtime = av_gettime();
210  delay = c->time_frame - curtime;
211  if (delay <= 0)
212  break;
213  av_usleep(delay);
214  }
215 
216  return curtime;
217 }
218 
219 #if CONFIG_LIBXCB_SHM
220 static int check_shm(xcb_connection_t *conn)
221 {
222  xcb_shm_query_version_cookie_t cookie = xcb_shm_query_version(conn);
223  xcb_shm_query_version_reply_t *reply;
224 
225  reply = xcb_shm_query_version_reply(conn, cookie, NULL);
226  if (reply) {
227  free(reply);
228  return 1;
229  }
230 
231  return 0;
232 }
233 
234 static void free_shm_buffer(void *opaque, uint8_t *data)
235 {
236  shmdt(data);
237 }
238 
239 static AVBufferRef *allocate_shm_buffer(void *opaque, int size)
240 {
241  xcb_connection_t *conn = opaque;
242  xcb_shm_seg_t segment;
243  AVBufferRef *ref;
244  uint8_t *data;
245  int id;
246 
247  id = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777);
248  if (id == -1)
249  return NULL;
250 
251  segment = xcb_generate_id(conn);
252  xcb_shm_attach(conn, segment, id, 0);
253  data = shmat(id, NULL, 0);
254  shmctl(id, IPC_RMID, 0);
255  if ((intptr_t)data == -1 || !data)
256  return NULL;
257 
258  ref = av_buffer_create(data, size, free_shm_buffer, (void *)(ptrdiff_t)segment, 0);
259  if (!ref)
260  shmdt(data);
261 
262  return ref;
263 }
264 
265 static int xcbgrab_frame_shm(AVFormatContext *s, AVPacket *pkt)
266 {
267  XCBGrabContext *c = s->priv_data;
268  xcb_shm_get_image_cookie_t iq;
269  xcb_shm_get_image_reply_t *img;
270  xcb_drawable_t drawable = c->screen->root;
271  xcb_generic_error_t *e = NULL;
272  AVBufferRef *buf;
273  xcb_shm_seg_t segment;
274 
275  buf = av_buffer_pool_get(c->shm_pool);
276  if (!buf) {
277  av_log(s, AV_LOG_ERROR, "Could not get shared memory buffer.\n");
278  return AVERROR(ENOMEM);
279  }
280  segment = (xcb_shm_seg_t)av_buffer_pool_buffer_get_opaque(buf);
281 
282  iq = xcb_shm_get_image(c->conn, drawable,
283  c->x, c->y, c->width, c->height, ~0,
284  XCB_IMAGE_FORMAT_Z_PIXMAP, segment, 0);
285  img = xcb_shm_get_image_reply(c->conn, iq, &e);
286 
287  xcb_flush(c->conn);
288 
289  if (e) {
290  av_log(s, AV_LOG_ERROR,
291  "Cannot get the image data "
292  "event_error: response_type:%u error_code:%u "
293  "sequence:%u resource_id:%u minor_code:%u major_code:%u.\n",
294  e->response_type, e->error_code,
295  e->sequence, e->resource_id, e->minor_code, e->major_code);
296 
297  free(e);
298  av_buffer_unref(&buf);
299  return AVERROR(EACCES);
300  }
301 
302  free(img);
303 
304  av_init_packet(pkt);
305 
306  pkt->buf = buf;
307  pkt->data = buf->data;
308  pkt->size = c->frame_size;
309 
310  return 0;
311 }
312 #endif /* CONFIG_LIBXCB_SHM */
313 
314 #if CONFIG_LIBXCB_XFIXES
315 static int check_xfixes(xcb_connection_t *conn)
316 {
317  xcb_xfixes_query_version_cookie_t cookie;
318  xcb_xfixes_query_version_reply_t *reply;
319 
320  cookie = xcb_xfixes_query_version(conn, XCB_XFIXES_MAJOR_VERSION,
321  XCB_XFIXES_MINOR_VERSION);
322  reply = xcb_xfixes_query_version_reply(conn, cookie, NULL);
323 
324  if (reply) {
325  free(reply);
326  return 1;
327  }
328  return 0;
329 }
330 
331 #define BLEND(target, source, alpha) \
332  (target) + ((source) * (255 - (alpha)) + 255 / 2) / 255
333 
334 static void xcbgrab_draw_mouse(AVFormatContext *s, AVPacket *pkt,
335  xcb_query_pointer_reply_t *p,
336  xcb_get_geometry_reply_t *geo)
337 {
338  XCBGrabContext *gr = s->priv_data;
339  uint32_t *cursor;
340  uint8_t *image = pkt->data;
341  int stride = gr->bpp / 8;
342  xcb_xfixes_get_cursor_image_cookie_t cc;
343  xcb_xfixes_get_cursor_image_reply_t *ci;
344  int cx, cy, x, y, w, h, c_off, i_off;
345 
346  cc = xcb_xfixes_get_cursor_image(gr->conn);
347  ci = xcb_xfixes_get_cursor_image_reply(gr->conn, cc, NULL);
348  if (!ci)
349  return;
350 
351  cursor = xcb_xfixes_get_cursor_image_cursor_image(ci);
352  if (!cursor)
353  return;
354 
355  cx = ci->x - ci->xhot;
356  cy = ci->y - ci->yhot;
357 
358  x = FFMAX(cx, gr->x);
359  y = FFMAX(cy, gr->y);
360 
361  w = FFMIN(cx + ci->width, gr->x + gr->width) - x;
362  h = FFMIN(cy + ci->height, gr->y + gr->height) - y;
363 
364  c_off = x - cx;
365  i_off = x - gr->x;
366 
367  cursor += (y - cy) * ci->width;
368  image += (y - gr->y) * gr->width * stride;
369 
370  for (y = 0; y < h; y++) {
371  cursor += c_off;
372  image += i_off * stride;
373  for (x = 0; x < w; x++, cursor++, image += stride) {
374  int r, g, b, a;
375 
376  r = *cursor & 0xff;
377  g = (*cursor >> 8) & 0xff;
378  b = (*cursor >> 16) & 0xff;
379  a = (*cursor >> 24) & 0xff;
380 
381  if (!a)
382  continue;
383 
384  if (a == 255) {
385  image[0] = r;
386  image[1] = g;
387  image[2] = b;
388  } else {
389  image[0] = BLEND(r, image[0], a);
390  image[1] = BLEND(g, image[1], a);
391  image[2] = BLEND(b, image[2], a);
392  }
393 
394  }
395  cursor += ci->width - w - c_off;
396  image += (gr->width - w - i_off) * stride;
397  }
398 
399  free(ci);
400 }
401 #endif /* CONFIG_LIBXCB_XFIXES */
402 
404 {
405  XCBGrabContext *c = s->priv_data;
406  const uint32_t args[] = { c->x - c->region_border,
407  c->y - c->region_border };
408 
409  xcb_configure_window(c->conn,
410  c->window,
411  XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
412  args);
413 }
414 
416 {
417  XCBGrabContext *c = s->priv_data;
418  xcb_query_pointer_cookie_t pc;
419  xcb_get_geometry_cookie_t gc;
420  xcb_query_pointer_reply_t *p = NULL;
421  xcb_get_geometry_reply_t *geo = NULL;
422  int ret = 0;
423  int64_t pts;
424 
425  pts = wait_frame(s, pkt);
426 
427  if (c->follow_mouse || c->draw_mouse) {
428  pc = xcb_query_pointer(c->conn, c->screen->root);
429  gc = xcb_get_geometry(c->conn, c->screen->root);
430  p = xcb_query_pointer_reply(c->conn, pc, NULL);
431  if (!p) {
432  av_log(s, AV_LOG_ERROR, "Failed to query xcb pointer\n");
433  return AVERROR_EXTERNAL;
434  }
435  geo = xcb_get_geometry_reply(c->conn, gc, NULL);
436  if (!geo) {
437  av_log(s, AV_LOG_ERROR, "Failed to get xcb geometry\n");
438  free(p);
439  return AVERROR_EXTERNAL;
440  }
441  }
442 
443  if (c->follow_mouse && p->same_screen)
444  xcbgrab_reposition(s, p, geo);
445 
446  if (c->show_region)
448 
449 #if CONFIG_LIBXCB_SHM
450  if (c->has_shm && xcbgrab_frame_shm(s, pkt) < 0) {
451  av_log(s, AV_LOG_WARNING, "Continuing without shared memory.\n");
452  c->has_shm = 0;
453  }
454 #endif
455  if (!c->has_shm)
456  ret = xcbgrab_frame(s, pkt);
457  pkt->dts = pkt->pts = pts;
458  pkt->duration = c->frame_duration;
459 
460 #if CONFIG_LIBXCB_XFIXES
461  if (ret >= 0 && c->draw_mouse && p->same_screen)
462  xcbgrab_draw_mouse(s, pkt, p, geo);
463 #endif
464 
465  free(p);
466  free(geo);
467 
468  return ret;
469 }
470 
472 {
474 
475 #if CONFIG_LIBXCB_SHM
476  av_buffer_pool_uninit(&ctx->shm_pool);
477 #endif
478 
479  xcb_disconnect(ctx->conn);
480 
481  return 0;
482 }
483 
484 static xcb_screen_t *get_screen(const xcb_setup_t *setup, int screen_num)
485 {
486  xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup);
487  xcb_screen_t *screen = NULL;
488 
489  for (; it.rem > 0; xcb_screen_next (&it)) {
490  if (!screen_num) {
491  screen = it.data;
492  break;
493  }
494 
495  screen_num--;
496  }
497 
498  return screen;
499 }
500 
502  int *pix_fmt, int *bpp)
503 {
504  XCBGrabContext *c = s->priv_data;
505  const xcb_setup_t *setup = xcb_get_setup(c->conn);
506  const xcb_format_t *fmt = xcb_setup_pixmap_formats(setup);
507  int length = xcb_setup_pixmap_formats_length(setup);
508 
509  *pix_fmt = 0;
510 
511  while (length--) {
512  if (fmt->depth == depth) {
513  switch (depth) {
514  case 32:
515  if (fmt->bits_per_pixel == 32)
516  *pix_fmt = AV_PIX_FMT_0RGB;
517  break;
518  case 24:
519  if (fmt->bits_per_pixel == 32)
520  *pix_fmt = AV_PIX_FMT_0RGB32;
521  else if (fmt->bits_per_pixel == 24)
522  *pix_fmt = AV_PIX_FMT_RGB24;
523  break;
524  case 16:
525  if (fmt->bits_per_pixel == 16)
526  *pix_fmt = AV_PIX_FMT_RGB565;
527  break;
528  case 15:
529  if (fmt->bits_per_pixel == 16)
530  *pix_fmt = AV_PIX_FMT_RGB555;
531  break;
532  case 8:
533  if (fmt->bits_per_pixel == 8)
534  *pix_fmt = AV_PIX_FMT_RGB8;
535  break;
536  }
537  }
538 
539  if (*pix_fmt) {
540  *bpp = fmt->bits_per_pixel;
541  return 0;
542  }
543 
544  fmt++;
545  }
546  avpriv_report_missing_feature(s, "Mapping this pixmap format");
547 
548  return AVERROR_PATCHWELCOME;
549 }
550 
552 {
553  XCBGrabContext *c = s->priv_data;
555  xcb_get_geometry_cookie_t gc;
556  xcb_get_geometry_reply_t *geo;
557  int64_t frame_size_bits;
558  int ret;
559 
560  if (!st)
561  return AVERROR(ENOMEM);
562 
564  if (ret < 0)
565  return ret;
566 
567  avpriv_set_pts_info(st, 64, 1, 1000000);
568 
569  gc = xcb_get_geometry(c->conn, c->screen->root);
570  geo = xcb_get_geometry_reply(c->conn, gc, NULL);
571  if (!geo)
572  return AVERROR_EXTERNAL;
573 
574  if (!c->width || !c->height) {
575  c->width = geo->width;
576  c->height = geo->height;
577  }
578 
579  if (c->x + c->width > geo->width ||
580  c->y + c->height > geo->height) {
581  av_log(s, AV_LOG_ERROR,
582  "Capture area %dx%d at position %d.%d "
583  "outside the screen size %dx%d\n",
584  c->width, c->height,
585  c->x, c->y,
586  geo->width, geo->height);
587  free(geo);
588  return AVERROR(EINVAL);
589  }
590 
592  st->avg_frame_rate.num };
594  c->time_frame = av_gettime();
595 
596  ret = pixfmt_from_pixmap_format(s, geo->depth, &st->codecpar->format, &c->bpp);
597  free(geo);
598  if (ret < 0)
599  return ret;
600 
601  frame_size_bits = (int64_t)c->width * c->height * c->bpp;
602  if (frame_size_bits / 8 + AV_INPUT_BUFFER_PADDING_SIZE > INT_MAX) {
603  av_log(s, AV_LOG_ERROR, "Captured area is too large\n");
604  return AVERROR_PATCHWELCOME;
605  }
606  c->frame_size = frame_size_bits / 8;
607 
608 #if CONFIG_LIBXCB_SHM
610  c->conn, allocate_shm_buffer, NULL);
611  if (!c->shm_pool)
612  return AVERROR(ENOMEM);
613 #endif
614 
617  st->codecpar->width = c->width;
618  st->codecpar->height = c->height;
619  st->codecpar->bit_rate = av_rescale(frame_size_bits, st->avg_frame_rate.num, st->avg_frame_rate.den);
620 
621  return ret;
622 }
623 
625 {
626  XCBGrabContext *c = s->priv_data;
627  xcb_gcontext_t gc = xcb_generate_id(c->conn);
628  uint32_t mask = XCB_GC_FOREGROUND |
629  XCB_GC_BACKGROUND |
630  XCB_GC_LINE_WIDTH |
631  XCB_GC_LINE_STYLE |
632  XCB_GC_FILL_STYLE;
633  uint32_t values[] = { c->screen->black_pixel,
634  c->screen->white_pixel,
635  c->region_border,
636  XCB_LINE_STYLE_DOUBLE_DASH,
637  XCB_FILL_STYLE_SOLID };
638  xcb_rectangle_t r = { 1, 1,
639  c->width + c->region_border * 2 - 3,
640  c->height + c->region_border * 2 - 3 };
641 
642  xcb_create_gc(c->conn, gc, c->window, mask, values);
643 
644  xcb_poly_rectangle(c->conn, c->window, gc, 1, &r);
645 }
646 
648 {
649  XCBGrabContext *c = s->priv_data;
650  uint32_t mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
651  uint32_t values[] = { 1,
652  XCB_EVENT_MASK_EXPOSURE |
653  XCB_EVENT_MASK_STRUCTURE_NOTIFY };
654  av_unused xcb_rectangle_t rect = { 0, 0, c->width, c->height };
655 
656  c->window = xcb_generate_id(c->conn);
657 
658  xcb_create_window(c->conn, XCB_COPY_FROM_PARENT,
659  c->window,
660  c->screen->root,
661  c->x - c->region_border,
662  c->y - c->region_border,
663  c->width + c->region_border * 2,
664  c->height + c->region_border * 2,
665  0,
666  XCB_WINDOW_CLASS_INPUT_OUTPUT,
667  XCB_COPY_FROM_PARENT,
668  mask, values);
669 
670 #if CONFIG_LIBXCB_SHAPE
671  xcb_shape_rectangles(c->conn, XCB_SHAPE_SO_SUBTRACT,
672  XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
673  c->window,
675  1, &rect);
676 #endif
677 
678  xcb_map_window(c->conn, c->window);
679 
680  draw_rectangle(s);
681 }
682 
683 #define CROSSHAIR_CURSOR 34
684 
685 static xcb_rectangle_t rectangle_from_corners(xcb_point_t *corner_a,
686  xcb_point_t *corner_b)
687 {
688  xcb_rectangle_t rectangle;
689  rectangle.x = FFMIN(corner_a->x, corner_b->x);
690  rectangle.y = FFMIN(corner_a->y, corner_b->y);
691  rectangle.width = FFABS(corner_a->x - corner_b->x);
692  rectangle.height = FFABS(corner_a->y - corner_b->y);
693  return rectangle;
694 }
695 
697 {
698  XCBGrabContext *c = s->priv_data;
699  xcb_connection_t *conn = c->conn;
700  xcb_screen_t *screen = c->screen;
701 
702  int ret = 0, done = 0, was_pressed = 0;
703  xcb_cursor_t cursor;
704  xcb_font_t cursor_font;
705  xcb_point_t press_position;
706  xcb_generic_event_t *event;
707  xcb_rectangle_t rectangle = { 0 };
708  xcb_grab_pointer_reply_t *reply;
709  xcb_grab_pointer_cookie_t cookie;
710 
711  xcb_window_t root_window = screen->root;
712  xcb_gcontext_t gc = xcb_generate_id(conn);
713  uint32_t mask = XCB_GC_FUNCTION | XCB_GC_SUBWINDOW_MODE;
714  uint32_t values[] = { XCB_GX_INVERT, XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS };
715  xcb_create_gc(conn, gc, root_window, mask, values);
716 
717  cursor_font = xcb_generate_id(conn);
718  xcb_open_font(conn, cursor_font, strlen("cursor"), "cursor");
719  cursor = xcb_generate_id(conn);
720  xcb_create_glyph_cursor(conn, cursor, cursor_font, cursor_font,
721  CROSSHAIR_CURSOR, CROSSHAIR_CURSOR + 1, 0, 0, 0,
722  0xFFFF, 0xFFFF, 0xFFFF);
723  cookie = xcb_grab_pointer(conn, 0, root_window,
724  XCB_EVENT_MASK_BUTTON_PRESS |
725  XCB_EVENT_MASK_BUTTON_RELEASE |
726  XCB_EVENT_MASK_BUTTON_MOTION,
727  XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
728  root_window, cursor, XCB_CURRENT_TIME);
729  reply = xcb_grab_pointer_reply(conn, cookie, NULL);
730  if (!reply || reply->status != XCB_GRAB_STATUS_SUCCESS) {
731  av_log(s, AV_LOG_ERROR,
732  "Failed to select region. Could not grab pointer.\n");
733  ret = AVERROR(EIO);
734  free(reply);
735  goto fail;
736  }
737  free(reply);
738 
739  xcb_grab_server(conn);
740 
741  while (!done && (event = xcb_wait_for_event(conn))) {
742  switch (event->response_type & ~0x80) {
743  case XCB_BUTTON_PRESS: {
744  xcb_button_press_event_t *press = (xcb_button_press_event_t *)event;
745  press_position = (xcb_point_t){ press->event_x, press->event_y };
746  rectangle.x = press_position.x;
747  rectangle.y = press_position.y;
748  xcb_poly_rectangle(conn, root_window, gc, 1, &rectangle);
749  was_pressed = 1;
750  break;
751  }
752  case XCB_MOTION_NOTIFY: {
753  if (was_pressed) {
754  xcb_motion_notify_event_t *motion =
755  (xcb_motion_notify_event_t *)event;
756  xcb_point_t cursor_position = { motion->event_x, motion->event_y };
757  xcb_poly_rectangle(conn, root_window, gc, 1, &rectangle);
758  rectangle = rectangle_from_corners(&press_position, &cursor_position);
759  xcb_poly_rectangle(conn, root_window, gc, 1, &rectangle);
760  }
761  break;
762  }
763  case XCB_BUTTON_RELEASE: {
764  xcb_poly_rectangle(conn, root_window, gc, 1, &rectangle);
765  done = 1;
766  break;
767  }
768  default:
769  break;
770  }
771  xcb_flush(conn);
772  free(event);
773  }
774  c->width = rectangle.width;
775  c->height = rectangle.height;
776  if (c->width && c->height) {
777  c->x = rectangle.x;
778  c->y = rectangle.y;
779  } else {
780  c->x = 0;
781  c->y = 0;
782  }
783  xcb_ungrab_server(conn);
784  xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
785  xcb_flush(conn);
786 
787 fail:
788  xcb_free_cursor(conn, cursor);
789  xcb_close_font(conn, cursor_font);
790  xcb_free_gc(conn, gc);
791  return ret;
792 }
793 
795 {
796  XCBGrabContext *c = s->priv_data;
797  int screen_num, ret;
798  const xcb_setup_t *setup;
799  char *display_name = av_strdup(s->url);
800 
801  if (!display_name)
802  return AVERROR(ENOMEM);
803 
804  if (!sscanf(s->url, "%[^+]+%d,%d", display_name, &c->x, &c->y)) {
805  *display_name = 0;
806  sscanf(s->url, "+%d,%d", &c->x, &c->y);
807  }
808 
809  c->conn = xcb_connect(display_name[0] ? display_name : NULL, &screen_num);
810  av_freep(&display_name);
811 
812  if ((ret = xcb_connection_has_error(c->conn))) {
813  av_log(s, AV_LOG_ERROR, "Cannot open display %s, error %d.\n",
814  s->url[0] ? s->url : "default", ret);
815  return AVERROR(EIO);
816  }
817 
818  setup = xcb_get_setup(c->conn);
819 
820  c->screen = get_screen(setup, screen_num);
821  if (!c->screen) {
822  av_log(s, AV_LOG_ERROR, "The screen %d does not exist.\n",
823  screen_num);
825  return AVERROR(EIO);
826  }
827 
828  if (c->select_region) {
829  ret = select_region(s);
830  if (ret < 0) {
832  return ret;
833  }
834  }
835 
836  ret = create_stream(s);
837 
838  if (ret < 0) {
840  return ret;
841  }
842 
843 #if CONFIG_LIBXCB_SHM
844  c->has_shm = check_shm(c->conn);
845 #endif
846 
847 #if CONFIG_LIBXCB_XFIXES
848  if (c->draw_mouse) {
849  if (!(c->draw_mouse = check_xfixes(c->conn))) {
851  "XFixes not available, cannot draw the mouse.\n");
852  }
853  if (c->bpp < 24) {
854  avpriv_report_missing_feature(s, "%d bits per pixel screen",
855  c->bpp);
856  c->draw_mouse = 0;
857  }
858  }
859 #endif
860 
861  if (c->show_region)
862  setup_window(s);
863 
864  return 0;
865 }
866 
868  .name = "x11grab",
869  .long_name = NULL_IF_CONFIG_SMALL("X11 screen capture, using XCB"),
870  .priv_data_size = sizeof(XCBGrabContext),
874  .flags = AVFMT_NOFILE,
875  .priv_class = &xcbgrab_class,
876 };
static xcb_screen_t * get_screen(const xcb_setup_t *setup, int screen_num)
Definition: xcbgrab.c:484
AVInputFormat ff_xcbgrab_demuxer
Definition: xcbgrab.c:867
#define NULL
Definition: coverity.c:32
xcb_connection_t * conn
Definition: xcbgrab.c:53
void * av_buffer_pool_buffer_get_opaque(AVBufferRef *ref)
Query the original opaque parameter of an allocated buffer in the pool.
Definition: buffer.c:389
static enum AVPixelFormat pix_fmt
static av_cold int xcbgrab_read_header(AVFormatContext *s)
Definition: xcbgrab.c:794
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:125
int av_parse_video_rate(AVRational *rate, const char *arg)
Parse str and store the detected values in *rate.
Definition: parseutils.c:179
static int create_stream(AVFormatContext *s)
Definition: xcbgrab.c:551
AVOption.
Definition: opt.h:248
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
static void xcbgrab_update_region(AVFormatContext *s)
Definition: xcbgrab.c:403
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
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:4871
const char * g
Definition: vf_curves.c:115
static void draw_rectangle(AVFormatContext *s)
Definition: xcbgrab.c:624
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
int num
Numerator.
Definition: rational.h:59
int size
Definition: packet.h:364
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
xcb_window_t window
Definition: xcbgrab.c:55
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:36
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition: time.c:84
static AVPacket pkt
int centered
Definition: xcbgrab.c:72
Format I/O context.
Definition: avformat.h:1239
#define img
int frame_size
Definition: xcbgrab.c:65
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
uint8_t
#define av_cold
Definition: attributes.h:88
int width
Video only.
Definition: codec_par.h:126
AVOptions.
#define f(width, name)
Definition: cbs_vp9.c:255
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:381
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4453
static const AVClass xcbgrab_class
Definition: xcbgrab.c:101
xcb_screen_t * screen
Definition: xcbgrab.c:54
static int pixfmt_from_pixmap_format(AVFormatContext *s, int depth, int *pix_fmt, int *bpp)
Definition: xcbgrab.c:501
uint8_t * data
Definition: packet.h:363
s EdgeDetect Foobar g libavfilter vf_edgedetect c libavfilter vf_foobar c edit libavfilter and add an entry for foobar following the pattern of the other filters edit libavfilter allfilters and add an entry for foobar following the pattern of the other filters configure make j< whatever > ffmpeg ffmpeg i you should get a foobar png with Lena edge detected That s it
static int xcbgrab_frame(AVFormatContext *s, AVPacket *pkt)
Definition: xcbgrab.c:155
static av_cold int read_close(AVFormatContext *ctx)
Definition: libcdio.c:145
ptrdiff_t size
Definition: opengl_enc.c:100
#define av_log(a,...)
The buffer pool.
int64_t bit_rate
The average bitrate of the encoded data (in bits per second).
Definition: codec_par.h:89
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
#define CROSSHAIR_CURSOR
Definition: xcbgrab.c:683
AVRational time_base
Definition: xcbgrab.c:60
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
static const uint16_t mask[17]
Definition: lzw.c:38
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:153
char * url
input or output URL.
Definition: avformat.h:1335
const char * r
Definition: vf_curves.c:114
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:56
AVBufferRef * buf
A reference to the reference-counted buffer where the packet data is stored.
Definition: packet.h:346
GLsizei GLsizei * length
Definition: opengl_enc.c:114
AVBufferRef * av_buffer_create(uint8_t *data, int size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:29
AVRational avg_frame_rate
Average framerate.
Definition: avformat.h:953
#define FFMAX(a, b)
Definition: common.h:94
#define fail()
Definition: checkasm.h:123
Definition: hls.c:68
common internal API header
#define b
Definition: input.c:41
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
Definition: mathematics.c:129
#define FFMIN(a, b)
Definition: common.h:96
static const AVOption options[]
Definition: xcbgrab.c:84
const char * framerate
Definition: xcbgrab.c:75
uint8_t w
Definition: llviddspenc.c:38
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 values
AVFormatContext * ctx
Definition: movenc.c:48
#define FFABS(a)
Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they are not representable ...
Definition: common.h:72
#define s(width, name)
Definition: cbs_vp9.c:257
AVBufferPool * av_buffer_pool_init2(int size, void *opaque, AVBufferRef *(*alloc)(void *opaque, int size), void(*pool_free)(void *opaque))
Allocate and initialize a buffer pool with a more complex allocator.
Definition: buffer.c:245
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:527
if(ret)
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:39
Stream structure.
Definition: avformat.h:880
#define AVERROR_PATCHWELCOME
Not yet implemented in FFmpeg, patches welcome.
Definition: error.h:62
static xcb_rectangle_t rectangle_from_corners(xcb_point_t *corner_a, xcb_point_t *corner_b)
Definition: xcbgrab.c:685
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
Definition: avio_reading.c:42
int64_t time_frame
Definition: xcbgrab.c:59
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:253
static int64_t wait_frame(AVFormatContext *s, AVPacket *pkt)
Definition: xcbgrab.c:201
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:260
uint8_t * data
The data buffer.
Definition: buffer.h:89
Tag MUST be and< 10hcoeff half pel interpolation filter coefficients, hcoeff[0] are the 2 middle coefficients[1] are the next outer ones and so on, resulting in a filter like:...eff[2], hcoeff[1], hcoeff[0], hcoeff[0], hcoeff[1], hcoeff[2]...the sign of the coefficients is not explicitly stored but alternates after each coeff and coeff[0] is positive, so...,+,-,+,-,+,+,-,+,-,+,...hcoeff[0] is not explicitly stored but found by subtracting the sum of all stored coefficients with signs from 32 hcoeff[0]=32-hcoeff[1]-hcoeff[2]-...a good choice for hcoeff and htaps is htaps=6 hcoeff={40,-10, 2}an alternative which requires more computations at both encoder and decoder side and may or may not be better is htaps=8 hcoeff={42,-14, 6,-2}ref_frames minimum of the number of available reference frames and max_ref_frames for example the first frame after a key frame always has ref_frames=1spatial_decomposition_type wavelet type 0 is a 9/7 symmetric compact integer wavelet 1 is a 5/3 symmetric compact integer wavelet others are reserved stored as delta from last, last is reset to 0 if always_reset||keyframeqlog quality(logarithmic quantizer scale) stored as delta from last, last is reset to 0 if always_reset||keyframemv_scale stored as delta from last, last is reset to 0 if always_reset||keyframe FIXME check that everything works fine if this changes between framesqbias dequantization bias stored as delta from last, last is reset to 0 if always_reset||keyframeblock_max_depth maximum depth of the block tree stored as delta from last, last is reset to 0 if always_reset||keyframequant_table quantization tableHighlevel bitstream structure:==============================--------------------------------------------|Header|--------------------------------------------|------------------------------------|||Block0||||split?||||yes no||||.........intra?||||:Block01:yes no||||:Block02:.................||||:Block03::y DC::ref index:||||:Block04::cb DC::motion x:||||.........:cr DC::motion y:||||.................|||------------------------------------||------------------------------------|||Block1|||...|--------------------------------------------|------------------------------------|||Y subbands||Cb subbands||Cr subbands||||------||------||------|||||LL0||HL0||||LL0||HL0||||LL0||HL0|||||------||------||------||||------||------||------|||||LH0||HH0||||LH0||HH0||||LH0||HH0|||||------||------||------||||------||------||------|||||HL1||LH1||||HL1||LH1||||HL1||LH1|||||------||------||------||||------||------||------|||||HH1||HL2||||HH1||HL2||||HH1||HL2|||||...||...||...|||------------------------------------|--------------------------------------------Decoding process:=================------------|||Subbands|------------||||------------|Intra DC||||LL0 subband prediction------------|\Dequantization-------------------\||Reference frames|\IDWT|--------------|Motion\|||Frame 0||Frame 1||Compensation.OBMC v-------|--------------|--------------.\------> Frame n output Frame Frame<----------------------------------/|...|-------------------Range Coder:============Binary Range Coder:-------------------The implemented range coder is an adapted version based upon"Range encoding: an algorithm for removing redundancy from a digitised message."by G.N.N.Martin.The symbols encoded by the Snow range coder are bits(0|1).The associated probabilities are not fix but change depending on the symbol mix seen so far.bit seen|new state---------+-----------------------------------------------0|256-state_transition_table[256-old_state];1|state_transition_table[old_state];state_transition_table={0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 194, 194, 195, 196, 197, 198, 199, 200, 201, 202, 202, 204, 205, 206, 207, 208, 209, 209, 210, 211, 212, 213, 215, 215, 216, 217, 218, 219, 220, 220, 222, 223, 224, 225, 226, 227, 227, 229, 229, 230, 231, 232, 234, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 248, 0, 0, 0, 0, 0, 0, 0};FIXME Range Coding of integers:-------------------------FIXME Neighboring Blocks:===================left and top are set to the respective blocks unless they are outside of the image in which case they are set to the Null block top-left is set to the top left block unless it is outside of the image in which case it is set to the left block if this block has no larger parent block or it is at the left side of its parent block and the top right block is not outside of the image then the top right block is used for top-right else the top-left block is used Null block y, cb, cr are 128 level, ref, mx and my are 0 Motion Vector Prediction:=========================1.the motion vectors of all the neighboring blocks are scaled to compensate for the difference of reference frames scaled_mv=(mv *(256 *(current_reference+1)/(mv.reference+1))+128)> the median of the scaled left
Definition: snow.txt:206
int select_region
Definition: xcbgrab.c:73
int show_region
Definition: xcbgrab.c:70
Describe the class of an AVClass context structure.
Definition: log.h:67
Definition: f_ebur128.c:91
void av_buffer_pool_uninit(AVBufferPool **ppool)
Mark the pool as being available for freeing.
Definition: buffer.c:303
static int xcbgrab_read_packet(AVFormatContext *s, AVPacket *pkt)
Definition: xcbgrab.c:415
Rational number (pair of numerator and denominator).
Definition: rational.h:58
offset must point to two consecutive integers
Definition: opt.h:235
misc parsing utilities
static void xcbgrab_image_reply_free(void *opaque, uint8_t *data)
Definition: xcbgrab.c:150
#define OFFSET(x)
Definition: xcbgrab.c:82
static void setup_window(AVFormatContext *s)
Definition: xcbgrab.c:647
void avpriv_report_missing_feature(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
static int64_t pts
#define flags(name, subs,...)
Definition: cbs_av1.c:560
static int xcbgrab_reposition(AVFormatContext *s, xcb_query_pointer_reply_t *p, xcb_get_geometry_reply_t *geo)
Definition: xcbgrab.c:109
A reference to a data buffer.
Definition: buffer.h:81
Main libavformat public API header.
GLint GLenum GLboolean GLsizei stride
Definition: opengl_enc.c:104
#define D
Definition: xcbgrab.c:83
static int ref[MAX_W *MAX_W]
Definition: jpeg2000dwt.c:107
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:458
int region_border
Definition: xcbgrab.c:71
static av_cold int xcbgrab_read_close(AVFormatContext *s)
Definition: xcbgrab.c:471
packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb)
Definition: pixfmt.h:86
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:387
void av_init_packet(AVPacket *pkt)
Initialize optional fields of a packet with default values.
Definition: avpacket.c:35
int den
Denominator.
Definition: rational.h:60
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
Definition: avcodec.h:215
int follow_mouse
Definition: xcbgrab.c:69
void * priv_data
Format private data.
Definition: avformat.h:1267
int64_t frame_duration
Definition: xcbgrab.c:61
#define AV_PIX_FMT_RGB565
Definition: pixfmt.h:386
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: packet.h:362
int draw_mouse
Definition: xcbgrab.c:68
#define av_freep(p)
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:652
#define FOLLOW_CENTER
Definition: xcbgrab.c:80
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1045
AVBufferRef * av_buffer_pool_get(AVBufferPool *pool)
Allocate a new AVBuffer, reusing an old buffer from the pool when available.
Definition: buffer.c:364
#define stride
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
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition: pixfmt.h:237
enum AVCodecID id
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
This structure stores compressed data.
Definition: packet.h:340
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:356
#define av_unused
Definition: attributes.h:131
#define AV_PIX_FMT_0RGB32
Definition: pixfmt.h:376