getframe.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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 <errno.h>
  10. #include <sys/mman.h>
  11. #include <getopt.h>
  12. #include <ctype.h>
  13. struct buffer {
  14. void *start;
  15. size_t length;
  16. };
  17. struct buffer *buffers;
  18. int
  19. xioctl(int fd, int request, void *arg)
  20. {
  21. int r;
  22. do {
  23. r = ioctl(fd, request, arg);
  24. } while (r == -1 && errno == EINTR);
  25. return r;
  26. }
  27. int
  28. main(int argc, char *argv[])
  29. {
  30. int c;
  31. int camera_id = 0;
  32. long res;
  33. char *end;
  34. while ((c = getopt(argc, argv, "c:")) != -1) {
  35. switch (c) {
  36. case 'c':
  37. res = strtol(optarg, &end, 10);
  38. if (end == optarg || end == NULL || *end != '\0') {
  39. fprintf(stderr, "Invalid number for -c\n");
  40. return 1;
  41. }
  42. camera_id = (int) res;
  43. break;
  44. case '?':
  45. if (optopt == 'd' || optopt == 'l') {
  46. fprintf(stderr, "Option -%c requires an argument.\n", optopt);
  47. } else if (isprint(optopt)) {
  48. fprintf(stderr, "Unknown option '-%c'\n", optopt);
  49. } else {
  50. fprintf(stderr, "Unknown option character x%x\n", optopt);
  51. }
  52. return 1;
  53. default:
  54. return 1;
  55. }
  56. }
  57. char configpath[PATH_MAX];
  58. int ret = libmegapixels_find_config(configpath);
  59. libmegapixels_devconfig *config = {0};
  60. if (ret) {
  61. printf("Using config: %s\n", configpath);
  62. libmegapixels_load_file(&config, configpath);
  63. } else {
  64. fprintf(stderr, "No config found for this device\n");
  65. return 1;
  66. }
  67. if (config->count == 0) {
  68. fprintf(stderr, "No valid camera configuration\n");
  69. return 1;
  70. }
  71. if (camera_id > config->count) {
  72. fprintf(stderr, "Camera id %d does not exist\n", camera_id);
  73. }
  74. libmegapixels_camera *camera = config->cameras[camera_id];
  75. if (libmegapixels_open(camera) != 0) {
  76. fprintf(stderr, "Could not open default camera\n");
  77. return 1;
  78. }
  79. libmegapixels_mode *mode = camera->modes[0];
  80. unsigned int frame_size = libmegapixels_select_mode(camera, mode);
  81. if (frame_size == 0) {
  82. fprintf(stderr, "Could not select mode\n");
  83. return 1;
  84. }
  85. // Do the reqular V4L2 stuff to get a frame
  86. struct v4l2_capability cap;
  87. if (ioctl(camera->video_fd, VIDIOC_QUERYCAP, &cap) != 0) {
  88. fprintf(stderr, "VIDIOC_QUERYCAP failed\n");
  89. return 1;
  90. }
  91. if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
  92. fprintf(stderr, "Device does not support streaming i/o\n");
  93. return 1;
  94. }
  95. struct v4l2_requestbuffers req = {0};
  96. req.count = 4;
  97. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  98. req.memory = V4L2_MEMORY_MMAP;
  99. if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
  100. fprintf(stderr, "VIDIOC_REQBUFS failed\n");
  101. return 1;
  102. }
  103. buffers = calloc(req.count, sizeof(*buffers));
  104. for (int i = 0; i < req.count; i++) {
  105. struct v4l2_buffer buf = {0};
  106. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  107. buf.memory = V4L2_MEMORY_MMAP;
  108. buf.index = i;
  109. if (xioctl(camera->video_fd, VIDIOC_QUERYBUF, &buf) == -1) {
  110. fprintf(stderr, "VIDIOC_QUERYBUF failed\n");
  111. return 1;
  112. }
  113. buffers[i].length = buf.length;
  114. buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, camera->video_fd, buf.m.offset);
  115. if (buffers[i].start == MAP_FAILED) {
  116. fprintf(stderr, "mmap() failed\n");
  117. return 1;
  118. }
  119. }
  120. for (int i = 0; i < req.count; i++) {
  121. struct v4l2_buffer qbuf = {0};
  122. qbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  123. qbuf.memory = V4L2_MEMORY_MMAP;
  124. qbuf.index = i;
  125. if (xioctl(camera->video_fd, VIDIOC_QBUF, &qbuf) == -1) {
  126. fprintf(stderr, "VIDIOC_QBUF failed\n");
  127. return 1;
  128. }
  129. }
  130. enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  131. if (xioctl(camera->video_fd, VIDIOC_STREAMON, &type) == -1) {
  132. fprintf(stderr, "VIDIOC_STREAMON failed\n");
  133. return 1;
  134. }
  135. int count = 5;
  136. while (count-- > 0) {
  137. while (1) {
  138. fd_set(fds);
  139. FD_ZERO(&fds);
  140. FD_SET(camera->video_fd, &fds);
  141. int sr = select(FD_SETSIZE, &fds, NULL, NULL, NULL);
  142. if (sr == -1) {
  143. if (errno == EINTR) {
  144. count++;
  145. continue;
  146. }
  147. fprintf(stderr, "select() failed: %s\n", strerror(errno));
  148. return 1;
  149. }
  150. struct v4l2_buffer buf = {0};
  151. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  152. buf.memory = V4L2_MEMORY_MMAP;
  153. if (xioctl(camera->video_fd, VIDIOC_DQBUF, &buf) == -1) {
  154. fprintf(stderr, "VIDIOC_DQBUF failed\n");
  155. return 1;
  156. }
  157. fprintf(stderr, "GOT FRAME!\n");
  158. if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
  159. fprintf(stderr, "VIDIOC_DQBUF failed\n");
  160. return 1;
  161. }
  162. break;
  163. }
  164. }
  165. return 0;
  166. }