camera_config.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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, buf);
  44. if(access(conffile, F_OK) != -1) {
  45. printf("Found config file at %s\n", conffile);
  46. return true;
  47. }
  48. // Check user overridden /etc/megapixels/config/$dt.ini
  49. sprintf(conffile, "%s/megapixels/config/%s.ini", SYSCONFDIR, buf);
  50. if(access(conffile, F_OK) != -1) {
  51. printf("Found config file at %s\n", conffile);
  52. return true;
  53. }
  54. // Check packaged /usr/share/megapixels/config/$dt.ini
  55. sprintf(conffile, "%s/megapixels/config/%s.ini", DATADIR, buf);
  56. if(access(conffile, F_OK) != -1) {
  57. printf("Found config file at %s\n", conffile);
  58. return true;
  59. }
  60. printf("%s not found\n", conffile);
  61. } else {
  62. printf("Could not read device name from device tree\n");
  63. }
  64. // If all else fails, fall back to /etc/megapixels.ini
  65. sprintf(conffile, "/etc/megapixels.ini");
  66. if (access(conffile, F_OK) != -1) {
  67. printf("Found config file at %s\n", conffile);
  68. return true;
  69. }
  70. return false;
  71. }
  72. static int
  73. strtoint(const char *nptr, char **endptr, int base)
  74. {
  75. long x = strtol(nptr, endptr, base);
  76. assert(x <= INT_MAX);
  77. return (int) x;
  78. }
  79. static bool
  80. config_handle_camera_mode(const char *prefix, MPCameraMode * mode, const char *name, const char *value)
  81. {
  82. int prefix_length = strlen(prefix);
  83. if (strncmp(prefix, name, prefix_length) != 0)
  84. return false;
  85. name += prefix_length;
  86. if (strcmp(name, "width") == 0) {
  87. mode->width = strtoint(value, NULL, 10);
  88. } else if (strcmp(name, "height") == 0) {
  89. mode->height = strtoint(value, NULL, 10);
  90. } else if (strcmp(name, "rate") == 0) {
  91. mode->frame_interval.numerator = 1;
  92. mode->frame_interval.denominator = strtoint(value, NULL, 10);
  93. } else if (strcmp(name, "fmt") == 0) {
  94. mode->pixel_format = mp_pixel_format_from_str(value);
  95. if (mode->pixel_format == MP_PIXEL_FMT_UNSUPPORTED) {
  96. g_printerr("Unsupported pixelformat %s\n", value);
  97. exit(1);
  98. }
  99. } else {
  100. return false;
  101. }
  102. return true;
  103. }
  104. static int
  105. config_ini_handler(void *user, const char *section, const char *name,
  106. const char *value)
  107. {
  108. if (strcmp(section, "device") == 0) {
  109. if (strcmp(name, "make") == 0) {
  110. exif_make = strdup(value);
  111. } else if (strcmp(name, "model") == 0) {
  112. exif_model = strdup(value);
  113. } else {
  114. g_printerr("Unknown key '%s' in [device]\n", name);
  115. exit(1);
  116. }
  117. } else {
  118. if (num_cameras == MP_MAX_CAMERAS) {
  119. g_printerr("More cameras defined than NUM_CAMERAS\n");
  120. exit(1);
  121. }
  122. size_t index = 0;
  123. for (; index < num_cameras; ++index) {
  124. if (strcmp(cameras[index].cfg_name, section) == 0) {
  125. break;
  126. }
  127. }
  128. if (index == num_cameras) {
  129. printf("Adding camera %s from config\n", section);
  130. ++num_cameras;
  131. cameras[index].index = index;
  132. strcpy(cameras[index].cfg_name, section);
  133. }
  134. struct mp_camera_config *cc = &cameras[index];
  135. if (config_handle_camera_mode("capture-", &cc->capture_mode, name, value)) {
  136. } else if (config_handle_camera_mode("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; ++i) {
  148. char **linkdef = g_strsplit(linkdefs[i], "->", 2);
  149. char **porta = g_strsplit(linkdef[0], ":", 2);
  150. char **portb = g_strsplit(linkdef[1], ":", 2);
  151. strcpy(cc->media_links[i].source_name, porta[0]);
  152. strcpy(cc->media_links[i].target_name, portb[0]);
  153. cc->media_links[i].source_port = strtoint(porta[1], NULL, 10);
  154. cc->media_links[i].target_port = strtoint(portb[1], NULL, 10);
  155. g_strfreev(portb);
  156. g_strfreev(porta);
  157. g_strfreev(linkdef);
  158. ++cc->num_media_links;
  159. }
  160. g_strfreev(linkdefs);
  161. } else if (strcmp(name, "colormatrix") == 0) {
  162. sscanf(value, "%f,%f,%f,%f,%f,%f,%f,%f,%f",
  163. cc->colormatrix+0,
  164. cc->colormatrix+1,
  165. cc->colormatrix+2,
  166. cc->colormatrix+3,
  167. cc->colormatrix+4,
  168. cc->colormatrix+5,
  169. cc->colormatrix+6,
  170. cc->colormatrix+7,
  171. cc->colormatrix+8
  172. );
  173. } else if (strcmp(name, "forwardmatrix") == 0) {
  174. sscanf(value, "%f,%f,%f,%f,%f,%f,%f,%f,%f",
  175. cc->forwardmatrix+0,
  176. cc->forwardmatrix+1,
  177. cc->forwardmatrix+2,
  178. cc->forwardmatrix+3,
  179. cc->forwardmatrix+4,
  180. cc->forwardmatrix+5,
  181. cc->forwardmatrix+6,
  182. cc->forwardmatrix+7,
  183. cc->forwardmatrix+8
  184. );
  185. } else if (strcmp(name, "whitelevel") == 0) {
  186. cc->whitelevel = strtoint(value, NULL, 10);
  187. } else if (strcmp(name, "blacklevel") == 0) {
  188. cc->blacklevel = strtoint(value, NULL, 10);
  189. } else if (strcmp(name, "focallength") == 0) {
  190. cc->focallength = strtof(value, NULL);
  191. } else if (strcmp(name, "cropfactor") == 0) {
  192. cc->cropfactor = strtof(value, NULL);
  193. } else if (strcmp(name, "fnumber") == 0) {
  194. cc->fnumber = strtod(value, NULL);
  195. } else if (strcmp(name, "iso-min") == 0) {
  196. cc->iso_min = strtod(value, NULL);
  197. } else if (strcmp(name, "iso-max") == 0) {
  198. cc->iso_max = strtod(value, NULL);
  199. } else {
  200. g_printerr("Unknown key '%s' in [%s]\n", name, section);
  201. exit(1);
  202. }
  203. }
  204. return 1;
  205. }
  206. void
  207. calculate_matrices() {
  208. for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) {
  209. if (cameras[i].colormatrix != NULL && cameras[i].forwardmatrix != NULL) {
  210. multiply_matrices(cameras[i].colormatrix, cameras[i].forwardmatrix, cameras[i].previewmatrix);
  211. }
  212. }
  213. }
  214. bool mp_load_config() {
  215. char file[512];
  216. if (!find_config(file)) {
  217. g_printerr("Could not find any config file\n");
  218. return false;
  219. }
  220. int result = ini_parse(file, config_ini_handler, NULL);
  221. if (result == -1) {
  222. g_printerr("Config file not found\n");
  223. return false;
  224. }
  225. if (result == -2) {
  226. g_printerr("Could not allocate memory to parse config file\n");
  227. return false;
  228. }
  229. if (result != 0) {
  230. g_printerr("Could not parse config file\n");
  231. return false;
  232. }
  233. calculate_matrices();
  234. return true;
  235. }
  236. const char * mp_get_device_make()
  237. {
  238. return exif_make;
  239. }
  240. const char * mp_get_device_model()
  241. {
  242. return exif_model;
  243. }
  244. const struct mp_camera_config * mp_get_camera_config(size_t index)
  245. {
  246. if (index >= num_cameras)
  247. return NULL;
  248. return &cameras[index];
  249. }