camera_config.c 11 KB

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