# Copyright (c) 2018, Xilinx, Inc.
# SPDX-License-Identifier: BSD-3-Clause
from pynq import DefaultIP
from .common import *
[docs]class ColorConverter(DefaultIP):
"""Driver for the color space converter
The colorspace convert implements a 3x4 matrix for performing arbitrary
linear color conversions. Each coefficient is represented as a 10 bit
signed fixed point number with 2 integer bits. The result of the
computation can visualised as a table
# in1 in2 in3 1
# out1 c1 c2 c3 c10
# out2 c4 c5 c6 c11
# out3 c7 c8 c9 c12
The color can be changed mid-stream.
Attributes
----------
colorspace : list of float
The coefficients of the colorspace conversion
"""
def __init__(self, description):
"""Construct an instance of the driver
Attributes
----------
description : dict
IP dict entry for the IP core
"""
super().__init__(description)
bindto = ["xilinx.com:hls:color_convert:1.0", "xilinx.com:hls:color_convert_2:1.0"]
@staticmethod
def _signextend(value):
"""Sign extend a 10-bit number
Derived from https://stackoverflow.com/questions/32030412/
twos-complement-sign-extension-python
"""
return (value & 0x1FF) - (value & 0x200)
@property
def colorspace(self):
"""The colorspace to convert. See the class description for
details of the coefficients. The coefficients are a list of
floats of length 12
"""
return [
ColorConverter._signextend(self.read(0x10 + 8 * i)) / 256 for i in range(12)
]
@colorspace.setter
def colorspace(self, color):
if len(color) != 12:
raise ValueError("Wrong number of elements in color specification")
for i, c in enumerate(color):
self.write(0x10 + 8 * i, int(c * 256))
[docs]class PixelPacker(DefaultIP):
"""Driver for the pixel format convert
Changes the number of bits per pixel in the video stream. The stream
should be paused prior to the width being changed. This can be targeted
at either a pixel_pack or a pixel_unpack IP core.For a packer the input
is always 24 bits per pixel while for an unpacker the output 24 bits per
pixel.
"""
def __init__(self, description):
"""Construct an instance of the driver
Attributes
----------
description : dict
IP dict entry for the IP core
"""
super().__init__(description)
self._bpp = 24
self.write(0x10, 0)
self._resample = False
bindto = [
"xilinx.com:hls:pixel_pack:1.0",
"xilinx.com:hls:pixel_unpack:1.0",
"xilinx.com:hls:pixel_pack_2:1.0",
"xilinx.com:hls:pixel_unpack_2:1.0",
]
@property
def bits_per_pixel(self):
"""Number of bits per pixel in the stream
Valid values are 8, 24 and 32. The following table describes the
operation for packing and unpacking for each width
Mode Pack Unpack
8 bpp Keep only the first channel Pad other channels with 0
16 bpp Dependent on resample Dependent on resample
24 bpp No change No change
32 bpp Pad channel 4 with 0 Discard channel 4
"""
mode = self.read(0x10)
if mode == 0:
return 24
elif mode == 1:
return 32
elif mode == 2:
return 8
elif mode <= 4:
return 16
@bits_per_pixel.setter
def bits_per_pixel(self, value):
if value == 24:
mode = 0
elif value == 32:
mode = 1
elif value == 8:
mode = 2
elif value == 16:
if self._resample:
mode = 4
else:
mode = 3
else:
raise ValueError("Bits per pixel must be 8, 16, 24 or 32")
self._bpp = value
self.write(0x10, mode)
@property
def resample(self):
"""Perform chroma resampling in 16 bpp mode
Boolean property that only affects 16 bpp mode. If True then
the two chroma channels are multiplexed on to the second output
pixel, otherwise only the first and second channels are transferred
and the third is discarded
"""
return self._resample
@resample.setter
def resample(self, value):
self._resample = value
# Make sure the mode is updated
if self.bits_per_pixel == 16:
self.bits_per_pixel = 16