SXXXXXXX_ControlPanel/VideoReceiverSFP/core/payload_dispatcher.py

210 lines
11 KiB
Python

"""Dispatch logic for decoded frames (MFD/SAR/generic).
Provides `dispatch_frame(module, frame, leader)` which encapsulates
recording, saving previews, and invoking registered callbacks.
"""
from typing import Any, Optional
import logging
import os
import time
import pathlib
try:
from PIL import Image, ImageOps, ImageEnhance
except Exception:
Image = None
ImageOps = None
ImageEnhance = None
def dispatch_frame(module: Any, frame: Any, leader: Optional[Any]) -> None:
"""Handle a decoded frame: start/ write video, save previews, and call callbacks.
`module` is the `SfpConnectorModule` instance.
"""
try:
# Determine image type
image_type_id = None
try:
if leader is not None:
image_type_id = int(leader.HEADER_DATA.TYPE)
except Exception:
image_type_id = None
# SAR path
if image_type_id == getattr(module, 'IMAGE_TYPE_SAR', 2):
try:
if Image is not None and hasattr(frame, 'copy'):
sar_img = frame.copy()
if getattr(module, '_sar_autocontrast', False) and ImageOps is not None:
try:
sar_img = ImageOps.autocontrast(sar_img)
except Exception:
pass
try:
bf = max(0.0, 1.0 + (float(getattr(module, '_sar_brightness', 0)) / 100.0))
cf = max(0.0, 1.0 + (float(getattr(module, '_sar_contrast', 0)) / 100.0))
if bf != 1.0 and ImageEnhance is not None:
sar_img = ImageEnhance.Brightness(sar_img).enhance(bf)
if cf != 1.0 and ImageEnhance is not None:
sar_img = ImageEnhance.Contrast(sar_img).enhance(cf)
except Exception:
pass
# save sar png
if getattr(module, '_sar_save_png', False):
try:
if getattr(module, '_dump_manager', None) is not None:
saved = module._dump_manager.save_preview_from_pil(sar_img, category='sar', fmt='png')
if saved:
logging.getLogger().info("VideoReceiverSFP: saved sar png %s", saved)
else:
ts = time.strftime('%Y%m%d_%H%M%S') + (f"_{int(time.time() * 1000) % 1000:03d}")
dumps_dir = getattr(module, '_dumps_dir', os.path.join(os.getcwd(), 'dumps'))
os.makedirs(dumps_dir, exist_ok=True)
pngpath = os.path.join(dumps_dir, f'VideoReceiverSFP_sar_{ts}.png')
sar_img.save(pngpath)
module._saved_sar_pngs.append(pngpath)
while len(module._saved_sar_pngs) > module._dump_keep:
old = module._saved_sar_pngs.popleft()
try:
pathlib.Path(old).unlink()
except Exception:
pass
except Exception:
logging.getLogger().exception("VideoReceiverSFP: failed saving sar png frame")
# sar video
try:
if getattr(module, '_record_sar_video', False) and getattr(module, '_dump_manager', None) is not None:
if not getattr(module, '_sar_video_active', False):
try:
w, h = None, None
if Image is not None and hasattr(sar_img, 'size'):
w, h = sar_img.size
else:
try:
import numpy as _np
arr = _np.asarray(sar_img)
if arr is not None and arr.ndim >= 2:
h, w = arr.shape[0], arr.shape[1]
except Exception:
pass
if w and h:
sar_fps = getattr(module, '_sar_video_fps', getattr(module, '_video_fps', 20))
started = module._dump_manager.start_video_record('sar', w, h, fps=sar_fps)
if started:
module._sar_video_active = True
try:
logging.getLogger().info("VideoReceiverSFP: started SAR video writer (%dx%d @ %s FPS)", w, h, sar_fps)
except Exception:
pass
except Exception:
logging.getLogger().exception("VideoReceiverSFP: failed to start sar video writer")
if getattr(module, '_sar_video_active', False):
try:
module._dump_manager.write_video_frame(sar_img, 'sar')
except Exception:
logging.getLogger().exception("VideoReceiverSFP: failed writing sar frame to video")
except Exception:
pass
# deliver to callbacks
for scb in list(getattr(module, '_sar_callbacks', [])):
try:
scb(sar_img)
except Exception:
pass
except Exception:
logging.getLogger().exception("VideoReceiverSFP: error processing SAR image for SAR callbacks")
# MFD path
if image_type_id == getattr(module, 'IMAGE_TYPE_MFD', 1):
try:
try:
if getattr(module, '_record_mfd_video', False) and getattr(module, '_dump_manager', None) is not None:
if not getattr(module, '_mfd_video_active', False):
try:
w, h = None, None
if Image is not None and hasattr(frame, 'size'):
w, h = frame.size
else:
try:
import numpy as _np
arr = _np.asarray(frame)
if arr is not None and arr.ndim >= 2:
h, w = arr.shape[0], arr.shape[1]
except Exception:
pass
if w and h:
started = module._dump_manager.start_video_record('mfd', w, h, fps=getattr(module, '_video_fps', 20))
if started:
module._mfd_video_active = True
try:
logging.getLogger().info("VideoReceiverSFP: started MFD video writer (%dx%d @ %s FPS)", w, h, getattr(module, '_video_fps', 20))
except Exception:
pass
except Exception:
logging.getLogger().exception('VideoReceiverSFP: failed to start mfd video writer')
if getattr(module, '_mfd_video_active', False):
try:
module._dump_manager.write_video_frame(frame, 'mfd')
except Exception:
logging.getLogger().exception('VideoReceiverSFP: failed writing mfd frame to video')
try:
if not getattr(module, '_mfd_callbacks', False):
logging.getLogger().debug('VideoReceiverSFP: mfd frames are being recorded but no MFD callbacks are registered')
except Exception:
pass
except Exception:
pass
for mcb in list(getattr(module, '_mfd_callbacks', [])):
try:
mcb(frame)
except Exception:
pass
except Exception:
pass
# generic callbacks and saving
try:
is_mfd = (image_type_id == getattr(module, 'IMAGE_TYPE_MFD', 1))
except Exception:
is_mfd = False
for cb in list(getattr(module, '_callbacks', [])):
try:
# Only the MFD generic save is controlled by _save_png. SAR has its
# own _sar_save_png flag handled earlier. Save MFD previews under
# the 'mfd' category so get_last_saved_mfd() can find them.
if is_mfd and getattr(module, '_save_png', False) and Image is not None and hasattr(frame, 'save'):
try:
if getattr(module, '_dump_manager', None) is not None:
saved = module._dump_manager.save_preview_from_pil(frame, category='mfd', fmt='png')
if saved:
logging.getLogger().info("VideoReceiverSFP: saved MFD preview to %s", saved)
else:
ts = time.strftime('%Y%m%d_%H%M%S') + (f"_{int(time.time() * 1000) % 1000:03d}")
dumps_dir = getattr(module, '_dumps_dir', os.path.join(os.getcwd(), 'dumps'))
os.makedirs(dumps_dir, exist_ok=True)
pngpath = os.path.join(dumps_dir, f'VideoReceiverSFP_mfd_{ts}.png')
frame.save(pngpath)
module._saved_pngs.append(pngpath)
while len(module._saved_pngs) > module._dump_keep:
old = module._saved_pngs.popleft()
try:
pathlib.Path(old).unlink()
except Exception:
pass
except Exception:
logging.getLogger().exception('VideoReceiverSFP: failed to save MFD preview png')
try:
cb(frame)
except Exception:
pass
except Exception:
pass
except Exception:
logging.getLogger().exception('VideoReceiverSFP: dispatch_frame unexpected error')