io_pipeline.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. #include "io_pipeline.h"
  2. #include "device.h"
  3. #include "camera.h"
  4. #include "pipeline.h"
  5. #include "process_pipeline.h"
  6. #include <string.h>
  7. #include <glib.h>
  8. #include <fcntl.h>
  9. #include <sys/ioctl.h>
  10. #include <errno.h>
  11. #include <assert.h>
  12. #include <stdio.h>
  13. struct media_link_info {
  14. unsigned int source_entity_id;
  15. unsigned int target_entity_id;
  16. char source_fname[260];
  17. char target_fname[260];
  18. };
  19. struct camera_info {
  20. size_t device_index;
  21. unsigned int pad_id;
  22. char dev_fname[260];
  23. int fd;
  24. MPCamera *camera;
  25. int gain_ctrl;
  26. int gain_max;
  27. bool has_auto_focus_continuous;
  28. bool has_auto_focus_start;
  29. // unsigned int entity_id;
  30. // enum v4l2_buf_type type;
  31. // char media_dev_fname[260];
  32. // char video_dev_fname[260];
  33. // int media_fd;
  34. // struct mp_media_link media_links[MP_MAX_LINKS];
  35. // int num_media_links;
  36. // int gain_ctrl;
  37. };
  38. struct device_info {
  39. const char *media_dev_name; // owned by camera config
  40. MPDevice *device;
  41. unsigned int interface_pad_id;
  42. int video_fd;
  43. };
  44. static struct camera_info cameras[MP_MAX_CAMERAS];
  45. static struct device_info devices[MP_MAX_CAMERAS];
  46. static size_t num_devices = 0;
  47. static const struct mp_camera_config *camera = NULL;
  48. static MPCameraMode mode;
  49. static bool just_switched_mode = false;
  50. static int blank_frame_count = 0;
  51. static int burst_length;
  52. static int captures_remaining = 0;
  53. static int preview_width;
  54. static int preview_height;
  55. struct control_state {
  56. bool gain_is_manual;
  57. int gain;
  58. bool exposure_is_manual;
  59. int exposure;
  60. };
  61. static struct control_state desired_controls = {};
  62. static struct control_state current_controls = {};
  63. static bool want_focus = false;
  64. static MPPipeline *pipeline;
  65. static GSource *capture_source;
  66. static int
  67. xioctl(int fd, int request, void *arg)
  68. {
  69. int c = 0;
  70. int r;
  71. do {
  72. r = ioctl(fd, request, arg);
  73. ++c;
  74. if (c > 1)
  75. printf("ioctl retry %d\n", c);
  76. } while (r == -1 && errno == EINTR);
  77. return r;
  78. }
  79. static int
  80. v4l2_ctrl_set(int fd, uint32_t id, int val)
  81. {
  82. struct v4l2_control ctrl = {0};
  83. ctrl.id = id;
  84. ctrl.value = val;
  85. if (xioctl(fd, VIDIOC_S_CTRL, &ctrl) == -1) {
  86. g_printerr("Failed to set control %d to %d\n", id, val);
  87. return -1;
  88. }
  89. return 0;
  90. }
  91. static int
  92. v4l2_ctrl_get(int fd, uint32_t id)
  93. {
  94. struct v4l2_control ctrl = {0};
  95. ctrl.id = id;
  96. if (xioctl(fd, VIDIOC_G_CTRL, &ctrl) == -1) {
  97. g_printerr("Failed to get control %d\n", id);
  98. return -1;
  99. }
  100. return ctrl.value;
  101. }
  102. static int
  103. v4l2_ctrl_get_max(int fd, uint32_t id)
  104. {
  105. struct v4l2_queryctrl queryctrl;
  106. int ret;
  107. memset(&queryctrl, 0, sizeof(queryctrl));
  108. queryctrl.id = id;
  109. ret = xioctl(fd, VIDIOC_QUERYCTRL, &queryctrl);
  110. if (ret)
  111. return 0;
  112. if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
  113. return 0;
  114. }
  115. return queryctrl.maximum;
  116. }
  117. static int
  118. v4l2_has_control(int fd, int control_id)
  119. {
  120. struct v4l2_queryctrl queryctrl;
  121. int ret;
  122. memset(&queryctrl, 0, sizeof(queryctrl));
  123. queryctrl.id = control_id;
  124. ret = xioctl(fd, VIDIOC_QUERYCTRL, &queryctrl);
  125. if (ret)
  126. return 0;
  127. if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
  128. return 0;
  129. }
  130. return 1;
  131. }
  132. static void setup_camera(MPDeviceList **device_list, const struct mp_camera_config *config)
  133. {
  134. // Find device info
  135. size_t device_index = 0;
  136. for (; device_index < num_devices; ++device_index) {
  137. if (strcmp(config->media_dev_name, devices[device_index].media_dev_name) == 0) {
  138. break;
  139. }
  140. }
  141. if (device_index == num_devices)
  142. {
  143. device_index = num_devices;
  144. // Initialize new device
  145. struct device_info *info = &devices[device_index];
  146. info->media_dev_name = config->media_dev_name;
  147. info->device = mp_device_list_find_remove(device_list, info->media_dev_name);
  148. if (!info->device) {
  149. g_printerr("Could not find /dev/media* node matching '%s'\n", info->media_dev_name);
  150. exit(EXIT_FAILURE);
  151. }
  152. const struct media_v2_entity *entity = mp_device_find_entity(info->device, info->media_dev_name);
  153. if (!entity) {
  154. g_printerr("Count not find device video entity\n");
  155. exit(EXIT_FAILURE);
  156. }
  157. const struct media_v2_pad *pad = mp_device_get_pad_from_entity(info->device, entity->id);
  158. info->interface_pad_id = pad->id;
  159. const struct media_v2_interface *interface = mp_device_find_entity_interface(info->device, entity->id);
  160. char dev_name[260];
  161. if (!mp_find_device_path(interface->devnode, dev_name, 260)) {
  162. g_printerr("Count not find video path\n");
  163. exit(EXIT_FAILURE);
  164. }
  165. info->video_fd = open(dev_name, O_RDWR);
  166. if (info->video_fd == -1) {
  167. g_printerr("Could not open %s\n", dev_name);
  168. exit(EXIT_FAILURE);
  169. }
  170. ++num_devices;
  171. }
  172. {
  173. struct camera_info *info = &cameras[config->index];
  174. struct device_info *dev_info = &devices[device_index];
  175. info->device_index = device_index;
  176. const struct media_v2_entity *entity = mp_device_find_entity(dev_info->device, config->dev_name);
  177. if (!entity) {
  178. g_printerr("Count not find camera entity matching '%s'\n", config->dev_name);
  179. exit(EXIT_FAILURE);
  180. }
  181. const struct media_v2_pad *pad = mp_device_get_pad_from_entity(dev_info->device, entity->id);
  182. info->pad_id = pad->id;
  183. // Make sure the camera starts out as disabled
  184. mp_device_setup_link(
  185. dev_info->device,
  186. info->pad_id,
  187. dev_info->interface_pad_id,
  188. false);
  189. const struct media_v2_interface *interface = mp_device_find_entity_interface(dev_info->device, entity->id);
  190. if (!mp_find_device_path(interface->devnode, info->dev_fname, 260)) {
  191. g_printerr("Count not find camera device path\n");
  192. exit(EXIT_FAILURE);
  193. }
  194. info->fd = open(info->dev_fname, O_RDWR);
  195. if (info->fd == -1) {
  196. g_printerr("Could not open %s\n", info->dev_fname);
  197. exit(EXIT_FAILURE);
  198. }
  199. info->camera = mp_camera_new(dev_info->video_fd, info->fd);
  200. // Trigger continuous auto focus if the sensor supports it
  201. if (v4l2_has_control(info->fd, V4L2_CID_FOCUS_AUTO)) {
  202. info->has_auto_focus_continuous = true;
  203. v4l2_ctrl_set(info->fd, V4L2_CID_FOCUS_AUTO, 1);
  204. }
  205. if (v4l2_has_control(info->fd, V4L2_CID_AUTO_FOCUS_START)) {
  206. info->has_auto_focus_start = true;
  207. }
  208. if (v4l2_has_control(info->fd, V4L2_CID_GAIN)) {
  209. info->gain_ctrl = V4L2_CID_GAIN;
  210. info->gain_max = v4l2_ctrl_get_max(info->fd, V4L2_CID_GAIN);
  211. }
  212. if (v4l2_has_control(info->fd, V4L2_CID_ANALOGUE_GAIN)) {
  213. info->gain_ctrl = V4L2_CID_ANALOGUE_GAIN;
  214. info->gain_max = v4l2_ctrl_get_max(info->fd, V4L2_CID_ANALOGUE_GAIN);
  215. }
  216. }
  217. }
  218. static void setup(MPPipeline *pipeline, const void *data)
  219. {
  220. MPDeviceList *device_list = mp_device_list_new();
  221. for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) {
  222. const struct mp_camera_config *config = mp_get_camera_config(i);
  223. if (!config) {
  224. break;
  225. }
  226. setup_camera(&device_list, config);
  227. }
  228. mp_device_list_free(device_list);
  229. }
  230. void mp_io_pipeline_start()
  231. {
  232. mp_process_pipeline_start();
  233. pipeline = mp_pipeline_new();
  234. mp_pipeline_invoke(pipeline, setup, NULL, 0);
  235. }
  236. void mp_io_pipeline_stop()
  237. {
  238. if (capture_source) {
  239. g_source_destroy(capture_source);
  240. }
  241. mp_pipeline_free(pipeline);
  242. mp_process_pipeline_stop();
  243. }
  244. static void
  245. update_process_pipeline()
  246. {
  247. struct camera_info *info = &cameras[camera->index];
  248. // Grab the latest control values
  249. if (!current_controls.gain_is_manual) {
  250. current_controls.gain = v4l2_ctrl_get(info->fd, info->gain_ctrl);
  251. }
  252. if (!current_controls.exposure_is_manual) {
  253. current_controls.exposure = v4l2_ctrl_get(info->fd, V4L2_CID_EXPOSURE);
  254. }
  255. struct mp_process_pipeline_state pipeline_state = {
  256. .camera = camera,
  257. .mode = mode,
  258. .burst_length = burst_length,
  259. .preview_width = preview_width,
  260. .preview_height = preview_height,
  261. .gain_is_manual = current_controls.gain_is_manual,
  262. .gain = current_controls.gain,
  263. .gain_max = info->gain_max,
  264. .exposure_is_manual = current_controls.exposure_is_manual,
  265. .exposure = current_controls.exposure,
  266. .has_auto_focus_continuous = info->has_auto_focus_continuous,
  267. .has_auto_focus_start = info->has_auto_focus_start,
  268. };
  269. mp_process_pipeline_update_state(&pipeline_state);
  270. }
  271. static void
  272. focus(MPPipeline *pipeline, const void *data)
  273. {
  274. want_focus = true;
  275. }
  276. void mp_io_pipeline_focus()
  277. {
  278. mp_pipeline_invoke(pipeline, focus, NULL, 0);
  279. }
  280. static void
  281. capture(MPPipeline *pipeline, const void *data)
  282. {
  283. struct camera_info *info = &cameras[camera->index];
  284. captures_remaining = burst_length;
  285. // Disable the autogain/exposure while taking the burst
  286. v4l2_ctrl_set(info->fd, V4L2_CID_AUTOGAIN, 0);
  287. v4l2_ctrl_set(info->fd, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL);
  288. // Change camera mode for capturing
  289. mp_camera_stop_capture(info->camera);
  290. mode = camera->capture_mode;
  291. mp_camera_set_mode(info->camera, &mode);
  292. just_switched_mode = true;
  293. mp_camera_start_capture(info->camera);
  294. update_process_pipeline();
  295. mp_process_pipeline_capture();
  296. }
  297. void mp_io_pipeline_capture()
  298. {
  299. mp_pipeline_invoke(pipeline, capture, NULL, 0);
  300. }
  301. static void
  302. update_controls()
  303. {
  304. // Don't update controls while capturing
  305. if (captures_remaining > 0) {
  306. return;
  307. }
  308. struct camera_info *info = &cameras[camera->index];
  309. if (want_focus) {
  310. if (info->has_auto_focus_continuous) {
  311. v4l2_ctrl_set(info->fd, V4L2_CID_FOCUS_AUTO, 1);
  312. } else if (info->has_auto_focus_start) {
  313. v4l2_ctrl_set(info->fd, V4L2_CID_AUTO_FOCUS_START, 1);
  314. }
  315. want_focus = false;
  316. }
  317. if (current_controls.gain_is_manual != desired_controls.gain_is_manual) {
  318. v4l2_ctrl_set(info->fd, V4L2_CID_AUTOGAIN, desired_controls.gain_is_manual ? 0 : 1);
  319. }
  320. if (!desired_controls.gain_is_manual && current_controls.gain != desired_controls.gain) {
  321. v4l2_ctrl_set(info->fd, info->gain_ctrl, desired_controls.gain);
  322. }
  323. if (current_controls.exposure_is_manual != desired_controls.exposure_is_manual) {
  324. v4l2_ctrl_set(
  325. info->fd,
  326. V4L2_CID_EXPOSURE_AUTO,
  327. desired_controls.exposure_is_manual ? V4L2_EXPOSURE_MANUAL : V4L2_EXPOSURE_AUTO);
  328. }
  329. if (!desired_controls.exposure_is_manual && current_controls.exposure != desired_controls.exposure) {
  330. v4l2_ctrl_set(info->fd, V4L2_CID_EXPOSURE, desired_controls.exposure);
  331. }
  332. current_controls = desired_controls;
  333. }
  334. static void
  335. on_frame(MPImage image, void *data)
  336. {
  337. // Only update controls right after a frame was captured
  338. update_controls();
  339. // When the mode is switched while capturing we get a couple blank frames,
  340. // presumably from buffers made ready during the switch. Ignore these.
  341. if (just_switched_mode)
  342. {
  343. if (blank_frame_count < 20) {
  344. // Only check a 50x50 area
  345. size_t test_size = MIN(50, image.width) * MIN(50, image.height);
  346. bool image_is_blank = true;
  347. for (size_t i = 0; i < test_size; ++i) {
  348. if (image.data[i] != 0) {
  349. image_is_blank = false;
  350. }
  351. }
  352. if (image_is_blank) {
  353. ++blank_frame_count;
  354. return;
  355. }
  356. } else {
  357. printf("Blank image limit reached, resulting capture may be blank\n");
  358. }
  359. just_switched_mode = false;
  360. blank_frame_count = 0;
  361. }
  362. // Copy from the camera buffer
  363. size_t size = mp_pixel_format_width_to_bytes(image.pixel_format, image.width) * image.height;
  364. uint8_t *buffer = malloc(size);
  365. memcpy(buffer, image.data, size);
  366. image.data = buffer;
  367. // Send the image off for processing
  368. mp_process_pipeline_process_image(image);
  369. if (captures_remaining > 0) {
  370. --captures_remaining;
  371. if (captures_remaining == 0) {
  372. struct camera_info *info = &cameras[camera->index];
  373. // Restore the auto exposure and gain if needed
  374. if (!current_controls.exposure_is_manual) {
  375. v4l2_ctrl_set(info->fd, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_AUTO);
  376. }
  377. if (!current_controls.gain_is_manual) {
  378. v4l2_ctrl_set(info->fd, V4L2_CID_AUTOGAIN, 1);
  379. }
  380. // Go back to preview mode
  381. mp_camera_stop_capture(info->camera);
  382. mode = camera->preview_mode;
  383. mp_camera_set_mode(info->camera, &mode);
  384. just_switched_mode = true;
  385. mp_camera_start_capture(info->camera);
  386. update_process_pipeline();
  387. }
  388. }
  389. }
  390. static void
  391. update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state)
  392. {
  393. // Make sure the state isn't updated more than it needs to be by checking
  394. // whether this state change actually changes anything.
  395. bool has_changed = false;
  396. if (camera != state->camera) {
  397. has_changed = true;
  398. if (camera) {
  399. struct camera_info *info = &cameras[camera->index];
  400. struct device_info *dev_info = &devices[info->device_index];
  401. mp_camera_stop_capture(info->camera);
  402. mp_device_setup_link(
  403. dev_info->device,
  404. info->pad_id,
  405. dev_info->interface_pad_id,
  406. false);
  407. }
  408. if (capture_source) {
  409. g_source_destroy(capture_source);
  410. capture_source = NULL;
  411. }
  412. camera = state->camera;
  413. if (camera) {
  414. struct camera_info *info = &cameras[camera->index];
  415. struct device_info *dev_info = &devices[info->device_index];
  416. mp_device_setup_link(
  417. dev_info->device,
  418. info->pad_id,
  419. dev_info->interface_pad_id,
  420. true);
  421. mode = camera->preview_mode;
  422. mp_camera_set_mode(info->camera, &mode);
  423. mp_camera_start_capture(info->camera);
  424. capture_source = mp_pipeline_add_capture_source(pipeline, info->camera, on_frame, NULL);
  425. current_controls.gain_is_manual = v4l2_ctrl_get(info->fd, V4L2_CID_EXPOSURE_AUTO) == V4L2_EXPOSURE_MANUAL;
  426. current_controls.gain = v4l2_ctrl_get(info->fd, info->gain_ctrl);
  427. current_controls.exposure_is_manual = v4l2_ctrl_get(info->fd, V4L2_CID_AUTOGAIN) == 0;
  428. current_controls.exposure = v4l2_ctrl_get(info->fd, V4L2_CID_EXPOSURE);
  429. }
  430. }
  431. has_changed = has_changed
  432. || burst_length != state->burst_length
  433. || preview_width != state->preview_width
  434. || preview_height != state->preview_height;
  435. burst_length = state->burst_length;
  436. preview_width = state->preview_width;
  437. preview_height = state->preview_height;
  438. if (camera) {
  439. struct control_state previous_desired = desired_controls;
  440. desired_controls.gain_is_manual = state->gain_is_manual;
  441. desired_controls.gain = state->gain;
  442. desired_controls.exposure_is_manual = state->exposure_is_manual;
  443. desired_controls.exposure = state->exposure;
  444. has_changed = has_changed || memcmp(&previous_desired, &desired_controls, sizeof(struct control_state)) != 0;
  445. }
  446. assert(has_changed);
  447. update_process_pipeline();
  448. }
  449. void mp_io_pipeline_update_state(const struct mp_io_pipeline_state *state)
  450. {
  451. mp_pipeline_invoke(pipeline, (MPPipelineCallback)update_state, state, sizeof(struct mp_io_pipeline_state));
  452. }