1.1.0版本
This commit is contained in:
3
UniTAP/dev/ports/modules/vtg/__init__.py
Normal file
3
UniTAP/dev/ports/modules/vtg/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .pg import PGPatternParams, SolidColorParams, WhiteVStripsParams, GradientStripsParams, MotionParams, \
|
||||
SquareWindowParams, StepsScrollingParams, ASParams, ConstantASParams, SquareASParams, ZigzagASParams, FixedASParams, \
|
||||
VideoPattern, PGStatus
|
||||
898
UniTAP/dev/ports/modules/vtg/pg.py
Normal file
898
UniTAP/dev/ports/modules/vtg/pg.py
Normal file
@@ -0,0 +1,898 @@
|
||||
import copy
|
||||
import os.path
|
||||
from typing import Union, List, Optional
|
||||
|
||||
from PIL import Image
|
||||
from UniTAP.utils import function_scheduler
|
||||
from UniTAP.libs.lib_tsi.tsi import *
|
||||
from UniTAP.libs.lib_tsi.tsi_io import PortIO
|
||||
from UniTAP.dev.modules import MemoryManager
|
||||
from UniTAP.dev.ports.modules.internal_utils.math import aligned
|
||||
from UniTAP.common import VideoMode, Timing, ColorInfo, VideoFrame, VideoFrameDSC
|
||||
from UniTAP.dev.ports.modules.internal_utils import uicl_image_from_vm_and_data, uicl_image_convert_to_vm
|
||||
from .types import VideoPattern, PGVideoMode, PGAdaptiveSyncPatternType, PGColorimetry, \
|
||||
PGColorInfo, PGColorDepth, PGStandard, PGDynamicRange, PGAspectRatio, ConstantASParams, SquareASParams, \
|
||||
ZigzagASParams, FixedASParams, ASParams
|
||||
from .private_types import get_as_params_value, PgCaps, CustomTimingFlags, PGPatternID, get_pattern_params_value, \
|
||||
PGPatternType
|
||||
from .pg_utils import pg_timingflags_from_vm, pg_pixel_format_from_vm, pg_colorformat_to_ci_colorformat, \
|
||||
pg_dynamicrange_to_ci_dynamicrange, pg_colorimetry_to_ci_colorimetry, pg_bpc_to_ci_bpc
|
||||
from .timing_manager import TimingManager
|
||||
from .pg_pattern_params import *
|
||||
from ..panel_replay import *
|
||||
|
||||
# Override MAX_IMAGE_PIXELS
|
||||
Image.MAX_IMAGE_PIXELS = None
|
||||
|
||||
|
||||
def _read_predefined_timings(io: PortIO) -> List[Timing]:
|
||||
count = io.get(TSI_R_PG_PREDEF_TIMING_COUNT)[1]
|
||||
|
||||
predefined_list = []
|
||||
|
||||
for i in range(count):
|
||||
io.set(TSI_W_PG_PREDEF_TIMING_SELECT, i)
|
||||
|
||||
timing = Timing()
|
||||
timing.htotal = io.get(TSI_PG_CUSTOM_TIMING_HTOTAL)[1]
|
||||
timing.vtotal = io.get(TSI_PG_CUSTOM_TIMING_VTOTAL)[1]
|
||||
timing.hactive = io.get(TSI_PG_CUSTOM_TIMING_HACTIVE)[1]
|
||||
timing.vactive = io.get(TSI_PG_CUSTOM_TIMING_VACTIVE)[1]
|
||||
timing.hstart = io.get(TSI_PG_CUSTOM_TIMING_HSTART)[1]
|
||||
timing.vstart = io.get(TSI_PG_CUSTOM_TIMING_VSTART)[1]
|
||||
timing.hswidth = io.get(TSI_PG_CUSTOM_TIMING_HSYNCW)[1]
|
||||
timing.vswidth = io.get(TSI_PG_CUSTOM_TIMING_VSYNCW)[1]
|
||||
timing.id = io.get(TSI_PG_CUSTOM_TIMING_ID)[1]
|
||||
# TODO: add conversion from pg AR to Timing AR
|
||||
timing.aspect_ratio = io.get(TSI_PG_CUSTOM_TIMING_ASPECT_RATIO)[1]
|
||||
timing.frame_rate = io.get(TSI_PG_CUSTOM_TIMING_FIELD_RATE)[1]
|
||||
timing.standard = Timing.Standard(io.get(TSI_PG_CUSTOM_TIMING_STANDARD)[1])
|
||||
|
||||
timing_flags = io.get(TSI_PG_CUSTOM_TIMING_FLAGS)[1]
|
||||
timing.hswidth *= (-1 if timing_flags >> 9 & 1 else 1)
|
||||
timing.vswidth *= (-1 if timing_flags >> 10 & 1 else 1)
|
||||
timing.reduce_blanking = Timing.ReduceBlanking((timing_flags >> 24) & 0x3)
|
||||
|
||||
predefined_list.append(timing)
|
||||
|
||||
return predefined_list
|
||||
|
||||
|
||||
class PGStatus:
|
||||
"""
|
||||
|
||||
Class `PGStatus` describes possible states of `PatternGenerator`.
|
||||
|
||||
"""
|
||||
|
||||
class PGError(IntEnum):
|
||||
"""
|
||||
|
||||
Class `PGError` contains codes of errors with the possibility of string representation.
|
||||
|
||||
"""
|
||||
NotReady = -1
|
||||
OK = 0
|
||||
HWFault = 1
|
||||
PixelClock = 2
|
||||
MemoryError = 3
|
||||
DscFileZero = 4
|
||||
DscPixelClockExceeds = 5
|
||||
DscSourceNotSupport = 6
|
||||
DscSinkNotSupport = 7
|
||||
DscFailReadDpcd = 8
|
||||
DscFailWriteDpcd = 9
|
||||
WrongColorFormat = 10
|
||||
WrongColorimetry = 11
|
||||
WrongBitsPerComponent = 12
|
||||
WrongDynamicRange = 13
|
||||
NotEnoughMemoryForPattern = 14
|
||||
|
||||
def __str__(self):
|
||||
if self.value == self.OK:
|
||||
return "OK"
|
||||
if self.value == self.HWFault:
|
||||
return "HW Fault."
|
||||
if self.value == self.PixelClock:
|
||||
return "Pixel clock exceed HW Caps."
|
||||
if self.value == self.MemoryError:
|
||||
return "Not enough memory for custom pattern."
|
||||
if self.value == self.DscFileZero:
|
||||
return "DSC isn’t enabled. DSC file has zero size."
|
||||
if self.value == self.DscPixelClockExceeds:
|
||||
return "DSC isn’t enabled. Video pixel clock exceeds hardware capabilities."
|
||||
if self.value == self.DscSourceNotSupport:
|
||||
return "DSC isn’t enabled. Source does not support DSC."
|
||||
if self.value == self.DscSinkNotSupport:
|
||||
return "DSC isn’t enabled. Sink does not support DSC."
|
||||
if self.value == self.DscFailReadDpcd:
|
||||
return "DSC isn’t enabled. Fail to read DSC DPCD 0x160."
|
||||
if self.value == self.DscFailWriteDpcd:
|
||||
return "DSC isn’t enabled. Fail to write DSC DPCD 0x160."
|
||||
if self.value == self.WrongColorFormat:
|
||||
return "Selected Color Format does not match the pattern."
|
||||
if self.value == self.WrongColorimetry:
|
||||
return "Selected Colorimetry does not match the pattern."
|
||||
if self.value == self.WrongBitsPerComponent:
|
||||
return "Selected BPC does not match the port capabilities."
|
||||
if self.value == self.WrongDynamicRange:
|
||||
return "Selected Dynamic Range does not match the pattern."
|
||||
else:
|
||||
return f"Unknown error: {self.value}"
|
||||
|
||||
def __init__(self, value: int):
|
||||
self._error = self.PGError(value & 0xFF)
|
||||
self._is_video_produced = (value >> 30) & 1 != 0
|
||||
self._non_applied_changes = (value >> 31) & 1 != 0
|
||||
|
||||
@property
|
||||
def error(self) -> PGError:
|
||||
"""
|
||||
|
||||
Returns pg error.
|
||||
|
||||
Returns:
|
||||
object of `PGError`
|
||||
"""
|
||||
return self._error
|
||||
|
||||
@property
|
||||
def is_video_produced(self) -> bool:
|
||||
"""
|
||||
|
||||
Returns state of video produced.
|
||||
|
||||
Returns:
|
||||
object of bool - is video produced or not
|
||||
"""
|
||||
return self._is_video_produced
|
||||
|
||||
@property
|
||||
def non_applied_changes(self) -> bool:
|
||||
"""
|
||||
|
||||
Returns state of applied changes.
|
||||
|
||||
Returns:
|
||||
object of bool - were there any changes or not
|
||||
"""
|
||||
return self._non_applied_changes
|
||||
|
||||
|
||||
class PatternGenerator:
|
||||
"""
|
||||
|
||||
Main class `PatternGenerator` allows working with PG functionality on the device: set different types of pattern
|
||||
`set_pattern`, set different video modes `set_vm`, set additional parameters for some patterns `set_pattern_params`,
|
||||
get information about current video mode on stream `get_stream_video_mode`, `apply` all transferred setting,
|
||||
`reset` settings and read pattern generator `status`.
|
||||
|
||||
"""
|
||||
|
||||
__available_patterns = '\n'.join([e.name for e in VideoPattern])
|
||||
__hardware_generated_patterns = ''.join([(e.name + '\n') if i <= 7 else '' for i, e in enumerate(VideoPattern)])
|
||||
|
||||
_MAP_PATTERN_PARAMETER = {PGPatternID.SolidColor: SolidColorParams,
|
||||
PGPatternID.WhiteVStrips: WhiteVStripsParams,
|
||||
PGPatternID.GradientRGBStripes: GradientStripsParams,
|
||||
PGPatternID.Motion_Pattern: MotionParams,
|
||||
PGPatternID.SquareWindow: SquareWindowParams}
|
||||
|
||||
def __init__(self, port_io: PortIO, memory_manager: MemoryManager, stream: int):
|
||||
self.__io = port_io
|
||||
self.__memory_manager = memory_manager
|
||||
self.__stream = stream
|
||||
self.__caps = self.__read_caps()
|
||||
self._pattern = None
|
||||
self._pattern_id = PGPatternID.Disabled
|
||||
self._pattern_params = None
|
||||
self._vm = None
|
||||
self.__panel_replay = PanelReplay(port_io, self.__caps)
|
||||
|
||||
def __read_caps(self):
|
||||
self._become_active()
|
||||
return self.__io.get(TSI_PG_CAPS_R, PgCaps)[1]
|
||||
|
||||
def _caps(self) -> PgCaps:
|
||||
return self.__caps
|
||||
|
||||
def __data_from_image_file(self, target_video_mode: VideoMode, path: str) -> bytearray:
|
||||
if target_video_mode is None:
|
||||
target_video_mode = self.get_stream_video_mode()
|
||||
current_video_mode = copy.deepcopy(target_video_mode)
|
||||
target_size = (target_video_mode.timing.hactive, target_video_mode.timing.vactive)
|
||||
|
||||
image = Image.open(path)
|
||||
image = image.resize(target_size)
|
||||
image = image.convert('RGB')
|
||||
data = bytearray([x for sets in list(image.getdata()) for x in sets])
|
||||
|
||||
current_video_mode.color_info.color_format = ColorInfo.ColorFormat.CF_RGB
|
||||
current_video_mode.color_info.bpc = 8
|
||||
current_video_mode.color_info.colorimetry = ColorInfo.Colorimetry.CM_sRGB
|
||||
|
||||
if current_video_mode != target_video_mode:
|
||||
image = uicl_image_from_vm_and_data(current_video_mode, data)
|
||||
data = uicl_image_convert_to_vm(image, target_video_mode)
|
||||
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def __data_from_dsc_file(target_video_mode: VideoMode, path: str) -> bytearray:
|
||||
with open(path, "rb") as dsc_file:
|
||||
data = bytearray(dsc_file.read())
|
||||
assert data[:4] == b"DSCF", 'DSC File missing \'DSCF\' header.'
|
||||
|
||||
return data
|
||||
|
||||
def __load_custom_image(self, video_mode: VideoMode, content_data: Union[str, bytearray, VideoFrame]):
|
||||
if video_mode is None:
|
||||
video_mode = self.get_stream_video_mode()
|
||||
|
||||
if isinstance(content_data, str):
|
||||
data = self.__data_from_image_file(video_mode, str(content_data))
|
||||
elif isinstance(content_data, VideoFrame):
|
||||
data = content_data.data
|
||||
else:
|
||||
image = uicl_image_from_vm_and_data(video_mode, content_data)
|
||||
data = uicl_image_convert_to_vm(image, video_mode)
|
||||
|
||||
block_sizes = PatternGenerator.__calculate_frame_size(video_mode.timing.hactive,
|
||||
video_mode.timing.vactive)
|
||||
self.__memory_manager.set_memory_layout([block_sizes])
|
||||
self.__memory_manager.set_memory_block_index(MemoryManager.MemoryOwner.MO_PatternGenerator)
|
||||
|
||||
self.__io.set(TSI_PG_CUSTOM_PATTERN_MEMORY_BLOCK_INDEX, 0)
|
||||
self.__io.set(TSI_PG_CUSTOM_PATTERN_WIDTH, video_mode.timing.hactive)
|
||||
self.__io.set(TSI_PG_CUSTOM_PATTERN_HEIGHT, video_mode.timing.vactive)
|
||||
self.__io.set(TSI_PG_CUSTOM_PATTERN_PIXEL_FORMAT, pg_pixel_format_from_vm(video_mode))
|
||||
self.__io.set(TSI_PG_CUSTOM_PATTERN_DATA, data, c_uint8, data_count=len(data))
|
||||
|
||||
def __load_dsc_image(self, video_mode: VideoMode, content_data: Union[str, bytearray, VideoFrameDSC]):
|
||||
if isinstance(content_data, str):
|
||||
data = self.__data_from_dsc_file(video_mode, str(content_data))
|
||||
elif isinstance(content_data, VideoFrameDSC):
|
||||
data = content_data.data
|
||||
else:
|
||||
data = content_data
|
||||
|
||||
block_sizes = len(data)
|
||||
self.__memory_manager.set_memory_layout([block_sizes])
|
||||
self.__memory_manager.set_memory_block_index(MemoryManager.MemoryOwner.MO_PatternGenerator)
|
||||
self.__io.set(TSI_PG_CUSTOM_PATTERN_MEMORY_BLOCK_INDEX, 0)
|
||||
self.__io.set(TSI_PG_CUSTOM_PATTERN_DATA, data, c_uint8, data_count=len(data))
|
||||
|
||||
@staticmethod
|
||||
def __calculate_frame_size(width: int, height: int) -> int:
|
||||
line_stride_bytes = width * 4
|
||||
line_stride_aligned_bytes = aligned(line_stride_bytes, 1024)
|
||||
|
||||
line_stride_bytes2 = width * 2
|
||||
line_stride_aligned_bytes2 = aligned(line_stride_bytes2, 1024)
|
||||
|
||||
return int((line_stride_aligned_bytes + line_stride_aligned_bytes2) * height)
|
||||
|
||||
def set_pattern(self, pattern: Union[VideoPattern, str, bytearray, VideoFrame, VideoFrameDSC]):
|
||||
"""
|
||||
|
||||
Allows setting video pattern on current stream.
|
||||
Possible variants:
|
||||
- type `VideoPattern` - value from enum `VideoPattern` (one of th e possible predefined patterns).
|
||||
- type str - path to image (bmp, png, jpeg, dsc and so on).
|
||||
- type bytearray - raw image data, which will be loaded to device memory.
|
||||
- type `VideoFrame` - object of class that contains the image data.
|
||||
- type `VideoFrameDSC` - object of class that contains dsc image data.
|
||||
|
||||
Args:
|
||||
pattern (Union[`VideoPattern`, str, bytearray, `VideoFrame`, `VideoFrameDSC`])
|
||||
|
||||
"""
|
||||
self._pattern = pattern
|
||||
|
||||
def _setup_pattern(self):
|
||||
if self._pattern is not None:
|
||||
if isinstance(self._pattern, VideoPattern):
|
||||
self._pattern_id = PGPatternID(self._pattern.value)
|
||||
if not self.__caps.flags.custom_vp and self._pattern_id in [PGPatternID.WhiteVStrips,
|
||||
PGPatternID.GradientRGBStripes,
|
||||
PGPatternID.ColorRamp,
|
||||
PGPatternID.ColorSquares,
|
||||
PGPatternID.Motion_Pattern]:
|
||||
raise ValueError(f'Current PG (stream {self.__stream}) does not support pattern '
|
||||
f'{self._pattern.name}. Please select another supported pattern from '
|
||||
f'"VideoPattern":\n{self.__hardware_generated_patterns}')
|
||||
elif isinstance(self._pattern, str) and os.path.exists(self._pattern):
|
||||
filename, file_extension = os.path.splitext(self._pattern)
|
||||
if file_extension.lower() == '.dsc' and self.__support_dsc():
|
||||
self.__load_dsc_image(self._vm, self._pattern)
|
||||
self._pattern_id = PGPatternID.DscImage
|
||||
else:
|
||||
self.__load_custom_image(self._vm, self._pattern)
|
||||
self._pattern_id = PGPatternID.ImageFile
|
||||
elif isinstance(self._pattern, VideoFrame):
|
||||
if self._pattern.color_info.color_format == ColorInfo.ColorFormat.CF_DSC and self.__support_dsc():
|
||||
self.__load_dsc_image(self._vm, self._pattern)
|
||||
self._pattern_id = PGPatternID.DscImage
|
||||
else:
|
||||
self.__load_custom_image(self._vm, self._pattern)
|
||||
self._pattern_id = PGPatternID.ImageFile
|
||||
elif isinstance(self._pattern, VideoFrameDSC):
|
||||
if self._pattern.data[:4] == b'DSCF' and self.__support_dsc():
|
||||
self.__load_dsc_image(self._vm, self._pattern)
|
||||
self._pattern_id = PGPatternID.DscImage
|
||||
elif isinstance(self._pattern, bytearray):
|
||||
if self._pattern[:4] == b'DSCF' and self.__support_dsc():
|
||||
self.__load_dsc_image(self._vm, self._pattern)
|
||||
self._pattern_id = PGPatternID.DscImage
|
||||
else:
|
||||
self.__load_custom_image(self._vm, self._pattern)
|
||||
self._pattern_id = PGPatternID.ImageFile
|
||||
else:
|
||||
raise TypeError(f"Incorrect input value: {self._pattern}.\n"
|
||||
f"If you want to select pattern, see following list of available patterns:\n"
|
||||
f"{self.__available_patterns}")
|
||||
self.__io.set(TSI_PG_PREDEF_PATTERN_SELECT, self._pattern_id.value)
|
||||
return True
|
||||
return False
|
||||
|
||||
def __support_dsc(self) -> bool:
|
||||
if not self.__caps.flags.dsc_supported:
|
||||
warnings.warn("Display Stream Compression is not supported.")
|
||||
return False
|
||||
return True
|
||||
|
||||
def set_vm(self, vm: VideoMode):
|
||||
"""
|
||||
|
||||
Allows setting `VideoMode` on current stream.
|
||||
|
||||
Args:
|
||||
vm (VideoMode)
|
||||
"""
|
||||
self._vm = vm
|
||||
|
||||
def _setup_vm(self):
|
||||
if self._vm is None:
|
||||
self.__read_pg_settings()
|
||||
return False
|
||||
if not self._vm.is_valid():
|
||||
raise ValueError(f"Incorrect Video Mode")
|
||||
if self.__caps.max_h_active >= self._vm.timing.hactive and \
|
||||
self.__caps.max_v_active >= self._vm.timing.vactive and \
|
||||
self.__caps.max_h_total >= self._vm.timing.htotal and \
|
||||
self.__caps.max_v_total >= self._vm.timing.vtotal and \
|
||||
self.__caps.max_frame >= int(self._vm.timing.frame_rate / 1000):
|
||||
self.__io.set(TSI_PG_CUSTOM_TIMING_FLAGS, pg_timingflags_from_vm(self._vm))
|
||||
self.__io.set(TSI_PG_CUSTOM_TIMING_HTOTAL, self._vm.timing.htotal, c_uint)
|
||||
self.__io.set(TSI_PG_CUSTOM_TIMING_VTOTAL, self._vm.timing.vtotal, c_uint)
|
||||
self.__io.set(TSI_PG_CUSTOM_TIMING_HACTIVE, self._vm.timing.hactive, c_uint)
|
||||
self.__io.set(TSI_PG_CUSTOM_TIMING_VACTIVE, self._vm.timing.vactive, c_uint)
|
||||
self.__io.set(TSI_PG_CUSTOM_TIMING_HSTART, self._vm.timing.hstart, c_uint)
|
||||
self.__io.set(TSI_PG_CUSTOM_TIMING_VSTART, self._vm.timing.vstart, c_uint)
|
||||
self.__io.set(TSI_PG_CUSTOM_TIMING_HSYNCW, abs(self._vm.timing.hswidth), c_uint)
|
||||
self.__io.set(TSI_PG_CUSTOM_TIMING_VSYNCW, abs(self._vm.timing.vswidth), c_uint)
|
||||
self.__io.set(TSI_PG_CUSTOM_TIMING_FIELD_RATE, self._vm.timing.frame_rate, c_uint)
|
||||
self.__io.set(TSI_PG_CUSTOM_TIMING_STANDARD, self._vm.timing.standard.value, c_uint)
|
||||
return True
|
||||
else:
|
||||
raise ValueError(f"Incorrect Video Mode (incorrect resolution and(or) frame rate")
|
||||
|
||||
def set_pattern_params(self, pattern_params: PGPatternParams):
|
||||
"""
|
||||
|
||||
Allows setting additional parameters for some patters on current stream.
|
||||
See available `PGPatternParams` types: `SolidColorParams`, `WhiteVStripsParams`, `GradientStripsParams`,
|
||||
`MotionParams`,`SquareWindowParams` (see in pg pattern params).
|
||||
|
||||
Args:
|
||||
pattern_params (PGPatternParams)
|
||||
"""
|
||||
self._pattern_params = pattern_params
|
||||
|
||||
def _setup_pattern_params(self):
|
||||
if self._pattern_params is not None and isinstance(self._pattern, VideoPattern):
|
||||
if self._MAP_PATTERN_PARAMETER.get(PGPatternID(self._pattern_id.value)) is not None:
|
||||
if isinstance(self._pattern_params,
|
||||
self._MAP_PATTERN_PARAMETER.get(PGPatternID(self._pattern_id.value))):
|
||||
self.__io.set(TSI_PG_PREDEF_PATTERN_PARAMS, get_pattern_params_value(self._pattern_params,
|
||||
self._vm.color_info.bpc),
|
||||
data_count=len(get_pattern_params_value(self._pattern_params)))
|
||||
return True
|
||||
else:
|
||||
warnings.warn(f"Incorrect pattern name {self._pattern} and "
|
||||
f"pattern params {type(self._pattern_params)}.\n"
|
||||
f"For {self._pattern} you need to use "
|
||||
f"{self._MAP_PATTERN_PARAMETER.get(self._pattern_id)}")
|
||||
return False
|
||||
|
||||
def __get_custom_timing_flags_to_video_mode(self) -> (ColorInfo, bool, bool):
|
||||
timing_flags = self.__io.get(TSI_PG_CUSTOM_TIMING_FLAGS, CustomTimingFlags)[1]
|
||||
|
||||
vm_color_format = pg_colorformat_to_ci_colorformat(PGColorInfo(timing_flags.color_space))
|
||||
|
||||
vm_colorimetry = pg_colorimetry_to_ci_colorimetry(PGColorInfo(timing_flags.color_space),
|
||||
PGColorimetry(timing_flags.colorimetry))
|
||||
|
||||
vm_dynamic_range = pg_dynamicrange_to_ci_dynamicrange(PGDynamicRange(timing_flags.dynamic_range))
|
||||
|
||||
vm_h_sync_polarity = bool(timing_flags.h_sync_polarity)
|
||||
vm_v_sync_polarity = bool(timing_flags.v_sync_polarity)
|
||||
|
||||
vm_bpc = pg_bpc_to_ci_bpc(timing_flags.color_depth)
|
||||
|
||||
color_info = ColorInfo()
|
||||
color_info.color_format = vm_color_format
|
||||
color_info.colorimetry = vm_colorimetry
|
||||
color_info.dynamic_range = vm_dynamic_range
|
||||
color_info.bpc = vm_bpc
|
||||
|
||||
return color_info, vm_h_sync_polarity, vm_v_sync_polarity
|
||||
|
||||
def get_stream_video_mode(self) -> VideoMode:
|
||||
"""
|
||||
|
||||
Returns `VideoMode` information about current stream.
|
||||
|
||||
Returns:
|
||||
object of VideoMode type
|
||||
"""
|
||||
self.__read_pg_settings()
|
||||
|
||||
video_mode = VideoMode()
|
||||
|
||||
video_mode.timing.hactive = self.__io.get(TSI_PG_CUSTOM_TIMING_HACTIVE, c_uint32)[1]
|
||||
video_mode.timing.vactive = self.__io.get(TSI_PG_CUSTOM_TIMING_VACTIVE, c_uint32)[1]
|
||||
video_mode.timing.htotal = self.__io.get(TSI_PG_CUSTOM_TIMING_HTOTAL, c_uint32)[1]
|
||||
video_mode.timing.vtotal = self.__io.get(TSI_PG_CUSTOM_TIMING_VTOTAL, c_uint32)[1]
|
||||
video_mode.timing.hstart = self.__io.get(TSI_PG_CUSTOM_TIMING_HSTART, c_uint32)[1]
|
||||
video_mode.timing.vstart = self.__io.get(TSI_PG_CUSTOM_TIMING_VSTART, c_uint32)[1]
|
||||
|
||||
video_mode.color_info, h_sync_polarity, v_sync_polarity = self.__get_custom_timing_flags_to_video_mode()
|
||||
|
||||
video_mode.timing.hswidth = self.__io.get(TSI_PG_CUSTOM_TIMING_HSYNCW, c_uint32)[1] * (
|
||||
-1 if h_sync_polarity else 1)
|
||||
video_mode.timing.vswidth = self.__io.get(TSI_PG_CUSTOM_TIMING_VSYNCW, c_uint32)[1] * (
|
||||
-1 if v_sync_polarity else 1)
|
||||
video_mode.timing.frame_rate = self.__io.get(TSI_PG_CUSTOM_TIMING_FIELD_RATE, c_uint32)[1]
|
||||
|
||||
return video_mode
|
||||
|
||||
def _become_active(self):
|
||||
self.__io.set(TSI_PG_STREAM_SELECT, self.__stream)
|
||||
|
||||
def __read_pg_settings(self):
|
||||
self.__io.set(TSI_PG_COMMAND_W, 2)
|
||||
|
||||
def apply(self) -> bool:
|
||||
"""
|
||||
|
||||
Apply all settings on current stream.
|
||||
|
||||
Returns:
|
||||
object of bool type - settings were set successfully or not
|
||||
"""
|
||||
self.__io.set(TSI_PG_COMMAND_W, 3)
|
||||
|
||||
def is_apply_pg_success(pg: PatternGenerator):
|
||||
return pg.status().error == PGStatus.PGError.OK
|
||||
|
||||
return function_scheduler(is_apply_pg_success, self, interval=1, timeout=10)
|
||||
|
||||
def status(self) -> PGStatus:
|
||||
"""
|
||||
|
||||
Returns `PGStatus` of current stream.
|
||||
|
||||
Returns:
|
||||
object of PGStatus type.
|
||||
"""
|
||||
self._become_active()
|
||||
return PGStatus(self.__io.get(TSI_PG_STATUS_R, c_uint32)[1])
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
|
||||
Reset all setting on current stream.
|
||||
|
||||
"""
|
||||
self._vm = VideoMode()
|
||||
self._pattern = None
|
||||
self._pattern_id = PGPatternID.Disabled
|
||||
self._pattern_params = None
|
||||
|
||||
def get_pixel_rate(self) -> int:
|
||||
"""
|
||||
|
||||
Returns current pixel rate.
|
||||
|
||||
Returns:
|
||||
object of int type
|
||||
"""
|
||||
vm = self.get_stream_video_mode()
|
||||
return vm.timing.htotal * vm.timing.vtotal * int(vm.timing.frame_rate / 1000)
|
||||
|
||||
def panel_replay(self) -> Optional[PanelReplay]:
|
||||
"""
|
||||
|
||||
Returns object of PanelReplay if device supports this feature.
|
||||
|
||||
Returns:
|
||||
object of 'PanelReplay' type or None
|
||||
"""
|
||||
if self.__caps.flags.panel_replay != 0 or self.__caps.flags.psr != 0:
|
||||
return self.__panel_replay
|
||||
return None
|
||||
|
||||
|
||||
class HdmiPatternGenerator(PatternGenerator):
|
||||
"""
|
||||
Class `HdmiPatternGenerator` inherited from class `PatternGenerator`.
|
||||
Allows getting `timing_manager`, `max_stream_count`, `apply` PG settings.
|
||||
Also has all the `PatternGenerator` functionality.
|
||||
"""
|
||||
|
||||
def __init__(self, port_io: PortIO, memory_manager: MemoryManager):
|
||||
super().__init__(port_io, memory_manager, 0)
|
||||
self.__timing_manager = TimingManager(_read_predefined_timings(port_io))
|
||||
|
||||
@property
|
||||
def timing_manager(self) -> TimingManager:
|
||||
"""
|
||||
|
||||
Should be used for working with available timings on device.
|
||||
|
||||
Returns:
|
||||
object of `TimingManager` type.
|
||||
"""
|
||||
return self.__timing_manager
|
||||
|
||||
@property
|
||||
def max_stream_count(self) -> int:
|
||||
"""
|
||||
|
||||
Returns maximum count of available streams.
|
||||
|
||||
Returns:
|
||||
object of int type.
|
||||
"""
|
||||
return 1
|
||||
|
||||
def apply(self) -> bool:
|
||||
"""
|
||||
|
||||
Apply all settings.
|
||||
|
||||
Returns:
|
||||
object of bool type - settings were set successfully or not
|
||||
"""
|
||||
self._become_active()
|
||||
res = self._setup_vm()
|
||||
res += self._setup_pattern()
|
||||
res += self._setup_pattern_params()
|
||||
if res != 0:
|
||||
return super().apply()
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class DpPatternGenerator(PatternGenerator):
|
||||
"""
|
||||
Class `DpPatternGenerator` inherited from class `PatternGenerator`.
|
||||
Allows getting `timing_manager`, `adaptive_sync_status`, `apply` and `reset` PG settings and set additional settings:
|
||||
`set_as_config`, `set_scrolling_params`.
|
||||
Also has all the `PatternGenerator` functionality.
|
||||
"""
|
||||
|
||||
def __init__(self, port_io: PortIO, memory_manager: MemoryManager, stream: int):
|
||||
super().__init__(port_io, memory_manager, stream)
|
||||
self.__scrolling_params = None
|
||||
self.__as_config = None
|
||||
self.__io = port_io
|
||||
self.__timing_manager = TimingManager(_read_predefined_timings(port_io))
|
||||
|
||||
@property
|
||||
def timing_manager(self) -> TimingManager:
|
||||
"""
|
||||
|
||||
Should be used for working with available timings on device.
|
||||
|
||||
Returns:
|
||||
object of `TimingManager` type.
|
||||
"""
|
||||
return self.__timing_manager
|
||||
|
||||
def set_as_config(self, as_config: ASParams):
|
||||
"""
|
||||
|
||||
Allows setting adaptive sync configuration.
|
||||
See available `ASParams` types: `ConstantASParams`, `SquareASParams`, `ZigzagASParams`, `FixedASParams`
|
||||
(see in types).
|
||||
|
||||
Args:
|
||||
as_config (ASParams)
|
||||
"""
|
||||
self.__as_config = as_config
|
||||
|
||||
def set_scrolling_params(self, scrolling_params: PGScrollingParams):
|
||||
"""
|
||||
|
||||
Allows setting additional configuration for "Scrolling pattern". See available `PGScrollingParams` types:
|
||||
`StepsScrollingParams` (see in pg pattern params).
|
||||
|
||||
Args:
|
||||
scrolling_params (PGScrollingParams)
|
||||
"""
|
||||
self.__scrolling_params = scrolling_params
|
||||
|
||||
def _setup_as_config(self):
|
||||
if self.__as_config is not None:
|
||||
if not self._caps().flags.adaptive_sync:
|
||||
warnings.warn("AdaptiveSync is not supported")
|
||||
self.__as_config = None
|
||||
return False
|
||||
|
||||
self.__io.set(TSI_PG_ADAPTIVE_SYNC_CTRL,
|
||||
get_as_params_value(self.__as_config),
|
||||
data_count=len(get_as_params_value(self.__as_config)))
|
||||
return True
|
||||
return False
|
||||
|
||||
def _setup_scrolling_params(self):
|
||||
if self.__scrolling_params is not None:
|
||||
if not self._caps().flags.scrolling_pattern:
|
||||
warnings.warn("Scrolling params is not supported")
|
||||
self.__scrolling_params = None
|
||||
return False
|
||||
if self._vm.color_info.color_format == ColorInfo.ColorFormat.CF_YCbCr_422 and \
|
||||
self.__scrolling_params.horizontally % 2:
|
||||
warnings.warn(f"Wrong horizontally param. Number must be even. Will be used param - 1: "
|
||||
f"{self.__scrolling_params.horizontally - 1}")
|
||||
self.__scrolling_params.horizontally -= 1
|
||||
elif self._vm.color_info.color_format == ColorInfo.ColorFormat.CF_YCbCr_420 and \
|
||||
self.__scrolling_params.vertically % 2:
|
||||
warnings.warn(f"Wrong vertically param. Number must be even. Will be used param - 1: "
|
||||
f"{self.__scrolling_params.vertically - 1}")
|
||||
self.__scrolling_params.vertically -= 1
|
||||
|
||||
if not (self._caps().patterns & (1 << self._pattern_id.value)):
|
||||
warnings.warn(f"Patterns scrolling feature is not supported on pattern {self._pattern_id.name}")
|
||||
return False
|
||||
value = 1
|
||||
value |= (1 << 31)
|
||||
self.__io.set(TSI_PG_CUSTOM_PATTERN_SCROLLING_CONTROL, value, c_uint32)
|
||||
self.__io.set(TSI_PG_CUSTOM_PATTERN_SCROLLING_CONFIG, get_pattern_params_value(self.__scrolling_params),
|
||||
data_count=len(get_pattern_params_value(self.__scrolling_params)))
|
||||
return True
|
||||
return False
|
||||
|
||||
def adaptive_sync_status(self) -> bool:
|
||||
"""
|
||||
|
||||
Returns work status of adaptive sync.
|
||||
|
||||
Returns:
|
||||
object of bool type - adaptive sync enabled or not
|
||||
"""
|
||||
self._become_active()
|
||||
|
||||
res = self.__io.get(TSI_PG_ADAPTIVE_SYNC_STS, c_uint32)
|
||||
|
||||
if res[0] < TSI_SUCCESS:
|
||||
return False
|
||||
|
||||
return res[1] & 1 != 0
|
||||
|
||||
def apply(self) -> bool:
|
||||
"""
|
||||
|
||||
Apply all settings.
|
||||
|
||||
Returns:
|
||||
object of bool type - settings were set successfully or not
|
||||
"""
|
||||
self._become_active()
|
||||
res = self._setup_vm()
|
||||
res += self._setup_pattern()
|
||||
res += self._setup_pattern_params()
|
||||
res += self._setup_scrolling_params()
|
||||
if res != 0:
|
||||
res = super().apply()
|
||||
else:
|
||||
res = False
|
||||
self._setup_as_config()
|
||||
return res
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
|
||||
Reset all setting.
|
||||
|
||||
"""
|
||||
self.__scrolling_params = None
|
||||
self.__as_config = None
|
||||
super().reset()
|
||||
|
||||
|
||||
class DpMstPatternGenerator:
|
||||
"""
|
||||
Class `DpMstPatternGenerator` allows working with one of the supported streams on the device (contains list of the
|
||||
`DpPatternGenerator` objects). To access the selected stream, use an override of `[ ]`.
|
||||
Also, allows working with stream number 0 directly and applying all settings of all streams together.
|
||||
"""
|
||||
|
||||
def __init__(self, port_io: PortIO, memory_manager: MemoryManager, max_stream_count: int):
|
||||
self.__pg_list = []
|
||||
self.__io = port_io
|
||||
self.__MAX_STREAM_COUNT = max_stream_count
|
||||
for i in range(self.max_stream_count):
|
||||
self.__pg_list.append(DpPatternGenerator(port_io, memory_manager, i))
|
||||
self.__timing_manager = self.__pg_list[0].timing_manager
|
||||
|
||||
def __getitem__(self, index: int):
|
||||
"""
|
||||
|
||||
Allows selecting one of the supported streams.
|
||||
Example:
|
||||
`'object of device role'.pg[index]`
|
||||
|
||||
"""
|
||||
if not (0 <= index < self.max_stream_count):
|
||||
raise ValueError(f"Index of PG must be in range [0..{self.max_stream_count}].")
|
||||
|
||||
return self.__pg_list[index]
|
||||
|
||||
@property
|
||||
def timing_manager(self) -> TimingManager:
|
||||
"""
|
||||
|
||||
Should be used for working with available timings on device.
|
||||
|
||||
Returns:
|
||||
object of `TimingManager` type.
|
||||
"""
|
||||
return self.__timing_manager
|
||||
|
||||
@property
|
||||
def max_stream_count(self) -> int:
|
||||
"""
|
||||
|
||||
Returns maximum count of available streams.
|
||||
|
||||
Returns:
|
||||
object of int type.
|
||||
"""
|
||||
return self.__MAX_STREAM_COUNT
|
||||
|
||||
def set_pattern(self, pattern: Union[VideoPattern, str, bytearray, VideoFrame, VideoFrameDSC]):
|
||||
"""
|
||||
|
||||
Allows setting video pattern on stream number 0 of pattern generator.
|
||||
Possible variants:
|
||||
- type `VideoPattern` - value from enum `VideoPattern` (one of th e possible predefined patterns).
|
||||
- type str - path to image (bmp, png, jpeg, dsc and so on).
|
||||
- type bytearray - raw image data, which will be loaded to device memory.
|
||||
- type `VideoFrame` - object of class that contains the image data.
|
||||
- type `VideoFrameDSC` - object of class that contains the dsc image data.
|
||||
|
||||
Args:
|
||||
pattern (Union[`VideoPattern`, str, bytearray, `VideoFrame`, `VideoFrameDSC`])
|
||||
|
||||
"""
|
||||
self.__pg_list[0].set_pattern(pattern)
|
||||
|
||||
def set_vm(self, vm: VideoMode):
|
||||
"""
|
||||
|
||||
Allows setting `VideoMode` on stream number 0 of pattern generator.
|
||||
|
||||
Args:
|
||||
vm (VideoMode)
|
||||
"""
|
||||
self.__pg_list[0].set_vm(vm)
|
||||
|
||||
def set_pattern_params(self, pattern_params: PGPatternParams):
|
||||
"""
|
||||
|
||||
Allows setting additional parameters for some patters on stream number 0 of pattern generator.
|
||||
See available `PGPatternParams` types: `SolidColorParams`, `WhiteVStripsParams`, `GradientStripsParams`,
|
||||
`MotionParams`,`SquareWindowParams` (see in pg pattern params).
|
||||
|
||||
Args:
|
||||
pattern_params (PGPatternParams)
|
||||
"""
|
||||
self.__pg_list[0].set_pattern_params(pattern_params)
|
||||
|
||||
def set_as_config(self, as_config: ASParams):
|
||||
"""
|
||||
|
||||
Allows setting adaptive sync configuration on stream number 0 of pattern generator.
|
||||
See available `ASParams` types: `ConstantASParams`, `SquareASParams`, `ZigzagASParams`, `FixedASParams`.
|
||||
(see in types).
|
||||
|
||||
Args:
|
||||
as_config (ASParams)
|
||||
"""
|
||||
self.__pg_list[0].set_as_config(as_config)
|
||||
|
||||
def set_scrolling_params(self, scrolling_params: PGScrollingParams):
|
||||
"""
|
||||
|
||||
Allows setting additional configuration for "Scrolling pattern" on stream number 0 of pattern generator.
|
||||
See available `PGScrollingParams` types: `StepsScrollingParams` (see in pg pattern params).
|
||||
|
||||
Args:
|
||||
scrolling_params (PGScrollingParams)
|
||||
"""
|
||||
self.__pg_list[0].set_scrolling_params(scrolling_params)
|
||||
|
||||
def get_stream_video_mode(self) -> VideoMode:
|
||||
"""
|
||||
|
||||
Returns `VideoMode` information about current configuration of PG on stream 0.
|
||||
|
||||
Returns:
|
||||
object of VideoMode type
|
||||
"""
|
||||
return self.__pg_list[0].get_stream_video_mode()
|
||||
|
||||
def apply(self) -> bool:
|
||||
"""
|
||||
|
||||
Apply all setting on stream number 0 of pattern generator.
|
||||
|
||||
Returns:
|
||||
object of bool type - settings were set successfully or not
|
||||
"""
|
||||
return self.__pg_list[0].apply()
|
||||
|
||||
def status(self) -> PGStatus:
|
||||
"""
|
||||
|
||||
Returns `PGStatus` on stream number 0 of pattern generator.
|
||||
|
||||
Returns:
|
||||
object of PGStatus type.
|
||||
"""
|
||||
return self.__pg_list[0].status()
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
|
||||
Reset all setting on stream number 0 of pattern generator.
|
||||
|
||||
"""
|
||||
self.__pg_list[0].reset()
|
||||
|
||||
def apply_all(self):
|
||||
"""
|
||||
|
||||
Apply all setting on all supported streams of pattern generator.
|
||||
|
||||
"""
|
||||
for i in range(self.max_stream_count):
|
||||
self.__pg_list[i].apply()
|
||||
|
||||
def get_pixel_rate(self, stream: int = 0) -> int:
|
||||
"""
|
||||
|
||||
Returns current pixel rate for selected stream.
|
||||
|
||||
Returns:
|
||||
object of int type
|
||||
"""
|
||||
return self.__pg_list[stream].get_pixel_rate()
|
||||
|
||||
@property
|
||||
def panel_replay(self) -> PanelReplay:
|
||||
"""
|
||||
|
||||
Returns object of PanelReplay if device supports this feature (first stream).
|
||||
|
||||
Returns:
|
||||
object of 'PanelReplay' type or None
|
||||
"""
|
||||
return self.__pg_list[0].panel_replay()
|
||||
|
||||
def __read_max_stream_count(self) -> int:
|
||||
result = self.__io.get(TSI_PG_MAX_STREAM_COUNT_R, c_uint32)
|
||||
return result[1]
|
||||
133
UniTAP/dev/ports/modules/vtg/pg_pattern_params.py
Normal file
133
UniTAP/dev/ports/modules/vtg/pg_pattern_params.py
Normal file
@@ -0,0 +1,133 @@
|
||||
import warnings
|
||||
from typing import TypeVar, Union
|
||||
|
||||
|
||||
class SolidColorParams:
|
||||
|
||||
"""
|
||||
Special configuration class for configure Solid color pattern. Contains information about R (Y) - first,
|
||||
G (Cb) - second, B(Cr) - third components.
|
||||
"""
|
||||
|
||||
def __init__(self, first: int = 0, second: int = 0, third: int = 0):
|
||||
if not (0 <= first <= 255):
|
||||
warnings.warn("Incorrect value. Must use value from range: 0 - 255. Will be used default value = 0")
|
||||
first = 0
|
||||
self.first = first
|
||||
|
||||
if not (0 <= second <= 255):
|
||||
warnings.warn("Incorrect value. Must use value from range: 0 - 255. Will be used default value = 0")
|
||||
second = 0
|
||||
self.second = second
|
||||
|
||||
if not (0 <= third <= 255):
|
||||
warnings.warn("Incorrect value. Must use value from range: 0 - 255. Will be used default value = 0")
|
||||
third = 0
|
||||
self.third = third
|
||||
|
||||
|
||||
class WhiteVStripsParams:
|
||||
|
||||
"""
|
||||
Special configuration class for configure White V Strips pattern. Contains information about white stripes width
|
||||
and black stripes width.
|
||||
"""
|
||||
|
||||
def __init__(self, white_stripes_width: int = 1, black_stripes_width: int = 1):
|
||||
if not (1 <= white_stripes_width <= 1000):
|
||||
warnings.warn("Incorrect value. Must use value from range: 1 - 1000. Will be used default value = 1")
|
||||
white_stripes_width = 1
|
||||
self.white_stripes_width = white_stripes_width
|
||||
|
||||
if not (0 <= black_stripes_width <= 1000):
|
||||
warnings.warn("Incorrect value. Must use value from range: 1 - 1000. Will be used default value = 1")
|
||||
black_stripes_width = 1
|
||||
self.black_stripes_width = black_stripes_width
|
||||
|
||||
|
||||
class GradientStripsParams:
|
||||
|
||||
"""
|
||||
Special configuration class for configure Gradient Strips pattern. Contains information about color steps conut.
|
||||
"""
|
||||
|
||||
def __init__(self, color_step: int = 10000):
|
||||
if not (0 <= color_step <= 10000):
|
||||
warnings.warn("Incorrect value. Must use value from range: 1 - 10000. Will be used default value = 1")
|
||||
color_step = 1
|
||||
self.color_step = color_step
|
||||
|
||||
|
||||
class MotionParams:
|
||||
|
||||
"""
|
||||
Special configuration class for configure Motion pattern. Contains information about frames conut.
|
||||
"""
|
||||
|
||||
def __init__(self, frames_count: int = 10000):
|
||||
if not (0 <= frames_count <= 10000):
|
||||
warnings.warn("Incorrect value. Must use value from range: 1 - 10000. Will be used default value = 1")
|
||||
frames_count = 1
|
||||
self.frames_count = frames_count
|
||||
|
||||
|
||||
class SquareWindowParams:
|
||||
|
||||
"""
|
||||
Special configuration class for configure Square Window pattern. Contains information about white square size.
|
||||
"""
|
||||
|
||||
def __init__(self, white_square: int = 30):
|
||||
if not (0 <= white_square <= 100):
|
||||
warnings.warn("Incorrect value. Must use value from range: 0 - 100. Will be used default value = 30")
|
||||
white_square = 30
|
||||
self.white_square = white_square
|
||||
|
||||
|
||||
class StepsScrollingParams:
|
||||
|
||||
"""
|
||||
Special configuration class for configure Scrolling (Steps type) pattern. Contains information about horizontally
|
||||
delta, vertically delta and frames count.
|
||||
"""
|
||||
|
||||
def __init__(self, horizontally: int = 0, vertically: int = 0, frames: int = 0):
|
||||
if not (-128 <= horizontally <= 127):
|
||||
warnings.warn("Incorrect value (horizontally). Must use value from range: (-)128 - 127. "
|
||||
"For YCbCr 422 range: (-)128 - 126 \n"
|
||||
"Will be used default value = 0")
|
||||
horizontally = 0
|
||||
if not (-128 <= vertically <= 127):
|
||||
warnings.warn("Incorrect value (vertically). Must use value from range: (-)128 - 127. "
|
||||
"For YCbCr 420 range: (-)128 - 126 \n"
|
||||
"Will be used default value = 0")
|
||||
vertically = 0
|
||||
if not (0 <= frames <= 255):
|
||||
warnings.warn("Incorrect value (frames). Must use value from range: 0 - 255. "
|
||||
"Will be used default value = 0")
|
||||
frames = 0
|
||||
self.horizontally = (-1) * horizontally
|
||||
self.vertically = vertically
|
||||
self.frames = frames
|
||||
|
||||
|
||||
class DistanceScrollingParams:
|
||||
"""
|
||||
Support of DistanceScrolling will be added later.
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
PGPatternParams = TypeVar("PGPatternParams",
|
||||
SolidColorParams,
|
||||
WhiteVStripsParams,
|
||||
GradientStripsParams,
|
||||
MotionParams,
|
||||
SquareWindowParams
|
||||
)
|
||||
|
||||
|
||||
PGScrollingParams = TypeVar("PGScrollingParams",
|
||||
StepsScrollingParams,
|
||||
DistanceScrollingParams)
|
||||
163
UniTAP/dev/ports/modules/vtg/pg_utils.py
Normal file
163
UniTAP/dev/ports/modules/vtg/pg_utils.py
Normal file
@@ -0,0 +1,163 @@
|
||||
from UniTAP.common import ColorInfo, VideoMode
|
||||
from UniTAP.libs.lib_tsi.tsi_types import TSI_IMF_PK444_RGB_W8_C8, TSI_IMF_PK444_RGB_W16_C12, \
|
||||
TSI_IMF_PK444_RGB_W16_C16, TSI_IMF_PK444_YCbCr_W8_C8, TSI_IMF_PK444_YCbCr_W16_C16, \
|
||||
TSI_IMF_PK422_CbYCrY_W16_C8, TSI_IMF_PK422_CbYCrY_W16_C16, TSI_IMF_PK420_CxYY0_W8_C8, \
|
||||
TSI_IMF_PK420_CxYY0_W8_C10, TSI_IMF_PK420_CxYY_W16_C12, TSI_IMF_PK420_CxYY_W16_C16
|
||||
from .types import PGColorInfo, PGColorDepth, PGColorimetry, PGDynamicRange
|
||||
|
||||
|
||||
def pg_colorformat_to_ci_colorformat(color_mode: PGColorInfo) -> ColorInfo.ColorFormat:
|
||||
if color_mode == PGColorInfo.RGB:
|
||||
return ColorInfo.ColorFormat.CF_RGB
|
||||
elif color_mode == PGColorInfo.YCbCr444:
|
||||
return ColorInfo.ColorFormat.CF_YCbCr_444
|
||||
elif color_mode == PGColorInfo.YCbCr422:
|
||||
return ColorInfo.ColorFormat.CF_YCbCr_422
|
||||
elif color_mode == PGColorInfo.YCbCr420:
|
||||
return ColorInfo.ColorFormat.CF_YCbCr_420
|
||||
elif color_mode == PGColorInfo.Y_only:
|
||||
return ColorInfo.ColorFormat.CF_Y_ONLY
|
||||
elif color_mode == PGColorInfo.RAW:
|
||||
return ColorInfo.ColorFormat.CF_RAW
|
||||
else:
|
||||
return ColorInfo.ColorFormat.CF_UNKNOWN
|
||||
|
||||
|
||||
def pg_colorformat_from_ci_colorformat(color_mode: ColorInfo.ColorFormat) -> PGColorInfo:
|
||||
if color_mode == ColorInfo.ColorFormat.CF_RGB:
|
||||
return PGColorInfo.RGB
|
||||
elif color_mode == ColorInfo.ColorFormat.CF_YCbCr_444:
|
||||
return PGColorInfo.YCbCr444
|
||||
elif color_mode == ColorInfo.ColorFormat.CF_YCbCr_422:
|
||||
return PGColorInfo.YCbCr422
|
||||
elif color_mode == ColorInfo.ColorFormat.CF_YCbCr_420:
|
||||
return PGColorInfo.YCbCr420
|
||||
elif color_mode == ColorInfo.ColorFormat.CF_Y_ONLY:
|
||||
return PGColorInfo.Y_only
|
||||
elif color_mode == ColorInfo.ColorFormat.CF_RAW:
|
||||
return PGColorInfo.RAW
|
||||
else:
|
||||
return PGColorInfo.Unknown
|
||||
|
||||
|
||||
def pg_colorimetry_to_ci_colorimetry(color_mode: PGColorInfo, colorimetry: PGColorimetry)\
|
||||
-> ColorInfo.Colorimetry:
|
||||
if color_mode == PGColorInfo.RGB:
|
||||
return ColorInfo.Colorimetry.CM_sRGB
|
||||
elif color_mode in [PGColorInfo.YCbCr444, PGColorInfo.YCbCr422, PGColorInfo.YCbCr420]:
|
||||
if colorimetry == PGColorimetry.ITU601:
|
||||
return ColorInfo.Colorimetry.CM_ITUR_BT601
|
||||
elif colorimetry == PGColorimetry.ITU709:
|
||||
return ColorInfo.Colorimetry.CM_ITUR_BT709
|
||||
else:
|
||||
return ColorInfo.Colorimetry.CM_RESERVED
|
||||
else:
|
||||
return ColorInfo.Colorimetry.CM_RESERVED
|
||||
|
||||
|
||||
def pg_colorimetry_from_ci_colorimetry(colorimetry: ColorInfo.Colorimetry) -> PGColorimetry:
|
||||
if colorimetry == ColorInfo.Colorimetry.CM_ITUR_BT601:
|
||||
return PGColorimetry.ITU601
|
||||
elif colorimetry == ColorInfo.Colorimetry.CM_ITUR_BT709:
|
||||
return PGColorimetry.ITU709
|
||||
else:
|
||||
return PGColorimetry.ITU601
|
||||
|
||||
|
||||
def pg_bpc_to_ci_bpc(bpc: PGColorDepth) -> int:
|
||||
if bpc == PGColorDepth.BPC6:
|
||||
return 6
|
||||
elif bpc == PGColorDepth.BPC8:
|
||||
return 8
|
||||
elif bpc == PGColorDepth.BPC10:
|
||||
return 10
|
||||
elif bpc == PGColorDepth.BPC12:
|
||||
return 12
|
||||
elif bpc == PGColorDepth.BPC16:
|
||||
return 16
|
||||
elif bpc == PGColorDepth.BPC7:
|
||||
return 7
|
||||
elif bpc == PGColorDepth.BPC14:
|
||||
return 14
|
||||
return 0
|
||||
|
||||
|
||||
def pg_bpc_from_ci_bpc(bpc: int) -> PGColorDepth:
|
||||
if bpc == 6:
|
||||
return PGColorDepth.BPC6
|
||||
elif bpc == 8:
|
||||
return PGColorDepth.BPC8
|
||||
elif bpc == 10:
|
||||
return PGColorDepth.BPC10
|
||||
elif bpc == 12:
|
||||
return PGColorDepth.BPC12
|
||||
elif bpc == 16:
|
||||
return PGColorDepth.BPC16
|
||||
elif bpc == 7:
|
||||
return PGColorDepth.BPC7
|
||||
elif bpc == 14:
|
||||
return PGColorDepth.BPC14
|
||||
return PGColorDepth.Unknown
|
||||
|
||||
|
||||
def pg_pixel_format_from_vm(vm: VideoMode) -> int:
|
||||
bpc = vm.color_info.bpc
|
||||
color_format = vm.color_info.color_format
|
||||
|
||||
if color_format == ColorInfo.ColorFormat.CF_RGB:
|
||||
if bpc == 8:
|
||||
return TSI_IMF_PK444_RGB_W8_C8
|
||||
elif bpc in [10, 12]:
|
||||
return TSI_IMF_PK444_RGB_W16_C12
|
||||
elif bpc == 16:
|
||||
return TSI_IMF_PK444_RGB_W16_C16
|
||||
elif color_format == ColorInfo.ColorFormat.CF_YCbCr_444:
|
||||
if bpc == 8:
|
||||
return TSI_IMF_PK444_YCbCr_W8_C8
|
||||
elif bpc in [10, 12, 16]:
|
||||
return TSI_IMF_PK444_YCbCr_W16_C16
|
||||
elif color_format == ColorInfo.ColorFormat.CF_YCbCr_422:
|
||||
if bpc == 8:
|
||||
return TSI_IMF_PK422_CbYCrY_W16_C8
|
||||
elif bpc in [10, 12, 16]:
|
||||
return TSI_IMF_PK422_CbYCrY_W16_C16
|
||||
elif color_format == ColorInfo.ColorFormat.CF_YCbCr_420:
|
||||
if bpc == 8:
|
||||
return TSI_IMF_PK420_CxYY0_W8_C8
|
||||
elif bpc == 10:
|
||||
return TSI_IMF_PK420_CxYY0_W8_C10
|
||||
elif bpc == 12:
|
||||
return TSI_IMF_PK420_CxYY_W16_C12
|
||||
elif bpc == 16:
|
||||
return TSI_IMF_PK420_CxYY_W16_C16
|
||||
|
||||
return 0xffffffff
|
||||
|
||||
|
||||
def pg_dynamicrange_to_ci_dynamicrange(dynamic_range: PGDynamicRange) -> ColorInfo.DynamicRange:
|
||||
if dynamic_range == PGDynamicRange.CTA:
|
||||
return ColorInfo.DynamicRange.DR_CTA
|
||||
elif dynamic_range == PGDynamicRange.VESA:
|
||||
return ColorInfo.DynamicRange.DR_VESA
|
||||
else:
|
||||
return ColorInfo.DynamicRange.DR_UNKNOWN
|
||||
|
||||
|
||||
def pg_dynamicrange_from_ci_dynamicrange(dynamic_range: ColorInfo.DynamicRange) -> PGDynamicRange:
|
||||
if dynamic_range == ColorInfo.DynamicRange.DR_CTA:
|
||||
return PGDynamicRange.CTA
|
||||
else:
|
||||
return PGDynamicRange.VESA
|
||||
|
||||
|
||||
def pg_timingflags_from_vm(vm: VideoMode) -> int:
|
||||
timing_flags = 0
|
||||
|
||||
timing_flags |= pg_bpc_from_ci_bpc(vm.color_info.bpc)
|
||||
timing_flags |= (1 << 9) if vm.timing.hswidth < 0 else 0
|
||||
timing_flags |= (1 << 10) if vm.timing.vswidth < 0 else 0
|
||||
timing_flags |= pg_colorformat_from_ci_colorformat(vm.color_info.color_format) << 11
|
||||
timing_flags |= pg_colorimetry_from_ci_colorimetry(vm.color_info.colorimetry) << 16
|
||||
timing_flags |= pg_dynamicrange_from_ci_dynamicrange(vm.color_info.dynamic_range) << 31
|
||||
|
||||
return timing_flags
|
||||
109
UniTAP/dev/ports/modules/vtg/private_types.py
Normal file
109
UniTAP/dev/ports/modules/vtg/private_types.py
Normal file
@@ -0,0 +1,109 @@
|
||||
from ctypes import Structure, c_uint32, c_uint64
|
||||
from enum import IntEnum
|
||||
from typing import Union
|
||||
from .types import ASParams, ConstantASParams, PGAdaptiveSyncPatternType, SquareASParams, ZigzagASParams, FixedASParams
|
||||
from .pg_pattern_params import PGPatternParams, PGScrollingParams, SolidColorParams, WhiteVStripsParams, \
|
||||
GradientStripsParams, MotionParams, SquareWindowParams, StepsScrollingParams
|
||||
|
||||
|
||||
class PGPatternID(IntEnum):
|
||||
Disabled = 0
|
||||
ColorBars = 1
|
||||
Chessboard = 2
|
||||
SolidColor = 3
|
||||
SolidWhite = 4
|
||||
SolidRed = 5
|
||||
SolidGreen = 6
|
||||
SolidBlue = 7
|
||||
WhiteVStrips = 8
|
||||
GradientRGBStripes = 9
|
||||
ColorRamp = 10
|
||||
ColorSquares = 11
|
||||
Motion_Pattern = 12
|
||||
ImageFile = 13
|
||||
Playback = 14
|
||||
SquareWindow = 15
|
||||
DscImage = 16
|
||||
|
||||
|
||||
class PGPatternType(IntEnum):
|
||||
FPGA = 0
|
||||
NIOS = 1
|
||||
Image = 2
|
||||
Scalable = 3
|
||||
VTG = 4
|
||||
Software = 5
|
||||
|
||||
|
||||
class PgCaps(Structure):
|
||||
class PgCapsFlags(Structure):
|
||||
_fields_ = [
|
||||
("custom_vp", c_uint32, 1),
|
||||
("playback_vp", c_uint32, 1),
|
||||
("vrr_supported", c_uint32, 1),
|
||||
("color_modes_for_non_fw_pattern", c_uint32, 1),
|
||||
("cea_vesa_dynamic_range", c_uint32, 1),
|
||||
("dsc_supported", c_uint32, 1),
|
||||
("high_dynamic_range", c_uint32, 1),
|
||||
("adaptive_sync", c_uint32, 1),
|
||||
("scrolling_pattern", c_uint32, 1),
|
||||
("panel_replay", c_uint32, 1),
|
||||
("alpm", c_uint32, 1),
|
||||
("raw_y_only", c_uint32, 1),
|
||||
("psr", c_uint32, 1),
|
||||
('reserved', c_uint32, 19)
|
||||
]
|
||||
|
||||
_fields_ = [
|
||||
('max_h_active', c_uint32),
|
||||
('max_v_active', c_uint32),
|
||||
('max_frame', c_uint32),
|
||||
('flags', PgCapsFlags),
|
||||
('max_h_total', c_uint32),
|
||||
('max_v_total', c_uint32),
|
||||
('max_pix_rate', c_uint64),
|
||||
('patterns', c_uint32)
|
||||
]
|
||||
|
||||
|
||||
class CustomTimingFlags(Structure):
|
||||
_fields_ = [
|
||||
('color_depth', c_uint32, 8),
|
||||
('interlace', c_uint32, 1),
|
||||
('h_sync_polarity', c_uint32, 1),
|
||||
('v_sync_polarity', c_uint32, 1),
|
||||
('color_space', c_uint32, 4),
|
||||
('', c_uint32, 1),
|
||||
('colorimetry', c_uint32, 4),
|
||||
('', c_uint32, 10),
|
||||
('dynamic_range', c_uint32, 1)
|
||||
]
|
||||
|
||||
|
||||
def get_as_params_value(params: ASParams) -> list:
|
||||
if isinstance(params, ConstantASParams):
|
||||
return [PGAdaptiveSyncPatternType.AS_Constant.value, params.lines]
|
||||
elif isinstance(params, SquareASParams):
|
||||
return [PGAdaptiveSyncPatternType.AS_Square.value, params.min_lanes, params.max_lanes, params.period_frames]
|
||||
elif isinstance(params, ZigzagASParams):
|
||||
return [PGAdaptiveSyncPatternType.AS_Zigzag.value, params.min_lanes, params.max_lanes, params.increase_lines,
|
||||
params.decrease_lines]
|
||||
elif isinstance(params, FixedASParams):
|
||||
return [PGAdaptiveSyncPatternType.AS_Fixed.value, params.refresh_rate, params.divide_by_1_001,
|
||||
params.increase_lines, params.decrease_lines]
|
||||
|
||||
|
||||
def get_pattern_params_value(params: Union[PGPatternParams, PGScrollingParams], bpc: int = 8) -> list:
|
||||
if isinstance(params, SolidColorParams):
|
||||
up_shift = 16 - bpc
|
||||
return [(((params.first << up_shift) << 16) | (params.second << up_shift)), (params.third << up_shift)]
|
||||
elif isinstance(params, WhiteVStripsParams):
|
||||
return [params.white_stripes_width, params.black_stripes_width]
|
||||
elif isinstance(params, GradientStripsParams):
|
||||
return [params.color_step]
|
||||
elif isinstance(params, MotionParams):
|
||||
return [params.frames_count]
|
||||
elif isinstance(params, SquareWindowParams):
|
||||
return [params.white_square]
|
||||
elif isinstance(params, StepsScrollingParams):
|
||||
return [params.frames, params.horizontally, params.frames, params.vertically]
|
||||
135
UniTAP/dev/ports/modules/vtg/timing_manager.py
Normal file
135
UniTAP/dev/ports/modules/vtg/timing_manager.py
Normal file
@@ -0,0 +1,135 @@
|
||||
import copy
|
||||
from UniTAP.common import Timing
|
||||
from typing import Union, List, Optional
|
||||
|
||||
|
||||
class TimingManager:
|
||||
"""
|
||||
|
||||
Class `TimingManager` allows working with all available predefined timings from device.
|
||||
You can get cvt timing by index `get_cvt`, dmt timing by index `get_dmt`, cta timing by index `get_cta`,
|
||||
get list of all timing `get_all` ot search timing by parameters `search`.
|
||||
|
||||
"""
|
||||
def __init__(self, available_list: List[Timing]):
|
||||
self.__timings = available_list
|
||||
|
||||
def get_cvt(self, index: int) -> Optional[Timing]:
|
||||
"""
|
||||
|
||||
Returns cvt `Timing` by index.
|
||||
|
||||
Args:
|
||||
index (int): CVT timing index
|
||||
|
||||
Returns:
|
||||
timing (Timing | None) - type `Timing` if search was success, `None` if not.
|
||||
"""
|
||||
return copy.deepcopy(self.__search_by_standard_and_index(Timing.Standard.SD_CVT, index))
|
||||
|
||||
def get_dmt(self, index: int) -> Optional[Timing]:
|
||||
"""
|
||||
|
||||
Returns cvt `Timing` by index.
|
||||
|
||||
Args:
|
||||
index (int): DMT timing index
|
||||
|
||||
Returns:
|
||||
timing (Timing | None) - type `Timing` if search was success, `None` if not.
|
||||
"""
|
||||
return copy.deepcopy(self.__search_by_standard_and_index(Timing.Standard.SD_DMT, index))
|
||||
|
||||
def get_cta(self, index: int) -> Optional[Timing]:
|
||||
"""
|
||||
|
||||
Returns cvt `Timing` by index.
|
||||
|
||||
Args:
|
||||
index (int): CTA timing index
|
||||
|
||||
Returns:
|
||||
timing (Timing | None) - type `Timing` if search was success, `None` if not.
|
||||
"""
|
||||
return copy.deepcopy(self.__search_by_standard_and_index(Timing.Standard.SD_CTA, index))
|
||||
|
||||
def get_all(self) -> List[Timing]:
|
||||
"""
|
||||
|
||||
Returns list of `Timing` objects.
|
||||
|
||||
Returns:
|
||||
timing (list[Timing])
|
||||
"""
|
||||
return copy.deepcopy(self.__timings)
|
||||
|
||||
def get_by_list_index(self, index: int) -> Optional[Timing]:
|
||||
"""
|
||||
|
||||
Returns `Timing` objects by index in timings list.
|
||||
|
||||
Args:
|
||||
index (int) index of timing in list
|
||||
|
||||
Returns:
|
||||
timing (Timing)
|
||||
"""
|
||||
if index < 0 or index >= len(self.__timings):
|
||||
raise ValueError(f"Incorrect index {index} of timings. Must be between 0 and {len(self.__timings)}")
|
||||
return self.__timings[index]
|
||||
|
||||
def print_all(self) -> str:
|
||||
"""
|
||||
|
||||
Print list of `Timing` objects.
|
||||
|
||||
Returns:
|
||||
str
|
||||
"""
|
||||
return " \n".join(f'# {index} - '
|
||||
f'{item.standard.name.replace("SD_", "") if item.standard != Timing.Standard.SD_NONE else ""} '
|
||||
f'{item.hactive}x{item.vactive} @ {item.frame_rate / 1000}Hz'
|
||||
f'{self.__print_timing_id(item)}'
|
||||
for index, item in enumerate(self.__timings))
|
||||
|
||||
def search(self, h_active: Optional[int] = None, v_active: Optional[int] = None, f_rate: Optional[int] = None,
|
||||
standard: Optional[Timing.Standard] = None,
|
||||
rb: Optional[Timing.ReduceBlanking] = None) -> Optional[Timing]:
|
||||
"""
|
||||
|
||||
Search timing by transferred parameters.
|
||||
|
||||
Args:
|
||||
h_active (int | None): h active resolution of timing
|
||||
v_active (int | None): v active resolution of timing
|
||||
f_rate (int | None): frame rate of timing
|
||||
standard (Standard | None): timing `Standard`
|
||||
rb (ReduceBlanking | None): timing `ReduceBlanking`
|
||||
|
||||
Returns:
|
||||
timing (Timing | None) - type `Timing` if search was success, `None` if not.
|
||||
"""
|
||||
for timing in self.__timings:
|
||||
if (timing.hactive == h_active or h_active is None) and (timing.vactive == v_active or v_active is None)\
|
||||
and (f_rate is None or abs(timing.frame_rate - f_rate) <= 500) \
|
||||
and (timing.standard == standard or standard is None) \
|
||||
and (timing.reduce_blanking == rb or rb is None):
|
||||
return copy.deepcopy(timing)
|
||||
|
||||
def __search_by_standard_and_index(self, sd: Timing.Standard, index: int) -> Union[Timing, None]:
|
||||
search_result = [
|
||||
t for t in self.__timings if t.id == index and t.standard == sd
|
||||
]
|
||||
return None if len(search_result) == 0 else search_result[0]
|
||||
|
||||
@staticmethod
|
||||
def __print_timing_id(timing: Timing) -> str:
|
||||
if timing.standard == Timing.Standard.SD_CTA:
|
||||
return f" (VIC {timing.id})"
|
||||
elif timing.standard == Timing.Standard.SD_DMT:
|
||||
return f" (ID {hex(timing.id).replace('0x', '').upper()}h)" \
|
||||
f"{f' [{timing.reduce_blanking.name}]' if timing.reduce_blanking != Timing.ReduceBlanking.RB_NONE else ''}"
|
||||
elif timing.standard == Timing.Standard.SD_CVT:
|
||||
return f" {f'[{timing.reduce_blanking.name}]' if timing.reduce_blanking != Timing.ReduceBlanking.RB_NONE else ''}"
|
||||
else:
|
||||
return ""
|
||||
208
UniTAP/dev/ports/modules/vtg/types.py
Normal file
208
UniTAP/dev/ports/modules/vtg/types.py
Normal file
@@ -0,0 +1,208 @@
|
||||
import warnings
|
||||
from enum import IntEnum
|
||||
from typing import TypeVar
|
||||
|
||||
|
||||
class VideoPattern(IntEnum):
|
||||
"""
|
||||
Class `VideoPattern` contains all possible variants of patterns which can be set in the function `set_pattern`.
|
||||
"""
|
||||
Disabled = 0
|
||||
ColorBars = 1
|
||||
Chessboard = 2
|
||||
SolidColor = 3
|
||||
SolidWhite = 4
|
||||
SolidRed = 5
|
||||
SolidGreen = 6
|
||||
SolidBlue = 7
|
||||
WhiteVStrips = 8
|
||||
GradientRGBStripes = 9
|
||||
ColorRamp = 10
|
||||
ColorSquares = 11
|
||||
MotionPattern = 12
|
||||
SquareWindow = 15
|
||||
|
||||
|
||||
class PGDynamicRange(IntEnum):
|
||||
"""
|
||||
Class `PGDynamicRange` contains all possible variants of Dynamic Range.
|
||||
"""
|
||||
VESA = 0x00
|
||||
CTA = 0x01
|
||||
|
||||
|
||||
class PGStandard(IntEnum):
|
||||
"""
|
||||
Class `PGStandard` contains all possible variants of Standard.
|
||||
"""
|
||||
CVT = 0x01
|
||||
DMT = 0x02
|
||||
CTA = 0x03
|
||||
|
||||
|
||||
class PGVideoMode(IntEnum):
|
||||
"""
|
||||
Class `PGVideoMode` contains all possible variants of Video mode.
|
||||
"""
|
||||
CTA = 0x00
|
||||
RB1 = 0x01
|
||||
RB2 = 0x02
|
||||
RB3 = 0x03
|
||||
|
||||
|
||||
class PGAspectRatio(IntEnum):
|
||||
"""
|
||||
Class `PGVideoMode` contains all possible variants of Aspect ratio.
|
||||
"""
|
||||
NoData = 0x00
|
||||
Ratio4x3 = 0x01
|
||||
Ratio16x9 = 0x02
|
||||
|
||||
|
||||
class PGColorInfo(IntEnum):
|
||||
"""
|
||||
Class `PGColorInfo` contains all possible variants of Color info.
|
||||
"""
|
||||
Unknown = -1
|
||||
RGB = 0
|
||||
YCbCr444 = 1
|
||||
YCbCr422 = 2
|
||||
YCbCr420 = 3
|
||||
Y_only = 4
|
||||
RAW = 5
|
||||
|
||||
|
||||
class PGColorimetry(IntEnum):
|
||||
"""
|
||||
Class `PGColorimetry` contains all possible variants of Colorimetry.
|
||||
"""
|
||||
Unknown = 0
|
||||
ITU601 = 0
|
||||
ITU709 = 1
|
||||
|
||||
|
||||
class PGColorDepth(IntEnum):
|
||||
"""
|
||||
Class `PGColorDepth` contains all possible variants of Color Depth.
|
||||
"""
|
||||
Unknown = -1
|
||||
BPC6 = 0
|
||||
BPC8 = 1
|
||||
BPC10 = 2
|
||||
BPC12 = 3
|
||||
BPC16 = 4
|
||||
BPC7 = 5
|
||||
BPC14 = 6
|
||||
|
||||
|
||||
class PGAdaptiveSyncPatternType(IntEnum):
|
||||
"""
|
||||
Class `PGAdaptiveSyncPatternType` contains all possible variants of Adaptive Sync Pattern.
|
||||
"""
|
||||
AS_None = 0
|
||||
AS_Constant = 1
|
||||
AS_Square = 2
|
||||
AS_Zigzag = 3
|
||||
AS_Fixed = 4
|
||||
|
||||
|
||||
class ConstantASParams:
|
||||
"""
|
||||
Special configuration class for configure Adaptive-Sync. Contains information about blank lines count.
|
||||
"""
|
||||
def __init__(self, lines: int = 0):
|
||||
if lines < 0:
|
||||
warnings.warn("Incorrect blank lines count. Must use more then 0. "
|
||||
"Will be used default value = 0")
|
||||
lines = 0
|
||||
self.lines = lines
|
||||
|
||||
|
||||
class SquareASParams:
|
||||
|
||||
"""
|
||||
Special configuration class for configure Adaptive-Sync. Contains information about blank lines minimum and maximum
|
||||
count and period frames count.
|
||||
"""
|
||||
|
||||
def __init__(self, min_lanes: int = 0, max_lanes: int = 1000, period_frames: int = 10):
|
||||
if min_lanes < 0:
|
||||
warnings.warn("Incorrect blank lines min count. Must use more then 0. "
|
||||
"Will be used default value = 0")
|
||||
min_lanes = 0
|
||||
if max_lanes < 0:
|
||||
warnings.warn("Incorrect blank lines max count. Must use more then 0. "
|
||||
"Will be used default value = 1000")
|
||||
max_lanes = 1000
|
||||
if period_frames < 0:
|
||||
warnings.warn("Incorrect period frames count. Must use more then 0. "
|
||||
"Will be used default value = 10")
|
||||
period_frames = 10
|
||||
self.min_lanes = min_lanes
|
||||
self.max_lanes = max_lanes
|
||||
self.period_frames = period_frames
|
||||
|
||||
|
||||
class ZigzagASParams:
|
||||
|
||||
"""
|
||||
Special configuration class for configure Adaptive-Sync. Contains information about blank lines minimum and maximum
|
||||
count, increase and decrease lanes count.
|
||||
"""
|
||||
|
||||
def __init__(self, min_lanes: int = 0, max_lanes: int = 1000, increase_lines: int = 100, decrease_lines: int = 100):
|
||||
if min_lanes < 0:
|
||||
warnings.warn("Incorrect blank lines min count. Must use more then 0. "
|
||||
"Will be used default value = 0")
|
||||
min_lanes = 0
|
||||
if max_lanes < 0:
|
||||
warnings.warn("Incorrect blank lines max count. Must use more then 0. "
|
||||
"Will be used default value = 1000")
|
||||
max_lanes = 1000
|
||||
if increase_lines < 0:
|
||||
warnings.warn("Incorrect increase lines count. Must use more then 0. "
|
||||
"Will be used default value = 100")
|
||||
increase_lines = 100
|
||||
if decrease_lines < 0:
|
||||
warnings.warn("Incorrect decrease lines count. Must use more then 0. "
|
||||
"Will be used default value = 100")
|
||||
decrease_lines = 100
|
||||
self.min_lanes = min_lanes
|
||||
self.max_lanes = max_lanes
|
||||
self.increase_lines = increase_lines
|
||||
self.decrease_lines = decrease_lines
|
||||
|
||||
|
||||
class FixedASParams:
|
||||
|
||||
"""
|
||||
Special configuration class for configure Adaptive-Sync. Contains information about refresh rate count, increase
|
||||
and decrease lanes count.
|
||||
"""
|
||||
|
||||
def __init__(self, refresh_rate: int = 60, divide_by_1_001: bool = False, increase_lines: int = 100,
|
||||
decrease_lines: int = 100):
|
||||
if refresh_rate < 0:
|
||||
warnings.warn("Incorrect refresh rate count. Must use more then 0. "
|
||||
"Will be used default value = 60")
|
||||
refresh_rate = 60
|
||||
if increase_lines < 0:
|
||||
warnings.warn("Incorrect increase lines count. Must use more then 0. "
|
||||
"Will be used default value = 100")
|
||||
increase_lines = 100
|
||||
if decrease_lines < 0:
|
||||
warnings.warn("Incorrect decrease lines count. Must use more then 0. "
|
||||
"Will be used default value = 100")
|
||||
decrease_lines = 100
|
||||
self.refresh_rate = refresh_rate
|
||||
self.divide_by_1_001 = int(divide_by_1_001)
|
||||
self.increase_lines = increase_lines
|
||||
self.decrease_lines = decrease_lines
|
||||
|
||||
|
||||
ASParams = TypeVar("ASParams",
|
||||
ConstantASParams,
|
||||
SquareASParams,
|
||||
ZigzagASParams,
|
||||
FixedASParams,
|
||||
)
|
||||
Reference in New Issue
Block a user