根据新版本调整set_pattern:0~65535
This commit is contained in:
111
app/ucd/pg_status.py
Normal file
111
app/ucd/pg_status.py
Normal file
@@ -0,0 +1,111 @@
|
||||
"""从 UniTAP Pattern Generator 读取状态并格式化为日志行。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
import UniTAP
|
||||
from UniTAP.common import ColorInfo
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _enum_display_name(name: str) -> str:
|
||||
spaced = re.sub(r"([a-z])([A-Z])", r"\1 \2", name)
|
||||
return spaced.replace("_", " ")
|
||||
|
||||
|
||||
def _format_pattern_name(pg, pattern_hint: str | None = None) -> str:
|
||||
if pattern_hint:
|
||||
return pattern_hint
|
||||
|
||||
pattern = getattr(pg, "_pattern", None)
|
||||
if isinstance(pattern, UniTAP.VideoPattern):
|
||||
return _enum_display_name(pattern.name)
|
||||
if isinstance(pattern, str):
|
||||
return os.path.basename(pattern) or "Image File"
|
||||
|
||||
pattern_id = getattr(pg, "_pattern_id", None)
|
||||
if pattern_id is not None:
|
||||
return _enum_display_name(getattr(pattern_id, "name", str(pattern_id)))
|
||||
return "—"
|
||||
|
||||
|
||||
def _format_cef(ci: ColorInfo) -> str:
|
||||
fmt_map = {
|
||||
ColorInfo.ColorFormat.CF_RGB: "RGB",
|
||||
ColorInfo.ColorFormat.CF_YCbCr_422: "YCbCr 4:2:2",
|
||||
ColorInfo.ColorFormat.CF_YCbCr_444: "YCbCr 4:4:4",
|
||||
ColorInfo.ColorFormat.CF_YCbCr_420: "YCbCr 4:2:0",
|
||||
ColorInfo.ColorFormat.CF_Y_ONLY: "Y only",
|
||||
ColorInfo.ColorFormat.CF_RAW: "RAW",
|
||||
ColorInfo.ColorFormat.CF_DSC: "DSC",
|
||||
}
|
||||
fmt = fmt_map.get(
|
||||
ci.color_format,
|
||||
ci.color_format.name.replace("CF_", "").replace("_", " "),
|
||||
)
|
||||
|
||||
if ci.color_format == ColorInfo.ColorFormat.CF_RGB:
|
||||
range_str = (
|
||||
"Legacy RGB mode"
|
||||
if ci.dynamic_range == ColorInfo.DynamicRange.DR_VESA
|
||||
else "Limited range"
|
||||
)
|
||||
elif ci.dynamic_range == ColorInfo.DynamicRange.DR_VESA:
|
||||
range_str = "Full range"
|
||||
else:
|
||||
range_str = "Limited range"
|
||||
return f"{fmt}/{range_str}"
|
||||
|
||||
|
||||
def _max_bitrate_gbps(pg, bpp: int) -> float:
|
||||
caps = pg._caps()
|
||||
effective_bpp = bpp if bpp > 0 else 24
|
||||
return round(caps.max_pix_rate * effective_bpp / 1_000_000_000.0, 3)
|
||||
|
||||
|
||||
def collect_pattern_generator_status(
|
||||
pg,
|
||||
*,
|
||||
pattern_hint: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
vm = pg.get_stream_video_mode()
|
||||
pg_status = pg.status()
|
||||
ci = vm.color_info
|
||||
|
||||
refresh_hz = vm.timing.frame_rate / 1000.0 if vm.timing.frame_rate else 0.0
|
||||
timing = f"{vm.timing.hactive} x {vm.timing.vactive} @ {refresh_hz:g}Hz"
|
||||
current_br = vm.bit_rate
|
||||
max_br = _max_bitrate_gbps(pg, ci.bpp)
|
||||
|
||||
return {
|
||||
"total_bitrate": f"{current_br:.3f} / {max_br:.3f} Gbps",
|
||||
"timing": timing,
|
||||
"pattern": _format_pattern_name(pg, pattern_hint),
|
||||
"cef": _format_cef(ci),
|
||||
"bpc": str(ci.bpc),
|
||||
"status": str(pg_status.error),
|
||||
}
|
||||
|
||||
|
||||
def format_pattern_generator_status_log(status: dict[str, Any]) -> list[str]:
|
||||
return [
|
||||
f"Total bitrate: {status['total_bitrate']}",
|
||||
f" Timing: {status['timing']}",
|
||||
f" Pattern: {status['pattern']}",
|
||||
f" CEF: {status['cef']}",
|
||||
f" BPC: {status['bpc']}",
|
||||
f" Status: {status['status']}",
|
||||
]
|
||||
|
||||
|
||||
def read_pattern_generator_status_lines(
|
||||
pg,
|
||||
*,
|
||||
pattern_hint: str | None = None,
|
||||
) -> list[str]:
|
||||
status = collect_pattern_generator_status(pg, pattern_hint=pattern_hint)
|
||||
return format_pattern_generator_status_log(status)
|
||||
Reference in New Issue
Block a user