Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
hdl/csc: add ycbcr422to444 and ycbcr444to422
  • Loading branch information
enjoy-digital committed Aug 11, 2015
1 parent 8c238f5 commit b868b68
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 10 deletions.
5 changes: 4 additions & 1 deletion hdl/csc/common.py
Expand Up @@ -21,5 +21,8 @@ def rgb_layout(dw):
return [("r", dw), ("g", dw), ("b", dw)]


def ycbcr_layout(dw):
def ycbcr444_layout(dw):
return [("y", dw), ("cb", dw), ("cr", dw)]

def ycbcr422_layout(dw):
return [("y", dw), ("cb_cr", dw)]
4 changes: 2 additions & 2 deletions hdl/csc/rgb2ycbcr.py
Expand Up @@ -31,7 +31,7 @@ def rgb2ycbcr_coefs(dw, cw=None):
class RGB2YCbCrDatapath(Module):
def __init__(self, rgb_w, ycbcr_w, coef_w):
self.sink = sink = Record(rgb_layout(rgb_w))
self.source = source = Record(ycbcr_layout(ycbcr_w))
self.source = source = Record(ycbcr444_layout(ycbcr_w))

# # #

Expand Down Expand Up @@ -132,7 +132,7 @@ def __init__(self, rgb_w, ycbcr_w, coef_w):
class RGB2YCbCr(PipelinedActor, Module):
def __init__(self, rgb_w=8, ycbcr_w=8, coef_w=8):
self.sink = sink = Sink(EndpointDescription(rgb_layout(rgb_w), packetized=True))
self.source = source = Source(EndpointDescription(ycbcr_layout(ycbcr_w), packetized=True))
self.source = source = Source(EndpointDescription(ycbcr444_layout(ycbcr_w), packetized=True))
PipelinedActor.__init__(self, datapath_latency)
self.latency = datapath_latency

Expand Down
3 changes: 3 additions & 0 deletions hdl/csc/test/Makefile
Expand Up @@ -8,3 +8,6 @@ rgb2ycbcr_tb:

ycbcr2rgb_tb:
$(CMD) ycbcr2rgb_tb.py

ycbcr_resampling_tb:
$(CMD) ycbcr_resampling_tb.py
4 changes: 2 additions & 2 deletions hdl/csc/test/rgb2ycbcr_tb.py
Expand Up @@ -38,7 +38,7 @@ def gen_simulation(self, selfp):
raw_image = RAWImage(rgb2ycbcr_coefs(8), "lena.png", 64)
raw_image.rgb2ycbcr_model()
raw_image.ycbcr2rgb()
raw_image.save("lena_reference.png")
raw_image.save("lena_rgb2ycbcr_reference.png")

for i in range(16):
yield
Expand All @@ -52,7 +52,7 @@ def gen_simulation(self, selfp):
raw_image.set_data(self.logger.packet)
raw_image.unpack_ycbcr()
raw_image.ycbcr2rgb()
raw_image.save("lena_implementation.png")
raw_image.save("lena_rgb2ycbcr.png")

if __name__ == "__main__":
run_simulation(TB(), ncycles=8192, vcd_name="my.vcd", keep_files=True)
4 changes: 2 additions & 2 deletions hdl/csc/test/ycbcr2rgb_tb.py
Expand Up @@ -36,7 +36,7 @@ def gen_simulation(self, selfp):
raw_image = RAWImage(ycbcr2rgb_coefs(8), "lena.png", 64)
raw_image.rgb2ycbcr()
raw_image.ycbcr2rgb_model()
raw_image.save("lena_reference.png")
raw_image.save("lena_ycbcr2rgb_reference.png")

for i in range(16):
yield
Expand All @@ -50,7 +50,7 @@ def gen_simulation(self, selfp):
yield from self.logger.receive()
raw_image.set_data(self.logger.packet)
raw_image.unpack_rgb()
raw_image.save("lena_implementation.png")
raw_image.save("lena_ycbcr2rgb.png")


if __name__ == "__main__":
Expand Down
57 changes: 57 additions & 0 deletions hdl/csc/test/ycbcr_resampling_tb.py
@@ -0,0 +1,57 @@
from migen.fhdl.std import *
from migen.sim.generic import run_simulation
from migen.flow.actor import EndpointDescription

from hdl.csc.common import *
from hdl.csc.ycbcr444to422 import YCbCr444to422
from hdl.csc.ycbcr422to444 import YCbCr422to444

from hdl.csc.test.common import *


class TB(Module):
def __init__(self):
self.submodules.streamer = PacketStreamer(EndpointDescription([("data", 24)], packetized=True))
self.submodules.ycbcr444to422 = YCbCr444to422()
self.submodules.ycbcr422to444 = YCbCr422to444()
self.submodules.logger = PacketLogger(EndpointDescription([("data", 24)], packetized=True))

self.comb += [
self.ycbcr444to422.sink.stb.eq(self.streamer.source.stb),
self.ycbcr444to422.sink.sop.eq(self.streamer.source.sop),
self.ycbcr444to422.sink.eop.eq(self.streamer.source.eop),
self.ycbcr444to422.sink.payload.y.eq(self.streamer.source.data[16:24]),
self.ycbcr444to422.sink.payload.cb.eq(self.streamer.source.data[8:16]),
self.ycbcr444to422.sink.payload.cr.eq(self.streamer.source.data[0:8]),
self.streamer.source.ack.eq(self.ycbcr444to422.sink.ack),

Record.connect(self.ycbcr444to422.source, self.ycbcr422to444.sink),

self.logger.sink.stb.eq(self.ycbcr422to444.source.stb),
self.logger.sink.sop.eq(self.ycbcr422to444.source.sop),
self.logger.sink.eop.eq(self.ycbcr422to444.source.eop),
self.logger.sink.data[16:24].eq(self.ycbcr422to444.source.y),
self.logger.sink.data[8:16].eq(self.ycbcr422to444.source.cb),
self.logger.sink.data[0:8].eq(self.ycbcr422to444.source.cr),
self.ycbcr422to444.source.ack.eq(self.logger.sink.ack)
]


def gen_simulation(self, selfp):
for i in range(16):
yield

# chain ycbcr444to422 and ycbcr422to444
raw_image = RAWImage(None, "lena.png", 64)
raw_image.rgb2ycbcr()
raw_image.pack_ycbcr()
packet = Packet(raw_image.data)
self.streamer.send(packet)
yield from self.logger.receive()
raw_image.set_data(self.logger.packet)
raw_image.unpack_ycbcr()
raw_image.ycbcr2rgb()
raw_image.save("lena_resampling.png")

if __name__ == "__main__":
run_simulation(TB(), ncycles=8192, vcd_name="my.vcd", keep_files=True)
6 changes: 3 additions & 3 deletions hdl/csc/ycbcr2rgb.py
Expand Up @@ -35,7 +35,7 @@ def ycbcr2rgb_coefs(dw, cw=None):
@DecorateModule(InsertCE)
class YCbCr2RGBDatapath(Module):
def __init__(self, ycbcr_w, rgb_w, coef_w):
self.sink = sink = Record(ycbcr_layout(ycbcr_w))
self.sink = sink = Record(ycbcr444_layout(ycbcr_w))
self.source = source = Record(rgb_layout(rgb_w))

# # #
Expand All @@ -45,7 +45,7 @@ def __init__(self, ycbcr_w, rgb_w, coef_w):
# delay ycbcr signals
ycbcr_delayed = [sink]
for i in range(datapath_latency):
ycbcr_n = Record(ycbcr_layout(ycbcr_w))
ycbcr_n = Record(ycbcr444_layout(ycbcr_w))
for name in ["y", "cb", "cr"]:
self.sync += getattr(ycbcr_n, name).eq(getattr(ycbcr_delayed[-1], name))
ycbcr_delayed.append(ycbcr_n)
Expand Down Expand Up @@ -106,7 +106,7 @@ def __init__(self, ycbcr_w, rgb_w, coef_w):

class YCbCr2RGB(PipelinedActor, Module):
def __init__(self, ycbcr_w=8, rgb_w=8, coef_w=8):
self.sink = sink = Sink(EndpointDescription(ycbcr_layout(ycbcr_w), packetized=True))
self.sink = sink = Sink(EndpointDescription(ycbcr444_layout(ycbcr_w), packetized=True))
self.source = source = Source(EndpointDescription(rgb_layout(rgb_w), packetized=True))
PipelinedActor.__init__(self, datapath_latency)
self.latency = datapath_latency
Expand Down
66 changes: 66 additions & 0 deletions hdl/csc/ycbcr422to444.py
@@ -0,0 +1,66 @@
# ycbcr422to444

from migen.fhdl.std import *
from migen.genlib.record import *
from migen.flow.actor import *

from hdl.csc.common import *

datapath_latency = 2

@DecorateModule(InsertCE)
class YCbCr422to444Datapath(Module):
"""YCbCr 422 to 444
Input: Output:
Y0 Y1 Y2 Y3 Y0 Y1 Y2 Y3
Cb01 Cr01 Cb23 Cr23 --> Cb01 Cb01 Cb23 Cb23
Cr01 Cr01 Cr23 Cr23
"""
def __init__(self, dw):
self.sink = sink = Record(ycbcr422_layout(dw))
self.source = source = Record(ycbcr444_layout(dw))
self.start = Signal()

# # #

# delay ycbcr signals
ycbcr_delayed = [sink]
for i in range(datapath_latency):
ycbcr_n = Record(ycbcr422_layout(dw))
for name in ["y", "cb_cr"]:
self.sync += getattr(ycbcr_n, name).eq(getattr(ycbcr_delayed[-1], name))
ycbcr_delayed.append(ycbcr_n)

# parity
parity = Signal()
self.sync += If(self.start, parity.eq(1)).Else(parity.eq(~parity))

# output
self.sync += [
If(parity,
self.source.y.eq(ycbcr_delayed[1].y),
self.source.cb.eq(ycbcr_delayed[1].cb_cr),
self.source.cr.eq(sink.cb_cr),
).Else(
self.source.y.eq(ycbcr_delayed[1].y),
self.source.cb.eq(ycbcr_delayed[2].cb_cr),
self.source.cr.eq(ycbcr_delayed[1].cb_cr)
)
]

class YCbCr422to444(PipelinedActor, Module):
def __init__(self, dw=8):
self.sink = sink = Sink(EndpointDescription(ycbcr422_layout(dw), packetized=True))
self.source = source = Source(EndpointDescription(ycbcr444_layout(dw), packetized=True))
PipelinedActor.__init__(self, datapath_latency)
self.latency = datapath_latency

# # #

self.submodules.datapath = YCbCr422to444Datapath(dw)
self.comb += self.datapath.ce.eq(self.pipe_ce)
for name in ["y", "cb_cr"]:
self.comb += getattr(self.datapath.sink, name).eq(getattr(sink, name))
for name in ["y", "cb", "cr"]:
self.comb += getattr(source, name).eq(getattr(self.datapath.source, name))
86 changes: 86 additions & 0 deletions hdl/csc/ycbcr444to422.py
@@ -0,0 +1,86 @@
# ycbcr444to422

from migen.fhdl.std import *
from migen.genlib.record import *
from migen.flow.actor import *

from hdl.csc.common import *

datapath_latency = 3

@DecorateModule(InsertCE)
class YCbCr444to422Datapath(Module):
"""YCbCr 444 to 422
Input: Output:
Y0 Y1 Y2 Y3 Y0 Y1 Y2 Y3
Cb0 Cb1 Cb2 Cb3 --> Cb01 Cr01 Cb23 Cr23
Cr0 Cr1 Cr2 Cr3
"""
def __init__(self, dw):
self.sink = sink = Record(ycbcr444_layout(dw))
self.source = source = Record(ycbcr422_layout(dw))
self.start = Signal()

# # #

# delay data signals
ycbcr_delayed = [sink]
for i in range(datapath_latency):
ycbcr_n = Record(ycbcr444_layout(dw))
for name in ["y", "cb", "cr"]:
self.sync += getattr(ycbcr_n, name).eq(getattr(ycbcr_delayed[-1], name))
ycbcr_delayed.append(ycbcr_n)

# parity
parity = Signal()
self.sync += If(self.start, parity.eq(1)).Else(parity.eq(~parity))

# compute mean of cb and cr compoments
cb_sum = Signal(dw+1)
cr_sum = Signal(dw+1)
cb_mean = Signal(dw)
cr_mean = Signal(dw)

self.comb += [
cb_mean.eq(cb_sum[1:]),
cr_mean.eq(cr_sum[1:])
]

self.sync += [
If(parity,
cb_sum.eq(sink.cb + ycbcr_delayed[1].cb),
cr_sum.eq(sink.cr + ycbcr_delayed[1].cr)
)
]

# output
self.sync += [
If(parity,
self.source.y.eq(ycbcr_delayed[2].y),
self.source.cb_cr.eq(cr_mean)
).Else(
self.source.y.eq(ycbcr_delayed[2].y),
self.source.cb_cr.eq(cb_mean)
)
]


class YCbCr444to422(PipelinedActor, Module):
def __init__(self, dw=8):
self.sink = sink = Sink(EndpointDescription(ycbcr444_layout(dw), packetized=True))
self.source = source = Source(EndpointDescription(ycbcr422_layout(dw), packetized=True))
PipelinedActor.__init__(self, datapath_latency)
self.latency = datapath_latency

# # #

self.submodules.datapath = YCbCr444to422Datapath(dw)
self.comb += [
self.datapath.start.eq(self.sink.stb & sink.sop),
self.datapath.ce.eq(self.pipe_ce),
]
for name in ["y", "cb", "cr"]:
self.comb += getattr(self.datapath.sink, name).eq(getattr(sink, name))
for name in ["y", "cb_cr"]:
self.comb += getattr(source, name).eq(getattr(self.datapath.source, name))

0 comments on commit b868b68

Please sign in to comment.