#include "dcp.h" #include #include #include #include #include unsigned int get_int32(const unsigned char *buffer, size_t offset) { return (buffer[offset + 3] << 24) | (buffer[offset + 2] << 16) | (buffer[offset + 1] << 8) | (buffer[offset]); } unsigned int get_int16(const unsigned char *buffer, size_t offset) { return (buffer[offset + 1] << 8) | (buffer[offset]); } float get_float(unsigned char *buffer, size_t offset) { float f; unsigned char b[] = { buffer[offset + 0], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3] }; memcpy(&f, &b, sizeof(f)); return f; } float get_srational(unsigned char *buffer, size_t offset) { int a = (int)get_int32(buffer, offset); int b = (int)get_int32(buffer, offset + 4); return (float)a / (float)b; } struct MPCameraCalibration parse_calibration_file(const char *path) { FILE *fp; size_t size; unsigned char *buffer; struct MPCameraCalibration result = { 0 }; fp = fopen(path, "rb"); if (fp == NULL) { return result; } fseek(fp, 0, SEEK_END); size = ftell(fp); fseek(fp, 0, SEEK_SET); buffer = malloc(sizeof(char) * size); size_t ret = fread(buffer, 1, size, fp); if (ret != size) { return result; } fclose(fp); if (buffer[0] != 'I' || buffer[1] != 'I') { fprintf(stderr, "Magic for DCP file incorrect\n"); return result; } if (buffer[2] != 0x52 || buffer[3] != 0x43) { fprintf(stderr, "Invalid DCP version\n"); return result; } unsigned int ifd0 = get_int32(buffer, 4); unsigned int tag_count = get_int16(buffer, ifd0); for (int i = 0; i < tag_count; i++) { int tag_offset = ifd0 + 2 + (i * 12); unsigned int tag = get_int16(buffer, tag_offset + 0); unsigned int type = get_int16(buffer, tag_offset + 2); unsigned int count = get_int32(buffer, tag_offset + 4); unsigned int offset = get_int32(buffer, tag_offset + 8); switch (tag) { case DCPTAG_COLOR_MATRIX_1: for (int j = 0; j < 9; j++) { float point = get_srational(buffer, offset + (j * 8)); result.color_matrix_1[j] = point; } break; case DCPTAG_COLOR_MATRIX_2: for (int j = 0; j < 9; j++) { float point = get_srational(buffer, offset + (j * 8)); result.color_matrix_2[j] = point; } break; case DCPTAG_FORWARD_MATRIX_1: for (int j = 0; j < 9; j++) { float point = get_srational(buffer, offset + (j * 8)); result.forward_matrix_1[j] = point; } break; case DCPTAG_FORWARD_MATRIX_2: for (int j = 0; j < 9; j++) { float point = get_srational(buffer, offset + (j * 8)); result.forward_matrix_2[j] = point; } break; case DCPTAG_CALIBRATION_ILLUMINANT_1: result.illuminant_1 = offset; break; case DCPTAG_CALIBRATION_ILLUMINANT_2: result.illuminant_2 = offset; break; case DCPTAG_PROFILE_TONE_CURVE: result.tone_curve = malloc(count * sizeof(float)); result.tone_curve_length = count; for (int j = 0; j < count; j++) { result.tone_curve[j] = get_float(buffer, offset + (j * 4)); } break; case DCPTAG_PROFILE_HUE_SAT_MAP_DIMS: result.hue_sat_map_dims[0] = get_int32(buffer, offset); result.hue_sat_map_dims[1] = get_int32(buffer, offset + 4); result.hue_sat_map_dims[2] = get_int32(buffer, offset + 8); break; case DCPTAG_PROFILE_HUE_SAT_MAP_DATA_1: result.hue_sat_map_data_1 = malloc(count * sizeof(float)); for (int j = 0; j < count; j++) { result.hue_sat_map_data_1[j] = get_float(buffer, offset + (j * 4)); } break; case DCPTAG_PROFILE_HUE_SAT_MAP_DATA_2: result.hue_sat_map_data_2 = malloc(count * sizeof(float)); for (int j = 0; j < count; j++) { result.hue_sat_map_data_2[j] = get_float(buffer, offset + (j * 4)); } break; } } return result; } bool find_calibration_by_model(char *conffile, char *model, const char *sensor) { // Check config/%model,%sensor.dcp in the current working directory sprintf(conffile, "config/%s,%s.dcp", model, sensor); if (access(conffile, F_OK) != -1) { printf("Found calibration file at %s\n", conffile); return true; } // Check user overridden /etc/megapixels/config/%model,%sensor.dcp sprintf(conffile, "%s/megapixels/config/%s,%s.dcp", SYSCONFDIR, model, sensor); if (access(conffile, F_OK) != -1) { printf("Found calibration file at %s\n", conffile); return true; } // Check packaged /usr/share/megapixels/config/%model,%sensor.ini sprintf(conffile, "%s/megapixels/config/%s,%s.dcp", DATADIR, model, sensor); if (access(conffile, F_OK) != -1) { printf("Found calibration file at %s\n", conffile); return true; } printf("No calibration found for %s,%s\n", model, sensor); return false; } bool find_calibration(char *conffile, const char *sensor) { char model[512]; FILE *fp; if (access("/proc/device-tree/compatible", F_OK) == -1) { return false; } fp = fopen("/proc/device-tree/compatible", "r"); char *modelptr = model; while (1) { int c = fgetc(fp); if (c == EOF) { *(modelptr) = '\0'; return find_calibration_by_model(conffile, model, sensor); } *(modelptr++) = (char)c; if (c == 0) { bool res = find_calibration_by_model(conffile, model, sensor); if (res) { return true; } modelptr = model; } } }