From 88981e492b395a0a9f3772c932f0af1cd5eb8366 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Thu, 25 Jul 2024 23:32:19 +0200 Subject: [PATCH 1/2] Added setting for using a custom LUT for SDR content --- src/json_rpc_client.c | 18 ++++++++---------- src/json_rpc_client.h | 2 +- src/service.c | 5 +++-- src/settings.c | 10 +++++++++- src/settings.h | 1 + 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/json_rpc_client.c b/src/json_rpc_client.c index 039dd6d..3c8c266 100644 --- a/src/json_rpc_client.c +++ b/src/json_rpc_client.c @@ -159,7 +159,7 @@ int get_daemon_flavor(char* host, ushort rpc_port, AmbientLightingDaemon* flavor return ret; } -int set_hdr_state(char* host, ushort rpc_port, bool hdr_active) +int set_hdr_state(char* host, ushort rpc_port, bool hdr_active, char* custom_sdr_lut) { int ret = 0; @@ -180,16 +180,15 @@ int set_hdr_state(char* host, ushort rpc_port, bool hdr_active) jvalue_ref response_body_jval; jvalue_ref post_body = jobject_create(); - jvalue_ref component_state_jobj = jobject_create(); - - // Assemble nested object first - // See: https://docs.hyperion-project.org/en/json/Control.html#control-components - jobject_set(component_state_jobj, j_cstr_to_buffer("component"), jstring_create("HDR")); - jobject_set(component_state_jobj, j_cstr_to_buffer("state"), jboolean_create(hdr_active)); // Assemble top-level json - jobject_set(post_body, j_cstr_to_buffer("command"), jstring_create("componentstate")); - jobject_set(post_body, j_cstr_to_buffer("componentstate"), component_state_jobj); + // Using HDR command that was added in: https://github.com/awawa-dev/HyperHDR/pull/334 + bool use_custom_sdr_lut = strlen(custom_sdr_lut) > 0; + jobject_set(post_body, j_cstr_to_buffer("command"), jstring_create("videomodehdr")); + jobject_set(post_body, j_cstr_to_buffer("HDR"), jnumber_create_i32(hdr_active || use_custom_sdr_lut ? 1 : 0)); // to use luts with SDR we need to enable HDR mode in hyperHDR + if (use_custom_sdr_lut) { + jobject_set(post_body, j_cstr_to_buffer("flatbuffers_user_lut_filename"), jstring_create(hdr_active ? "" : custom_sdr_lut)); // empty string = default + } if ((ret = send_rpc_message(host, rpc_port, post_body, &response_body_jval)) != 0) { WARN("set_hdr_state: Failed to send RPC message, code: %d", ret); @@ -197,6 +196,5 @@ int set_hdr_state(char* host, ushort rpc_port, bool hdr_active) } j_release(&post_body); - j_release(&component_state_jobj); return ret; } \ No newline at end of file diff --git a/src/json_rpc_client.h b/src/json_rpc_client.h index 8fbfe6d..43408a3 100644 --- a/src/json_rpc_client.h +++ b/src/json_rpc_client.h @@ -16,4 +16,4 @@ const char* daemon_to_string(AmbientLightingDaemon flavor); int do_http_post(char* url, const char* post_body, char** response_body, int out_buf_sz); int send_rpc_message(char* host, ushort rpc_port, jvalue_ref post_body_jval, jvalue_ref* response_body_jval); int get_daemon_flavor(char* host, ushort rpc_port, AmbientLightingDaemon* flavor); -int set_hdr_state(char* host, ushort rpc_port, bool hdr_active); \ No newline at end of file +int set_hdr_state(char* host, ushort rpc_port, bool hdr_active, char* custom_sdr_lut); \ No newline at end of file diff --git a/src/service.c b/src/service.c index eb0d68d..2bdaff4 100644 --- a/src/service.c +++ b/src/service.c @@ -443,6 +443,7 @@ static bool videooutput_callback(LSHandle* sh __attribute__((unused)), LSMessage raw_buffer hdr_type_buf = jstring_get(hdr_type_ref); const char* hdr_type_str = hdr_type_buf.m_str; + // hdr_type_str: for DynamicRange or Dolby Vision it's 'dolbyHdr', for HDR it's 'hdr and for SDR it's 'none' if (strcmp(hdr_type_str, "none") == 0) { INFO("videooutput_callback: hdrType: %s --> SDR mode", hdr_type_str); hdr_enabled = false; @@ -451,7 +452,7 @@ static bool videooutput_callback(LSHandle* sh __attribute__((unused)), LSMessage hdr_enabled = true; } - int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, hdr_enabled); + int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, hdr_enabled, service->settings->custom_sdr_lut); if (ret != 0) { ERR("videooutput_callback: set_hdr_state failed, ret: %d", ret); } @@ -507,7 +508,7 @@ static bool picture_callback(LSHandle* sh __attribute__((unused)), LSMessage* ms hdr_enabled = true; } - int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, hdr_enabled); + int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, hdr_enabled, service->settings->custom_sdr_lut); if (ret != 0) { ERR("videooutput_callback: set_hdr_state failed, ret: %d", ret); } diff --git a/src/settings.c b/src/settings.c index 1a14904..be5a7bc 100644 --- a/src/settings.c +++ b/src/settings.c @@ -22,6 +22,7 @@ void settings_init(settings_t* settings) settings->vsync = true; settings->no_hdr = false; + settings->custom_sdr_lut = strdup(""); settings->no_powerstate = false; settings->dump_frames = false; @@ -78,6 +79,12 @@ int settings_load_json(settings_t* settings, jvalue_ref source) if ((value = jobject_get(source, j_cstr_to_buffer("nohdr"))) && jis_boolean(value)) jboolean_get(value, &settings->no_hdr); + if ((value = jobject_get(source, j_cstr_to_buffer("customsdrlut"))) && jis_string(value)) { + free(settings->custom_sdr_lut); + raw_buffer str = jstring_get(value); + settings->custom_sdr_lut = strdup(str.m_str); + jstring_free_buffer(str); + } if ((value = jobject_get(source, j_cstr_to_buffer("nopowerstate"))) && jis_boolean(value)) jboolean_get(value, &settings->no_powerstate); @@ -105,6 +112,7 @@ int settings_save_json(settings_t* settings, jvalue_ref target) jobject_set(target, j_cstr_to_buffer("autostart"), jboolean_create(settings->autostart)); jobject_set(target, j_cstr_to_buffer("nohdr"), jboolean_create(settings->no_hdr)); + jobject_set(target, j_cstr_to_buffer("customsdrlut"), jstring_create(settings->custom_sdr_lut)); jobject_set(target, j_cstr_to_buffer("nopowerstate"), jboolean_create(settings->no_powerstate)); return 0; @@ -169,4 +177,4 @@ int settings_save_file(settings_t* settings, char* target) j_release(&jobj); return 0; -} +} \ No newline at end of file diff --git a/src/settings.h b/src/settings.h index 44918ee..511c62a 100644 --- a/src/settings.h +++ b/src/settings.h @@ -30,6 +30,7 @@ typedef struct _settings_t { bool dump_frames; bool no_hdr; + char* custom_sdr_lut; bool no_powerstate; } settings_t; From d298dbc7e31726cecd16a7e3d87efd4988a19076 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Sat, 27 Jul 2024 23:52:00 +0200 Subject: [PATCH 2/2] Enabled custom LUTs for hdr and dolbyHDR --- src/json_rpc_client.c | 13 ++++++++----- src/json_rpc_client.h | 2 +- src/service.c | 22 ++++++++++++++-------- src/settings.c | 16 ++++++++-------- src/settings.h | 3 ++- 5 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/json_rpc_client.c b/src/json_rpc_client.c index 3c8c266..d2a38d2 100644 --- a/src/json_rpc_client.c +++ b/src/json_rpc_client.c @@ -159,7 +159,7 @@ int get_daemon_flavor(char* host, ushort rpc_port, AmbientLightingDaemon* flavor return ret; } -int set_hdr_state(char* host, ushort rpc_port, bool hdr_active, char* custom_sdr_lut) +int set_hdr_state(char* host, ushort rpc_port, const char* dynamic_range, bool sdr_tone_mapping) { int ret = 0; @@ -183,11 +183,14 @@ int set_hdr_state(char* host, ushort rpc_port, bool hdr_active, char* custom_sdr // Assemble top-level json // Using HDR command that was added in: https://github.com/awawa-dev/HyperHDR/pull/334 - bool use_custom_sdr_lut = strlen(custom_sdr_lut) > 0; + bool enable_tone_mapping = sdr_tone_mapping || !strcmp(dynamic_range, "sdr"); jobject_set(post_body, j_cstr_to_buffer("command"), jstring_create("videomodehdr")); - jobject_set(post_body, j_cstr_to_buffer("HDR"), jnumber_create_i32(hdr_active || use_custom_sdr_lut ? 1 : 0)); // to use luts with SDR we need to enable HDR mode in hyperHDR - if (use_custom_sdr_lut) { - jobject_set(post_body, j_cstr_to_buffer("flatbuffers_user_lut_filename"), jstring_create(hdr_active ? "" : custom_sdr_lut)); // empty string = default + jobject_set(post_body, j_cstr_to_buffer("HDR"), jnumber_create_i32(enable_tone_mapping ? 1 : 0)); + if (enable_tone_mapping) { + char* lut_filename = malloc(strlen(dynamic_range) + 20); + strcpy(lut_filename, dynamic_range); + strcat(lut_filename, "_lut_lin_tables.3d"); + jobject_set(post_body, j_cstr_to_buffer("flatbuffers_user_lut_filename"), jstring_create(lut_filename)); } if ((ret = send_rpc_message(host, rpc_port, post_body, &response_body_jval)) != 0) { diff --git a/src/json_rpc_client.h b/src/json_rpc_client.h index 43408a3..0eda99c 100644 --- a/src/json_rpc_client.h +++ b/src/json_rpc_client.h @@ -16,4 +16,4 @@ const char* daemon_to_string(AmbientLightingDaemon flavor); int do_http_post(char* url, const char* post_body, char** response_body, int out_buf_sz); int send_rpc_message(char* host, ushort rpc_port, jvalue_ref post_body_jval, jvalue_ref* response_body_jval); int get_daemon_flavor(char* host, ushort rpc_port, AmbientLightingDaemon* flavor); -int set_hdr_state(char* host, ushort rpc_port, bool hdr_active, char* custom_sdr_lut); \ No newline at end of file +int set_hdr_state(char* host, ushort rpc_port, const char* dynamic_range, bool sdr_tone_mapping); \ No newline at end of file diff --git a/src/service.c b/src/service.c index 2bdaff4..35891e7 100644 --- a/src/service.c +++ b/src/service.c @@ -35,6 +35,14 @@ void* connection_loop(void* data) } else { INFO("hyperion-client connected!"); service->connected = true; + + if (service->settings->sdr_on_start) { + int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, "sdr", service->settings->sdr_tone_mapping); + if (ret != 0) { + ERR("startup: set_hdr_state failed, ret: %d", ret); + } + } + while (service->connection_loop_running) { if (hyperion_read() < 0) { ERR("Error! Connection timeout."); @@ -439,20 +447,20 @@ static bool videooutput_callback(LSHandle* sh __attribute__((unused)), LSMessage return false; } - bool hdr_enabled; raw_buffer hdr_type_buf = jstring_get(hdr_type_ref); const char* hdr_type_str = hdr_type_buf.m_str; + const char* dynamic_range; // hdr_type_str: for DynamicRange or Dolby Vision it's 'dolbyHdr', for HDR it's 'hdr and for SDR it's 'none' if (strcmp(hdr_type_str, "none") == 0) { INFO("videooutput_callback: hdrType: %s --> SDR mode", hdr_type_str); - hdr_enabled = false; + dynamic_range = "sdr"; } else { INFO("videooutput_callback: hdrType: %s --> HDR mode", hdr_type_str); - hdr_enabled = true; + dynamic_range = hdr_type_str; } - int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, hdr_enabled, service->settings->custom_sdr_lut); + int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, dynamic_range, service->settings->sdr_tone_mapping); if (ret != 0) { ERR("videooutput_callback: set_hdr_state failed, ret: %d", ret); } @@ -496,19 +504,17 @@ static bool picture_callback(LSHandle* sh __attribute__((unused)), LSMessage* ms return false; } - bool hdr_enabled; raw_buffer dynamic_range_buf = jstring_get(dynamic_range_ref); const char* dynamic_range_str = dynamic_range_buf.m_str; + // dynamic_range_str is "sdr" for SDR, dolbyHDR for dolbyVision and "hdr" for HDR? if (strcmp(dynamic_range_str, "sdr") == 0) { INFO("picture_callback: dynamicRange: %s --> SDR mode", dynamic_range_str); - hdr_enabled = false; } else { INFO("picture_callback: dynamicRange: %s --> HDR mode", dynamic_range_str); - hdr_enabled = true; } - int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, hdr_enabled, service->settings->custom_sdr_lut); + int ret = set_hdr_state(service->settings->unix_socket ? "127.0.0.1" : service->settings->address, RPC_PORT, dynamic_range_str, service->settings->sdr_tone_mapping); if (ret != 0) { ERR("videooutput_callback: set_hdr_state failed, ret: %d", ret); } diff --git a/src/settings.c b/src/settings.c index be5a7bc..3f72840 100644 --- a/src/settings.c +++ b/src/settings.c @@ -22,7 +22,8 @@ void settings_init(settings_t* settings) settings->vsync = true; settings->no_hdr = false; - settings->custom_sdr_lut = strdup(""); + settings->sdr_tone_mapping = false; + settings->sdr_on_start = false; settings->no_powerstate = false; settings->dump_frames = false; @@ -79,12 +80,10 @@ int settings_load_json(settings_t* settings, jvalue_ref source) if ((value = jobject_get(source, j_cstr_to_buffer("nohdr"))) && jis_boolean(value)) jboolean_get(value, &settings->no_hdr); - if ((value = jobject_get(source, j_cstr_to_buffer("customsdrlut"))) && jis_string(value)) { - free(settings->custom_sdr_lut); - raw_buffer str = jstring_get(value); - settings->custom_sdr_lut = strdup(str.m_str); - jstring_free_buffer(str); - } + if ((value = jobject_get(source, j_cstr_to_buffer("sdrtonemapping"))) && jis_boolean(value)) + jboolean_get(value, &settings->sdr_tone_mapping); + if ((value = jobject_get(source, j_cstr_to_buffer("sdronstart"))) && jis_boolean(value)) + jboolean_get(value, &settings->sdr_on_start); if ((value = jobject_get(source, j_cstr_to_buffer("nopowerstate"))) && jis_boolean(value)) jboolean_get(value, &settings->no_powerstate); @@ -112,7 +111,8 @@ int settings_save_json(settings_t* settings, jvalue_ref target) jobject_set(target, j_cstr_to_buffer("autostart"), jboolean_create(settings->autostart)); jobject_set(target, j_cstr_to_buffer("nohdr"), jboolean_create(settings->no_hdr)); - jobject_set(target, j_cstr_to_buffer("customsdrlut"), jstring_create(settings->custom_sdr_lut)); + jobject_set(target, j_cstr_to_buffer("sdrtonemapping"), jboolean_create(settings->sdr_tone_mapping)); + jobject_set(target, j_cstr_to_buffer("sdronstart"), jboolean_create(settings->sdr_on_start)); jobject_set(target, j_cstr_to_buffer("nopowerstate"), jboolean_create(settings->no_powerstate)); return 0; diff --git a/src/settings.h b/src/settings.h index 511c62a..246464d 100644 --- a/src/settings.h +++ b/src/settings.h @@ -30,7 +30,8 @@ typedef struct _settings_t { bool dump_frames; bool no_hdr; - char* custom_sdr_lut; + bool sdr_tone_mapping; + bool sdr_on_start; bool no_powerstate; } settings_t;