fix: KC color strip test preview — use LiveStreamManager instead of raw engine
Lint & Test / test (push) Successful in 1m28s

BetterCam (DXGI) only supports one capture session per display, so creating
a second engine for the KC test produced no frames when a target was already
running. Now uses LiveStreamManager.acquire() which ref-counts and reuses
the running capture.

Also removed double postprocessing — ProcessedLiveStream already applies
filters, so re-applying them in the KC test halved the resolution (960x400
→ 240x100).
This commit is contained in:
2026-03-29 14:11:01 +03:00
parent 78ce6c84d7
commit a9e6e8cb82
@@ -485,7 +485,6 @@ async def test_key_colors_ws(
calculate_dominant_color,
calculate_median_color,
)
from wled_controller.core.filters import FilterRegistry, ImagePool
from wled_controller.storage.picture_source import ScreenCapturePictureSource
from wled_controller.utils.image_codec import encode_jpeg_data_uri, resize_down
@@ -497,7 +496,6 @@ async def test_key_colors_ws(
source_store = get_picture_source_store()
manager = get_processor_manager()
device_store = get_device_store()
pp_store = get_pp_template_store()
try:
source = store.get_source(source_id)
@@ -546,11 +544,19 @@ async def test_key_colors_ws(
await websocket.accept()
logger.info(f"KC CSS test WS connected for {source_id} (fps={fps})")
# Use LiveStreamManager — reuses the already-running capture engine when a
# target is active. BetterCam (DXGI) only supports one session per display,
# so creating a second engine would produce no frames.
live_stream_mgr = manager._live_stream_manager
live_stream = None
try:
live_stream = await asyncio.to_thread(live_stream_mgr.acquire, source.picture_source_id)
except Exception as e:
logger.error(f"KC test: LiveStream acquire failed: {e}")
await websocket.send_text(ws_json.dumps({"type": "error", "detail": str(e)}))
await websocket.close(code=4003, reason=str(e))
return
try:
prev_frame_ref = None
while True:
@@ -564,26 +570,14 @@ async def test_key_colors_ws(
await asyncio.sleep(frame_interval * 0.5)
continue
prev_frame_ref = capture
cur_image = capture.image
if not isinstance(cur_image, np.ndarray):
await asyncio.sleep(frame_interval)
continue
# Apply postprocessing
pp_ids = chain.get("postprocessing_template_ids", [])
if pp_ids and pp_store:
pool = ImagePool()
for pp_id in pp_ids:
try:
pp = pp_store.get_template(pp_id)
for fi in pp_store.resolve_filter_instances(pp.filters):
f = FilterRegistry.create_instance(fi.filter_id, fi.options)
result = f.process_image(cur_image, pool)
if result is not None:
cur_image = result
except Exception:
pass
# NOTE: postprocessing is already applied by the ProcessedLiveStream
# when using LiveStreamManager.acquire() — do NOT re-apply here.
# Re-read source for hot-update support
try:
@@ -647,11 +641,10 @@ async def test_key_colors_ws(
except Exception as e:
logger.error(f"KC CSS test WS error: {e}", exc_info=True)
finally:
if live_stream is not None:
try:
await asyncio.to_thread(live_stream_mgr.release, source.picture_source_id)
except Exception:
pass
try:
await asyncio.to_thread(live_stream_mgr.release, source.picture_source_id)
except Exception:
pass
# ===== CALIBRATION TEST =====