parse.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  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. if (!config_setting_lookup_string(root, "SensorDriver", &sensor_driver)) {
  165. return -1;
  166. }
  167. if (!config_setting_lookup_string(root, "BridgeDriver", &bridge_driver)) {
  168. return -1;
  169. }
  170. libmegapixels_camera *camera;
  171. camera = malloc(sizeof(libmegapixels_camera));
  172. camera->sensor_fd = 0;
  173. camera->media_fd = 0;
  174. camera->video_fd = 0;
  175. int res = find_media_node(camera, bridge_driver, sensor_driver);
  176. if (res < 0) {
  177. free(camera);
  178. return -1;
  179. }
  180. camera->name = strdup(name);
  181. camera->sensor_name = strdup(sensor_driver);
  182. camera->bridge_name = strdup(bridge_driver);
  183. config->cameras = realloc(config->cameras, (config->count + 1) * sizeof(config->cameras));
  184. if (config->cameras == NULL) {
  185. return -1;
  186. }
  187. config->cameras[config->count++] = camera;
  188. config_setting_t *modes = config_setting_lookup(root, "Modes");
  189. config_setting_t *mode;
  190. int num_modes = config_setting_length(modes);
  191. camera->modes = malloc(num_modes * sizeof(libmegapixels_mode *));
  192. camera->num_modes = num_modes;
  193. int n = 0;
  194. while (1) {
  195. mode = config_setting_get_elem(modes, n);
  196. if (mode == NULL) {
  197. break;
  198. }
  199. libmegapixels_mode *mm = malloc(sizeof(libmegapixels_mode));
  200. camera->modes[n] = mm;
  201. if (!config_setting_lookup_int(mode, "Width", &mm->width)) {
  202. log_error("Missing Width\n");
  203. return -1;
  204. }
  205. if (!config_setting_lookup_int(mode, "Height", &mm->height)) {
  206. log_error("Missing Height\n");
  207. return -1;
  208. }
  209. if (!config_setting_lookup_int(mode, "Rate", &mm->rate)) {
  210. log_error("Missing Rate\n");
  211. return -1;
  212. }
  213. const char *fmt;
  214. config_setting_lookup_string(mode, "Format", &fmt);
  215. mm->v4l_pixfmt = format_name_to_v4l_pixfmt(fmt);
  216. if (mm->v4l_pixfmt == 0) {
  217. log_error("Unknown format '%s'\n", fmt);
  218. return -1;
  219. }
  220. mm->media_busfmt = format_name_to_media_busfmt(fmt);
  221. if (!config_setting_lookup_int(mode, "Rotate", &mm->rotation)) {
  222. mm->rotation = 0;
  223. }
  224. if (!config_setting_lookup_float(mode, "FocalLength", &mm->focal_length)) {
  225. mm->focal_length = 0.0f;
  226. }
  227. if (!config_setting_lookup_float(mode, "FNumber", &mm->f_number)) {
  228. mm->f_number = 0.0f;
  229. }
  230. config_setting_t *cmds = config_setting_lookup(mode, "Pipeline");
  231. config_setting_t *cmd;
  232. if (cmds == NULL) {
  233. log_error("Mode has no pipeline\n");
  234. n++;
  235. continue;
  236. }
  237. int num_cmds = config_setting_length(cmds);
  238. mm->cmds = (libmegapixels_cmd **) calloc(num_cmds, sizeof(libmegapixels_cmd *));
  239. mm->num_cmds = num_cmds;
  240. int m = 0;
  241. while (1) {
  242. cmd = config_setting_get_elem(cmds, m);
  243. if (cmd == NULL) {
  244. break;
  245. }
  246. libmegapixels_cmd *cur = calloc(1, sizeof(libmegapixels_cmd));
  247. mm->cmds[m] = cur;
  248. const char *type;
  249. if (!config_setting_lookup_string(cmd, "Type", &type)) {
  250. break;
  251. }
  252. if (strcmp(type, "Link") == 0) {
  253. camera->modes[n]->cmds[m]->type = LIBMEGAPIXELS_CMD_LINK;
  254. if (!config_setting_lookup_string(cmd, "From", &cur->entity_from)) {
  255. fprintf(stderr, "Missing From\n");
  256. break;
  257. }
  258. if (!config_setting_lookup_string(cmd, "To", &cur->entity_to)) {
  259. fprintf(stderr, "Missing To\n");
  260. break;
  261. }
  262. if (!config_setting_lookup_int(cmd, "FromPad", &cur->pad_from)) {
  263. cur->pad_from = 0;
  264. }
  265. if (!config_setting_lookup_int(cmd, "ToPad", &cur->pad_to)) {
  266. cur->pad_to = 0;
  267. }
  268. } else if (strcmp(type, "Mode") == 0) {
  269. camera->modes[n]->cmds[m]->type = LIBMEGAPIXELS_CMD_MODE;
  270. if (!config_setting_lookup_string(cmd, "Entity", &cur->entity_from)) {
  271. fprintf(stderr, "Missing entity\n");
  272. break;
  273. }
  274. if (!config_setting_lookup_int(cmd, "Width", &cur->width)) {
  275. cur->width = camera->modes[n]->width;
  276. }
  277. if (!config_setting_lookup_int(cmd, "Height", &cur->height)) {
  278. cur->height = camera->modes[n]->height;
  279. }
  280. }
  281. m++;
  282. }
  283. n++;
  284. }
  285. return 0;
  286. }
  287. int
  288. libmegapixels_load_file(libmegapixels_devconfig *config, const char *file)
  289. {
  290. if (config->loaded_config) {
  291. log_error("Config already loaded\n");
  292. return 0;
  293. }
  294. config->loaded_config = 1;
  295. config_t cfg;
  296. config_setting_t *setting, *member;
  297. config->path = strdup(file);
  298. if (config->count == 0) {
  299. config->cameras = malloc(0);
  300. }
  301. config_init(&cfg);
  302. if (!config_read_file(&cfg, file)) {
  303. fprintf(stderr, "Could not read %s\n", file);
  304. config_destroy(&cfg);
  305. return 0;
  306. }
  307. int version = 0;
  308. if (config_lookup_int(&cfg, "Version", &version)) {
  309. if (version != 1) {
  310. fprintf(stderr, "Invalid version %d\n", version);
  311. return 0;
  312. }
  313. } else {
  314. fprintf(stderr, "Missing version\n");
  315. return 0;
  316. }
  317. if (!config_lookup_string(&cfg, "Make", &config->make)) {
  318. config->make = strdup("Megapixels");
  319. }
  320. if (!config_lookup_string(&cfg, "Model", &config->model)) {
  321. config->model = strdup("Camera");
  322. }
  323. setting = config_root_setting(&cfg);
  324. int n = 0;
  325. while (1) {
  326. member = config_setting_get_elem(setting, n++);
  327. if (member == NULL) {
  328. break;
  329. }
  330. if (strcmp(member->name, "Version") == 0) {
  331. continue;
  332. }
  333. if (strcmp(member->name, "Make") == 0) {
  334. continue;
  335. }
  336. if (strcmp(member->name, "Model") == 0) {
  337. continue;
  338. }
  339. load_camera(config, &cfg, member->name);
  340. }
  341. return 1;
  342. }
  343. void
  344. uvc_create_modes(libmegapixels_camera *camera, int fd)
  345. {
  346. struct v4l2_fmtdesc fmtdesc = {0};
  347. fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  348. while (xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
  349. fmtdesc.index++;
  350. struct libmegapixels_modename *mn = v4l_pixfmt_to_mode(fmtdesc.pixelformat);
  351. if (mn == NULL) {
  352. continue;
  353. }
  354. struct v4l2_frmsizeenum framesize = {0};
  355. framesize.pixel_format = fmtdesc.pixelformat;
  356. while (xioctl(fd, VIDIOC_ENUM_FRAMESIZES, &framesize) == 0) {
  357. if (framesize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
  358. struct v4l2_frmivalenum frameinterval = {0};
  359. frameinterval.pixel_format = framesize.pixel_format;
  360. frameinterval.width = framesize.discrete.width;
  361. frameinterval.height = framesize.discrete.height;
  362. while (xioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameinterval) == 0) {
  363. frameinterval.index++;
  364. if (frameinterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
  365. libmegapixels_mode *mode = calloc(1, sizeof(libmegapixels_mode));
  366. mode->v4l_pixfmt = fmtdesc.pixelformat;
  367. mode->width = (int) framesize.discrete.width;
  368. mode->height = (int) framesize.discrete.height;
  369. mode->media_busfmt = mn->media_bus_format;
  370. mode->rotation = 0;
  371. mode->rate = (int) ((double) frameinterval.discrete.denominator /
  372. (double) frameinterval.discrete.numerator);
  373. camera->modes = realloc(camera->modes, (camera->num_modes + 1) * sizeof(camera->modes));
  374. if (camera->modes == NULL) {
  375. return;
  376. }
  377. camera->modes[camera->num_modes++] = mode;
  378. }
  379. }
  380. }
  381. framesize.index++;
  382. }
  383. }
  384. }
  385. int
  386. libmegapixels_load_uvc(libmegapixels_devconfig *config)
  387. {
  388. if (config->loaded_uvc) {
  389. log_error("libmegapixels_load_uvc was already called\n");
  390. return 0;
  391. }
  392. config->loaded_uvc = 1;
  393. struct dirent *dir;
  394. DIR *d = opendir("/dev");
  395. while ((dir = readdir(d)) != NULL) {
  396. if (strncmp(dir->d_name, "video", 5) == 0) {
  397. char path[PATH_MAX];
  398. snprintf(path, PATH_MAX, "/dev/%s", dir->d_name);
  399. int fd = open(path, O_RDWR);
  400. if (fd < 0) {
  401. continue;
  402. }
  403. struct v4l2_capability vid_cap = {0};
  404. if (xioctl(fd, VIDIOC_QUERYCAP, &vid_cap) == -1) {
  405. perror("QUERYCAP");
  406. continue;
  407. }
  408. if (strcmp(vid_cap.driver, "uvcvideo") != 0) {
  409. continue;
  410. }
  411. if (!(vid_cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
  412. continue;
  413. }
  414. if (!(vid_cap.capabilities & V4L2_CAP_STREAMING)) {
  415. continue;
  416. }
  417. struct v4l2_fmtdesc fmtdesc = {0};
  418. fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  419. if (xioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != 0) {
  420. continue;
  421. }
  422. libmegapixels_camera *camera;
  423. camera = calloc(1, sizeof(libmegapixels_camera));
  424. camera->name = strdup((const char *) vid_cap.card);
  425. camera->video_path = strdup(path);
  426. uvc_create_modes(camera, fd);
  427. close(fd);
  428. config->cameras = realloc(config->cameras, (config->count + 1) * sizeof(config->cameras));
  429. if (config->cameras == NULL) {
  430. return -1;
  431. }
  432. config->cameras[config->count++] = camera;
  433. }
  434. }
  435. closedir(d);
  436. return 1;
  437. }
  438. int
  439. libmegapixels_init(libmegapixels_devconfig **config)
  440. {
  441. *config = calloc(1, sizeof(libmegapixels_devconfig));
  442. return 1;
  443. }