FFmpeg  4.4
kmsgrab.c
Go to the documentation of this file.
1 /*
2  * KMS/DRM input device
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <fcntl.h>
22 #include <unistd.h>
23 
24 #include <drm.h>
25 #include <drm_fourcc.h>
26 #include <drm_mode.h>
27 #include <xf86drm.h>
28 #include <xf86drmMode.h>
29 
30 // Required for compatibility when building against libdrm < 2.4.83.
31 #ifndef DRM_FORMAT_MOD_INVALID
32 #define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
33 #endif
34 
35 #include "libavutil/hwcontext.h"
37 #include "libavutil/internal.h"
38 #include "libavutil/mathematics.h"
39 #include "libavutil/opt.h"
40 #include "libavutil/pixfmt.h"
41 #include "libavutil/pixdesc.h"
42 #include "libavutil/time.h"
43 
44 #include "libavformat/avformat.h"
45 #include "libavformat/internal.h"
46 
47 typedef struct KMSGrabContext {
48  const AVClass *class;
49 
54 
57 
58  uint32_t plane_id;
59  uint32_t drm_format;
60  unsigned int width;
61  unsigned int height;
62 
63  int64_t frame_delay;
64  int64_t frame_last;
65 
66  const char *device_path;
67  enum AVPixelFormat format;
69  int64_t source_plane;
70  int64_t source_crtc;
73 
74 static void kmsgrab_free_desc(void *opaque, uint8_t *data)
75 {
77  int i;
78 
79  for (i = 0; i < desc->nb_objects; i++)
80  close(desc->objects[i].fd);
81 
82  av_free(desc);
83 }
84 
85 static void kmsgrab_free_frame(void *opaque, uint8_t *data)
86 {
88 
90 }
91 
92 static int kmsgrab_get_fb(AVFormatContext *avctx,
93  drmModePlane *plane,
95 {
96  KMSGrabContext *ctx = avctx->priv_data;
97  drmModeFB *fb = NULL;
98  int err, fd;
99 
100  fb = drmModeGetFB(ctx->hwctx->fd, plane->fb_id);
101  if (!fb) {
102  err = errno;
103  av_log(avctx, AV_LOG_ERROR, "Failed to get framebuffer "
104  "%"PRIu32": %s.\n", plane->fb_id, strerror(err));
105  err = AVERROR(err);
106  goto fail;
107  }
108  if (fb->width != ctx->width || fb->height != ctx->height) {
109  av_log(avctx, AV_LOG_ERROR, "Plane %"PRIu32" framebuffer "
110  "dimensions changed: now %"PRIu32"x%"PRIu32".\n",
111  ctx->plane_id, fb->width, fb->height);
112  err = AVERROR(EIO);
113  goto fail;
114  }
115  if (!fb->handle) {
116  av_log(avctx, AV_LOG_ERROR, "No handle set on framebuffer.\n");
117  err = AVERROR(EIO);
118  goto fail;
119  }
120 
121  err = drmPrimeHandleToFD(ctx->hwctx->fd, fb->handle, O_RDONLY, &fd);
122  if (err < 0) {
123  err = errno;
124  av_log(avctx, AV_LOG_ERROR, "Failed to get PRIME fd from "
125  "framebuffer handle: %s.\n", strerror(err));
126  err = AVERROR(err);
127  goto fail;
128  }
129 
131  .nb_objects = 1,
132  .objects[0] = {
133  .fd = fd,
134  .size = fb->height * fb->pitch,
135  .format_modifier = ctx->drm_format_modifier,
136  },
137  .nb_layers = 1,
138  .layers[0] = {
139  .format = ctx->drm_format,
140  .nb_planes = 1,
141  .planes[0] = {
142  .object_index = 0,
143  .offset = 0,
144  .pitch = fb->pitch,
145  },
146  },
147  };
148 
149  err = 0;
150 fail:
151  drmModeFreeFB(fb);
152  return err;
153 }
154 
155 #if HAVE_LIBDRM_GETFB2
156 static int kmsgrab_get_fb2(AVFormatContext *avctx,
157  drmModePlane *plane,
159 {
160  KMSGrabContext *ctx = avctx->priv_data;
161  drmModeFB2 *fb;
162  int err, i, nb_objects;
163  uint64_t modifier = ctx->drm_format_modifier;
164 
165  fb = drmModeGetFB2(ctx->hwctx->fd, plane->fb_id);
166  if (!fb) {
167  err = errno;
168  av_log(avctx, AV_LOG_ERROR, "Failed to get framebuffer "
169  "%"PRIu32": %s.\n", plane->fb_id, strerror(err));
170  return AVERROR(err);
171  }
172  if (fb->pixel_format != ctx->drm_format) {
173  av_log(avctx, AV_LOG_ERROR, "Plane %"PRIu32" framebuffer "
174  "format changed: now %"PRIx32".\n",
175  ctx->plane_id, fb->pixel_format);
176  err = AVERROR(EIO);
177  goto fail;
178  }
179  if (fb->width != ctx->width || fb->height != ctx->height) {
180  av_log(avctx, AV_LOG_ERROR, "Plane %"PRIu32" framebuffer "
181  "dimensions changed: now %"PRIu32"x%"PRIu32".\n",
182  ctx->plane_id, fb->width, fb->height);
183  err = AVERROR(EIO);
184  goto fail;
185  }
186  if (!fb->handles[0]) {
187  av_log(avctx, AV_LOG_ERROR, "No handle set on framebuffer.\n");
188  err = AVERROR(EIO);
189  goto fail;
190  }
191 
192  if (fb->flags & DRM_MODE_FB_MODIFIERS)
193  modifier = fb->modifier;
194 
196  .nb_layers = 1,
197  .layers[0] = {
198  .format = ctx->drm_format,
199  },
200  };
201 
202  nb_objects = 0;
203  for (i = 0; i < 4 && fb->handles[i]; i++) {
204  size_t size;
205  int dup = 0, j, obj;
206 
207  size = fb->offsets[i] + fb->height * fb->pitches[i];
208 
209  for (j = 0; j < i; j++) {
210  if (fb->handles[i] == fb->handles[j]) {
211  dup = 1;
212  break;
213  }
214  }
215  if (dup) {
216  obj = desc->layers[0].planes[j].object_index;
217 
218  if (desc->objects[j].size < size)
219  desc->objects[j].size = size;
220 
221  desc->layers[0].planes[i] = (AVDRMPlaneDescriptor) {
222  .object_index = obj,
223  .offset = fb->offsets[i],
224  .pitch = fb->pitches[i],
225  };
226 
227  } else {
228  int fd;
229  err = drmPrimeHandleToFD(ctx->hwctx->fd, fb->handles[i],
230  O_RDONLY, &fd);
231  if (err < 0) {
232  err = errno;
233  av_log(avctx, AV_LOG_ERROR, "Failed to get PRIME fd from "
234  "framebuffer handle: %s.\n", strerror(err));
235  err = AVERROR(err);
236  goto fail;
237  }
238 
239  obj = nb_objects++;
240  desc->objects[obj] = (AVDRMObjectDescriptor) {
241  .fd = fd,
242  .size = size,
243  .format_modifier = modifier,
244  };
245  desc->layers[0].planes[i] = (AVDRMPlaneDescriptor) {
246  .object_index = obj,
247  .offset = fb->offsets[i],
248  .pitch = fb->pitches[i],
249  };
250  }
251  }
252  desc->nb_objects = nb_objects;
253  desc->layers[0].nb_planes = i;
254 
255  err = 0;
256 fail:
257  drmModeFreeFB2(fb);
258  return err;
259 }
260 #endif
261 
263 {
264  KMSGrabContext *ctx = avctx->priv_data;
265  drmModePlane *plane = NULL;
267  AVFrame *frame = NULL;
268  int64_t now;
269  int err;
270 
271  now = av_gettime_relative();
272  if (ctx->frame_last) {
273  int64_t delay;
274  while (1) {
275  delay = ctx->frame_last + ctx->frame_delay - now;
276  if (delay <= 0)
277  break;
278  av_usleep(delay);
279  now = av_gettime_relative();
280  }
281  }
282  ctx->frame_last = now;
283  now = av_gettime();
284 
285  plane = drmModeGetPlane(ctx->hwctx->fd, ctx->plane_id);
286  if (!plane) {
287  err = errno;
288  av_log(avctx, AV_LOG_ERROR, "Failed to get plane "
289  "%"PRIu32": %s.\n", ctx->plane_id, strerror(err));
290  err = AVERROR(err);
291  goto fail;
292  }
293  if (!plane->fb_id) {
294  av_log(avctx, AV_LOG_ERROR, "Plane %"PRIu32" no longer has "
295  "an associated framebuffer.\n", ctx->plane_id);
296  err = AVERROR(EIO);
297  goto fail;
298  }
299 
300  desc = av_mallocz(sizeof(*desc));
301  if (!desc) {
302  err = AVERROR(ENOMEM);
303  goto fail;
304  }
305 
306 #if HAVE_LIBDRM_GETFB2
307  if (ctx->fb2_available)
308  err = kmsgrab_get_fb2(avctx, plane, desc);
309  else
310 #endif
311  err = kmsgrab_get_fb(avctx, plane, desc);
312  if (err < 0)
313  goto fail;
314 
315  frame = av_frame_alloc();
316  if (!frame) {
317  err = AVERROR(ENOMEM);
318  goto fail;
319  }
320 
321  frame->hw_frames_ctx = av_buffer_ref(ctx->frames_ref);
322  if (!frame->hw_frames_ctx) {
323  err = AVERROR(ENOMEM);
324  goto fail;
325  }
326 
327  frame->buf[0] = av_buffer_create((uint8_t*)desc, sizeof(*desc),
328  &kmsgrab_free_desc, avctx, 0);
329  if (!frame->buf[0]) {
330  err = AVERROR(ENOMEM);
331  goto fail;
332  }
333 
334  frame->data[0] = (uint8_t*)desc;
336  frame->width = ctx->width;
337  frame->height = ctx->height;
338 
339  drmModeFreePlane(plane);
340  plane = NULL;
341  desc = NULL;
342 
343  pkt->buf = av_buffer_create((uint8_t*)frame, sizeof(*frame),
344  &kmsgrab_free_frame, avctx, 0);
345  if (!pkt->buf) {
346  err = AVERROR(ENOMEM);
347  goto fail;
348  }
349 
350  pkt->data = (uint8_t*)frame;
351  pkt->size = sizeof(*frame);
352  pkt->pts = now;
354 
355  return 0;
356 
357 fail:
358  drmModeFreePlane(plane);
359  av_freep(&desc);
361  return err;
362 }
363 
364 static const struct {
365  enum AVPixelFormat pixfmt;
366  uint32_t drm_format;
367 } kmsgrab_formats[] = {
368  // Monochrome.
369 #ifdef DRM_FORMAT_R8
370  { AV_PIX_FMT_GRAY8, DRM_FORMAT_R8 },
371 #endif
372 #ifdef DRM_FORMAT_R16
373  { AV_PIX_FMT_GRAY16LE, DRM_FORMAT_R16 },
374  { AV_PIX_FMT_GRAY16BE, DRM_FORMAT_R16 | DRM_FORMAT_BIG_ENDIAN },
375 #endif
376  // <8-bit RGB.
377  { AV_PIX_FMT_BGR8, DRM_FORMAT_BGR233 },
378  { AV_PIX_FMT_RGB555LE, DRM_FORMAT_XRGB1555 },
379  { AV_PIX_FMT_RGB555BE, DRM_FORMAT_XRGB1555 | DRM_FORMAT_BIG_ENDIAN },
380  { AV_PIX_FMT_BGR555LE, DRM_FORMAT_XBGR1555 },
381  { AV_PIX_FMT_BGR555BE, DRM_FORMAT_XBGR1555 | DRM_FORMAT_BIG_ENDIAN },
382  { AV_PIX_FMT_RGB565LE, DRM_FORMAT_RGB565 },
383  { AV_PIX_FMT_RGB565BE, DRM_FORMAT_RGB565 | DRM_FORMAT_BIG_ENDIAN },
384  { AV_PIX_FMT_BGR565LE, DRM_FORMAT_BGR565 },
385  { AV_PIX_FMT_BGR565BE, DRM_FORMAT_BGR565 | DRM_FORMAT_BIG_ENDIAN },
386  // 8-bit RGB.
387  { AV_PIX_FMT_RGB24, DRM_FORMAT_RGB888 },
388  { AV_PIX_FMT_BGR24, DRM_FORMAT_BGR888 },
389  { AV_PIX_FMT_0RGB, DRM_FORMAT_BGRX8888 },
390  { AV_PIX_FMT_0BGR, DRM_FORMAT_RGBX8888 },
391  { AV_PIX_FMT_RGB0, DRM_FORMAT_XBGR8888 },
392  { AV_PIX_FMT_BGR0, DRM_FORMAT_XRGB8888 },
393  { AV_PIX_FMT_ARGB, DRM_FORMAT_BGRA8888 },
394  { AV_PIX_FMT_ABGR, DRM_FORMAT_RGBA8888 },
395  { AV_PIX_FMT_RGBA, DRM_FORMAT_ABGR8888 },
396  { AV_PIX_FMT_BGRA, DRM_FORMAT_ARGB8888 },
397  // 10-bit RGB.
398  { AV_PIX_FMT_X2RGB10LE, DRM_FORMAT_XRGB2101010 },
399  { AV_PIX_FMT_X2RGB10BE, DRM_FORMAT_XRGB2101010 | DRM_FORMAT_BIG_ENDIAN },
400  // 8-bit YUV 4:2:0.
401  { AV_PIX_FMT_NV12, DRM_FORMAT_NV12 },
402  // 8-bit YUV 4:2:2.
403  { AV_PIX_FMT_YUYV422, DRM_FORMAT_YUYV },
404  { AV_PIX_FMT_YVYU422, DRM_FORMAT_YVYU },
405  { AV_PIX_FMT_UYVY422, DRM_FORMAT_UYVY },
406 };
407 
409 {
410  KMSGrabContext *ctx = avctx->priv_data;
411  drmModePlaneRes *plane_res = NULL;
412  drmModePlane *plane = NULL;
413  drmModeFB *fb = NULL;
414 #if HAVE_LIBDRM_GETFB2
415  drmModeFB2 *fb2 = NULL;
416 #endif
417  AVStream *stream;
418  int err, i;
419 
420  err = av_hwdevice_ctx_create(&ctx->device_ref, AV_HWDEVICE_TYPE_DRM,
421  ctx->device_path, NULL, 0);
422  if (err < 0) {
423  av_log(avctx, AV_LOG_ERROR, "Failed to open DRM device.\n");
424  return err;
425  }
426  ctx->device = (AVHWDeviceContext*) ctx->device_ref->data;
427  ctx->hwctx = (AVDRMDeviceContext*)ctx->device->hwctx;
428 
429  err = drmSetClientCap(ctx->hwctx->fd,
430  DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
431  if (err < 0) {
432  av_log(avctx, AV_LOG_WARNING, "Failed to set universal planes "
433  "capability: primary planes will not be usable.\n");
434  }
435 
436  if (ctx->source_plane > 0) {
437  plane = drmModeGetPlane(ctx->hwctx->fd, ctx->source_plane);
438  if (!plane) {
439  err = errno;
440  av_log(avctx, AV_LOG_ERROR, "Failed to get plane %"PRId64": "
441  "%s.\n", ctx->source_plane, strerror(err));
442  err = AVERROR(err);
443  goto fail;
444  }
445 
446  if (plane->fb_id == 0) {
447  av_log(avctx, AV_LOG_ERROR, "Plane %"PRId64" does not have "
448  "an attached framebuffer.\n", ctx->source_plane);
449  err = AVERROR(EINVAL);
450  goto fail;
451  }
452  } else {
453  plane_res = drmModeGetPlaneResources(ctx->hwctx->fd);
454  if (!plane_res) {
455  err = errno;
456  av_log(avctx, AV_LOG_ERROR, "Failed to get plane "
457  "resources: %s.\n", strerror(err));
458  err = AVERROR(err);
459  goto fail;
460  }
461 
462  for (i = 0; i < plane_res->count_planes; i++) {
463  plane = drmModeGetPlane(ctx->hwctx->fd,
464  plane_res->planes[i]);
465  if (!plane) {
466  err = errno;
467  av_log(avctx, AV_LOG_VERBOSE, "Failed to get "
468  "plane %"PRIu32": %s.\n",
469  plane_res->planes[i], strerror(err));
470  continue;
471  }
472 
473  av_log(avctx, AV_LOG_DEBUG, "Plane %"PRIu32": "
474  "CRTC %"PRIu32" FB %"PRIu32".\n",
475  plane->plane_id, plane->crtc_id, plane->fb_id);
476 
477  if ((ctx->source_crtc > 0 &&
478  plane->crtc_id != ctx->source_crtc) ||
479  plane->fb_id == 0) {
480  // Either not connected to the target source CRTC
481  // or not active.
482  drmModeFreePlane(plane);
483  plane = NULL;
484  continue;
485  }
486 
487  break;
488  }
489 
490  if (i == plane_res->count_planes) {
491  if (ctx->source_crtc > 0) {
492  av_log(avctx, AV_LOG_ERROR, "No usable planes found on "
493  "CRTC %"PRId64".\n", ctx->source_crtc);
494  } else {
495  av_log(avctx, AV_LOG_ERROR, "No usable planes found.\n");
496  }
497  err = AVERROR(EINVAL);
498  goto fail;
499  }
500 
501  av_log(avctx, AV_LOG_INFO, "Using plane %"PRIu32" to "
502  "locate framebuffers.\n", plane->plane_id);
503  }
504 
505  ctx->plane_id = plane->plane_id;
506 
507 #if HAVE_LIBDRM_GETFB2
508  fb2 = drmModeGetFB2(ctx->hwctx->fd, plane->fb_id);
509  if (!fb2 && errno == ENOSYS) {
510  av_log(avctx, AV_LOG_INFO, "GETFB2 not supported, "
511  "will try to use GETFB instead.\n");
512  } else if (!fb2) {
513  err = errno;
514  av_log(avctx, AV_LOG_ERROR, "Failed to get "
515  "framebuffer %"PRIu32": %s.\n",
516  plane->fb_id, strerror(err));
517  err = AVERROR(err);
518  goto fail;
519  } else {
520  av_log(avctx, AV_LOG_INFO, "Template framebuffer is "
521  "%"PRIu32": %"PRIu32"x%"PRIu32" "
522  "format %"PRIx32" modifier %"PRIx64" flags %"PRIx32".\n",
523  fb2->fb_id, fb2->width, fb2->height,
524  fb2->pixel_format, fb2->modifier, fb2->flags);
525 
526  ctx->width = fb2->width;
527  ctx->height = fb2->height;
528 
529  if (!fb2->handles[0]) {
530  av_log(avctx, AV_LOG_ERROR, "No handle set on framebuffer: "
531  "maybe you need some additional capabilities?\n");
532  err = AVERROR(EINVAL);
533  goto fail;
534  }
535 
536  for (i = 0; i < FF_ARRAY_ELEMS(kmsgrab_formats); i++) {
537  if (kmsgrab_formats[i].drm_format == fb2->pixel_format) {
538  if (ctx->format != AV_PIX_FMT_NONE &&
539  ctx->format != kmsgrab_formats[i].pixfmt) {
540  av_log(avctx, AV_LOG_ERROR, "Framebuffer pixel format "
541  "%"PRIx32" does not match expected format.\n",
542  fb2->pixel_format);
543  err = AVERROR(EINVAL);
544  goto fail;
545  }
546  ctx->drm_format = fb2->pixel_format;
547  ctx->format = kmsgrab_formats[i].pixfmt;
548  break;
549  }
550  }
551  if (i == FF_ARRAY_ELEMS(kmsgrab_formats)) {
552  av_log(avctx, AV_LOG_ERROR, "Framebuffer pixel format "
553  "%"PRIx32" is not a known supported format.\n",
554  fb2->pixel_format);
555  err = AVERROR(EINVAL);
556  goto fail;
557  }
558 
559  if (fb2->flags & DRM_MODE_FB_MODIFIERS) {
560  if (ctx->drm_format_modifier != DRM_FORMAT_MOD_INVALID &&
561  ctx->drm_format_modifier != fb2->modifier) {
562  av_log(avctx, AV_LOG_ERROR, "Framebuffer format modifier "
563  "%"PRIx64" does not match expected modifier.\n",
564  fb2->modifier);
565  err = AVERROR(EINVAL);
566  goto fail;
567  } else {
568  ctx->drm_format_modifier = fb2->modifier;
569  }
570  }
571  av_log(avctx, AV_LOG_VERBOSE, "Format is %s, from "
572  "DRM format %"PRIx32" modifier %"PRIx64".\n",
573  av_get_pix_fmt_name(ctx->format),
574  ctx->drm_format, ctx->drm_format_modifier);
575 
576  ctx->fb2_available = 1;
577  }
578 #endif
579 
580  if (!ctx->fb2_available) {
581  if (ctx->format == AV_PIX_FMT_NONE) {
582  // Backward compatibility: assume BGR0 if no format supplied.
583  ctx->format = AV_PIX_FMT_BGR0;
584  }
585  for (i = 0; i < FF_ARRAY_ELEMS(kmsgrab_formats); i++) {
586  if (kmsgrab_formats[i].pixfmt == ctx->format) {
587  ctx->drm_format = kmsgrab_formats[i].drm_format;
588  break;
589  }
590  }
591  if (i >= FF_ARRAY_ELEMS(kmsgrab_formats)) {
592  av_log(avctx, AV_LOG_ERROR, "Unsupported format %s.\n",
593  av_get_pix_fmt_name(ctx->format));
594  return AVERROR(EINVAL);
595  }
596 
597  fb = drmModeGetFB(ctx->hwctx->fd, plane->fb_id);
598  if (!fb) {
599  err = errno;
600  av_log(avctx, AV_LOG_ERROR, "Failed to get "
601  "framebuffer %"PRIu32": %s.\n",
602  plane->fb_id, strerror(err));
603  err = AVERROR(err);
604  goto fail;
605  }
606 
607  av_log(avctx, AV_LOG_INFO, "Template framebuffer is %"PRIu32": "
608  "%"PRIu32"x%"PRIu32" %"PRIu32"bpp %"PRIu32"b depth.\n",
609  fb->fb_id, fb->width, fb->height, fb->bpp, fb->depth);
610 
611  ctx->width = fb->width;
612  ctx->height = fb->height;
613 
614  if (!fb->handle) {
615  av_log(avctx, AV_LOG_ERROR, "No handle set on framebuffer: "
616  "maybe you need some additional capabilities?\n");
617  err = AVERROR(EINVAL);
618  goto fail;
619  }
620  }
621 
622  stream = avformat_new_stream(avctx, NULL);
623  if (!stream) {
624  err = AVERROR(ENOMEM);
625  goto fail;
626  }
627 
630  stream->codecpar->width = ctx->width;
631  stream->codecpar->height = ctx->height;
633 
634  avpriv_set_pts_info(stream, 64, 1, 1000000);
635 
636  ctx->frames_ref = av_hwframe_ctx_alloc(ctx->device_ref);
637  if (!ctx->frames_ref) {
638  err = AVERROR(ENOMEM);
639  goto fail;
640  }
641  ctx->frames = (AVHWFramesContext*)ctx->frames_ref->data;
642 
643  ctx->frames->format = AV_PIX_FMT_DRM_PRIME;
644  ctx->frames->sw_format = ctx->format,
645  ctx->frames->width = ctx->width;
646  ctx->frames->height = ctx->height;
647 
648  err = av_hwframe_ctx_init(ctx->frames_ref);
649  if (err < 0) {
650  av_log(avctx, AV_LOG_ERROR, "Failed to initialise "
651  "hardware frames context: %d.\n", err);
652  goto fail;
653  }
654 
655  ctx->frame_delay = av_rescale_q(1, (AVRational) { ctx->framerate.den,
656  ctx->framerate.num }, AV_TIME_BASE_Q);
657 
658  err = 0;
659 fail:
660  drmModeFreePlaneResources(plane_res);
661  drmModeFreePlane(plane);
662  drmModeFreeFB(fb);
663 #if HAVE_LIBDRM_GETFB2
664  drmModeFreeFB2(fb2);
665 #endif
666  return err;
667 }
668 
670 {
671  KMSGrabContext *ctx = avctx->priv_data;
672 
673  av_buffer_unref(&ctx->frames_ref);
674  av_buffer_unref(&ctx->device_ref);
675 
676  return 0;
677 }
678 
679 #define OFFSET(x) offsetof(KMSGrabContext, x)
680 #define FLAGS AV_OPT_FLAG_DECODING_PARAM
681 static const AVOption options[] = {
682  { "device", "DRM device path",
683  OFFSET(device_path), AV_OPT_TYPE_STRING,
684  { .str = "/dev/dri/card0" }, 0, 0, FLAGS },
685  { "format", "Pixel format for framebuffer",
687  { .i64 = AV_PIX_FMT_NONE }, -1, INT32_MAX, FLAGS },
688  { "format_modifier", "DRM format modifier for framebuffer",
689  OFFSET(drm_format_modifier), AV_OPT_TYPE_INT64,
690  { .i64 = DRM_FORMAT_MOD_INVALID }, 0, INT64_MAX, FLAGS },
691  { "crtc_id", "CRTC ID to define capture source",
692  OFFSET(source_crtc), AV_OPT_TYPE_INT64,
693  { .i64 = 0 }, 0, UINT32_MAX, FLAGS },
694  { "plane_id", "Plane ID to define capture source",
695  OFFSET(source_plane), AV_OPT_TYPE_INT64,
696  { .i64 = 0 }, 0, UINT32_MAX, FLAGS },
697  { "framerate", "Framerate to capture at",
699  { .dbl = 30.0 }, 0, 1000, FLAGS },
700  { NULL },
701 };
702 
703 static const AVClass kmsgrab_class = {
704  .class_name = "kmsgrab indev",
705  .item_name = av_default_item_name,
706  .option = options,
707  .version = LIBAVUTIL_VERSION_INT,
709 };
710 
712  .name = "kmsgrab",
713  .long_name = NULL_IF_CONFIG_SMALL("KMS screen capture"),
714  .priv_data_size = sizeof(KMSGrabContext),
718  .flags = AVFMT_NOFILE,
719  .priv_class = &kmsgrab_class,
720 };
static const char *const format[]
Definition: af_aiir.c:456
#define av_cold
Definition: attributes.h:88
uint8_t
Main libavformat public API header.
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:458
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
Definition: avio_reading.c:42
#define fb(width, name)
Definition: cbs_av1.c:549
#define flags(name, subs,...)
Definition: cbs_av1.c:561
#define fail()
Definition: checkasm.h:133
#define NULL
Definition: coverity.c:32
static AVFrame * frame
static int read_header(FFV1Context *f)
Definition: ffv1dec.c:527
@ AV_OPT_TYPE_PIXEL_FMT
Definition: opt.h:236
@ AV_OPT_TYPE_RATIONAL
Definition: opt.h:230
@ AV_OPT_TYPE_INT64
Definition: opt.h:226
@ AV_OPT_TYPE_STRING
Definition: opt.h:229
@ AV_CODEC_ID_WRAPPED_AVFRAME
Passthrough codec, AVFrames wrapped in AVPacket.
Definition: codec_id.h:574
#define AV_PKT_FLAG_TRUSTED
The packet comes from a trusted source.
Definition: packet.h:424
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4505
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
AVBufferRef * av_buffer_create(uint8_t *data, buffer_size_t size, void(*free)(void *opaque, uint8_t *data), void *opaque, int flags)
Create an AVBuffer from an existing array.
Definition: buffer.c:29
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:190
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:215
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:210
#define AV_LOG_INFO
Standard information.
Definition: log.h:205
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:235
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
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:260
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type, const char *device, AVDictionary *opts, int flags)
Open a device of the specified type and create an AVHWDeviceContext for it.
Definition: hwcontext.c:610
int av_hwframe_ctx_init(AVBufferRef *ref)
Finalize the context before use.
Definition: hwcontext.c:333
AVBufferRef * av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
Allocate an AVHWFramesContext tied to a given device context.
Definition: hwcontext.c:247
@ AV_HWDEVICE_TYPE_DRM
Definition: hwcontext.h:36
API-specific header for AV_HWDEVICE_TYPE_DRM.
int i
Definition: input.c:407
static const AVClass kmsgrab_class
Definition: kmsgrab.c:703
static const AVOption options[]
Definition: kmsgrab.c:681
static int kmsgrab_get_fb(AVFormatContext *avctx, drmModePlane *plane, AVDRMFrameDescriptor *desc)
Definition: kmsgrab.c:92
static const struct @192 kmsgrab_formats[]
#define FLAGS
Definition: kmsgrab.c:680
static av_cold int kmsgrab_read_header(AVFormatContext *avctx)
Definition: kmsgrab.c:408
uint32_t drm_format
Definition: kmsgrab.c:366
static av_cold int kmsgrab_read_close(AVFormatContext *avctx)
Definition: kmsgrab.c:669
static int kmsgrab_read_packet(AVFormatContext *avctx, AVPacket *pkt)
Definition: kmsgrab.c:262
enum AVPixelFormat pixfmt
Definition: kmsgrab.c:365
AVInputFormat ff_kmsgrab_demuxer
Definition: kmsgrab.c:711
#define OFFSET(x)
Definition: kmsgrab.c:679
static void kmsgrab_free_desc(void *opaque, uint8_t *data)
Definition: kmsgrab.c:74
#define DRM_FORMAT_MOD_INVALID
Definition: kmsgrab.c:32
static void kmsgrab_free_frame(void *opaque, uint8_t *data)
Definition: kmsgrab.c:85
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:4941
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
static av_cold int read_close(AVFormatContext *ctx)
Definition: libcdio.c:145
const char * desc
Definition: libsvtav1.c:79
@ AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT
Definition: log.h:42
const char data[16]
Definition: mxf.c:142
AVOptions.
const char * av_get_pix_fmt_name(enum AVPixelFormat pix_fmt)
Return the short name for a pixel format, NULL in case pix_fmt is unknown.
Definition: pixdesc.c:2489
pixel format definitions
AVPixelFormat
Pixel format.
Definition: pixfmt.h:64
@ AV_PIX_FMT_GRAY16BE
Y , 16bpp, big-endian.
Definition: pixfmt.h:97
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
Definition: pixfmt.h:89
@ AV_PIX_FMT_NONE
Definition: pixfmt.h:65
@ AV_PIX_FMT_RGB24
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
@ AV_PIX_FMT_BGR565BE
packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian
Definition: pixfmt.h:110
@ AV_PIX_FMT_BGR0
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:240
@ AV_PIX_FMT_ARGB
packed ARGB 8:8:8:8, 32bpp, ARGBARGB...
Definition: pixfmt.h:92
@ AV_PIX_FMT_RGB555BE
packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), big-endian , X=unused/undefined
Definition: pixfmt.h:107
@ AV_PIX_FMT_YVYU422
packed YUV 4:2:2, 16bpp, Y0 Cr Y1 Cb
Definition: pixfmt.h:210
@ AV_PIX_FMT_BGRA
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
@ AV_PIX_FMT_GRAY8
Y , 8bpp.
Definition: pixfmt.h:74
@ AV_PIX_FMT_UYVY422
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
Definition: pixfmt.h:81
@ AV_PIX_FMT_ABGR
packed ABGR 8:8:8:8, 32bpp, ABGRABGR...
Definition: pixfmt.h:94
@ AV_PIX_FMT_0BGR
packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined
Definition: pixfmt.h:239
@ AV_PIX_FMT_BGR8
packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb)
Definition: pixfmt.h:83
@ AV_PIX_FMT_DRM_PRIME
DRM-managed buffers exposed through PRIME buffer sharing.
Definition: pixfmt.h:328
@ AV_PIX_FMT_RGBA
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
@ AV_PIX_FMT_RGB565LE
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian
Definition: pixfmt.h:106
@ AV_PIX_FMT_RGB555LE
packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined
Definition: pixfmt.h:108
@ AV_PIX_FMT_BGR555BE
packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), big-endian , X=unused/undefined
Definition: pixfmt.h:112
@ AV_PIX_FMT_X2RGB10LE
packed RGB 10:10:10, 30bpp, (msb)2X 10R 10G 10B(lsb), little-endian, X=unused/undefined
Definition: pixfmt.h:361
@ AV_PIX_FMT_RGB0
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:238
@ AV_PIX_FMT_GRAY16LE
Y , 16bpp, little-endian.
Definition: pixfmt.h:98
@ AV_PIX_FMT_RGB565BE
packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian
Definition: pixfmt.h:105
@ AV_PIX_FMT_BGR555LE
packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), little-endian, X=unused/undefined
Definition: pixfmt.h:113
@ AV_PIX_FMT_YUYV422
packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr
Definition: pixfmt.h:67
@ AV_PIX_FMT_BGR24
packed RGB 8:8:8, 24bpp, BGRBGR...
Definition: pixfmt.h:69
@ AV_PIX_FMT_0RGB
packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined
Definition: pixfmt.h:237
@ AV_PIX_FMT_BGR565LE
packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian
Definition: pixfmt.h:111
@ AV_PIX_FMT_X2RGB10BE
packed RGB 10:10:10, 30bpp, (msb)2X 10R 10G 10B(lsb), big-endian, X=unused/undefined
Definition: pixfmt.h:362
#define FF_ARRAY_ELEMS(a)
A reference to a data buffer.
Definition: buffer.h:84
Describe the class of an AVClass context structure.
Definition: log.h:67
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
int width
Video only.
Definition: codec_par.h:126
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:56
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:60
DRM frame descriptor.
DRM object descriptor.
Definition: hwcontext_drm.h:48
DRM plane descriptor.
Definition: hwcontext_drm.h:74
Format I/O context.
Definition: avformat.h:1232
void * priv_data
Format private data.
Definition: avformat.h:1260
This structure describes decoded (raw) audio or video data.
Definition: frame.h:318
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:332
int width
Definition: frame.h:376
AVBufferRef * hw_frames_ctx
For hwaccel-format frames, this should be a reference to the AVHWFramesContext describing the frame.
Definition: frame.h:657
int height
Definition: frame.h:376
AVBufferRef * buf[AV_NUM_DATA_POINTERS]
AVBuffer references backing the data for this frame.
Definition: frame.h:509
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames,...
Definition: frame.h:391
This struct aggregates all the (hardware/vendor-specific) "high-level" state, i.e.
Definition: hwcontext.h:61
This struct describes a set or pool of "hardware" frames (i.e.
Definition: hwcontext.h:124
const char * name
A comma separated list of short names for the format.
Definition: avformat.h:645
AVOption.
Definition: opt.h:248
This structure stores compressed data.
Definition: packet.h:346
AVBufferRef * buf
A reference to the reference-counted buffer where the packet data is stored.
Definition: packet.h:352
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:375
int size
Definition: packet.h:370
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:362
uint8_t * data
Definition: packet.h:369
Rational number (pair of numerator and denominator).
Definition: rational.h:58
Stream structure.
Definition: avformat.h:873
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1038
unsigned int width
Definition: kmsgrab.c:60
AVRational framerate
Definition: kmsgrab.c:71
int64_t drm_format_modifier
Definition: kmsgrab.c:68
const char * device_path
Definition: kmsgrab.c:66
AVHWFramesContext * frames
Definition: kmsgrab.c:56
AVBufferRef * frames_ref
Definition: kmsgrab.c:55
unsigned int height
Definition: kmsgrab.c:61
uint32_t plane_id
Definition: kmsgrab.c:58
int fb2_available
Definition: kmsgrab.c:53
int64_t source_crtc
Definition: kmsgrab.c:70
AVHWDeviceContext * device
Definition: kmsgrab.c:51
int64_t source_plane
Definition: kmsgrab.c:69
int64_t frame_delay
Definition: kmsgrab.c:63
AVBufferRef * device_ref
Definition: kmsgrab.c:50
enum AVPixelFormat format
Definition: kmsgrab.c:67
int64_t frame_last
Definition: kmsgrab.c:64
AVDRMDeviceContext * hwctx
Definition: kmsgrab.c:52
uint32_t drm_format
Definition: kmsgrab.c:59
#define av_free(p)
#define av_freep(p)
#define av_log(a,...)
int framerate
Definition: h264_levels.c:65
AVPacket * pkt
Definition: movenc.c:59
AVFormatContext * ctx
Definition: movenc.c:48
int av_usleep(unsigned usec)
Sleep for a period of time.
Definition: time.c:84
int64_t av_gettime_relative(void)
Get the current time in microseconds since some unspecified starting point.
Definition: time.c:56
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:39
int size