diff --git a/src/main.c b/src/main.c index 8038dd7..37be6cc 100644 --- a/src/main.c +++ b/src/main.c @@ -31,6 +31,7 @@ static struct option long_options[] = { { "no-vsync", no_argument, 0, 'n' }, { "no-hdr", no_argument, 0, 'r' }, { "no-powerstate", no_argument, 0, 's' }, + { "lut-table", required_argument, 0, 't' }, { "backend", required_argument, 0, 'b' }, { "ui-backend", required_argument, 0, 'u' }, { "quirks", required_argument, 0, 'q' }, @@ -62,6 +63,7 @@ static void print_usage() printf(" -n, --no-vsync Disable vsync (may increase framerate at the cost of tearing/artifacts)\n"); printf(" -r, --no-hdr Disable automatic HDR mode switching\n"); printf(" -s, --no-powerstate Disable automatic powerstate switching\n"); + printf(" -t, --lut-table=FILE LUT table file\n"); printf(" -q, --quirks=QUIRKS Enable certain handling for per-device quirks\n"); printf(" -c, --config=PATH Absolute path for configfile to load settings. Giving additional runtime arguments will overwrite loaded ones.\n"); printf(" -d, --dump-frames Dump raw video frames to /tmp/.\n"); @@ -76,7 +78,7 @@ static int parse_options(int argc, char* argv[]) int opt, longindex; int ret; - while ((opt = getopt_long(argc, argv, "x:y:a:p:f:b:u:q:c:lvnhdVGrs", long_options, &longindex)) != -1) { + while ((opt = getopt_long(argc, argv, "x:y:a:p:f:b:u:q:c:t:lvnhdVGrs", long_options, &longindex)) != -1) { switch (opt) { case 'x': settings.width = atoi(optarg); @@ -129,6 +131,10 @@ static int parse_options(int argc, char* argv[]) case 'q': settings.quirks = atoi(optarg); break; + case 't': + free(settings.lut_table); + settings.lut_table = strdup(optarg); + break; case 'c': DBG("Loading config file %s...", optarg); if ((ret = settings_load_file(&settings, optarg)) != 0) { diff --git a/src/service.c b/src/service.c index 74bc247..64bda21 100644 --- a/src/service.c +++ b/src/service.c @@ -84,6 +84,8 @@ int service_init(service_t* service, settings_t* settings) service->unicapture.callback_data = (void*)service; service->unicapture.dump_frames = settings->dump_frames; + unicapture_load_lut_table(&service->unicapture, settings->lut_table); + char* ui_backends[] = { "libgm_backend.so", "libhalgal_backend.so", NULL }; char* video_backends[] = { "libvtcapture_backend.so", "libdile_vt_backend.so", NULL }; char backend_name[FILENAME_MAX] = { 0 }; diff --git a/src/settings.c b/src/settings.c index 1a14904..8a977a9 100644 --- a/src/settings.c +++ b/src/settings.c @@ -16,6 +16,8 @@ void settings_init(settings_t* settings) settings->height = 180; settings->quirks = 0; + settings->lut_table = strdup(""); + settings->no_video = false; settings->no_gui = false; settings->autostart = false; @@ -58,6 +60,13 @@ int settings_load_json(settings_t* settings, jvalue_ref source) if ((value = jobject_get(source, j_cstr_to_buffer("unix-socket"))) && jis_boolean(value)) jboolean_get(value, &settings->unix_socket); + if ((value = jobject_get(source, j_cstr_to_buffer("lut-table"))) && jis_string(value)) { + free(settings->lut_table); + raw_buffer str = jstring_get(value); + settings->lut_table = strdup(str.m_str); + jstring_free_buffer(str); + } + if ((value = jobject_get(source, j_cstr_to_buffer("fps"))) && jis_number(value)) jnumber_get_i32(value, &settings->fps); if ((value = jobject_get(source, j_cstr_to_buffer("width"))) && jis_number(value)) @@ -94,6 +103,8 @@ int settings_save_json(settings_t* settings, jvalue_ref target) jobject_set(target, j_cstr_to_buffer("priority"), jnumber_create_i32(settings->priority)); jobject_set(target, j_cstr_to_buffer("unix-socket"), jboolean_create(settings->unix_socket)); + jobject_set(target, j_cstr_to_buffer("lut-table"), jstring_create(settings->lut_table)); + jobject_set(target, j_cstr_to_buffer("fps"), jnumber_create_i32(settings->fps)); jobject_set(target, j_cstr_to_buffer("width"), jnumber_create_i32(settings->width)); jobject_set(target, j_cstr_to_buffer("height"), jnumber_create_i32(settings->height)); diff --git a/src/settings.h b/src/settings.h index 44918ee..4acf9de 100644 --- a/src/settings.h +++ b/src/settings.h @@ -22,6 +22,8 @@ typedef struct _settings_t { bool vsync; int quirks; + char* lut_table; + bool no_video; bool no_gui; diff --git a/src/unicapture.c b/src/unicapture.c index 4bf4ecf..d90cf9f 100644 --- a/src/unicapture.c +++ b/src/unicapture.c @@ -9,6 +9,9 @@ #include #include +#define LUT_INDEX(y, u, v) ((y + (u << 8) + (v << 16)) * 3) +#define LUT_FILE_SIZE 256 * 256 * 256 * 3 + #define DLSYM_ERROR_CHECK() \ if ((error = dlerror()) != NULL) { \ ERR("Error! dlsym failed, msg: %s", error); \ @@ -189,6 +192,17 @@ void* unicapture_run(void* data) if (video_frame.pixel_format != PIXFMT_INVALID) { converter_run(&video_converter, &video_frame, &video_frame_converted, PIXFMT_ARGB); + + if (this->lut_table != NULL) { + for (int i = 0; i < video_frame_converted.width * video_frame_converted.height * 4; i += 4) { + // This is somehow RGBA instead of the supposed ARGB + uint8_t r = ((uint8_t*)(video_frame_converted.planes[0].buffer))[i + 0]; + uint8_t g = ((uint8_t*)(video_frame_converted.planes[0].buffer))[i + 1]; + uint8_t b = ((uint8_t*)(video_frame_converted.planes[0].buffer))[i + 2]; + + memcpy(&((uint8_t*)video_frame_converted.planes[0].buffer)[i + 0], &this->lut_table[LUT_INDEX(r, g, b)], 3); + } + } } uint64_t frame_converted = getticks_us(); @@ -339,6 +353,52 @@ void unicapture_init(unicapture_state_t* this) { memset(this, 0, sizeof(unicapture_state_t)); this->vsync = true; + this->lut_table = NULL; +} + +int unicapture_load_lut_table(unicapture_state_t* this, char* lut_table_file) +{ + if (this->lut_table) { + free(this->lut_table); + } + this->lut_table = NULL; + + if (strcmp(lut_table_file, "") == 0) { + return 1; + } + + FILE* file = fopen(lut_table_file, "r"); + + if (!file) { + INFO("LUT file could not be read: %s", lut_table_file); + return 1; + } + + size_t length; + INFO("LUT file read: %s", lut_table_file); + + fseek(file, 0, SEEK_END); + length = ftell(file); + fseek(file, 0, SEEK_SET); + + if (length != LUT_FILE_SIZE) { + ERR("LUT file has invalid length: %i", length); + fclose(file); + return 1; + } + + this->lut_table = (unsigned char*)malloc(length + 1); + if (fread(this->lut_table, 1, length, file) != length) { + free(this->lut_table); + this->lut_table = NULL; + ERR("Error reading LUT file"); + fclose(file); + return 1; + } + + INFO("LUT file has been loaded"); + + return 0; } int unicapture_start(unicapture_state_t* this) diff --git a/src/unicapture.h b/src/unicapture.h index 3dbe60c..e804d1f 100644 --- a/src/unicapture.h +++ b/src/unicapture.h @@ -102,6 +102,8 @@ typedef struct _unicapture_state { struct { double framerate; } metrics; + + uint8_t* lut_table; } unicapture_state_t; #ifdef __cplusplus @@ -112,6 +114,7 @@ int unicapture_try_backends(cap_backend_config_t* config, capture_backend_t* bac int unicapture_init_backend(cap_backend_config_t* config, capture_backend_t* backend, char* name); int unicapture_start(unicapture_state_t* state); int unicapture_stop(unicapture_state_t* state); +int unicapture_load_lut_table(unicapture_state_t* state, char* lut_table_file); #ifdef __cplusplus } #endif