3 Commits
Author SHA1 Message Date
matze19999 ef03258e22 Release 0.13.3 2026-10-12 18:23:52 +02:00
matze19999 2f6efd9864 Release 0.13.2 2026-10-12 18:19:11 +02:00
matze19999 c3040680a0 Release 0.13.1 2026-10-12 18:11:51 +02:00
18 changed files with 112 additions and 13 deletions

No files matched your search

+4 -4
View File
@@ -1,15 +1,15 @@
{ {
"id": "org.webosbrew.histogramhyperion", "id": "org.webosbrew.histogramhyperion",
"version": "0.13.0", "version": "0.13.3",
"type": "web", "type": "web",
"title": "HyperDRM", "title": "HyperDRM",
"appDescription": "Ambient lighting for webOS, Hyperion and HyperHDR", "appDescription": "Ambient lighting for webOS, Hyperion and HyperHDR",
"iconUri": "https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/app/icon.png", "iconUri": "https://gitea.adnau.de/matze19999/HyperDRM/raw/branch/main/app/icon.png",
"sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM", "sourceUrl": "https://gitea.adnau.de/matze19999/HyperDRM",
"rootRequired": true, "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.3_arm.ipk",
"ipkHash": { "ipkHash": {
"sha256": "a7ab184db8c948ceb4657f093c2cf10c13df3565ff9ed4d8482dcf2d59896a0a" "sha256": "acb0978100796e8765e586a91183599ef4eb783631d8b68205d716621790e232"
}, },
"ipkSize": 1207634 "ipkSize": 1208120
} }
Binary file not shown.
+5 -1
View File
@@ -27,7 +27,7 @@ Only the own service is modified. Optional Auto PicCap can configure its receive
## Installation ## 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.3_arm.ipk](HyperDRM_0.13.3_arm.ipk). Install it using the TV's webOS/Homebrew package installation workflow.
Elevate the installed own service through Homebrew Channel: Elevate the installed own service through Homebrew Channel:
@@ -233,3 +233,7 @@ and briefly interrupts ambient lighting; it never runs automatically.
`python release.py --sanitizers` additionally checks protocol, atomic-file, `python release.py --sanitizers` additionally checks protocol, atomic-file,
receiver-output and simulated service-lifecycle tests with ASan/UBSan. These host 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. 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 16 or less, gradually restores brightness between 16 and 32, and preserves brighter colors. This applies only to histogram output; PicCap, receiver calibration and raw calibration samples are unchanged.
Thin letterbox detection compares both edges against lit interior histogram samples and requires a consistently dark upper edge for at least two seconds. Histogram probes cannot determine the exact bar height or guarantee detection on every scene.
+1 -1
View File
@@ -1 +1 @@
0.13.0 0.13.3
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"id": "org.webosbrew.histogramhyperion", "id": "org.webosbrew.histogramhyperion",
"version": "0.13.0", "version": "0.13.3",
"vendor": "Local development", "vendor": "Local development",
"type": "web", "type": "web",
"main": "index.html", "main": "index.html",
+1 -1
View File
@@ -1,2 +1,2 @@
'use strict'; 'use strict';
var HYPERDRM_APP_VERSION = '0.13.0'; var HYPERDRM_APP_VERSION = '0.13.3';
+5
View File
@@ -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.
+3
View File
@@ -0,0 +1,3 @@
# HyperDRM 0.13.2
Raise the histogram black cutoff to 16 and extend the proportional transition to 32. Live measurements showed raw [13,14,7] causing residual [1,1,0] to [2,2,1] at the bottom-right LEDs with the previous cutoff. Regression coverage now includes this sample. Brighter colors, PicCap and saved settings remain unchanged; very dark detail is suppressed more strongly.
+3
View File
@@ -0,0 +1,3 @@
# HyperDRM 0.13.3
Detect thinner horizontal black bars using edge-versus-interior contrast, distributed upper-edge support and lower-edge support. Preserve the existing dark-scene rejection, wide-bar rule and two-second stability gate. Regression tests include live G4 measurements, one-sided and isolated dark edges, dim frames and insufficient contrast. This is a histogram heuristic; it does not measure exact bar heights.
+25 -2
View File
@@ -4,14 +4,17 @@
* or dark frame so darkness alone cannot switch the active capture mode. */ * or dark frame so darkness alone cannot switch the active capture mode. */
static inline int letterbox_candidate(const unsigned black[16], const unsigned char color[16][3]) { static inline int letterbox_candidate(const unsigned black[16], const unsigned char color[16][3]) {
const unsigned interior[] = {2, 6, 10, 15}; const unsigned interior[] = {2, 6, 10, 15};
unsigned lit = 0; unsigned lit = 0, interior_black = 0, interior_peak = 0;
for (unsigned i = 0; i < 4; i++) { for (unsigned i = 0; i < 4; i++) {
unsigned r = interior[i], peak = color[r][0]; unsigned r = interior[i], peak = color[r][0];
for (unsigned c = 1; c < 3; c++) for (unsigned c = 1; c < 3; c++)
if (color[r][c] > peak) if (color[r][c] > peak)
peak = color[r][c]; peak = color[r][c];
if (black[r] < 20 && peak > 35) if (black[r] < 20 && peak > 35) {
lit++; lit++;
interior_black += black[r];
interior_peak += peak;
}
} }
if (lit < 2) if (lit < 2)
return -1; return -1;
@@ -19,6 +22,26 @@ static inline int letterbox_candidate(const unsigned black[16], const unsigned c
unsigned bottom = (black[1] + black[5] + black[9]) / 3; unsigned bottom = (black[1] + black[5] + black[9]) / 3;
if (top >= 55 && bottom >= 25) if (top >= 55 && bottom >= 25)
return 1; return 1;
/* Thin bars occupy only part of an edge probe. Require a broad upper
* dark edge, lower-edge support and contrast against lit interior probes.
* This remains a histogram heuristic, not a pixel-accurate crop. */
const unsigned top_regions[] = {3, 11, 12};
const unsigned bottom_regions[] = {1, 5, 9};
unsigned top_support = 0, bottom_support = 0, top_peak = 0;
for (unsigned i = 0; i < 3; i++) {
unsigned r = top_regions[i], peak = color[r][0];
for (unsigned c = 1; c < 3; c++)
if (color[r][c] > peak)
peak = color[r][c];
top_peak += peak;
top_support += black[r] >= 12;
bottom_support += black[bottom_regions[i]] >= 8;
}
unsigned baseline = interior_black / lit;
if (top_support == 3 && bottom_support >= 2 && top >= 12 && bottom >= 10 &&
top >= baseline + 8 && bottom >= baseline + 8 &&
(unsigned long)top_peak * lit * 100 <= (unsigned long)interior_peak * 3 * 60)
return 1;
if (top < 20 && bottom < 20) if (top < 20 && bottom < 20)
return 0; return 0;
return -1; return -1;
+3
View File
@@ -153,11 +153,14 @@ static int tick(void *unused) {
} }
for (int c = 0; c < 3; c++) for (int c = 0; c < 3; c++)
capture_ctx.sent_rgb[c] = (unsigned char)(aggregate[c] / 16); capture_ctx.sent_rgb[c] = (unsigned char)(aggregate[c] / 16);
dark_color_filter(capture_ctx.sent_rgb);
unsigned char boosted_mean[3]; unsigned char boosted_mean[3];
boost_color(capture_ctx.sent_rgb, boosted_mean); boost_color(capture_ctx.sent_rgb, boosted_mean);
memcpy(capture_ctx.sent_rgb, boosted_mean, 3); memcpy(capture_ctx.sent_rgb, boosted_mean, 3);
unsigned char mapped_rgb[16][3], stable_rgb[16][3]; unsigned char mapped_rgb[16][3], stable_rgb[16][3];
calibration_colors(capture_ctx.rgb, mapped_rgb); 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); continuity_frame(&capture_ctx.continuity, true, mapped_rgb, now, stable_rgb);
receiver_layout.interpolation = receiver_layout.count && calibration_effective() != CAL_AVERAGE; receiver_layout.interpolation = receiver_layout.count && calibration_effective() != CAL_AVERAGE;
char *line = region_command(stable_rgb, receiver_layout.blends, receiver_layout.count, 1500); char *line = region_command(stable_rgb, receiver_layout.blends, receiver_layout.count, 1500);
+16
View File
@@ -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 >= 32)
return;
unsigned gain = peak > 16 ? peak - 16 : 0;
for (unsigned c = 0; c < 3; c++)
color[c] = (unsigned char)((color[c] * gain + 8) / 16);
}
#endif
+1
View File
@@ -199,6 +199,7 @@ static bool respond(void *h, void *m, const char *s) {
#include "receiver_stream.h" #include "receiver_stream.h"
#include "source_bridge.h" #include "source_bridge.h"
#include "service_api.h" #include "service_api.h"
#include "dark_color.h"
#include "capture_loop.h" #include "capture_loop.h"
static void *symbol(void *lib, const char *name) { static void *symbol(void *lib, const char *name) {
void *s = dlsym(lib, name); void *s = dlsym(lib, name);
+18 -1
View File
@@ -11,5 +11,22 @@ int main(void){
for(unsigned i=0;i<16;i++)black[i]=100; for(unsigned i=0;i<16;i++)black[i]=100;
memset(color,0,sizeof(color));assert(letterbox_candidate(black,color)==-1); memset(color,0,sizeof(color));assert(letterbox_candidate(black,color)==-1);
memset(black,0,sizeof(black));assert(letterbox_candidate(black,color)==-1); memset(black,0,sizeof(black));assert(letterbox_candidate(black,color)==-1);
puts("PASS: full frame, measured letterbox, one edge only, black frame, dark frame"); unsigned thin_black[16]={12,23,1,21,9,6,6,16,18,12,26,23,23,22,37,8};
unsigned char thin_color[16][3]={{57,52,48},{97,94,92},{51,42,35},{25,24,21},
{71,65,60},{128,122,118},{84,74,67},{34,32,27},{47,41,36},{59,47,43},
{37,29,25},{19,18,15},{22,20,16},{22,19,15},{14,13,11},{78,75,72}};
assert(letterbox_candidate(thin_black,thin_color)==1);
thin_black[1]=thin_black[5]=thin_black[9]=0;
assert(letterbox_candidate(thin_black,thin_color)!=1);
thin_black[1]=23;thin_black[5]=6;thin_black[9]=12;
thin_black[11]=0;
assert(letterbox_candidate(thin_black,thin_color)!=1);
thin_black[11]=23;
memset(thin_color,10,sizeof(thin_color));
assert(letterbox_candidate(thin_black,thin_color)==-1);
memset(thin_color,100,sizeof(thin_color));
assert(letterbox_candidate(thin_black,thin_color)!=1);
memset(thin_black,15,sizeof(thin_black));
assert(letterbox_candidate(thin_black,thin_color)!=1);
puts("PASS: measured wide/thin bars, full frame, one-sided/isolated edges, dark frame and low contrast");
} }
+24
View File
@@ -0,0 +1,24 @@
#include <assert.h>
#include <stdio.h>
#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 <= 16 ? 0 : v >= 32 ? v : (v * (v - 16) + 8) / 16;
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 measured[3] = {13, 14, 7};
dark_color_filter(measured);
assert(!measured[0] && !measured[1] && !measured[2]);
unsigned char transition[3] = {12, 24, 8};
dark_color_filter(transition);
assert(transition[0] == 6 && transition[1] == 12 && transition[2] == 4);
unsigned char saturated[3] = {0, 32, 0};
dark_color_filter(saturated);
assert(saturated[0] == 0 && saturated[1] == 32 && saturated[2] == 0);
puts("PASS: near-black suppression, gradual transition, unchanged brighter colors");
}
+1 -1
View File
@@ -1,4 +1,4 @@
#ifndef HYPERDRM_VERSION_H #ifndef HYPERDRM_VERSION_H
#define HYPERDRM_VERSION_H #define HYPERDRM_VERSION_H
#define HYPERDRM_VERSION "0.13.0" #define HYPERDRM_VERSION "0.13.3"
#endif #endif
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"id": "org.webosbrew.histogramhyperion", "id": "org.webosbrew.histogramhyperion",
"version": "0.13.0", "version": "0.13.3",
"vendor": "Local development", "vendor": "Local development",
"app": "org.webosbrew.histogramhyperion", "app": "org.webosbrew.histogramhyperion",
"services": [ "services": [
Binary file not shown.