camera.c 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133
  1. #include "camera.h"
  2. #include <assert.h>
  3. #include <errno.h>
  4. #include <glib.h>
  5. #include <stdio.h>
  6. #include <sys/ioctl.h>
  7. #include <sys/mman.h>
  8. #define MAX_VIDEO_BUFFERS 20
  9. static const char *pixel_format_names[MP_PIXEL_FMT_MAX] = {
  10. "unsupported",
  11. "BGGR8",
  12. "GBRG8",
  13. "GRBG8",
  14. "RGGB8",
  15. "BGGR10P",
  16. "GBRG10P",
  17. "GRBG10P",
  18. "RGGB10P",
  19. "UYVY",
  20. "YUYV",
  21. };
  22. const char *mp_pixel_format_to_str(uint32_t pixel_format)
  23. {
  24. g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, "INVALID");
  25. return pixel_format_names[pixel_format];
  26. }
  27. MPPixelFormat mp_pixel_format_from_str(const char *name)
  28. {
  29. for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
  30. if (strcasecmp(pixel_format_names[i], name) == 0) {
  31. return i;
  32. }
  33. }
  34. g_return_val_if_reached(MP_PIXEL_FMT_UNSUPPORTED);
  35. }
  36. static const uint32_t pixel_format_v4l_pixel_formats[MP_PIXEL_FMT_MAX] = {
  37. 0,
  38. V4L2_PIX_FMT_SBGGR8,
  39. V4L2_PIX_FMT_SGBRG8,
  40. V4L2_PIX_FMT_SGRBG8,
  41. V4L2_PIX_FMT_SRGGB8,
  42. V4L2_PIX_FMT_SBGGR10P,
  43. V4L2_PIX_FMT_SGBRG10P,
  44. V4L2_PIX_FMT_SGRBG10P,
  45. V4L2_PIX_FMT_SRGGB10P,
  46. V4L2_PIX_FMT_UYVY,
  47. V4L2_PIX_FMT_YUYV,
  48. };
  49. uint32_t mp_pixel_format_to_v4l_pixel_format(MPPixelFormat pixel_format)
  50. {
  51. g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
  52. return pixel_format_v4l_pixel_formats[pixel_format];
  53. }
  54. MPPixelFormat mp_pixel_format_from_v4l_pixel_format(uint32_t v4l_pixel_format)
  55. {
  56. for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
  57. if (pixel_format_v4l_pixel_formats[i] == v4l_pixel_format) {
  58. return i;
  59. }
  60. }
  61. return MP_PIXEL_FMT_UNSUPPORTED;
  62. }
  63. static const uint32_t pixel_format_v4l_bus_codes[MP_PIXEL_FMT_MAX] = {
  64. 0,
  65. MEDIA_BUS_FMT_SBGGR8_1X8,
  66. MEDIA_BUS_FMT_SGBRG8_1X8,
  67. MEDIA_BUS_FMT_SGRBG8_1X8,
  68. MEDIA_BUS_FMT_SRGGB8_1X8,
  69. MEDIA_BUS_FMT_SBGGR10_1X10,
  70. MEDIA_BUS_FMT_SGBRG10_1X10,
  71. MEDIA_BUS_FMT_SGRBG10_1X10,
  72. MEDIA_BUS_FMT_SRGGB10_1X10,
  73. MEDIA_BUS_FMT_UYVY8_2X8,
  74. MEDIA_BUS_FMT_YUYV8_2X8,
  75. };
  76. uint32_t mp_pixel_format_to_v4l_bus_code(MPPixelFormat pixel_format)
  77. {
  78. g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
  79. return pixel_format_v4l_bus_codes[pixel_format];
  80. }
  81. MPPixelFormat mp_pixel_format_from_v4l_bus_code(uint32_t v4l_bus_code)
  82. {
  83. for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
  84. if (pixel_format_v4l_bus_codes[i] == v4l_bus_code) {
  85. return i;
  86. }
  87. }
  88. return MP_PIXEL_FMT_UNSUPPORTED;
  89. }
  90. uint32_t mp_pixel_format_bits_per_pixel(MPPixelFormat pixel_format)
  91. {
  92. g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
  93. switch (pixel_format) {
  94. case MP_PIXEL_FMT_BGGR8:
  95. case MP_PIXEL_FMT_GBRG8:
  96. case MP_PIXEL_FMT_GRBG8:
  97. case MP_PIXEL_FMT_RGGB8: return 8;
  98. case MP_PIXEL_FMT_BGGR10P:
  99. case MP_PIXEL_FMT_GBRG10P:
  100. case MP_PIXEL_FMT_GRBG10P:
  101. case MP_PIXEL_FMT_RGGB10P: return 10;
  102. case MP_PIXEL_FMT_UYVY:
  103. case MP_PIXEL_FMT_YUYV: return 16;
  104. default: return 0;
  105. }
  106. }
  107. uint32_t mp_pixel_format_width_to_bytes(MPPixelFormat pixel_format, uint32_t width)
  108. {
  109. uint32_t bits_per_pixel = mp_pixel_format_bits_per_pixel(pixel_format);
  110. uint64_t bits_per_width = width * (uint64_t) bits_per_pixel;
  111. uint64_t remainder = bits_per_width % 8;
  112. if (remainder == 0)
  113. return bits_per_width / 8;
  114. return (bits_per_width + 8 - remainder) / 8;
  115. }
  116. uint32_t mp_pixel_format_width_to_colors(MPPixelFormat pixel_format, uint32_t width)
  117. {
  118. g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
  119. switch (pixel_format) {
  120. case MP_PIXEL_FMT_BGGR8:
  121. case MP_PIXEL_FMT_GBRG8:
  122. case MP_PIXEL_FMT_GRBG8:
  123. case MP_PIXEL_FMT_RGGB8: return width / 2;
  124. case MP_PIXEL_FMT_BGGR10P:
  125. case MP_PIXEL_FMT_GBRG10P:
  126. case MP_PIXEL_FMT_GRBG10P:
  127. case MP_PIXEL_FMT_RGGB10P: return width / 2 * 5;
  128. case MP_PIXEL_FMT_UYVY:
  129. case MP_PIXEL_FMT_YUYV: return width;
  130. default: return 0;
  131. }
  132. }
  133. uint32_t mp_pixel_format_height_to_colors(MPPixelFormat pixel_format, uint32_t height)
  134. {
  135. g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
  136. switch (pixel_format) {
  137. case MP_PIXEL_FMT_BGGR8:
  138. case MP_PIXEL_FMT_GBRG8:
  139. case MP_PIXEL_FMT_GRBG8:
  140. case MP_PIXEL_FMT_RGGB8:
  141. case MP_PIXEL_FMT_BGGR10P:
  142. case MP_PIXEL_FMT_GBRG10P:
  143. case MP_PIXEL_FMT_GRBG10P:
  144. case MP_PIXEL_FMT_RGGB10P: return height / 2;
  145. case MP_PIXEL_FMT_UYVY:
  146. case MP_PIXEL_FMT_YUYV: return height;
  147. default: return 0;
  148. }
  149. }
  150. bool mp_camera_mode_is_equivalent(const MPCameraMode *m1, const MPCameraMode *m2)
  151. {
  152. return m1->pixel_format == m2->pixel_format
  153. && m1->frame_interval.numerator == m2->frame_interval.numerator
  154. && m1->frame_interval.denominator == m2->frame_interval.denominator
  155. && m1->width == m2->width
  156. && m1->height == m2->height;
  157. }
  158. static void errno_printerr(const char *s)
  159. {
  160. g_printerr("MPCamera: %s error %d, %s\n", s, errno, strerror(errno));
  161. }
  162. static int xioctl(int fd, int request, void *arg)
  163. {
  164. int r;
  165. do {
  166. r = ioctl(fd, request, arg);
  167. } while (r == -1 && errno == EINTR);
  168. return r;
  169. }
  170. struct video_buffer {
  171. uint32_t length;
  172. uint8_t *data;
  173. };
  174. struct _MPCamera {
  175. int video_fd;
  176. int subdev_fd;
  177. bool has_set_mode;
  178. MPCameraMode current_mode;
  179. struct video_buffer buffers[MAX_VIDEO_BUFFERS];
  180. uint32_t num_buffers;
  181. bool use_mplane;
  182. };
  183. MPCamera *mp_camera_new(int video_fd, int subdev_fd)
  184. {
  185. g_return_val_if_fail(video_fd != -1, NULL);
  186. // Query capabilities
  187. struct v4l2_capability cap;
  188. if (xioctl(video_fd, VIDIOC_QUERYCAP, &cap) == -1) {
  189. return NULL;
  190. }
  191. // Check whether this is a video capture device
  192. bool use_mplane;
  193. if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) {
  194. use_mplane = true;
  195. printf("!!\n");
  196. } else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
  197. use_mplane = false;
  198. } else {
  199. return NULL;
  200. }
  201. MPCamera *camera = malloc(sizeof(MPCamera));
  202. camera->video_fd = video_fd;
  203. camera->subdev_fd = subdev_fd;
  204. camera->has_set_mode = false;
  205. camera->num_buffers = 0;
  206. camera->use_mplane = use_mplane;
  207. return camera;
  208. }
  209. void mp_camera_free(MPCamera *camera)
  210. {
  211. g_warn_if_fail(camera->num_buffers == 0);
  212. if (camera->num_buffers != 0) {
  213. mp_camera_stop_capture(camera);
  214. }
  215. free(camera);
  216. }
  217. bool mp_camera_is_subdev(MPCamera *camera)
  218. {
  219. return camera->subdev_fd != -1;
  220. }
  221. int mp_camera_get_video_fd(MPCamera *camera)
  222. {
  223. return camera->video_fd;
  224. }
  225. int mp_camera_get_subdev_fd(MPCamera *camera)
  226. {
  227. return camera->subdev_fd;
  228. }
  229. static bool camera_mode_impl(MPCamera *camera, int request, MPCameraMode *mode)
  230. {
  231. uint32_t pixfmt = mp_pixel_format_from_v4l_pixel_format(mode->pixel_format);
  232. struct v4l2_format fmt = {};
  233. if (camera->use_mplane) {
  234. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
  235. fmt.fmt.pix_mp.width = mode->width;
  236. fmt.fmt.pix_mp.height = mode->height;
  237. fmt.fmt.pix_mp.pixelformat = pixfmt;
  238. fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
  239. } else {
  240. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  241. fmt.fmt.pix.width = mode->width;
  242. fmt.fmt.pix.height = mode->height;
  243. fmt.fmt.pix.pixelformat = pixfmt;
  244. fmt.fmt.pix.field = V4L2_FIELD_ANY;
  245. }
  246. if (xioctl(camera->video_fd, request, &fmt) == -1) {
  247. return false;
  248. }
  249. if (camera->use_mplane) {
  250. mode->width = fmt.fmt.pix_mp.width;
  251. mode->height = fmt.fmt.pix_mp.height;
  252. mode->pixel_format = mp_pixel_format_from_v4l_pixel_format(
  253. fmt.fmt.pix_mp.pixelformat);
  254. } else {
  255. mode->width = fmt.fmt.pix.width;
  256. mode->height = fmt.fmt.pix.height;
  257. mode->pixel_format = mp_pixel_format_from_v4l_pixel_format(
  258. fmt.fmt.pix.pixelformat);
  259. }
  260. return true;
  261. }
  262. bool mp_camera_try_mode(MPCamera *camera, MPCameraMode *mode)
  263. {
  264. if (!camera_mode_impl(camera, VIDIOC_TRY_FMT, mode)) {
  265. errno_printerr("VIDIOC_S_FMT");
  266. return false;
  267. }
  268. return true;
  269. }
  270. const MPCameraMode *mp_camera_get_mode(const MPCamera *camera)
  271. {
  272. return &camera->current_mode;
  273. }
  274. bool mp_camera_set_mode(MPCamera *camera, MPCameraMode *mode)
  275. {
  276. // Set the mode in the subdev the camera is one
  277. if (mp_camera_is_subdev(camera))
  278. {
  279. struct v4l2_subdev_frame_interval interval = {};
  280. interval.pad = 0;
  281. interval.interval = mode->frame_interval;
  282. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &interval) == -1) {
  283. errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL");
  284. return false;
  285. }
  286. bool did_set_frame_rate =
  287. interval.interval.numerator == mode->frame_interval.numerator
  288. && interval.interval.denominator == mode->frame_interval.denominator;
  289. struct v4l2_subdev_format fmt = {};
  290. fmt.pad = 0;
  291. fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
  292. fmt.format.width = mode->width;
  293. fmt.format.height = mode->height;
  294. fmt.format.code = mp_pixel_format_to_v4l_bus_code(mode->pixel_format);
  295. fmt.format.field = V4L2_FIELD_ANY;
  296. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FMT, &fmt) == -1) {
  297. errno_printerr("VIDIOC_SUBDEV_S_FMT");
  298. return false;
  299. }
  300. // Some drivers like ov5640 don't allow you to set the frame format with
  301. // too high a frame-rate, but that means the frame-rate won't be set
  302. // after the format change. So we need to try again here if we didn't
  303. // succeed before. Ideally we'd be able to set both at once.
  304. if (!did_set_frame_rate)
  305. {
  306. interval.interval = mode->frame_interval;
  307. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &interval) == -1) {
  308. errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL");
  309. return false;
  310. }
  311. }
  312. // Update the mode
  313. mode->pixel_format = mp_pixel_format_from_v4l_bus_code(fmt.format.code);
  314. mode->frame_interval = interval.interval;
  315. mode->width = fmt.format.width;
  316. mode->height = fmt.format.height;
  317. }
  318. // Set the mode for the video device
  319. {
  320. if (!camera_mode_impl(camera, VIDIOC_S_FMT, mode)) {
  321. errno_printerr("VIDIOC_S_FMT");
  322. return false;
  323. }
  324. }
  325. camera->has_set_mode = true;
  326. camera->current_mode = *mode;
  327. return true;
  328. }
  329. bool mp_camera_start_capture(MPCamera *camera)
  330. {
  331. g_return_val_if_fail(camera->has_set_mode, false);
  332. g_return_val_if_fail(camera->num_buffers == 0, false);
  333. // Start by requesting buffers
  334. struct v4l2_requestbuffers req = {};
  335. req.count = MAX_VIDEO_BUFFERS;
  336. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  337. req.memory = V4L2_MEMORY_MMAP;
  338. if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
  339. errno_printerr("VIDIOC_REQBUFS");
  340. return false;
  341. }
  342. if (req.count < 2) {
  343. g_printerr("Insufficient buffer memory. Only %d buffers available.\n",
  344. req.count);
  345. goto error;
  346. }
  347. for (uint32_t i = 0; i < req.count; ++i) {
  348. // Query each buffer and mmap it
  349. struct v4l2_buffer buf = {
  350. .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  351. .memory = V4L2_MEMORY_MMAP,
  352. .index = i,
  353. };
  354. struct v4l2_plane planes[1];
  355. if (camera->use_mplane) {
  356. buf.m.planes = planes;
  357. buf.length = 1;
  358. }
  359. if (xioctl(camera->video_fd, VIDIOC_QUERYBUF, &buf) == -1) {
  360. errno_printerr("VIDIOC_QUERYBUF");
  361. break;
  362. }
  363. if (camera->use_mplane) {
  364. camera->buffers[i].length = planes[0].length;
  365. camera->buffers[i].data = mmap(
  366. NULL,
  367. planes[0].length,
  368. PROT_READ,
  369. MAP_SHARED,
  370. camera->video_fd,
  371. planes[0].m.mem_offset);
  372. } else {
  373. camera->buffers[i].length = buf.length;
  374. camera->buffers[i].data = mmap(
  375. NULL,
  376. buf.length,
  377. PROT_READ,
  378. MAP_SHARED,
  379. camera->video_fd,
  380. buf.m.offset);
  381. }
  382. if (camera->buffers[i].data == MAP_FAILED) {
  383. errno_printerr("mmap");
  384. break;
  385. }
  386. ++camera->num_buffers;
  387. }
  388. if (camera->num_buffers != req.count) {
  389. g_printerr("Unable to map all buffers\n");
  390. goto error;
  391. }
  392. for (uint32_t i = 0; i < camera->num_buffers; ++i) {
  393. struct v4l2_buffer buf = {
  394. .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
  395. .memory = V4L2_MEMORY_MMAP,
  396. .index = i,
  397. };
  398. struct v4l2_plane planes[1];
  399. if (camera->use_mplane) {
  400. buf.m.planes = planes;
  401. buf.length = 1;
  402. }
  403. // Queue the buffer for capture
  404. if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
  405. errno_printerr("VIDIOC_QBUF");
  406. goto error;
  407. }
  408. }
  409. // Start capture
  410. enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  411. if (xioctl(camera->video_fd, VIDIOC_STREAMON, &type) == -1) {
  412. errno_printerr("VIDIOC_STREAMON");
  413. goto error;
  414. }
  415. return true;
  416. error:
  417. // Unmap any mapped buffers
  418. assert(camera->num_buffers <= MAX_VIDEO_BUFFERS);
  419. for (uint32_t i = 0; i < camera->num_buffers; ++i) {
  420. if (munmap(camera->buffers[i].data, camera->buffers[i].length) == -1) {
  421. errno_printerr("munmap");
  422. }
  423. }
  424. // Reset allocated buffers
  425. {
  426. struct v4l2_requestbuffers req = {};
  427. req.count = 0;
  428. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  429. req.memory = V4L2_MEMORY_MMAP;
  430. if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
  431. errno_printerr("VIDIOC_REQBUFS");
  432. }
  433. }
  434. return false;
  435. }
  436. bool mp_camera_stop_capture(MPCamera *camera)
  437. {
  438. g_return_val_if_fail(camera->num_buffers > 0, false);
  439. enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  440. if (xioctl(camera->video_fd, VIDIOC_STREAMOFF, &type) == -1) {
  441. errno_printerr("VIDIOC_STREAMOFF");
  442. }
  443. assert(camera->num_buffers <= MAX_VIDEO_BUFFERS);
  444. for (int i = 0; i < camera->num_buffers; ++i) {
  445. if (munmap(camera->buffers[i].data, camera->buffers[i].length) == -1) {
  446. errno_printerr("munmap");
  447. }
  448. }
  449. camera->num_buffers = 0;
  450. struct v4l2_requestbuffers req = {};
  451. req.count = 0;
  452. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  453. req.memory = V4L2_MEMORY_MMAP;
  454. if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
  455. errno_printerr("VIDIOC_REQBUFS");
  456. }
  457. return true;
  458. }
  459. bool mp_camera_is_capturing(MPCamera *camera)
  460. {
  461. return camera->num_buffers > 0;
  462. }
  463. bool mp_camera_capture_image(MPCamera *camera, void (*callback)(MPImage, void *), void *user_data)
  464. {
  465. struct v4l2_buffer buf = {};
  466. buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  467. buf.memory = V4L2_MEMORY_MMAP;
  468. struct v4l2_plane planes[1];
  469. if (camera->use_mplane) {
  470. buf.m.planes = planes;
  471. buf.length = 1;
  472. }
  473. if (xioctl(camera->video_fd, VIDIOC_DQBUF, &buf) == -1) {
  474. switch (errno) {
  475. case EAGAIN:
  476. return true;
  477. case EIO:
  478. /* Could ignore EIO, see spec. */
  479. /* fallthrough */
  480. default:
  481. errno_printerr("VIDIOC_DQBUF");
  482. return false;
  483. }
  484. }
  485. uint32_t pixel_format = camera->current_mode.pixel_format;
  486. uint32_t width = camera->current_mode.width;
  487. uint32_t height = camera->current_mode.height;
  488. uint32_t bytesused;
  489. if (camera->use_mplane) {
  490. bytesused = planes[0].bytesused;
  491. } else {
  492. bytesused = buf.bytesused;
  493. }
  494. assert(bytesused == mp_pixel_format_width_to_bytes(pixel_format, width) * height);
  495. assert(bytesused == camera->buffers[buf.index].length);
  496. MPImage image = {
  497. .pixel_format = pixel_format,
  498. .width = width,
  499. .height = height,
  500. .data = camera->buffers[buf.index].data,
  501. };
  502. callback(image, user_data);
  503. // The callback may have stopped the capture, only queue the buffer if we're
  504. // still capturing.
  505. if (mp_camera_is_capturing(camera)) {
  506. if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
  507. errno_printerr("VIDIOC_QBUF");
  508. return false;
  509. }
  510. }
  511. return true;
  512. }
  513. struct _MPCameraModeList {
  514. MPCameraMode mode;
  515. MPCameraModeList *next;
  516. };
  517. static MPCameraModeList *
  518. get_subdev_modes(MPCamera *camera, bool (*check)(MPCamera *, MPCameraMode *))
  519. {
  520. MPCameraModeList *item = NULL;
  521. for (uint32_t fmt_index = 0;; ++fmt_index) {
  522. struct v4l2_subdev_mbus_code_enum fmt = {};
  523. fmt.index = fmt_index;
  524. fmt.pad = 0;
  525. fmt.which = V4L2_SUBDEV_FORMAT_TRY;
  526. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &fmt) == -1) {
  527. if (errno != EINVAL) {
  528. errno_printerr("VIDIOC_SUBDEV_ENUM_MBUS_CODE");
  529. }
  530. break;
  531. }
  532. // Skip unsupported formats
  533. uint32_t format = mp_pixel_format_from_v4l_bus_code(fmt.code);
  534. if (format == MP_PIXEL_FMT_UNSUPPORTED) {
  535. continue;
  536. }
  537. for (uint32_t frame_index = 0;; ++frame_index) {
  538. struct v4l2_subdev_frame_size_enum frame = {};
  539. frame.index = frame_index;
  540. frame.pad = 0;
  541. frame.code = fmt.code;
  542. frame.which = V4L2_SUBDEV_FORMAT_TRY;
  543. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &frame) == -1) {
  544. if (errno != EINVAL) {
  545. errno_printerr("VIDIOC_SUBDEV_ENUM_FRAME_SIZE");
  546. }
  547. break;
  548. }
  549. // TODO: Handle other types
  550. if (frame.min_width != frame.max_width
  551. || frame.min_height != frame.max_height) {
  552. break;
  553. }
  554. for (uint32_t interval_index = 0;; ++interval_index) {
  555. struct v4l2_subdev_frame_interval_enum interval = {};
  556. interval.index = interval_index;
  557. interval.pad = 0;
  558. interval.code = fmt.code;
  559. interval.width = frame.max_width;
  560. interval.height = frame.max_height;
  561. interval.which = V4L2_SUBDEV_FORMAT_TRY;
  562. if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &interval) == -1) {
  563. if (errno != EINVAL) {
  564. errno_printerr("VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL");
  565. }
  566. break;
  567. }
  568. MPCameraMode mode = {
  569. .pixel_format = format,
  570. .frame_interval = interval.interval,
  571. .width = frame.max_width,
  572. .height = frame.max_height,
  573. };
  574. if (!check(camera, &mode)) {
  575. continue;
  576. }
  577. MPCameraModeList *new_item = malloc(sizeof(MPCameraModeList));
  578. new_item->mode = mode;
  579. new_item->next = item;
  580. item = new_item;
  581. }
  582. }
  583. }
  584. return item;
  585. }
  586. static MPCameraModeList *
  587. get_video_modes(MPCamera *camera, bool (*check)(MPCamera *, MPCameraMode *))
  588. {
  589. MPCameraModeList *item = NULL;
  590. for (uint32_t fmt_index = 0;; ++fmt_index) {
  591. struct v4l2_fmtdesc fmt = {};
  592. fmt.index = fmt_index;
  593. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  594. if (xioctl(camera->video_fd, VIDIOC_ENUM_FMT, &fmt) == -1) {
  595. if (errno != EINVAL) {
  596. errno_printerr("VIDIOC_ENUM_FMT");
  597. }
  598. break;
  599. }
  600. // Skip unsupported formats
  601. uint32_t format = mp_pixel_format_from_v4l_pixel_format(fmt.pixelformat);
  602. if (format == MP_PIXEL_FMT_UNSUPPORTED) {
  603. continue;
  604. }
  605. for (uint32_t frame_index = 0;; ++frame_index) {
  606. struct v4l2_frmsizeenum frame = {};
  607. frame.index = frame_index;
  608. frame.pixel_format = fmt.pixelformat;
  609. if (xioctl(camera->video_fd, VIDIOC_ENUM_FRAMESIZES, &frame) == -1) {
  610. if (errno != EINVAL) {
  611. errno_printerr("VIDIOC_ENUM_FRAMESIZES");
  612. }
  613. break;
  614. }
  615. // TODO: Handle other types
  616. if (frame.type != V4L2_FRMSIZE_TYPE_DISCRETE) {
  617. break;
  618. }
  619. for (uint32_t interval_index = 0;; ++interval_index) {
  620. struct v4l2_frmivalenum interval = {};
  621. interval.index = interval_index;
  622. interval.pixel_format = fmt.pixelformat;
  623. interval.width = frame.discrete.width;
  624. interval.height = frame.discrete.height;
  625. if (xioctl(camera->video_fd, VIDIOC_ENUM_FRAMEINTERVALS, &interval) == -1) {
  626. if (errno != EINVAL) {
  627. errno_printerr("VIDIOC_ENUM_FRAMESIZES");
  628. }
  629. break;
  630. }
  631. // TODO: Handle other types
  632. if (interval.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
  633. break;
  634. }
  635. MPCameraMode mode = {
  636. .pixel_format = format,
  637. .frame_interval = interval.discrete,
  638. .width = frame.discrete.width,
  639. .height = frame.discrete.height,
  640. };
  641. if (!check(camera, &mode)) {
  642. continue;
  643. }
  644. MPCameraModeList *new_item = malloc(sizeof(MPCameraModeList));
  645. new_item->mode = mode;
  646. new_item->next = item;
  647. item = new_item;
  648. }
  649. }
  650. }
  651. return item;
  652. }
  653. static bool all_modes(MPCamera *camera, MPCameraMode *mode)
  654. {
  655. return true;
  656. }
  657. static bool available_modes(MPCamera *camera, MPCameraMode *mode)
  658. {
  659. MPCameraMode attempt = *mode;
  660. return mp_camera_try_mode(camera, &attempt)
  661. && mp_camera_mode_is_equivalent(mode, &attempt);
  662. }
  663. MPCameraModeList *mp_camera_list_supported_modes(MPCamera *camera)
  664. {
  665. if (mp_camera_is_subdev(camera)) {
  666. return get_subdev_modes(camera, all_modes);
  667. } else {
  668. return get_video_modes(camera, all_modes);
  669. }
  670. }
  671. MPCameraModeList *mp_camera_list_available_modes(MPCamera *camera)
  672. {
  673. if (mp_camera_is_subdev(camera)) {
  674. return get_subdev_modes(camera, available_modes);
  675. } else {
  676. return get_video_modes(camera, available_modes);
  677. }
  678. }
  679. MPCameraMode *mp_camera_mode_list_get(MPCameraModeList *list)
  680. {
  681. g_return_val_if_fail(list, NULL);
  682. return &list->mode;
  683. }
  684. MPCameraModeList *mp_camera_mode_list_next(MPCameraModeList *list)
  685. {
  686. g_return_val_if_fail(list, NULL);
  687. return list->next;
  688. }
  689. void mp_camera_mode_list_free(MPCameraModeList *list)
  690. {
  691. while (list) {
  692. MPCameraModeList *tmp = list;
  693. list = tmp->next;
  694. free(tmp);
  695. }
  696. }
  697. struct int_str_pair {
  698. uint32_t value;
  699. const char *str;
  700. };
  701. struct int_str_pair control_id_names[] = {
  702. { V4L2_CID_BRIGHTNESS, "BRIGHTNESS" },
  703. { V4L2_CID_CONTRAST, "CONTRAST" },
  704. { V4L2_CID_SATURATION, "SATURATION" },
  705. { V4L2_CID_HUE, "HUE" },
  706. { V4L2_CID_AUDIO_VOLUME, "AUDIO_VOLUME" },
  707. { V4L2_CID_AUDIO_BALANCE, "AUDIO_BALANCE" },
  708. { V4L2_CID_AUDIO_BASS, "AUDIO_BASS" },
  709. { V4L2_CID_AUDIO_TREBLE, "AUDIO_TREBLE" },
  710. { V4L2_CID_AUDIO_MUTE, "AUDIO_MUTE" },
  711. { V4L2_CID_AUDIO_LOUDNESS, "AUDIO_LOUDNESS" },
  712. { V4L2_CID_BLACK_LEVEL, "BLACK_LEVEL" },
  713. { V4L2_CID_AUTO_WHITE_BALANCE, "AUTO_WHITE_BALANCE" },
  714. { V4L2_CID_DO_WHITE_BALANCE, "DO_WHITE_BALANCE" },
  715. { V4L2_CID_RED_BALANCE, "RED_BALANCE" },
  716. { V4L2_CID_BLUE_BALANCE, "BLUE_BALANCE" },
  717. { V4L2_CID_GAMMA, "GAMMA" },
  718. { V4L2_CID_WHITENESS, "WHITENESS" },
  719. { V4L2_CID_EXPOSURE, "EXPOSURE" },
  720. { V4L2_CID_AUTOGAIN, "AUTOGAIN" },
  721. { V4L2_CID_GAIN, "GAIN" },
  722. { V4L2_CID_HFLIP, "HFLIP" },
  723. { V4L2_CID_VFLIP, "VFLIP" },
  724. { V4L2_CID_POWER_LINE_FREQUENCY, "POWER_LINE_FREQUENCY" },
  725. { V4L2_CID_HUE_AUTO, "HUE_AUTO" },
  726. { V4L2_CID_WHITE_BALANCE_TEMPERATURE, "WHITE_BALANCE_TEMPERATURE" },
  727. { V4L2_CID_SHARPNESS, "SHARPNESS" },
  728. { V4L2_CID_BACKLIGHT_COMPENSATION, "BACKLIGHT_COMPENSATION" },
  729. { V4L2_CID_CHROMA_AGC, "CHROMA_AGC" },
  730. { V4L2_CID_COLOR_KILLER, "COLOR_KILLER" },
  731. { V4L2_CID_COLORFX, "COLORFX" },
  732. { V4L2_CID_AUTOBRIGHTNESS, "AUTOBRIGHTNESS" },
  733. { V4L2_CID_BAND_STOP_FILTER, "BAND_STOP_FILTER" },
  734. { V4L2_CID_ROTATE, "ROTATE" },
  735. { V4L2_CID_BG_COLOR, "BG_COLOR" },
  736. { V4L2_CID_CHROMA_GAIN, "CHROMA_GAIN" },
  737. { V4L2_CID_ILLUMINATORS_1, "ILLUMINATORS_1" },
  738. { V4L2_CID_ILLUMINATORS_2, "ILLUMINATORS_2" },
  739. { V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, "MIN_BUFFERS_FOR_CAPTURE" },
  740. { V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, "MIN_BUFFERS_FOR_OUTPUT" },
  741. { V4L2_CID_ALPHA_COMPONENT, "ALPHA_COMPONENT" },
  742. { V4L2_CID_COLORFX_CBCR, "COLORFX_CBCR" },
  743. { V4L2_CID_LASTP1, "LASTP1" },
  744. { V4L2_CID_USER_MEYE_BASE, "USER_MEYE_BASE" },
  745. { V4L2_CID_USER_BTTV_BASE, "USER_BTTV_BASE" },
  746. { V4L2_CID_USER_S2255_BASE, "USER_S2255_BASE" },
  747. { V4L2_CID_USER_SI476X_BASE, "USER_SI476X_BASE" },
  748. { V4L2_CID_USER_TI_VPE_BASE, "USER_TI_VPE_BASE" },
  749. { V4L2_CID_USER_SAA7134_BASE, "USER_SAA7134_BASE" },
  750. { V4L2_CID_USER_ADV7180_BASE, "USER_ADV7180_BASE" },
  751. { V4L2_CID_USER_TC358743_BASE, "USER_TC358743_BASE" },
  752. { V4L2_CID_USER_MAX217X_BASE, "USER_MAX217X_BASE" },
  753. { V4L2_CID_USER_IMX_BASE, "USER_IMX_BASE" },
  754. // { V4L2_CID_USER_ATMEL_ISC_BASE, "USER_ATMEL_ISC_BASE" },
  755. { V4L2_CID_CAMERA_CLASS_BASE, "CAMERA_CLASS_BASE" },
  756. { V4L2_CID_CAMERA_CLASS, "CAMERA_CLASS" },
  757. { V4L2_CID_EXPOSURE_AUTO, "EXPOSURE_AUTO" },
  758. { V4L2_CID_EXPOSURE_ABSOLUTE, "EXPOSURE_ABSOLUTE" },
  759. { V4L2_CID_EXPOSURE_AUTO_PRIORITY, "EXPOSURE_AUTO_PRIORITY" },
  760. { V4L2_CID_PAN_RELATIVE, "PAN_RELATIVE" },
  761. { V4L2_CID_TILT_RELATIVE, "TILT_RELATIVE" },
  762. { V4L2_CID_PAN_RESET, "PAN_RESET" },
  763. { V4L2_CID_TILT_RESET, "TILT_RESET" },
  764. { V4L2_CID_PAN_ABSOLUTE, "PAN_ABSOLUTE" },
  765. { V4L2_CID_TILT_ABSOLUTE, "TILT_ABSOLUTE" },
  766. { V4L2_CID_FOCUS_ABSOLUTE, "FOCUS_ABSOLUTE" },
  767. { V4L2_CID_FOCUS_RELATIVE, "FOCUS_RELATIVE" },
  768. { V4L2_CID_FOCUS_AUTO, "FOCUS_AUTO" },
  769. { V4L2_CID_ZOOM_ABSOLUTE, "ZOOM_ABSOLUTE" },
  770. { V4L2_CID_ZOOM_RELATIVE, "ZOOM_RELATIVE" },
  771. { V4L2_CID_ZOOM_CONTINUOUS, "ZOOM_CONTINUOUS" },
  772. { V4L2_CID_PRIVACY, "PRIVACY" },
  773. { V4L2_CID_IRIS_ABSOLUTE, "IRIS_ABSOLUTE" },
  774. { V4L2_CID_IRIS_RELATIVE, "IRIS_RELATIVE" },
  775. { V4L2_CID_AUTO_EXPOSURE_BIAS, "AUTO_EXPOSURE_BIAS" },
  776. { V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, "AUTO_N_PRESET_WHITE_BALANCE" },
  777. { V4L2_CID_WIDE_DYNAMIC_RANGE, "WIDE_DYNAMIC_RANGE" },
  778. { V4L2_CID_IMAGE_STABILIZATION, "IMAGE_STABILIZATION" },
  779. { V4L2_CID_ISO_SENSITIVITY, "ISO_SENSITIVITY" },
  780. { V4L2_CID_ISO_SENSITIVITY_AUTO, "ISO_SENSITIVITY_AUTO" },
  781. { V4L2_CID_EXPOSURE_METERING, "EXPOSURE_METERING" },
  782. { V4L2_CID_SCENE_MODE, "SCENE_MODE" },
  783. { V4L2_CID_3A_LOCK, "3A_LOCK" },
  784. { V4L2_CID_AUTO_FOCUS_START, "AUTO_FOCUS_START" },
  785. { V4L2_CID_AUTO_FOCUS_STOP, "AUTO_FOCUS_STOP" },
  786. { V4L2_CID_AUTO_FOCUS_STATUS, "AUTO_FOCUS_STATUS" },
  787. { V4L2_CID_AUTO_FOCUS_RANGE, "AUTO_FOCUS_RANGE" },
  788. { V4L2_CID_PAN_SPEED, "PAN_SPEED" },
  789. { V4L2_CID_TILT_SPEED, "TILT_SPEED" },
  790. // { V4L2_CID_CAMERA_ORIENTATION, "CAMERA_ORIENTATION" },
  791. // { V4L2_CID_CAMERA_SENSOR_ROTATION, "CAMERA_SENSOR_ROTATION" },
  792. { V4L2_CID_FLASH_LED_MODE, "FLASH_LED_MODE" },
  793. { V4L2_CID_FLASH_STROBE_SOURCE, "FLASH_STROBE_SOURCE" },
  794. { V4L2_CID_FLASH_STROBE, "FLASH_STROBE" },
  795. { V4L2_CID_FLASH_STROBE_STOP, "FLASH_STROBE_STOP" },
  796. { V4L2_CID_FLASH_STROBE_STATUS, "FLASH_STROBE_STATUS" },
  797. { V4L2_CID_FLASH_TIMEOUT, "FLASH_TIMEOUT" },
  798. { V4L2_CID_FLASH_INTENSITY, "FLASH_INTENSITY" },
  799. { V4L2_CID_FLASH_TORCH_INTENSITY, "FLASH_TORCH_INTENSITY" },
  800. { V4L2_CID_FLASH_INDICATOR_INTENSITY, "FLASH_INDICATOR_INTENSITY" },
  801. { V4L2_CID_FLASH_FAULT, "FLASH_FAULT" },
  802. { V4L2_CID_FLASH_CHARGE, "FLASH_CHARGE" },
  803. { V4L2_CID_FLASH_READY, "FLASH_READY" },
  804. };
  805. const char *mp_control_id_to_str(uint32_t id)
  806. {
  807. size_t size = sizeof(control_id_names) / sizeof(*control_id_names);
  808. for (size_t i = 0; i < size; ++i) {
  809. if (control_id_names[i].value == id) {
  810. return control_id_names[i].str;
  811. }
  812. }
  813. return "UNKNOWN";
  814. }
  815. struct int_str_pair control_type_names[] = {
  816. { V4L2_CTRL_TYPE_INTEGER, "INTEGER" },
  817. { V4L2_CTRL_TYPE_BOOLEAN, "BOOLEAN" },
  818. { V4L2_CTRL_TYPE_MENU, "MENU" },
  819. { V4L2_CTRL_TYPE_INTEGER_MENU, "INTEGER_MENU" },
  820. { V4L2_CTRL_TYPE_BITMASK, "BITMASK" },
  821. { V4L2_CTRL_TYPE_BUTTON, "BUTTON" },
  822. { V4L2_CTRL_TYPE_INTEGER64, "INTEGER64" },
  823. { V4L2_CTRL_TYPE_STRING, "STRING" },
  824. { V4L2_CTRL_TYPE_CTRL_CLASS, "CTRL_CLASS" },
  825. { V4L2_CTRL_TYPE_U8, "U8" },
  826. { V4L2_CTRL_TYPE_U16, "U16" },
  827. { V4L2_CTRL_TYPE_U32, "U32" },
  828. // { V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS, "MPEG2_SLICE_PARAMS" },
  829. // { V4L2_CTRL_TYPE_MPEG2_QUANTIZATION, "MPEG2_QUANTIZATION" },
  830. // { V4L2_CTRL_TYPE_AREA, "AREA" },
  831. // { V4L2_CTRL_TYPE_H264_SPS, "H264_SPS" },
  832. // { V4L2_CTRL_TYPE_H264_PPS, "H264_PPS" },
  833. // { V4L2_CTRL_TYPE_H264_SCALING_MATRIX, "H264_SCALING_MATRIX" },
  834. // { V4L2_CTRL_TYPE_H264_SLICE_PARAMS, "H264_SLICE_PARAMS" },
  835. // { V4L2_CTRL_TYPE_H264_DECODE_PARAMS, "H264_DECODE_PARAMS" },
  836. // { V4L2_CTRL_TYPE_HEVC_SPS, "HEVC_SPS" },
  837. // { V4L2_CTRL_TYPE_HEVC_PPS, "HEVC_PPS" },
  838. // { V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, "HEVC_SLICE_PARAMS" },
  839. };
  840. const char *mp_control_type_to_str(uint32_t type)
  841. {
  842. size_t size = sizeof(control_type_names) / sizeof(*control_type_names);
  843. for (size_t i = 0; i < size; ++i) {
  844. if (control_type_names[i].value == type) {
  845. return control_type_names[i].str;
  846. }
  847. }
  848. return "UNKNOWN";
  849. }
  850. struct _MPControlList {
  851. MPControl control;
  852. MPControlList *next;
  853. };
  854. static int control_fd(MPCamera *camera)
  855. {
  856. if (camera->subdev_fd != -1) {
  857. return camera->subdev_fd;
  858. }
  859. return camera->video_fd;
  860. }
  861. MPControlList *mp_camera_list_controls(MPCamera *camera)
  862. {
  863. MPControlList *item = NULL;
  864. struct v4l2_query_ext_ctrl ctrl = {};
  865. ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
  866. while (true) {
  867. if (xioctl(control_fd(camera), VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) {
  868. if (errno != EINVAL) {
  869. errno_printerr("VIDIOC_QUERY_EXT_CTRL");
  870. }
  871. break;
  872. }
  873. MPControl control = {
  874. .id = ctrl.id,
  875. .type = ctrl.type,
  876. .name = {},
  877. .min = ctrl.minimum,
  878. .max = ctrl.maximum,
  879. .step = ctrl.step,
  880. .default_value = ctrl.default_value,
  881. .flags = ctrl.flags,
  882. .element_size = ctrl.elem_size,
  883. .element_count = ctrl.elems,
  884. .dimensions_count = ctrl.nr_of_dims,
  885. .dimensions = {},
  886. };
  887. strcpy(control.name, ctrl.name);
  888. memcpy(control.dimensions, ctrl.dims, sizeof(uint32_t) * V4L2_CTRL_MAX_DIMS);
  889. MPControlList *new_item = malloc(sizeof(MPControlList));
  890. new_item->control = control;
  891. new_item->next = item;
  892. item = new_item;
  893. ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
  894. }
  895. return item;
  896. }
  897. MPControl *mp_control_list_get(MPControlList *list)
  898. {
  899. g_return_val_if_fail(list, NULL);
  900. return &list->control;
  901. }
  902. MPControlList *mp_control_list_next(MPControlList *list)
  903. {
  904. g_return_val_if_fail(list, NULL);
  905. return list->next;
  906. }
  907. void mp_control_list_free(MPControlList *list)
  908. {
  909. while (list) {
  910. MPControlList *tmp = list;
  911. list = tmp->next;
  912. free(tmp);
  913. }
  914. }
  915. bool mp_camera_query_control(MPCamera *camera, uint32_t id, MPControl *control)
  916. {
  917. struct v4l2_query_ext_ctrl ctrl = {};
  918. ctrl.id = id;
  919. if (xioctl(control_fd(camera), VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) {
  920. errno_printerr("VIDIOC_QUERY_EXT_CTRL");
  921. return false;
  922. }
  923. if (control) {
  924. control->id = ctrl.id;
  925. control->type = ctrl.type;
  926. strcpy(control->name, ctrl.name);
  927. control->min = ctrl.minimum;
  928. control->max = ctrl.maximum;
  929. control->step = ctrl.step;
  930. control->default_value = ctrl.default_value;
  931. control->flags = ctrl.flags;
  932. control->element_size = ctrl.elem_size;
  933. control->element_count = ctrl.elems;
  934. control->dimensions_count = ctrl.nr_of_dims;
  935. memcpy(control->dimensions, ctrl.dims, sizeof(uint32_t) * V4L2_CTRL_MAX_DIMS);
  936. }
  937. return true;
  938. }
  939. static bool control_impl_int32(MPCamera *camera, uint32_t id, int request, int32_t *value)
  940. {
  941. struct v4l2_ext_control ctrl = {};
  942. ctrl.id = id;
  943. ctrl.value = *value;
  944. struct v4l2_ext_controls ctrls = {
  945. .ctrl_class = 0,
  946. .which = V4L2_CTRL_WHICH_CUR_VAL,
  947. .count = 1,
  948. .controls = &ctrl,
  949. };
  950. if (xioctl(control_fd(camera), request, &ctrls) == -1) {
  951. return false;
  952. }
  953. *value = ctrl.value;
  954. return true;
  955. }
  956. bool mp_camera_control_try_int32(MPCamera *camera, uint32_t id, int32_t *v)
  957. {
  958. return control_impl_int32(camera, id, VIDIOC_TRY_EXT_CTRLS, v);
  959. }
  960. bool mp_camera_control_set_int32(MPCamera *camera, uint32_t id, int32_t v)
  961. {
  962. return control_impl_int32(camera, id, VIDIOC_S_EXT_CTRLS, &v);
  963. }
  964. int32_t mp_camera_control_get_int32(MPCamera *camera, uint32_t id)
  965. {
  966. int32_t v = 0;
  967. control_impl_int32(camera, id, VIDIOC_G_EXT_CTRLS, &v);
  968. return v;
  969. }
  970. bool mp_camera_control_try_boolean(MPCamera *camera, uint32_t id, bool *v)
  971. {
  972. int32_t value = *v;
  973. bool s = control_impl_int32(camera, id, VIDIOC_TRY_EXT_CTRLS, &value);
  974. *v = value;
  975. return s;
  976. }
  977. bool mp_camera_control_set_bool(MPCamera *camera, uint32_t id, bool v)
  978. {
  979. int32_t value = v;
  980. return control_impl_int32(camera, id, VIDIOC_S_EXT_CTRLS, &value);
  981. }
  982. bool mp_camera_control_get_bool(MPCamera *camera, uint32_t id)
  983. {
  984. int32_t v = false;
  985. control_impl_int32(camera, id, VIDIOC_G_EXT_CTRLS, &v);
  986. return v;
  987. }