parse.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  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)
  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. int res = find_media_node(camera, bridge_driver, sensor_driver);
  179. if (res < 0) {
  180. log_debug(" Could not find media node with this sensor\n");
  181. free(camera);
  182. return -1;
  183. }
  184. camera->name = strdup(name);
  185. camera->sensor_name = strdup(sensor_driver);
  186. camera->bridge_name = strdup(bridge_driver);
  187. config->cameras = realloc(config->cameras, (config->count + 1) * sizeof(config->cameras));
  188. if (config->cameras == NULL) {
  189. return -1;
  190. }
  191. config->cameras[config->count++] = camera;
  192. config_setting_t *modes = config_setting_lookup(root, "Modes");
  193. config_setting_t *mode;
  194. int num_modes = config_setting_length(modes);
  195. camera->modes = malloc(num_modes * sizeof(libmegapixels_mode *));
  196. camera->num_modes = num_modes;
  197. int n = 0;
  198. while (1) {
  199. mode = config_setting_get_elem(modes, n);
  200. if (mode == NULL) {
  201. break;
  202. }
  203. libmegapixels_mode *mm = malloc(sizeof(libmegapixels_mode));
  204. camera->modes[n] = mm;
  205. if (!config_setting_lookup_int(mode, "Width", &mm->width)) {
  206. log_error("Missing Width\n");
  207. return -1;
  208. }
  209. if (!config_setting_lookup_int(mode, "Height", &mm->height)) {
  210. log_error("Missing Height\n");
  211. return -1;
  212. }
  213. if (!config_setting_lookup_int(mode, "Rate", &mm->rate)) {
  214. log_error("Missing Rate\n");
  215. return -1;
  216. }
  217. const char *fmt;
  218. config_setting_lookup_string(mode, "Format", &fmt);
  219. mm->format = libmegapixels_format_name_to_index(fmt);
  220. if (!mm->format) {
  221. log_error("Unknown format '%s'\n", fmt);
  222. return -1;
  223. }
  224. mm->v4l_pixfmt = libmegapixels_format_to_v4l_pixfmt(mm->format);
  225. mm->media_busfmt = libmegapixels_format_to_media_busfmt(mm->format);
  226. const char *xfer;
  227. if (config_setting_lookup_string(mode, "Transfer", &xfer)) {
  228. if (strcmp(xfer, "srgb") == 0) {
  229. mm->xfer = LIBMEGAPIXELS_XFER_SRGB;
  230. } else {
  231. mm->xfer = LIBMEGAPIXELS_XFER_RAW;
  232. }
  233. } else {
  234. mm->xfer = LIBMEGAPIXELS_XFER_RAW;
  235. }
  236. if (!config_setting_lookup_int(mode, "Rotate", &mm->rotation)) {
  237. mm->rotation = 0;
  238. }
  239. if (!config_setting_lookup_float(mode, "FocalLength", &mm->focal_length)) {
  240. mm->focal_length = 0.0f;
  241. }
  242. if (!config_setting_lookup_float(mode, "FNumber", &mm->f_number)) {
  243. mm->f_number = 0.0f;
  244. }
  245. char modename[32] = {0};
  246. mode_snprintf(modename, 31, mm);
  247. log_debug(" Adding mode [%s]\n", modename);
  248. config_setting_t *cmds = config_setting_lookup(mode, "Pipeline");
  249. config_setting_t *cmd;
  250. if (cmds == NULL) {
  251. log_error("Mode has no pipeline\n");
  252. n++;
  253. continue;
  254. }
  255. int num_cmds = config_setting_length(cmds);
  256. mm->cmds = (libmegapixels_cmd **) calloc(num_cmds, sizeof(libmegapixels_cmd *));
  257. mm->num_cmds = num_cmds;
  258. int m = 0;
  259. int last_width = camera->modes[n]->width;
  260. int last_height = camera->modes[n]->height;
  261. int last_format = camera->modes[n]->format;
  262. while (1) {
  263. cmd = config_setting_get_elem(cmds, m);
  264. if (cmd == NULL) {
  265. break;
  266. }
  267. libmegapixels_cmd *cur = calloc(1, sizeof(libmegapixels_cmd));
  268. mm->cmds[m] = cur;
  269. const char *type;
  270. if (!config_setting_lookup_string(cmd, "Type", &type)) {
  271. break;
  272. }
  273. if (strcmp(type, "Link") == 0) {
  274. camera->modes[n]->cmds[m]->type = LIBMEGAPIXELS_CMD_LINK;
  275. if (!config_setting_lookup_string(cmd, "From", &cur->entity_from)) {
  276. fprintf(stderr, "Missing From\n");
  277. break;
  278. }
  279. if (!config_setting_lookup_string(cmd, "To", &cur->entity_to)) {
  280. fprintf(stderr, "Missing To\n");
  281. break;
  282. }
  283. if (!config_setting_lookup_int(cmd, "FromPad", &cur->pad_from)) {
  284. cur->pad_from = 0;
  285. }
  286. if (!config_setting_lookup_int(cmd, "ToPad", &cur->pad_to)) {
  287. cur->pad_to = 0;
  288. }
  289. } else if (strcmp(type, "Mode") == 0) {
  290. camera->modes[n]->cmds[m]->type = LIBMEGAPIXELS_CMD_MODE;
  291. if (!config_setting_lookup_string(cmd, "Entity", &cur->entity_from)) {
  292. fprintf(stderr, "Missing entity\n");
  293. break;
  294. }
  295. if (!config_setting_lookup_int(cmd, "Width", &cur->width)) {
  296. cur->width = last_width;
  297. }
  298. last_width = cur->width;
  299. if (!config_setting_lookup_int(cmd, "Height", &cur->height)) {
  300. cur->height = last_height;
  301. }
  302. last_height = cur->height;
  303. if (!config_setting_lookup_int(cmd, "Pad", &cur->pad_from)) {
  304. cur->pad_from = 0;
  305. }
  306. const char *newfmt;
  307. if (config_setting_lookup_string(cmd, "Format", &newfmt)) {
  308. cur->format = libmegapixels_format_name_to_index(newfmt);
  309. last_format = cur->format;
  310. } else {
  311. cur->format = last_format;
  312. }
  313. } else if (strcmp(type, "Rate") == 0) {
  314. camera->modes[n]->cmds[m]->type = LIBMEGAPIXELS_CMD_INTERVAL;
  315. if (!config_setting_lookup_string(cmd, "Entity", &cur->entity_from)) {
  316. fprintf(stderr, "Missing entity\n");
  317. break;
  318. }
  319. if (!config_setting_lookup_int(cmd, "Rate", &cur->rate)) {
  320. cur->rate = mm->rate;
  321. }
  322. } else if (strcmp(type, "Crop") == 0) {
  323. camera->modes[n]->cmds[m]->type = LIBMEGAPIXELS_CMD_CROP;
  324. if (!config_setting_lookup_string(cmd, "Entity", &cur->entity_from)) {
  325. fprintf(stderr, "Missing entity\n");
  326. break;
  327. }
  328. if (!config_setting_lookup_int(cmd, "Width", &cur->width)) {
  329. cur->width = camera->modes[n]->width;
  330. }
  331. last_width = cur->width;
  332. if (!config_setting_lookup_int(cmd, "Height", &cur->height)) {
  333. cur->height = camera->modes[n]->height;
  334. }
  335. last_height = cur->height;
  336. if (!config_setting_lookup_int(cmd, "Top", &cur->top)) {
  337. cur->top = 0;
  338. }
  339. if (!config_setting_lookup_int(cmd, "Left", &cur->left)) {
  340. cur->left = 0;
  341. }
  342. if (!config_setting_lookup_int(cmd, "Pad", &cur->pad_from)) {
  343. cur->pad_from = 0;
  344. }
  345. }
  346. m++;
  347. }
  348. n++;
  349. }
  350. return 0;
  351. }
  352. int
  353. libmegapixels_load_file(libmegapixels_devconfig *config, const char *file)
  354. {
  355. if (config->loaded_config) {
  356. log_error("Config already loaded\n");
  357. return 0;
  358. }
  359. log_debug("Load config file %s\n", file);
  360. config->loaded_config = 1;
  361. config_t cfg;
  362. config_setting_t *setting, *member;
  363. config->path = strdup(file);
  364. if (config->count == 0) {
  365. config->cameras = malloc(0);
  366. }
  367. config_init(&cfg);
  368. if (!config_read_file(&cfg, file)) {
  369. fprintf(stderr, "Could not read %s\n", file);
  370. config_destroy(&cfg);
  371. return 0;
  372. }
  373. int version = 0;
  374. if (config_lookup_int(&cfg, "Version", &version)) {
  375. if (version != 1) {
  376. fprintf(stderr, "Invalid version %d\n", version);
  377. return 0;
  378. }
  379. } else {
  380. fprintf(stderr, "Missing version\n");
  381. return 0;
  382. }
  383. if (!config_lookup_string(&cfg, "Make", &config->make)) {
  384. config->make = strdup("Megapixels");
  385. }
  386. if (!config_lookup_string(&cfg, "Model", &config->model)) {
  387. config->model = strdup("Camera");
  388. }
  389. setting = config_root_setting(&cfg);
  390. int n = 0;
  391. while (1) {
  392. member = config_setting_get_elem(setting, n++);
  393. if (member == NULL) {
  394. break;
  395. }
  396. if (strcmp(member->name, "Version") == 0) {
  397. continue;
  398. }
  399. if (strcmp(member->name, "Make") == 0) {
  400. continue;
  401. }
  402. if (strcmp(member->name, "Model") == 0) {
  403. continue;
  404. }
  405. load_camera(config, &cfg, member->name);
  406. }
  407. return 1;
  408. }
  409. void
  410. uvc_create_modes(libmegapixels_camera *camera, int fd)
  411. {
  412. struct v4l2_fmtdesc fmtdesc = {0};
  413. fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  414. while (xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
  415. fmtdesc.index++;
  416. libmegapixels_v4l_pixfmt_to_index(fmtdesc.pixelformat);
  417. int format = libmegapixels_v4l_pixfmt_to_index(fmtdesc.pixelformat);
  418. if (!format) {
  419. continue;
  420. }
  421. struct v4l2_frmsizeenum framesize = {0};
  422. framesize.pixel_format = fmtdesc.pixelformat;
  423. while (xioctl(fd, VIDIOC_ENUM_FRAMESIZES, &framesize) == 0) {
  424. if (framesize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
  425. struct v4l2_frmivalenum frameinterval = {0};
  426. frameinterval.pixel_format = framesize.pixel_format;
  427. frameinterval.width = framesize.discrete.width;
  428. frameinterval.height = framesize.discrete.height;
  429. while (xioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameinterval) == 0) {
  430. frameinterval.index++;
  431. if (frameinterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
  432. libmegapixels_mode *mode = calloc(1, sizeof(libmegapixels_mode));
  433. mode->format = format;
  434. mode->v4l_pixfmt = fmtdesc.pixelformat;
  435. mode->width = (int) framesize.discrete.width;
  436. mode->height = (int) framesize.discrete.height;
  437. mode->media_busfmt = libmegapixels_format_to_media_busfmt(format);
  438. mode->rotation = 0;
  439. mode->rate = (int) ((double) frameinterval.discrete.denominator /
  440. (double) frameinterval.discrete.numerator);
  441. camera->modes = realloc(camera->modes, (camera->num_modes + 1) * sizeof(camera->modes));
  442. if (camera->modes == NULL) {
  443. return;
  444. }
  445. camera->modes[camera->num_modes++] = mode;
  446. }
  447. }
  448. }
  449. framesize.index++;
  450. }
  451. }
  452. }
  453. int
  454. libmegapixels_load_uvc(libmegapixels_devconfig *config)
  455. {
  456. if (config->loaded_uvc) {
  457. log_error("libmegapixels_load_uvc was already called\n");
  458. return 0;
  459. }
  460. log_debug("Loading UVC cameras\n");
  461. config->loaded_uvc = 1;
  462. struct dirent *dir;
  463. DIR *d = opendir("/dev");
  464. while ((dir = readdir(d)) != NULL) {
  465. if (strncmp(dir->d_name, "video", 5) == 0) {
  466. char path[PATH_MAX];
  467. snprintf(path, PATH_MAX, "/dev/%s", dir->d_name);
  468. int fd = open(path, O_RDWR);
  469. if (fd < 0) {
  470. continue;
  471. }
  472. struct v4l2_capability vid_cap = {0};
  473. if (xioctl(fd, VIDIOC_QUERYCAP, &vid_cap) == -1) {
  474. perror("QUERYCAP");
  475. continue;
  476. }
  477. if (strcmp((char *) vid_cap.driver, "uvcvideo") != 0) {
  478. continue;
  479. }
  480. if (!(vid_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
  481. continue;
  482. }
  483. if (!(vid_cap.capabilities & V4L2_CAP_STREAMING)) {
  484. continue;
  485. }
  486. struct v4l2_fmtdesc fmtdesc = {0};
  487. fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  488. if (xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != 0) {
  489. continue;
  490. }
  491. libmegapixels_camera *camera;
  492. camera = calloc(1, sizeof(libmegapixels_camera));
  493. camera->name = strdup((const char *) vid_cap.card);
  494. camera->video_path = strdup(path);
  495. uvc_create_modes(camera, fd);
  496. close(fd);
  497. config->cameras = realloc(config->cameras, (config->count + 1) * sizeof(config->cameras));
  498. if (config->cameras == NULL) {
  499. return -1;
  500. }
  501. config->cameras[config->count++] = camera;
  502. camera->index = config->count;
  503. }
  504. }
  505. closedir(d);
  506. return 1;
  507. }
  508. int
  509. libmegapixels_init(libmegapixels_devconfig **config)
  510. {
  511. *config = calloc(1, sizeof(libmegapixels_devconfig));
  512. init_log(0);
  513. return 1;
  514. }