io_pipeline.c 16 KB

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