camera.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. #include "camera.h"
  2. #include <assert.h>
  3. #include <errno.h>
  4. #include <glib.h>
  5. #include <sys/ioctl.h>
  6. #include <sys/mman.h>
  7. #define MAX_VIDEO_BUFFERS 20
  8. static const char *pixel_format_names[MP_PIXEL_FMT_MAX] = {
  9. "unsupported",
  10. "BGGR8",
  11. "GBRG8",
  12. "GRBG8",
  13. "RGGB8",
  14. };
  15. const char *mp_pixel_format_to_str(uint32_t pixel_format)
  16. {
  17. g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, "INVALID");
  18. return pixel_format_names[pixel_format];
  19. }
  20. MPPixelFormat mp_pixel_format_from_str(const char *name)
  21. {
  22. for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
  23. if (strcasecmp(pixel_format_names[i], name) == 0) {
  24. return i;
  25. }
  26. }
  27. g_return_val_if_reached(MP_PIXEL_FMT_UNSUPPORTED);
  28. }
  29. static const uint32_t pixel_format_v4l_pixel_formats[MP_PIXEL_FMT_MAX] = {
  30. 0,
  31. V4L2_PIX_FMT_SBGGR8,
  32. V4L2_PIX_FMT_SGBRG8,
  33. V4L2_PIX_FMT_SGRBG8,
  34. V4L2_PIX_FMT_SRGGB8,
  35. };
  36. uint32_t mp_pixel_format_to_v4l_pixel_format(MPPixelFormat pixel_format)
  37. {
  38. g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
  39. return pixel_format_v4l_pixel_formats[pixel_format];
  40. }
  41. MPPixelFormat mp_pixel_format_from_v4l_pixel_format(uint32_t v4l_pixel_format)
  42. {
  43. for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
  44. if (pixel_format_v4l_pixel_formats[i] == v4l_pixel_format) {
  45. return i;
  46. }
  47. }
  48. return MP_PIXEL_FMT_UNSUPPORTED;
  49. }
  50. static const uint32_t pixel_format_v4l_bus_codes[MP_PIXEL_FMT_MAX] = {
  51. 0,
  52. MEDIA_BUS_FMT_SBGGR8_1X8,
  53. MEDIA_BUS_FMT_SGBRG8_1X8,
  54. MEDIA_BUS_FMT_SGRBG8_1X8,
  55. MEDIA_BUS_FMT_SRGGB8_1X8,
  56. };
  57. uint32_t mp_pixel_format_to_v4l_bus_code(MPPixelFormat pixel_format)
  58. {
  59. g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
  60. return pixel_format_v4l_bus_codes[pixel_format];
  61. }
  62. MPPixelFormat mp_pixel_format_from_v4l_bus_code(uint32_t v4l_bus_code)
  63. {
  64. for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
  65. if (pixel_format_v4l_bus_codes[i] == v4l_bus_code) {
  66. return i;
  67. }
  68. }
  69. return MP_PIXEL_FMT_UNSUPPORTED;
  70. }
  71. uint32_t mp_pixel_format_bytes_per_pixel(MPPixelFormat pixel_format)
  72. {
  73. g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
  74. switch (pixel_format) {
  75. case MP_PIXEL_FMT_BGGR8:
  76. case MP_PIXEL_FMT_GBRG8:
  77. case MP_PIXEL_FMT_GRBG8:
  78. case MP_PIXEL_FMT_RGGB8: return 1;
  79. default: return 0;
  80. }
  81. }
  82. bool mp_camera_mode_is_equivalent(const MPCameraMode *m1, const MPCameraMode *m2)
  83. {
  84. return m1->pixel_format == m2->pixel_format
  85. && m1->frame_interval.numerator == m2->frame_interval.numerator
  86. && m1->frame_interval.denominator == m2->frame_interval.denominator
  87. && m1->width == m2->width
  88. && m1->height == m2->height;
  89. }
  90. struct video_buffer {
  91. uint32_t length;
  92. uint8_t *data;
  93. };
  94. struct _MPCamera {
  95. int video_fd;
  96. int subdev_fd;
  97. bool has_set_mode;
  98. MPCameraMode current_mode;
  99. struct video_buffer buffers[MAX_VIDEO_BUFFERS];
  100. uint32_t num_buffers;
  101. };
  102. MPCamera *mp_camera_new(int video_fd, int subdev_fd)
  103. {
  104. g_return_val_if_fail(video_fd != -1, NULL);
  105. MPCamera *camera = malloc(sizeof(MPCamera));
  106. camera->video_fd = video_fd;
  107. camera->subdev_fd = subdev_fd;
  108. camera->has_set_mode = false;
  109. camera->num_buffers = 0;
  110. return camera;
  111. }
  112. void mp_camera_free(MPCamera *camera)
  113. {
  114. g_warn_if_fail(camera->num_buffers == 0);
  115. if (camera->num_buffers != 0) {
  116. mp_camera_stop_capture(camera);
  117. }
  118. free(camera);
  119. }
  120. bool mp_camera_is_subdev(MPCamera *camera)
  121. {
  122. return camera->subdev_fd != -1;
  123. }
  124. int mp_camera_get_video_fd(MPCamera *camera)
  125. {
  126. return camera->video_fd;
  127. }
  128. int mp_camera_get_subdev_fd(MPCamera *camera)
  129. {
  130. return camera->subdev_fd;
  131. }
  132. static void errno_printerr(const char *s)
  133. {
  134. g_printerr("MPCamera: %s error %d, %s\n", s, errno, strerror(errno));
  135. }
  136. static int xioctl(int fd, int request, void *arg)
  137. {
  138. int r;
  139. do {
  140. r = ioctl(fd, request, arg);
  141. } while (r == -1 && errno == EINTR);
  142. return r;
  143. }
  144. bool mp_camera_try_mode(MPCamera *camera, MPCameraMode *mode)
  145. {
  146. struct v4l2_format fmt = {};
  147. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  148. fmt.fmt.pix.width = mode->width;
  149. fmt.fmt.pix.height = mode->height;
  150. fmt.fmt.pix.pixelformat = mp_pixel_format_from_v4l_pixel_format(mode->pixel_format);
  151. fmt.fmt.pix.field = V4L2_FIELD_ANY;
  152. if (xioctl(camera->video_fd, VIDIOC_TRY_FMT, &fmt) == -1) {
  153. errno_printerr("VIDIOC_S_FMT");
  154. return false;
  155. }
  156. mode->width = fmt.fmt.pix.width;
  157. mode->height = fmt.fmt.pix.height;
  158. mode->pixel_format = mp_pixel_format_from_v4l_pixel_format(fmt.fmt.pix.pixelformat);
  159. return true;
  160. }
  161. const MPCameraMode *mp_camera_get_mode(const MPCamera *camera)
  162. {
  163. return &camera->current_mode;
  164. }
  165. bool mp_camera_set_mode(MPCamera *camera, MPCameraMode *mode)
  166. {
  167. // Set the mode in the subdev the camera is one
  168. if (mp_camera_is_subdev(camera))
  169. {
  170. struct v4l2_subdev_frame_interval interval = {};
  171. interval.pad = 0;
  172. interval.interval = mode->frame_interval;
  173. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &interval) == -1) {
  174. errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL");
  175. return false;
  176. }
  177. bool did_set_frame_rate =
  178. interval.interval.numerator == mode->frame_interval.numerator
  179. && interval.interval.denominator == mode->frame_interval.denominator;
  180. struct v4l2_subdev_format fmt = {};
  181. fmt.pad = 0;
  182. fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
  183. fmt.format.width = mode->width;
  184. fmt.format.height = mode->height;
  185. fmt.format.code = mp_pixel_format_to_v4l_bus_code(mode->pixel_format);
  186. fmt.format.field = V4L2_FIELD_ANY;
  187. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FMT, &fmt) == -1) {
  188. errno_printerr("VIDIOC_SUBDEV_S_FMT");
  189. return false;
  190. }
  191. // Some drivers like ov5640 don't allow you to set the frame format with
  192. // too high a frame-rate, but that means the frame-rate won't be set
  193. // after the format change. So we need to try again here if we didn't
  194. // succeed before. Ideally we'd be able to set both at once.
  195. if (!did_set_frame_rate)
  196. {
  197. interval.interval = mode->frame_interval;
  198. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &interval) == -1) {
  199. errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL");
  200. return false;
  201. }
  202. }
  203. // Update the mode
  204. mode->pixel_format = mp_pixel_format_from_v4l_bus_code(fmt.format.code);
  205. mode->frame_interval = interval.interval;
  206. mode->width = fmt.format.width;
  207. mode->height = fmt.format.height;
  208. }
  209. // Set the mode for the video device
  210. {
  211. struct v4l2_format fmt = {};
  212. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  213. fmt.fmt.pix.width = mode->width;
  214. fmt.fmt.pix.height = mode->height;
  215. fmt.fmt.pix.pixelformat = mp_pixel_format_to_v4l_pixel_format(mode->pixel_format);
  216. fmt.fmt.pix.field = V4L2_FIELD_ANY;
  217. if (xioctl(camera->video_fd, VIDIOC_S_FMT, &fmt) == -1) {
  218. errno_printerr("VIDIOC_S_FMT");
  219. return false;
  220. }
  221. // Update the mode
  222. mode->pixel_format = mp_pixel_format_from_v4l_pixel_format(fmt.fmt.pix.pixelformat);
  223. mode->width = fmt.fmt.pix.width;
  224. mode->height = fmt.fmt.pix.height;
  225. }
  226. camera->has_set_mode = true;
  227. camera->current_mode = *mode;
  228. return true;
  229. }
  230. bool mp_camera_start_capture(MPCamera *camera)
  231. {
  232. g_return_val_if_fail(camera->has_set_mode, false);
  233. g_return_val_if_fail(camera->num_buffers == 0, false);
  234. // Start by requesting buffers
  235. struct v4l2_requestbuffers req = {};
  236. req.count = MAX_VIDEO_BUFFERS;
  237. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  238. req.memory = V4L2_MEMORY_MMAP;
  239. if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
  240. errno_printerr("VIDIOC_REQBUFS");
  241. return false;
  242. }
  243. if (req.count < 2) {
  244. g_printerr("Insufficient buffer memory. Only %d buffers available.\n",
  245. req.count);
  246. goto error;
  247. }
  248. for (uint32_t i = 0; i < req.count; ++i) {
  249. // Query each buffer and mmap it
  250. struct v4l2_buffer buf = {
  251. .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  252. .memory = V4L2_MEMORY_MMAP,
  253. .index = i,
  254. };
  255. if (xioctl(camera->video_fd, VIDIOC_QUERYBUF, &buf) == -1) {
  256. errno_printerr("VIDIOC_QUERYBUF");
  257. break;
  258. }
  259. camera->buffers[i].length = buf.length;
  260. camera->buffers[i].data = mmap(
  261. NULL,
  262. buf.length,
  263. PROT_READ,
  264. MAP_SHARED,
  265. camera->video_fd,
  266. buf.m.offset);
  267. if (camera->buffers[i].data == MAP_FAILED) {
  268. errno_printerr("mmap");
  269. break;
  270. }
  271. ++camera->num_buffers;
  272. }
  273. if (camera->num_buffers != req.count) {
  274. g_printerr("Unable to map all buffers\n");
  275. goto error;
  276. }
  277. for (uint32_t i = 0; i < camera->num_buffers; ++i) {
  278. struct v4l2_buffer buf = {
  279. .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  280. .memory = V4L2_MEMORY_MMAP,
  281. .index = i,
  282. };
  283. // Queue the buffer for capture
  284. if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
  285. errno_printerr("VIDIOC_QBUF");
  286. goto error;
  287. }
  288. }
  289. // Start capture
  290. enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  291. if (xioctl(camera->video_fd, VIDIOC_STREAMON, &type) == -1) {
  292. errno_printerr("VIDIOC_STREAMON");
  293. goto error;
  294. }
  295. return true;
  296. error:
  297. // Unmap any mapped buffers
  298. assert(camera->num_buffers <= MAX_VIDEO_BUFFERS);
  299. for (uint32_t i = 0; i < camera->num_buffers; ++i) {
  300. if (munmap(camera->buffers[i].data, camera->buffers[i].length) == -1) {
  301. errno_printerr("munmap");
  302. }
  303. }
  304. // Reset allocated buffers
  305. {
  306. struct v4l2_requestbuffers req = {};
  307. req.count = 0;
  308. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  309. req.memory = V4L2_MEMORY_MMAP;
  310. if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
  311. errno_printerr("VIDIOC_REQBUFS");
  312. }
  313. }
  314. return false;
  315. }
  316. bool mp_camera_stop_capture(MPCamera *camera)
  317. {
  318. g_return_val_if_fail(camera->num_buffers > 0, false);
  319. enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  320. if (xioctl(camera->video_fd, VIDIOC_STREAMOFF, &type) == -1) {
  321. errno_printerr("VIDIOC_STREAMOFF");
  322. }
  323. assert(camera->num_buffers <= MAX_VIDEO_BUFFERS);
  324. for (int i = 0; i < camera->num_buffers; ++i) {
  325. if (munmap(camera->buffers[i].data, camera->buffers[i].length) == -1) {
  326. errno_printerr("munmap");
  327. }
  328. }
  329. camera->num_buffers = 0;
  330. struct v4l2_requestbuffers req = {};
  331. req.count = 0;
  332. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  333. req.memory = V4L2_MEMORY_MMAP;
  334. if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
  335. errno_printerr("VIDIOC_REQBUFS");
  336. }
  337. return true;
  338. }
  339. bool mp_camera_is_capturing(MPCamera *camera)
  340. {
  341. return camera->num_buffers > 0;
  342. }
  343. bool mp_camera_capture_image(MPCamera *camera, void (*callback)(MPImage, void *), void *user_data)
  344. {
  345. struct v4l2_buffer buf = {};
  346. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  347. buf.memory = V4L2_MEMORY_MMAP;
  348. if (xioctl(camera->video_fd, VIDIOC_DQBUF, &buf) == -1) {
  349. switch (errno) {
  350. case EAGAIN:
  351. return true;
  352. case EIO:
  353. /* Could ignore EIO, see spec. */
  354. /* fallthrough */
  355. default:
  356. errno_printerr("VIDIOC_DQBUF");
  357. return false;
  358. }
  359. }
  360. uint32_t pixel_format = camera->current_mode.pixel_format;
  361. uint32_t width = camera->current_mode.width;
  362. uint32_t height = camera->current_mode.height;
  363. assert(buf.bytesused == mp_pixel_format_bytes_per_pixel(pixel_format) * width * height);
  364. assert(buf.bytesused == camera->buffers[buf.index].length);
  365. MPImage image = {
  366. .pixel_format = pixel_format,
  367. .width = width,
  368. .height = height,
  369. .data = camera->buffers[buf.index].data,
  370. };
  371. callback(image, user_data);
  372. // The callback may have stopped the capture, only queue the buffer if we're
  373. // still capturing.
  374. if (mp_camera_is_capturing(camera)) {
  375. if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
  376. errno_printerr("VIDIOC_QBUF");
  377. return false;
  378. }
  379. }
  380. return true;
  381. }
  382. struct _MPCameraModeList {
  383. MPCameraMode mode;
  384. MPCameraModeList *next;
  385. };
  386. static MPCameraModeList *
  387. get_subdev_modes(MPCamera *camera, bool (*check)(MPCamera *, MPCameraMode *))
  388. {
  389. MPCameraModeList *item = NULL;
  390. for (uint32_t fmt_index = 0;; ++fmt_index) {
  391. struct v4l2_subdev_mbus_code_enum fmt = {};
  392. fmt.index = fmt_index;
  393. fmt.pad = 0;
  394. fmt.which = V4L2_SUBDEV_FORMAT_TRY;
  395. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &fmt) == -1) {
  396. if (errno != EINVAL) {
  397. errno_printerr("VIDIOC_SUBDEV_ENUM_MBUS_CODE");
  398. }
  399. break;
  400. }
  401. // Skip unsupported formats
  402. uint32_t format = mp_pixel_format_from_v4l_bus_code(fmt.code);
  403. if (format == MP_PIXEL_FMT_UNSUPPORTED) {
  404. continue;
  405. }
  406. for (uint32_t frame_index = 0;; ++frame_index) {
  407. struct v4l2_subdev_frame_size_enum frame = {};
  408. frame.index = frame_index;
  409. frame.pad = 0;
  410. frame.code = fmt.code;
  411. frame.which = V4L2_SUBDEV_FORMAT_TRY;
  412. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &frame) == -1) {
  413. if (errno != EINVAL) {
  414. errno_printerr("VIDIOC_SUBDEV_ENUM_FRAME_SIZE");
  415. }
  416. break;
  417. }
  418. // TODO: Handle other types
  419. if (frame.min_width != frame.max_width
  420. || frame.min_height != frame.max_height) {
  421. break;
  422. }
  423. for (uint32_t interval_index = 0;; ++interval_index) {
  424. struct v4l2_subdev_frame_interval_enum interval = {};
  425. interval.index = interval_index;
  426. interval.pad = 0;
  427. interval.code = fmt.code;
  428. interval.width = frame.max_width;
  429. interval.height = frame.max_height;
  430. interval.which = V4L2_SUBDEV_FORMAT_TRY;
  431. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &interval) == -1) {
  432. if (errno != EINVAL) {
  433. errno_printerr("VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL");
  434. }
  435. break;
  436. }
  437. MPCameraMode mode = {
  438. .pixel_format = format,
  439. .frame_interval = interval.interval,
  440. .width = frame.max_width,
  441. .height = frame.max_height,
  442. };
  443. if (!check(camera, &mode)) {
  444. continue;
  445. }
  446. MPCameraModeList *new_item = malloc(sizeof(MPCameraModeList));
  447. new_item->mode = mode;
  448. new_item->next = item;
  449. item = new_item;
  450. }
  451. }
  452. }
  453. return item;
  454. }
  455. static MPCameraModeList *
  456. get_video_modes(MPCamera *camera, bool (*check)(MPCamera *, MPCameraMode *))
  457. {
  458. MPCameraModeList *item = NULL;
  459. for (uint32_t fmt_index = 0;; ++fmt_index) {
  460. struct v4l2_fmtdesc fmt = {};
  461. fmt.index = fmt_index;
  462. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  463. if (xioctl(camera->video_fd, VIDIOC_ENUM_FMT, &fmt) == -1) {
  464. if (errno != EINVAL) {
  465. errno_printerr("VIDIOC_ENUM_FMT");
  466. }
  467. break;
  468. }
  469. // Skip unsupported formats
  470. uint32_t format = mp_pixel_format_from_v4l_pixel_format(fmt.pixelformat);
  471. if (format == MP_PIXEL_FMT_UNSUPPORTED) {
  472. continue;
  473. }
  474. for (uint32_t frame_index = 0;; ++frame_index) {
  475. struct v4l2_frmsizeenum frame = {};
  476. frame.index = frame_index;
  477. frame.pixel_format = fmt.pixelformat;
  478. if (xioctl(camera->video_fd, VIDIOC_ENUM_FRAMESIZES, &frame) == -1) {
  479. if (errno != EINVAL) {
  480. errno_printerr("VIDIOC_ENUM_FRAMESIZES");
  481. }
  482. break;
  483. }
  484. // TODO: Handle other types
  485. if (frame.type != V4L2_FRMSIZE_TYPE_DISCRETE) {
  486. break;
  487. }
  488. for (uint32_t interval_index = 0;; ++interval_index) {
  489. struct v4l2_frmivalenum interval = {};
  490. interval.index = interval_index;
  491. interval.pixel_format = fmt.pixelformat;
  492. interval.width = frame.discrete.width;
  493. interval.height = frame.discrete.height;
  494. if (xioctl(camera->video_fd, VIDIOC_ENUM_FRAMEINTERVALS, &interval) == -1) {
  495. if (errno != EINVAL) {
  496. errno_printerr("VIDIOC_ENUM_FRAMESIZES");
  497. }
  498. break;
  499. }
  500. // TODO: Handle other types
  501. if (interval.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
  502. break;
  503. }
  504. MPCameraMode mode = {
  505. .pixel_format = format,
  506. .frame_interval = interval.discrete,
  507. .width = frame.discrete.width,
  508. .height = frame.discrete.height,
  509. };
  510. if (!check(camera, &mode)) {
  511. continue;
  512. }
  513. MPCameraModeList *new_item = malloc(sizeof(MPCameraModeList));
  514. new_item->mode = mode;
  515. new_item->next = item;
  516. item = new_item;
  517. }
  518. }
  519. }
  520. return item;
  521. }
  522. static bool all_modes(MPCamera *camera, MPCameraMode *mode)
  523. {
  524. return true;
  525. }
  526. static bool available_modes(MPCamera *camera, MPCameraMode *mode)
  527. {
  528. MPCameraMode attempt = *mode;
  529. return mp_camera_try_mode(camera, &attempt)
  530. && mp_camera_mode_is_equivalent(mode, &attempt);
  531. }
  532. MPCameraModeList *mp_camera_list_supported_modes(MPCamera *camera)
  533. {
  534. if (mp_camera_is_subdev(camera)) {
  535. return get_subdev_modes(camera, all_modes);
  536. } else {
  537. return get_video_modes(camera, all_modes);
  538. }
  539. }
  540. MPCameraModeList *mp_camera_list_available_modes(MPCamera *camera)
  541. {
  542. if (mp_camera_is_subdev(camera)) {
  543. return get_subdev_modes(camera, available_modes);
  544. } else {
  545. return get_video_modes(camera, available_modes);
  546. }
  547. }
  548. MPCameraMode *mp_camera_mode_list_get(MPCameraModeList *list)
  549. {
  550. g_return_val_if_fail(list, NULL);
  551. return &list->mode;
  552. }
  553. MPCameraModeList *mp_camera_mode_list_next(MPCameraModeList *list)
  554. {
  555. g_return_val_if_fail(list, NULL);
  556. return list->next;
  557. }
  558. void mp_camera_mode_list_free(MPCameraModeList *list)
  559. {
  560. while (list) {
  561. MPCameraModeList *tmp = list;
  562. list = tmp->next;
  563. free(tmp);
  564. }
  565. }