io_pipeline.c 13 KB

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