parse.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. #include <stdio.h>
  2. #include <libconfig.h>
  3. #include <malloc.h>
  4. #include <string.h>
  5. #include <dirent.h>
  6. #include <fcntl.h>
  7. #include <unistd.h>
  8. #include <sys/ioctl.h>
  9. #include <errno.h>
  10. #include <linux/media.h>
  11. #include <stdint.h>
  12. #include <limits.h>
  13. #include <linux/videodev2.h>
  14. #include "libmegapixels.h"
  15. #include "mode.h"
  16. #include "util.h"
  17. #include "log.h"
  18. char *
  19. find_path_for_devnode(struct media_v2_intf_devnode devnode)
  20. {
  21. char uevent_path[PATH_MAX];
  22. snprintf(uevent_path, PATH_MAX, "/sys/dev/char/%d:%d/uevent", devnode.major, devnode.minor);
  23. FILE *fp = fopen(uevent_path, "r");
  24. if (!fp) {
  25. return NULL;
  26. }
  27. char line[PATH_MAX];
  28. char path[PATH_MAX];
  29. while (fgets(line, PATH_MAX, fp)) {
  30. if (strncmp(line, "DEVNAME=", 8) == 0) {
  31. // Drop newline
  32. unsigned long length = strlen(line);
  33. if (line[length - 1] == '\n')
  34. line[length - 1] = '\0';
  35. snprintf(path, length, "/dev/%s", line + 8);
  36. return strdup(path);
  37. }
  38. }
  39. return "";
  40. }
  41. int
  42. find_media_node(libmegapixels_camera *camera, const char *media_name, const char *sensor_name)
  43. {
  44. struct dirent *dir;
  45. DIR *d = opendir("/dev");
  46. while ((dir = readdir(d)) != NULL) {
  47. if (strncmp(dir->d_name, "media", 5) == 0) {
  48. char path[PATH_MAX];
  49. snprintf(path, PATH_MAX, "/dev/%s", dir->d_name);
  50. int media_fd = open(path, O_RDWR);
  51. if (media_fd == -1) {
  52. fprintf(stderr, "Could not open %s\n", path);
  53. continue;
  54. }
  55. struct media_device_info mdi;
  56. if (xioctl(media_fd, MEDIA_IOC_DEVICE_INFO, &mdi) == -1) {
  57. fprintf(stderr, "Could not MDI\n");
  58. close(media_fd);
  59. }
  60. if (strcmp(mdi.driver, media_name) != 0 && strcmp(mdi.model, media_name) != 0) {
  61. close(media_fd);
  62. continue;
  63. }
  64. // This media device matches on model or driver, scan the entities for the sensor
  65. struct media_v2_topology topology = {0};
  66. if (xioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topology) == -1 ||
  67. topology.num_entities == 0) {
  68. close(media_fd);
  69. continue;
  70. }
  71. struct media_v2_entity *entities = calloc(topology.num_entities, sizeof(struct media_v2_entity));
  72. struct media_v2_interface *interfaces = calloc(topology.num_interfaces, sizeof(struct media_v2_interface));
  73. struct media_v2_pad *pads = calloc(topology.num_pads, sizeof(struct media_v2_pad));
  74. struct media_v2_link *links = calloc(topology.num_links, sizeof(struct media_v2_link));
  75. topology.ptr_entities = (uint64_t) entities;
  76. topology.ptr_interfaces = (uint64_t) interfaces;
  77. topology.ptr_pads = (uint64_t) pads;
  78. topology.ptr_links = (uint64_t) links;
  79. if (xioctl(media_fd, MEDIA_IOC_G_TOPOLOGY, &topology) == -1) {
  80. close(media_fd);
  81. continue;
  82. }
  83. // Find the sensor
  84. unsigned long len = strlen(sensor_name);
  85. int found = 0;
  86. for (int i = 0; i < topology.num_entities; i++) {
  87. if (strncmp(entities[i].name, sensor_name, len) == 0) {
  88. found++;
  89. for (int j = 0; j < topology.num_links; j++) {
  90. if (links[j].sink_id != entities[i].id) {
  91. continue;
  92. }
  93. for (int k = 0; k < topology.num_interfaces; k++) {
  94. if (interfaces[k].id != links[j].source_id) {
  95. continue;
  96. }
  97. camera->sensor_path = find_path_for_devnode(interfaces[k].devnode);
  98. break;
  99. }
  100. }
  101. break;
  102. }
  103. }
  104. // Find the bridge
  105. for (int i = 0; i < topology.num_entities; i++) {
  106. if (entities[i].function == MEDIA_ENT_F_IO_V4L) {
  107. found++;
  108. for (int j = 0; j < topology.num_links; j++) {
  109. if (links[j].sink_id != entities[i].id) {
  110. continue;
  111. }
  112. for (int k = 0; k < topology.num_interfaces; k++) {
  113. if (interfaces[k].id != links[j].source_id) {
  114. continue;
  115. }
  116. camera->video_path = find_path_for_devnode(interfaces[k].devnode);
  117. break;
  118. }
  119. }
  120. break;
  121. }
  122. }
  123. camera->num_handles = 0;
  124. for (int i = 0; i < topology.num_links; i++) {
  125. if (!(links[i].flags & MEDIA_LNK_FL_INTERFACE_LINK)) {
  126. continue;
  127. }
  128. camera->num_handles++;
  129. }
  130. camera->handles = calloc(camera->num_handles, sizeof(libmegapixels_subdev));
  131. int h = 0;
  132. for (int i = 0; i < topology.num_links; i++) {
  133. if (!(links[i].flags & MEDIA_LNK_FL_INTERFACE_LINK)) {
  134. continue;
  135. }
  136. libmegapixels_subdev *sd;
  137. sd = malloc(sizeof(libmegapixels_subdev));
  138. camera->handles[h] = sd;
  139. camera->handles[h]->entity_id = links[i].sink_id;
  140. camera->handles[h]->fd = 0;
  141. for (int j = 0; j < topology.num_interfaces; j++) {
  142. if (links[i].source_id != interfaces[j].id) {
  143. continue;
  144. }
  145. camera->handles[h]->path = find_path_for_devnode(interfaces[j].devnode);
  146. }
  147. h++;
  148. }
  149. close(media_fd);
  150. if (found == 2) {
  151. camera->media_path = strdup(path);
  152. return 1;
  153. }
  154. }
  155. }
  156. closedir(d);
  157. return -1;
  158. }
  159. int
  160. load_camera(libmegapixels_devconfig *config, config_t *cfg, const char *name, int lint)
  161. {
  162. const char *sensor_driver, *bridge_driver;
  163. config_setting_t *root = config_lookup(cfg, name);
  164. log_debug("Loading camera '%s'\n", name);
  165. if (!config_setting_lookup_string(root, "SensorDriver", &sensor_driver)) {
  166. log_debug(" Section is missing SensorDriver\n");
  167. return -1;
  168. }
  169. if (!config_setting_lookup_string(root, "BridgeDriver", &bridge_driver)) {
  170. log_debug(" Section is missing BridgeDriver\n");
  171. return -1;
  172. }
  173. libmegapixels_camera *camera;
  174. camera = malloc(sizeof(libmegapixels_camera));
  175. camera->sensor_fd = 0;
  176. camera->media_fd = 0;
  177. camera->video_fd = 0;
  178. // Don't access hardware in linting mode
  179. if (lint == 0) {
  180. int res = find_media_node(camera, bridge_driver, sensor_driver);
  181. if (res < 0) {
  182. log_debug(" Could not find media node with this sensor\n");
  183. free(camera);
  184. return -1;
  185. }
  186. }
  187. camera->name = strdup(name);
  188. camera->sensor_name = strdup(sensor_driver);
  189. camera->bridge_name = strdup(bridge_driver);
  190. config->cameras = realloc(config->cameras, (config->count + 1) * sizeof(config->cameras));
  191. if (config->cameras == NULL) {
  192. return -1;
  193. }
  194. camera->index = config->count;
  195. config->cameras[config->count++] = camera;
  196. config_setting_t *modes = config_setting_lookup(root, "Modes");
  197. config_setting_t *mode;
  198. if (modes == NULL) {
  199. log_error("Sensor '%s' does not define any modes\n", camera->name);
  200. return -1;
  201. }
  202. int num_modes = config_setting_length(modes);
  203. camera->modes = malloc(num_modes * sizeof(libmegapixels_mode *));
  204. camera->num_modes = num_modes;
  205. int n = 0;
  206. while (1) {
  207. mode = config_setting_get_elem(modes, n);
  208. if (mode == NULL) {
  209. break;
  210. }
  211. libmegapixels_mode *mm = malloc(sizeof(libmegapixels_mode));
  212. camera->modes[n] = mm;
  213. if (!config_setting_lookup_int(mode, "Width", &mm->width)) {
  214. log_error("Missing Width\n");
  215. return -1;
  216. }
  217. if (!config_setting_lookup_int(mode, "Height", &mm->height)) {
  218. log_error("Missing Height\n");
  219. return -1;
  220. }
  221. if (!config_setting_lookup_int(mode, "Rate", &mm->rate)) {
  222. log_error("Missing Rate\n");
  223. return -1;
  224. }
  225. const char *fmt;
  226. config_setting_lookup_string(mode, "Format", &fmt);
  227. mm->format = libmegapixels_format_name_to_index(fmt);
  228. if (!mm->format) {
  229. log_error("Unknown format '%s'\n", fmt);
  230. return -1;
  231. }
  232. mm->v4l_pixfmt = libmegapixels_format_to_v4l_pixfmt(mm->format);
  233. mm->media_busfmt = libmegapixels_format_to_media_busfmt(mm->format);
  234. const char *xfer;
  235. if (config_setting_lookup_string(mode, "Transfer", &xfer)) {
  236. if (strcmp(xfer, "srgb") == 0) {
  237. mm->xfer = LIBMEGAPIXELS_XFER_SRGB;
  238. } else {
  239. mm->xfer = LIBMEGAPIXELS_XFER_RAW;
  240. }
  241. } else {
  242. mm->xfer = LIBMEGAPIXELS_XFER_RAW;
  243. }
  244. if (!config_setting_lookup_int(mode, "Rotate", &mm->rotation)) {
  245. mm->rotation = 0;
  246. }
  247. if (!config_setting_lookup_bool(mode, "Mirror", &mm->mirrored)) {
  248. mm->mirrored = 0;
  249. }
  250. if (!config_setting_lookup_float(mode, "FocalLength", &mm->focal_length)) {
  251. mm->focal_length = 0.0f;
  252. }
  253. if (!config_setting_lookup_float(mode, "FNumber", &mm->f_number)) {
  254. mm->f_number = 0.0f;
  255. }
  256. char modename[32] = {0};
  257. mode_snprintf(modename, 31, mm);
  258. log_debug(" Adding mode [%s]\n", modename);
  259. config_setting_t *cmds = config_setting_lookup(mode, "Pipeline");
  260. config_setting_t *cmd;
  261. if (cmds == NULL) {
  262. log_error("Mode has no pipeline\n");
  263. n++;
  264. continue;
  265. }
  266. int num_cmds = config_setting_length(cmds);
  267. mm->cmds = (libmegapixels_cmd **) calloc(num_cmds, sizeof(libmegapixels_cmd *));
  268. mm->num_cmds = num_cmds;
  269. int m = 0;
  270. int last_width = camera->modes[n]->width;
  271. int last_height = camera->modes[n]->height;
  272. int last_format = camera->modes[n]->format;
  273. while (1) {
  274. cmd = config_setting_get_elem(cmds, m);
  275. if (cmd == NULL) {
  276. break;
  277. }
  278. libmegapixels_cmd *cur = calloc(1, sizeof(libmegapixels_cmd));
  279. mm->cmds[m] = cur;
  280. const char *type;
  281. if (!config_setting_lookup_string(cmd, "Type", &type)) {
  282. break;
  283. }
  284. if (strcmp(type, "Link") == 0) {
  285. camera->modes[n]->cmds[m]->type = LIBMEGAPIXELS_CMD_LINK;
  286. if (!config_setting_lookup_string(cmd, "From", &cur->entity_from)) {
  287. fprintf(stderr, "Missing From\n");
  288. break;
  289. }
  290. if (!config_setting_lookup_string(cmd, "To", &cur->entity_to)) {
  291. fprintf(stderr, "Missing To\n");
  292. break;
  293. }
  294. if (!config_setting_lookup_int(cmd, "FromPad", &cur->pad_from)) {
  295. cur->pad_from = 0;
  296. }
  297. if (!config_setting_lookup_int(cmd, "ToPad", &cur->pad_to)) {
  298. cur->pad_to = 0;
  299. }
  300. } else if (strcmp(type, "Mode") == 0) {
  301. camera->modes[n]->cmds[m]->type = LIBMEGAPIXELS_CMD_MODE;
  302. if (!config_setting_lookup_string(cmd, "Entity", &cur->entity_from)) {
  303. fprintf(stderr, "Missing entity\n");
  304. break;
  305. }
  306. if (!config_setting_lookup_int(cmd, "Width", &cur->width)) {
  307. cur->width = last_width;
  308. }
  309. last_width = cur->width;
  310. if (!config_setting_lookup_int(cmd, "Height", &cur->height)) {
  311. cur->height = last_height;
  312. }
  313. last_height = cur->height;
  314. if (!config_setting_lookup_int(cmd, "Pad", &cur->pad_from)) {
  315. cur->pad_from = 0;
  316. }
  317. const char *newfmt;
  318. if (config_setting_lookup_string(cmd, "Format", &newfmt)) {
  319. cur->format = libmegapixels_format_name_to_index(newfmt);
  320. last_format = cur->format;
  321. } else {
  322. cur->format = last_format;
  323. }
  324. } else if (strcmp(type, "Rate") == 0) {
  325. camera->modes[n]->cmds[m]->type = LIBMEGAPIXELS_CMD_INTERVAL;
  326. if (!config_setting_lookup_string(cmd, "Entity", &cur->entity_from)) {
  327. fprintf(stderr, "Missing entity\n");
  328. break;
  329. }
  330. if (!config_setting_lookup_int(cmd, "Rate", &cur->rate)) {
  331. cur->rate = mm->rate;
  332. }
  333. } else if (strcmp(type, "Crop") == 0) {
  334. camera->modes[n]->cmds[m]->type = LIBMEGAPIXELS_CMD_CROP;
  335. if (!config_setting_lookup_string(cmd, "Entity", &cur->entity_from)) {
  336. fprintf(stderr, "Missing entity\n");
  337. break;
  338. }
  339. if (!config_setting_lookup_int(cmd, "Width", &cur->width)) {
  340. cur->width = camera->modes[n]->width;
  341. }
  342. last_width = cur->width;
  343. if (!config_setting_lookup_int(cmd, "Height", &cur->height)) {
  344. cur->height = camera->modes[n]->height;
  345. }
  346. last_height = cur->height;
  347. if (!config_setting_lookup_int(cmd, "Top", &cur->top)) {
  348. cur->top = 0;
  349. }
  350. if (!config_setting_lookup_int(cmd, "Left", &cur->left)) {
  351. cur->left = 0;
  352. }
  353. if (!config_setting_lookup_int(cmd, "Pad", &cur->pad_from)) {
  354. cur->pad_from = 0;
  355. }
  356. }
  357. m++;
  358. }
  359. n++;
  360. }
  361. if (n == 0) {
  362. log_debug("No modes defined for sensor '%s'\n", camera->name);
  363. return -1;
  364. }
  365. return 0;
  366. }
  367. int
  368. libmegapixels_load_file(libmegapixels_devconfig *config, const char *file)
  369. {
  370. return libmegapixels_load_file_lint(config, file, 0);
  371. }
  372. int
  373. libmegapixels_load_file_lint(libmegapixels_devconfig *config, const char *file, int linting)
  374. {
  375. if (config->loaded_config) {
  376. log_error("Config already loaded\n");
  377. return 0;
  378. }
  379. log_debug("Load config file %s\n", file);
  380. config->loaded_config = 1;
  381. config_t cfg;
  382. config_setting_t *setting, *member;
  383. config->path = strdup(file);
  384. if (config->count == 0) {
  385. config->cameras = malloc(0);
  386. }
  387. config_init(&cfg);
  388. if (!config_read_file(&cfg, file)) {
  389. if (config_error_type(&cfg) == CONFIG_ERR_FILE_IO) {
  390. fprintf(stderr, "Could not read %s: %s\n", file, config_error_text(&cfg));
  391. } else {
  392. fprintf(stderr, "Could not read %s:\n", file);
  393. fprintf(stderr, "\t%s:%d - %s\n",
  394. config_error_file(&cfg), config_error_line(&cfg), config_error_text(&cfg));
  395. }
  396. config_destroy(&cfg);
  397. return 0;
  398. }
  399. int version = 0;
  400. if (config_lookup_int(&cfg, "Version", &version)) {
  401. if (version != 1) {
  402. fprintf(stderr, "Could not load '%s': Invalid version %d\n", file, version);
  403. return 0;
  404. }
  405. } else {
  406. fprintf(stderr, "Could not load '%s': Missing version\n", file);
  407. return 0;
  408. }
  409. if (!config_lookup_string(&cfg, "Make", &config->make)) {
  410. config->make = strdup("Megapixels");
  411. }
  412. if (!config_lookup_string(&cfg, "Model", &config->model)) {
  413. config->model = strdup("Camera");
  414. }
  415. setting = config_root_setting(&cfg);
  416. int n = 0;
  417. while (1) {
  418. member = config_setting_get_elem(setting, n++);
  419. if (member == NULL) {
  420. break;
  421. }
  422. if (strcmp(member->name, "Version") == 0) {
  423. continue;
  424. }
  425. if (strcmp(member->name, "Make") == 0) {
  426. continue;
  427. }
  428. if (strcmp(member->name, "Model") == 0) {
  429. continue;
  430. }
  431. load_camera(config, &cfg, member->name, linting);
  432. }
  433. return 1;
  434. }
  435. void
  436. uvc_create_modes(libmegapixels_camera *camera, int fd)
  437. {
  438. struct v4l2_fmtdesc fmtdesc = {0};
  439. fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  440. while (xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
  441. fmtdesc.index++;
  442. libmegapixels_v4l_pixfmt_to_index(fmtdesc.pixelformat);
  443. int format = libmegapixels_v4l_pixfmt_to_index(fmtdesc.pixelformat);
  444. if (!format) {
  445. continue;
  446. }
  447. struct v4l2_frmsizeenum framesize = {0};
  448. framesize.pixel_format = fmtdesc.pixelformat;
  449. while (xioctl(fd, VIDIOC_ENUM_FRAMESIZES, &framesize) == 0) {
  450. if (framesize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
  451. struct v4l2_frmivalenum frameinterval = {0};
  452. frameinterval.pixel_format = framesize.pixel_format;
  453. frameinterval.width = framesize.discrete.width;
  454. frameinterval.height = framesize.discrete.height;
  455. while (xioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameinterval) == 0) {
  456. frameinterval.index++;
  457. if (frameinterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
  458. libmegapixels_mode *mode = calloc(1, sizeof(libmegapixels_mode));
  459. mode->format = format;
  460. mode->v4l_pixfmt = fmtdesc.pixelformat;
  461. mode->width = (int) framesize.discrete.width;
  462. mode->height = (int) framesize.discrete.height;
  463. mode->media_busfmt = libmegapixels_format_to_media_busfmt(format);
  464. mode->rotation = 0;
  465. mode->rate = (int) ((double) frameinterval.discrete.denominator /
  466. (double) frameinterval.discrete.numerator);
  467. camera->modes = realloc(camera->modes, (camera->num_modes + 1) * sizeof(camera->modes));
  468. if (camera->modes == NULL) {
  469. return;
  470. }
  471. camera->modes[camera->num_modes++] = mode;
  472. }
  473. }
  474. }
  475. framesize.index++;
  476. }
  477. }
  478. }
  479. int
  480. libmegapixels_load_uvc(libmegapixels_devconfig *config)
  481. {
  482. if (config->loaded_uvc) {
  483. log_error("libmegapixels_load_uvc was already called\n");
  484. return 0;
  485. }
  486. log_debug("Loading UVC cameras\n");
  487. config->loaded_uvc = 1;
  488. struct dirent *dir;
  489. DIR *d = opendir("/dev");
  490. while ((dir = readdir(d)) != NULL) {
  491. if (strncmp(dir->d_name, "video", 5) == 0) {
  492. char path[PATH_MAX];
  493. snprintf(path, PATH_MAX, "/dev/%s", dir->d_name);
  494. int fd = open(path, O_RDWR);
  495. if (fd < 0) {
  496. continue;
  497. }
  498. struct v4l2_capability vid_cap = {0};
  499. if (xioctl(fd, VIDIOC_QUERYCAP, &vid_cap) == -1) {
  500. perror("QUERYCAP");
  501. continue;
  502. }
  503. if (strcmp((char *) vid_cap.driver, "uvcvideo") != 0) {
  504. continue;
  505. }
  506. if (!(vid_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
  507. continue;
  508. }
  509. if (!(vid_cap.capabilities & V4L2_CAP_STREAMING)) {
  510. continue;
  511. }
  512. struct v4l2_fmtdesc fmtdesc = {0};
  513. fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  514. if (xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != 0) {
  515. continue;
  516. }
  517. libmegapixels_camera *camera;
  518. camera = calloc(1, sizeof(libmegapixels_camera));
  519. camera->name = strdup((const char *) vid_cap.card);
  520. camera->video_path = strdup(path);
  521. uvc_create_modes(camera, fd);
  522. close(fd);
  523. config->cameras = realloc(config->cameras, (config->count + 1) * sizeof(config->cameras));
  524. if (config->cameras == NULL) {
  525. return -1;
  526. }
  527. camera->index = config->count;
  528. config->cameras[config->count++] = camera;
  529. }
  530. }
  531. closedir(d);
  532. return 1;
  533. }
  534. int
  535. libmegapixels_init(libmegapixels_devconfig **config)
  536. {
  537. *config = calloc(1, sizeof(libmegapixels_devconfig));
  538. init_log(0);
  539. return 1;
  540. }