#include "camera_config.h" #include "ini.h" #include "config.h" #include #include #include #include #include #include #include static struct mp_camera_config cameras[MP_MAX_CAMERAS]; static size_t num_cameras = 0; static char *exif_make; static char *exif_model; static bool find_config(char *conffile) { char buf[512]; char *xdg_config_home; wordexp_t exp_result; FILE *fp; // Resolve XDG stuff if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL) { xdg_config_home = "~/.config"; } wordexp(xdg_config_home, &exp_result, 0); xdg_config_home = strdup(exp_result.we_wordv[0]); wordfree(&exp_result); if (access("/proc/device-tree/compatible", F_OK) != -1) { // Reads to compatible string of the current device tree, looks like: // pine64,pinephone-1.2\0allwinner,sun50i-a64\0 fp = fopen("/proc/device-tree/compatible", "r"); fgets(buf, 512, fp); fclose(fp); // Check config/%dt.ini in the current working directory sprintf(conffile, "config/%s.ini", buf); if(access(conffile, F_OK) != -1) { printf("Found config file at %s\n", conffile); return true; } // Check for a config file in XDG_CONFIG_HOME sprintf(conffile, "%s/megapixels/config/%s.ini", xdg_config_home, buf); if(access(conffile, F_OK) != -1) { printf("Found config file at %s\n", conffile); return true; } // Check user overridden /etc/megapixels/config/$dt.ini sprintf(conffile, "%s/megapixels/config/%s.ini", SYSCONFDIR, buf); if(access(conffile, F_OK) != -1) { printf("Found config file at %s\n", conffile); return true; } // Check packaged /usr/share/megapixels/config/$dt.ini sprintf(conffile, "%s/megapixels/config/%s.ini", DATADIR, buf); if(access(conffile, F_OK) != -1) { printf("Found config file at %s\n", conffile); return true; } printf("%s not found\n", conffile); } else { printf("Could not read device name from device tree\n"); } // If all else fails, fall back to /etc/megapixels.ini sprintf(conffile, "/etc/megapixels.ini"); if (access(conffile, F_OK) != -1) { printf("Found config file at %s\n", conffile); return true; } return false; } static int strtoint(const char *nptr, char **endptr, int base) { long x = strtol(nptr, endptr, base); assert(x <= INT_MAX); return (int) x; } static bool config_handle_camera_mode(const char *prefix, MPCameraMode * mode, const char *name, const char *value) { int prefix_length = strlen(prefix); if (strncmp(prefix, name, prefix_length) != 0) return false; name += prefix_length; if (strcmp(name, "width") == 0) { mode->width = strtoint(value, NULL, 10); } else if (strcmp(name, "height") == 0) { mode->height = strtoint(value, NULL, 10); } else if (strcmp(name, "rate") == 0) { mode->frame_interval.numerator = 1; mode->frame_interval.denominator = strtoint(value, NULL, 10); } else if (strcmp(name, "fmt") == 0) { mode->pixel_format = mp_pixel_format_from_str(value); if (mode->pixel_format == MP_PIXEL_FMT_UNSUPPORTED) { g_printerr("Unsupported pixelformat %s\n", value); exit(1); } } else { return false; } return true; } static int config_ini_handler(void *user, const char *section, const char *name, const char *value) { if (strcmp(section, "device") == 0) { if (strcmp(name, "make") == 0) { exif_make = strdup(value); } else if (strcmp(name, "model") == 0) { exif_model = strdup(value); } else { g_printerr("Unknown key '%s' in [device]\n", name); exit(1); } } else { if (num_cameras == MP_MAX_CAMERAS) { g_printerr("More cameras defined than NUM_CAMERAS\n"); exit(1); } size_t index = 0; for (; index < num_cameras; ++index) { if (strcmp(cameras[index].cfg_name, section) == 0) { break; } } if (index == num_cameras) { printf("Adding camera %s from config\n", section); ++num_cameras; cameras[index].index = index; strcpy(cameras[index].cfg_name, section); } struct mp_camera_config *cc = &cameras[index]; if (config_handle_camera_mode("capture-", &cc->capture_mode, name, value)) { } else if (config_handle_camera_mode("preview-", &cc->preview_mode, name, value)) { } else if (strcmp(name, "rotate") == 0) { cc->rotate = strtoint(value, NULL, 10); } else if (strcmp(name, "mirrored") == 0) { cc->mirrored = strcmp(value, "true") == 0; } else if (strcmp(name, "driver") == 0) { strcpy(cc->dev_name, value); } else if (strcmp(name, "media-driver") == 0) { strcpy(cc->media_dev_name, value); } else if (strcmp(name, "media-links") == 0) { char **linkdefs = g_strsplit(value, ",", 0); for (int i = 0; i < MP_MAX_LINKS && linkdefs[i] != NULL; ++i) { char **linkdef = g_strsplit(linkdefs[i], "->", 2); char **porta = g_strsplit(linkdef[0], ":", 2); char **portb = g_strsplit(linkdef[1], ":", 2); strcpy(cc->media_links[i].source_name, porta[0]); strcpy(cc->media_links[i].target_name, portb[0]); cc->media_links[i].source_port = strtoint(porta[1], NULL, 10); cc->media_links[i].target_port = strtoint(portb[1], NULL, 10); g_strfreev(portb); g_strfreev(porta); g_strfreev(linkdef); ++cc->num_media_links; } g_strfreev(linkdefs); } else if (strcmp(name, "colormatrix") == 0) { sscanf(value, "%f,%f,%f,%f,%f,%f,%f,%f,%f", cc->colormatrix+0, cc->colormatrix+1, cc->colormatrix+2, cc->colormatrix+3, cc->colormatrix+4, cc->colormatrix+5, cc->colormatrix+6, cc->colormatrix+7, cc->colormatrix+8 ); } else if (strcmp(name, "forwardmatrix") == 0) { sscanf(value, "%f,%f,%f,%f,%f,%f,%f,%f,%f", cc->forwardmatrix+0, cc->forwardmatrix+1, cc->forwardmatrix+2, cc->forwardmatrix+3, cc->forwardmatrix+4, cc->forwardmatrix+5, cc->forwardmatrix+6, cc->forwardmatrix+7, cc->forwardmatrix+8 ); } else if (strcmp(name, "whitelevel") == 0) { cc->whitelevel = strtoint(value, NULL, 10); } else if (strcmp(name, "blacklevel") == 0) { cc->blacklevel = strtoint(value, NULL, 10); } else if (strcmp(name, "focallength") == 0) { cc->focallength = strtof(value, NULL); } else if (strcmp(name, "cropfactor") == 0) { cc->cropfactor = strtof(value, NULL); } else if (strcmp(name, "fnumber") == 0) { cc->fnumber = strtod(value, NULL); } else if (strcmp(name, "iso-min") == 0) { cc->iso_min = strtod(value, NULL); } else if (strcmp(name, "iso-max") == 0) { cc->iso_max = strtod(value, NULL); } else { g_printerr("Unknown key '%s' in [%s]\n", name, section); exit(1); } } return 1; } bool mp_load_config() { char file[512]; if (!find_config(file)) { g_printerr("Could not find any config file\n"); return false; } int result = ini_parse(file, config_ini_handler, NULL); if (result == -1) { g_printerr("Config file not found\n"); } else if (result == -2) { g_printerr("Could not allocate memory to parse config file\n"); } else if (result != 0) { g_printerr("Could not parse config file\n"); } else { return true; } return false; } const char * mp_get_device_make() { return exif_make; } const char * mp_get_device_model() { return exif_model; } const struct mp_camera_config * mp_get_camera_config(size_t index) { if (index >= num_cameras) return NULL; return &cameras[index]; }