getframe.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #include <libmegapixels.h>
  2. #include <stdio.h>
  3. #include <limits.h>
  4. #include <string.h>
  5. #include <linux/videodev2.h>
  6. #include <sys/ioctl.h>
  7. #include <stdlib.h>
  8. #include <sys/types.h>
  9. #include <unistd.h>
  10. #include <errno.h>
  11. #include <sys/mman.h>
  12. struct buffer {
  13. void *start;
  14. size_t length;
  15. };
  16. struct buffer *buffers;
  17. int
  18. xioctl(int fd, int request, void *arg)
  19. {
  20. int r;
  21. do {
  22. r = ioctl(fd, request, arg);
  23. } while (r == -1 && errno == EINTR);
  24. return r;
  25. }
  26. int
  27. main()
  28. {
  29. char configpath[PATH_MAX];
  30. int ret = libmegapixels_find_config(configpath);
  31. libmegapixels_devconfig *config = {0};
  32. if (ret) {
  33. printf("Using config: %s\n", configpath);
  34. libmegapixels_load_file(&config, configpath);
  35. } else {
  36. fprintf(stderr, "No config found for this device\n");
  37. return 1;
  38. }
  39. if (config->count == 0) {
  40. fprintf(stderr, "No valid camera configuration\n");
  41. return 1;
  42. }
  43. libmegapixels_camera *camera = config->cameras[0];
  44. if (libmegapixels_open(camera) != 0) {
  45. fprintf(stderr, "Could not open default camera\n");
  46. return 1;
  47. }
  48. libmegapixels_mode *mode = &camera->modes[0];
  49. unsigned int frame_size = libmegapixels_select_mode(camera, mode);
  50. if (frame_size == 0) {
  51. fprintf(stderr, "Could not select mode\n");
  52. return 1;
  53. }
  54. // Do the reqular V4L2 stuff to get a frame
  55. struct v4l2_capability cap;
  56. if (ioctl(camera->video_fd, VIDIOC_QUERYCAP, &cap) != 0) {
  57. fprintf(stderr, "VIDIOC_QUERYCAP failed\n");
  58. return 1;
  59. }
  60. if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
  61. fprintf(stderr, "Device does not support streaming i/o\n");
  62. return 1;
  63. }
  64. struct v4l2_requestbuffers req = {0};
  65. req.count = 4;
  66. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  67. req.memory = V4L2_MEMORY_MMAP;
  68. if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
  69. fprintf(stderr, "VIDIOC_REQBUFS failed\n");
  70. return 1;
  71. }
  72. buffers = calloc(req.count, sizeof(*buffers));
  73. for (int i = 0; i < req.count; i++) {
  74. struct v4l2_buffer buf = {0};
  75. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  76. buf.memory = V4L2_MEMORY_MMAP;
  77. buf.index = i;
  78. if (xioctl(camera->video_fd, VIDIOC_QUERYBUF, &buf) == -1) {
  79. fprintf(stderr, "VIDIOC_QUERYBUF failed\n");
  80. return 1;
  81. }
  82. buffers[i].length = buf.length;
  83. buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, camera->video_fd, buf.m.offset);
  84. if (buffers[i].start == MAP_FAILED) {
  85. fprintf(stderr, "mmap() failed\n");
  86. return 1;
  87. }
  88. }
  89. for (int i = 0; i < req.count; i++) {
  90. struct v4l2_buffer qbuf = {0};
  91. qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  92. qbuf.memory = V4L2_MEMORY_MMAP;
  93. qbuf.index = i;
  94. if (xioctl(camera->video_fd, VIDIOC_QBUF, &qbuf) == -1) {
  95. fprintf(stderr, "VIDIOC_QBUF failed\n");
  96. return 1;
  97. }
  98. }
  99. enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  100. if (xioctl(camera->video_fd, VIDIOC_STREAMON, &type) == -1) {
  101. fprintf(stderr, "VIDIOC_STREAMON failed\n");
  102. return 1;
  103. }
  104. int count = 5;
  105. while (count-- > 0) {
  106. while (1) {
  107. fd_set(fds);
  108. FD_ZERO(&fds);
  109. FD_SET(camera->video_fd, &fds);
  110. int sr = select(FD_SETSIZE, &fds, NULL, NULL, NULL);
  111. if (sr == -1) {
  112. if (errno == EINTR) {
  113. count++;
  114. continue;
  115. }
  116. fprintf(stderr, "select() failed: %s\n", strerror(errno));
  117. return 1;
  118. }
  119. struct v4l2_buffer buf = {0};
  120. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  121. buf.memory = V4L2_MEMORY_MMAP;
  122. if (xioctl(camera->video_fd, VIDIOC_DQBUF, &buf) == -1) {
  123. fprintf(stderr, "VIDIOC_DQBUF failed\n");
  124. return 1;
  125. }
  126. fprintf(stderr, "GOT FRAME!\n");
  127. if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
  128. fprintf(stderr, "VIDIOC_DQBUF failed\n");
  129. return 1;
  130. }
  131. break;
  132. }
  133. }
  134. return 0;
  135. }