camera_config.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #include "camera_config.h"
  2. #include "ini.h"
  3. #include "config.h"
  4. #include "matrix.h"
  5. #include <wordexp.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <glib.h>
  11. #include <assert.h>
  12. static struct mp_camera_config cameras[MP_MAX_CAMERAS];
  13. static size_t num_cameras = 0;
  14. static char *exif_make;
  15. static char *exif_model;
  16. static bool
  17. find_config(char *conffile)
  18. {
  19. char buf[512];
  20. char *xdg_config_home;
  21. wordexp_t exp_result;
  22. FILE *fp;
  23. // Resolve XDG stuff
  24. if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL) {
  25. xdg_config_home = "~/.config";
  26. }
  27. wordexp(xdg_config_home, &exp_result, 0);
  28. xdg_config_home = strdup(exp_result.we_wordv[0]);
  29. wordfree(&exp_result);
  30. if (access("/proc/device-tree/compatible", F_OK) != -1) {
  31. // Reads to compatible string of the current device tree, looks like:
  32. // pine64,pinephone-1.2\0allwinner,sun50i-a64\0
  33. fp = fopen("/proc/device-tree/compatible", "r");
  34. fgets(buf, 512, fp);
  35. fclose(fp);
  36. // Check config/%dt.ini in the current working directory
  37. sprintf(conffile, "config/%s.ini", buf);
  38. if (access(conffile, F_OK) != -1) {
  39. printf("Found config file at %s\n", conffile);
  40. return true;
  41. }
  42. // Check for a config file in XDG_CONFIG_HOME
  43. sprintf(conffile, "%s/megapixels/config/%s.ini", xdg_config_home,
  44. buf);
  45. if (access(conffile, F_OK) != -1) {
  46. printf("Found config file at %s\n", conffile);
  47. return true;
  48. }
  49. // Check user overridden /etc/megapixels/config/$dt.ini
  50. sprintf(conffile, "%s/megapixels/config/%s.ini", SYSCONFDIR, buf);
  51. if (access(conffile, F_OK) != -1) {
  52. printf("Found config file at %s\n", conffile);
  53. return true;
  54. }
  55. // Check packaged /usr/share/megapixels/config/$dt.ini
  56. sprintf(conffile, "%s/megapixels/config/%s.ini", DATADIR, buf);
  57. if (access(conffile, F_OK) != -1) {
  58. printf("Found config file at %s\n", conffile);
  59. return true;
  60. }
  61. printf("%s not found\n", conffile);
  62. } else {
  63. printf("Could not read device name from device tree\n");
  64. }
  65. // If all else fails, fall back to /etc/megapixels.ini
  66. sprintf(conffile, "/etc/megapixels.ini");
  67. if (access(conffile, F_OK) != -1) {
  68. printf("Found config file at %s\n", conffile);
  69. return true;
  70. }
  71. return false;
  72. }
  73. static int
  74. strtoint(const char *nptr, char **endptr, int base)
  75. {
  76. long x = strtol(nptr, endptr, base);
  77. assert(x <= INT_MAX);
  78. return (int)x;
  79. }
  80. static bool
  81. config_handle_camera_mode(const char *prefix, MPCameraMode *mode, const char *name,
  82. const char *value)
  83. {
  84. int prefix_length = strlen(prefix);
  85. if (strncmp(prefix, name, prefix_length) != 0)
  86. return false;
  87. name += prefix_length;
  88. if (strcmp(name, "width") == 0) {
  89. mode->width = strtoint(value, NULL, 10);
  90. } else if (strcmp(name, "height") == 0) {
  91. mode->height = strtoint(value, NULL, 10);
  92. } else if (strcmp(name, "rate") == 0) {
  93. mode->frame_interval.numerator = 1;
  94. mode->frame_interval.denominator = strtoint(value, NULL, 10);
  95. } else if (strcmp(name, "fmt") == 0) {
  96. mode->pixel_format = mp_pixel_format_from_str(value);
  97. if (mode->pixel_format == MP_PIXEL_FMT_UNSUPPORTED) {
  98. g_printerr("Unsupported pixelformat %s\n", value);
  99. exit(1);
  100. }
  101. } else {
  102. return false;
  103. }
  104. return true;
  105. }
  106. static int
  107. config_ini_handler(void *user, const char *section, const char *name,
  108. const char *value)
  109. {
  110. if (strcmp(section, "device") == 0) {
  111. if (strcmp(name, "make") == 0) {
  112. exif_make = strdup(value);
  113. } else if (strcmp(name, "model") == 0) {
  114. exif_model = strdup(value);
  115. } else {
  116. g_printerr("Unknown key '%s' in [device]\n", name);
  117. exit(1);
  118. }
  119. } else {
  120. if (num_cameras == MP_MAX_CAMERAS) {
  121. g_printerr("More cameras defined than NUM_CAMERAS\n");
  122. exit(1);
  123. }
  124. size_t index = 0;
  125. for (; index < num_cameras; ++index) {
  126. if (strcmp(cameras[index].cfg_name, section) == 0) {
  127. break;
  128. }
  129. }
  130. if (index == num_cameras) {
  131. printf("Adding camera %s from config\n", section);
  132. ++num_cameras;
  133. cameras[index].index = index;
  134. strcpy(cameras[index].cfg_name, section);
  135. }
  136. struct mp_camera_config *cc = &cameras[index];
  137. if (config_handle_camera_mode("capture-", &cc->capture_mode, name,
  138. value)) {
  139. } else if (config_handle_camera_mode("preview-", &cc->preview_mode,
  140. name, value)) {
  141. } else if (strcmp(name, "rotate") == 0) {
  142. cc->rotate = strtoint(value, NULL, 10);
  143. } else if (strcmp(name, "mirrored") == 0) {
  144. cc->mirrored = strcmp(value, "true") == 0;
  145. } else if (strcmp(name, "driver") == 0) {
  146. strcpy(cc->dev_name, value);
  147. } else if (strcmp(name, "media-driver") == 0) {
  148. strcpy(cc->media_dev_name, value);
  149. } else if (strcmp(name, "media-links") == 0) {
  150. char **linkdefs = g_strsplit(value, ",", 0);
  151. for (int i = 0; i < MP_MAX_LINKS && linkdefs[i] != NULL;
  152. ++i) {
  153. char **linkdef = g_strsplit(linkdefs[i], "->", 2);
  154. char **porta = g_strsplit(linkdef[0], ":", 2);
  155. char **portb = g_strsplit(linkdef[1], ":", 2);
  156. strcpy(cc->media_links[i].source_name, porta[0]);
  157. strcpy(cc->media_links[i].target_name, portb[0]);
  158. cc->media_links[i].source_port =
  159. strtoint(porta[1], NULL, 10);
  160. cc->media_links[i].target_port =
  161. strtoint(portb[1], NULL, 10);
  162. g_strfreev(portb);
  163. g_strfreev(porta);
  164. g_strfreev(linkdef);
  165. ++cc->num_media_links;
  166. }
  167. g_strfreev(linkdefs);
  168. } else if (strcmp(name, "colormatrix") == 0) {
  169. sscanf(value, "%f,%f,%f,%f,%f,%f,%f,%f,%f",
  170. cc->colormatrix + 0, cc->colormatrix + 1,
  171. cc->colormatrix + 2, cc->colormatrix + 3,
  172. cc->colormatrix + 4, cc->colormatrix + 5,
  173. cc->colormatrix + 6, cc->colormatrix + 7,
  174. cc->colormatrix + 8);
  175. } else if (strcmp(name, "forwardmatrix") == 0) {
  176. sscanf(value, "%f,%f,%f,%f,%f,%f,%f,%f,%f",
  177. cc->forwardmatrix + 0, cc->forwardmatrix + 1,
  178. cc->forwardmatrix + 2, cc->forwardmatrix + 3,
  179. cc->forwardmatrix + 4, cc->forwardmatrix + 5,
  180. cc->forwardmatrix + 6, cc->forwardmatrix + 7,
  181. cc->forwardmatrix + 8);
  182. } else if (strcmp(name, "whitelevel") == 0) {
  183. cc->whitelevel = strtoint(value, NULL, 10);
  184. } else if (strcmp(name, "blacklevel") == 0) {
  185. cc->blacklevel = strtoint(value, NULL, 10);
  186. } else if (strcmp(name, "focallength") == 0) {
  187. cc->focallength = strtof(value, NULL);
  188. } else if (strcmp(name, "cropfactor") == 0) {
  189. cc->cropfactor = strtof(value, NULL);
  190. } else if (strcmp(name, "fnumber") == 0) {
  191. cc->fnumber = strtod(value, NULL);
  192. } else if (strcmp(name, "iso-min") == 0) {
  193. cc->iso_min = strtod(value, NULL);
  194. } else if (strcmp(name, "iso-max") == 0) {
  195. cc->iso_max = strtod(value, NULL);
  196. } else {
  197. g_printerr("Unknown key '%s' in [%s]\n", name, section);
  198. exit(1);
  199. }
  200. }
  201. return 1;
  202. }
  203. void
  204. calculate_matrices()
  205. {
  206. for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) {
  207. if (cameras[i].colormatrix != NULL &&
  208. cameras[i].forwardmatrix != NULL) {
  209. multiply_matrices(cameras[i].colormatrix,
  210. cameras[i].forwardmatrix,
  211. cameras[i].previewmatrix);
  212. }
  213. }
  214. }
  215. bool
  216. mp_load_config()
  217. {
  218. char file[512];
  219. if (!find_config(file)) {
  220. g_printerr("Could not find any config file\n");
  221. return false;
  222. }
  223. int result = ini_parse(file, config_ini_handler, NULL);
  224. if (result == -1) {
  225. g_printerr("Config file not found\n");
  226. return false;
  227. }
  228. if (result == -2) {
  229. g_printerr("Could not allocate memory to parse config file\n");
  230. return false;
  231. }
  232. if (result != 0) {
  233. g_printerr("Could not parse config file\n");
  234. return false;
  235. }
  236. calculate_matrices();
  237. return true;
  238. }
  239. const char *
  240. mp_get_device_make()
  241. {
  242. return exif_make;
  243. }
  244. const char *
  245. mp_get_device_model()
  246. {
  247. return exif_model;
  248. }
  249. const struct mp_camera_config *
  250. mp_get_camera_config(size_t index)
  251. {
  252. if (index >= num_cameras)
  253. return NULL;
  254. return &cameras[index];
  255. }