diff --git a/HyperDRM.manifest.json b/HyperDRM.manifest.json index c7e58bb..691894f 100644 --- a/HyperDRM.manifest.json +++ b/HyperDRM.manifest.json @@ -1,15 +1,15 @@ { "id": "org.webosbrew.histogramhyperion", - "version": "0.13.0", + "version": "0.13.1", "type": "web", "title": "HyperDRM", "appDescription": "Ambient lighting for webOS, Hyperion and HyperHDR", "iconUri": "https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/app/icon.png", "sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM", "rootRequired": true, - "ipkUrl": "https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/HyperDRM_0.13.0_arm.ipk", + "ipkUrl": "https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/HyperDRM_0.13.1_arm.ipk", "ipkHash": { - "sha256": "a7ab184db8c948ceb4657f093c2cf10c13df3565ff9ed4d8482dcf2d59896a0a" + "sha256": "7ee27c6c8c0f7649690f1eb6e055b0add5ba2e57461cec58cbc8e144316af1d6" }, - "ipkSize": 1207634 + "ipkSize": 1207854 } diff --git a/HyperDRM_0.13.0_arm.ipk b/HyperDRM_0.13.1_arm.ipk similarity index 92% rename from HyperDRM_0.13.0_arm.ipk rename to HyperDRM_0.13.1_arm.ipk index 8c21f83..eb80875 100644 Binary files a/HyperDRM_0.13.0_arm.ipk and b/HyperDRM_0.13.1_arm.ipk differ diff --git a/README.md b/README.md index 527b125..0ff342f 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Only the own service is modified. Optional Auto PicCap can configure its receive ## Installation -The current package is [HyperDRM_0.13.0_arm.ipk](HyperDRM_0.13.0_arm.ipk). Install it using the TV's webOS/Homebrew package installation workflow. +The current package is [HyperDRM_0.13.1_arm.ipk](HyperDRM_0.13.1_arm.ipk). Install it using the TV's webOS/Homebrew package installation workflow. Elevate the installed own service through Homebrew Channel: @@ -233,3 +233,5 @@ and briefly interrupts ambient lighting; it never runs automatically. `python release.py --sanitizers` additionally checks protocol, atomic-file, receiver-output and simulated service-lifecycle tests with ASan/UBSan. These host tests do not replace real LG capture and remote-control validation on a TV. + +Histogram near-black handling suppresses colors with a maximum RGB channel of 12 or less, gradually restores brightness between 12 and 24, and preserves brighter colors. This applies only to histogram output; PicCap, receiver calibration and raw calibration samples are unchanged. diff --git a/VERSION b/VERSION index 54d1a4f..c317a91 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.13.0 +0.13.1 diff --git a/app/appinfo.json b/app/appinfo.json index 6cae3d6..4a5826a 100644 --- a/app/appinfo.json +++ b/app/appinfo.json @@ -1,6 +1,6 @@ { "id": "org.webosbrew.histogramhyperion", - "version": "0.13.0", + "version": "0.13.1", "vendor": "Local development", "type": "web", "main": "index.html", diff --git a/app/version.js b/app/version.js index c99d394..ffa86a7 100644 --- a/app/version.js +++ b/app/version.js @@ -1,2 +1,2 @@ 'use strict'; -var HYPERDRM_APP_VERSION = '0.13.0'; +var HYPERDRM_APP_VERSION = '0.13.1'; diff --git a/docs/release-0.13.1.md b/docs/release-0.13.1.md new file mode 100644 index 0000000..b28dc68 --- /dev/null +++ b/docs/release-0.13.1.md @@ -0,0 +1,5 @@ +# HyperDRM 0.13.1 + +Suppress near-black histogram residuals that can appear green on SK6812 LEDs. Colors whose maximum channel is at most 12 become black; values between 12 and 24 fade in proportionally; brighter colors retain their original values. Raw histogram diagnostics and calibration samples remain available unchanged. PicCap frames are not filtered. + +Validation: regression tests cover black, the measured green residual, transition values and unchanged brighter colors. The release workflow runs the existing native and UI suites and verifies the packaged version and checksum. diff --git a/native/capture_loop.h b/native/capture_loop.h index 5aeedb4..9c71b4a 100644 --- a/native/capture_loop.h +++ b/native/capture_loop.h @@ -153,11 +153,14 @@ static int tick(void *unused) { } for (int c = 0; c < 3; c++) capture_ctx.sent_rgb[c] = (unsigned char)(aggregate[c] / 16); + dark_color_filter(capture_ctx.sent_rgb); unsigned char boosted_mean[3]; boost_color(capture_ctx.sent_rgb, boosted_mean); memcpy(capture_ctx.sent_rgb, boosted_mean, 3); unsigned char mapped_rgb[16][3], stable_rgb[16][3]; calibration_colors(capture_ctx.rgb, mapped_rgb); + for (unsigned i = 0; i < 16; i++) + dark_color_filter(mapped_rgb[i]); continuity_frame(&capture_ctx.continuity, true, mapped_rgb, now, stable_rgb); receiver_layout.interpolation = receiver_layout.count && calibration_effective() != CAL_AVERAGE; char *line = region_command(stable_rgb, receiver_layout.blends, receiver_layout.count, 1500); diff --git a/native/dark_color.h b/native/dark_color.h new file mode 100644 index 0000000..c2cb6e7 --- /dev/null +++ b/native/dark_color.h @@ -0,0 +1,16 @@ +#ifndef HYPERDRM_DARK_COLOR_H +#define HYPERDRM_DARK_COLOR_H +/* Suppress near-black histogram residuals without changing channel ratios. + * Apply only to fresh histogram colors, before continuity and interpolation. */ +static inline void dark_color_filter(unsigned char color[3]) { + unsigned peak = color[0]; + for (unsigned c = 1; c < 3; c++) + if (color[c] > peak) + peak = color[c]; + if (peak >= 24) + return; + unsigned gain = peak > 12 ? peak - 12 : 0; + for (unsigned c = 0; c < 3; c++) + color[c] = (unsigned char)((color[c] * gain + 6) / 12); +} +#endif diff --git a/native/service.c b/native/service.c index 0a66df9..dbfc50b 100644 --- a/native/service.c +++ b/native/service.c @@ -199,6 +199,7 @@ static bool respond(void *h, void *m, const char *s) { #include "receiver_stream.h" #include "source_bridge.h" #include "service_api.h" +#include "dark_color.h" #include "capture_loop.h" static void *symbol(void *lib, const char *name) { void *s = dlsym(lib, name); diff --git a/native/test_dark_color.c b/native/test_dark_color.c new file mode 100644 index 0000000..b94ff31 --- /dev/null +++ b/native/test_dark_color.c @@ -0,0 +1,21 @@ +#include +#include +#include "dark_color.h" +int main(void) { + for (unsigned v = 0; v <= 255; v++) { + unsigned char gray[3] = {v, v, v}; + dark_color_filter(gray); + unsigned expected = v <= 12 ? 0 : v >= 24 ? v : (v * (v - 12) + 6) / 12; + for (unsigned c = 0; c < 3; c++) assert(gray[c] == expected); + } + unsigned char residual[3] = {4, 8, 2}; + dark_color_filter(residual); + assert(!residual[0] && !residual[1] && !residual[2]); + unsigned char transition[3] = {9, 18, 6}; + dark_color_filter(transition); + assert(transition[0] == 5 && transition[1] == 9 && transition[2] == 3); + unsigned char saturated[3] = {0, 24, 0}; + dark_color_filter(saturated); + assert(saturated[0] == 0 && saturated[1] == 24 && saturated[2] == 0); + puts("PASS: near-black suppression, gradual transition, unchanged brighter colors"); +} diff --git a/native/version.h b/native/version.h index 880184d..52bdd06 100644 --- a/native/version.h +++ b/native/version.h @@ -1,4 +1,4 @@ #ifndef HYPERDRM_VERSION_H #define HYPERDRM_VERSION_H -#define HYPERDRM_VERSION "0.13.0" +#define HYPERDRM_VERSION "0.13.1" #endif diff --git a/package/packageinfo.json b/package/packageinfo.json index 74ef435..16a6b20 100644 --- a/package/packageinfo.json +++ b/package/packageinfo.json @@ -1,6 +1,6 @@ { "id": "org.webosbrew.histogramhyperion", - "version": "0.13.0", + "version": "0.13.1", "vendor": "Local development", "app": "org.webosbrew.histogramhyperion", "services": [ diff --git a/service/histogram-service b/service/histogram-service index 4f5ad3d..58a1526 100644 Binary files a/service/histogram-service and b/service/histogram-service differ