capture_fb.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <sys/mman.h>
  7. #include <sys/ioctl.h>
  8. #include <xf86drm.h>
  9. #include <xf86drmMode.h>
  10. #include <drm_fourcc.h>
  11. int main(void) {
  12. int fd = open("/dev/dri/card0", O_RDWR);
  13. if (fd < 0) { perror("open"); return 1; }
  14. drmModeRes *res = drmModeGetResources(fd);
  15. if (!res) { perror("getResources"); return 1; }
  16. drmModeCrtc *crtc = NULL;
  17. uint32_t crtc_id = 0;
  18. for (int i = 0; i < res->count_crtcs; i++) {
  19. crtc = drmModeGetCrtc(fd, res->crtcs[i]);
  20. if (crtc && crtc->buffer_id) { crtc_id = crtc->crtc_id; break; }
  21. if (crtc) { drmModeFreeCrtc(crtc); crtc = NULL; }
  22. }
  23. if (!crtc || !crtc->buffer_id) {
  24. fprintf(stderr, "No active CRTC\n");
  25. drmModeFreeResources(res);
  26. return 1;
  27. }
  28. fprintf(stderr, "CRTC %u -> FB %u, %ux%u\n",
  29. crtc_id, crtc->buffer_id, crtc->width, crtc->height);
  30. drmModeFB2 *fb = drmModeGetFB2(fd, crtc->buffer_id);
  31. if (!fb) {
  32. fprintf(stderr, "drmModeGetFB2 failed, trying FB...\n");
  33. drmModeFB *fb1 = drmModeGetFB(fd, crtc->buffer_id);
  34. if (!fb1) { perror("getFB"); return 1; }
  35. fprintf(stderr, "FB: %ux%u pitch=%u handle=%u\n",
  36. fb1->width, fb1->height, fb1->pitch, fb1->handle);
  37. uint32_t size = fb1->pitch * fb1->height;
  38. void *map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
  39. if (map == MAP_FAILED) {
  40. struct drm_mode_map_dumb mreq = { .handle = fb1->handle };
  41. if (ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq)) { perror("map"); return 1; }
  42. map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, mreq.offset);
  43. if (map == MAP_FAILED) { perror("mmap2"); return 1; }
  44. }
  45. FILE *fp = fopen("/tmp/frame.bin", "wb");
  46. fwrite(map, 1, size, fp);
  47. fclose(fp);
  48. fprintf(stderr, "Dumped %u bytes to /tmp/frame.bin\n", size);
  49. munmap(map, size);
  50. drmModeFreeFB(fb1);
  51. drmModeFreeCrtc(crtc);
  52. drmModeFreeResources(res);
  53. return 0;
  54. }
  55. fprintf(stderr, "FB2: %ux%u format=0x%x\n", fb->width, fb->height, fb->pixel_format);
  56. for (int i = 0; i < 4; i++)
  57. fprintf(stderr, " plane[%d]: handle=%u pitch=%u offset=%u\n",
  58. i, fb->handles[i], fb->pitches[i], fb->offsets[i]);
  59. if (fb->handles[0] == 0) {
  60. fprintf(stderr, "No handle on plane 0\n");
  61. drmModeFreeFB2(fb); drmModeFreeCrtc(crtc); drmModeFreeResources(res);
  62. return 1;
  63. }
  64. uint32_t w = fb->width, h = fb->height;
  65. uint32_t pitch = fb->pitches[0];
  66. uint32_t size = pitch * h;
  67. struct drm_mode_map_dumb mreq = { .handle = fb->handles[0] };
  68. if (ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq)) { perror("map_dumb"); return 1; }
  69. void *map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, mreq.offset);
  70. if (map == MAP_FAILED) { perror("mmap"); return 1; }
  71. FILE *fp = fopen("/tmp/frame.bin", "wb");
  72. fwrite(map, 1, size, fp);
  73. fclose(fp);
  74. fprintf(stderr, "Dumped %ux%u (pitch=%u, %u bytes) to /tmp/frame.bin\n", w, h, pitch, size);
  75. munmap(map, size);
  76. drmModeFreeFB2(fb);
  77. drmModeFreeCrtc(crtc);
  78. drmModeFreeResources(res);
  79. return 0;
  80. }