m1n1/proxyclient/experiments/jpeg.py

1223 lines
43 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
import sys, pathlib
sys.path.append(str(pathlib.Path(__file__).resolve().parents[1]))
from m1n1.setup import *
from m1n1.hw.dart import DART, DARTRegs
from m1n1.hw.jpeg import *
from m1n1.utils import *
import argparse
import struct
import time
from enum import IntEnum
from PIL import Image, ImageDraw
def divroundup(val, div):
return (val + div - 1) // div
def yuv2rgb(y, u, v):
y -= 16
u -= 128
v -= 128
y /= 255
u /= 255
v /= 255
r = y + 1.13983 * v
g = y - 0.39465 * u - 0.58060 * v
b = y + 2.03211 * u
r = min(255, max(0, int(r * 255)))
g = min(255, max(0, int(g * 255)))
b = min(255, max(0, int(b * 255)))
return (r, g, b)
def rgb2yuv(r, g, b):
r /= 255
g /= 255
b /= 255
y = 0.299*r + 0.587*g + 0.114*b
u = -0.14713*r - 0.28886*g + 0.436*b
v = 0.615*r - 0.51499*g - 0.10001*b
y = y * 255 + 16
u = u * 255 + 128
v = v * 255 + 128
y = min(255, max(0, int(y)))
u = min(255, max(0, int(u)))
v = min(255, max(0, int(v)))
return (y, u, v)
ap = argparse.ArgumentParser(description='JPEG block experiment')
ap.add_argument("--jpeg", dest='which_jpeg', type=str, default='jpeg0',
help='which JPEG instance (jpeg0/jpeg1)')
g = ap.add_mutually_exclusive_group(required=True)
g.add_argument("-e", "--encode", action='store_true')
g.add_argument("-d", "--decode", action='store_true')
ap.add_argument("--raw-output", type=str, required=False)
ap.add_argument("--decode-scale", type=int, required=False, default=1)
ap.add_argument("--decode-pixelfmt", type=str, required=False, default='RGBA')
ap.add_argument("--decode-rgba-alpha", type=int, required=False, default=255)
ap.add_argument("--encode-subsampling", type=str, required=False, default='444')
ap.add_argument("--encode-rst-interval", type=int, required=False)
ap.add_argument("--encode-pixelfmt", type=str, required=False, default='RGB888')
ap.add_argument("input", type=str)
ap.add_argument("output", type=str)
args = ap.parse_args()
# print(args)
# Perform necessary pre-parsing
if args.decode:
assert args.decode_scale in [1, 2, 4, 8]
decode_scale = args.decode_scale
# FIXME: verify behavior on non-evenly-divisible sizes
assert args.decode_pixelfmt in [
'RGBA',
'BGRA',
'RGB565',
'YUV422-CbYCrY',
'YUV422-YCbYCr',
'YUV422-planar',
'YUV420-planar',
'YUV444-planar',
]
pixfmt = args.decode_pixelfmt
with open(args.input, 'rb') as f:
jpeg_data = f.read()
found_sof0 = False
jpeg_work = jpeg_data
while jpeg_work:
seg_marker = struct.unpack(">H", jpeg_work[:2])[0]
print(f"Seg {seg_marker:04X}")
if seg_marker == 0xFFD8:
# SOI
jpeg_work = jpeg_work[2:]
elif seg_marker == 0xFFDA:
# SOS
break
else:
seg_len = struct.unpack(">H", jpeg_work[2:4])[0]
assert seg_len >= 2
seg_data = jpeg_work[4:4 + seg_len - 2]
jpeg_work = jpeg_work[4 + seg_len - 2:]
if seg_marker == 0xFFC0:
# SOF0
assert not found_sof0
found_sof0 = True
sof0 = struct.unpack(">BHHB", seg_data[:6])
(jpeg_bpp, jpeg_H, jpeg_W, jpeg_components_cnt) = sof0
# it is not yet verified what the requirements are for inputs
assert jpeg_bpp == 8
assert jpeg_components_cnt == 1 or jpeg_components_cnt == 3
if jpeg_components_cnt == 1:
jpeg_MODE = '400'
else:
jpeg_components = {}
for i in range(jpeg_components_cnt):
comp_id, comp_sampling, _ = seg_data[6+3*i:6+3*(i+1)]
jpeg_components[comp_id] = comp_sampling
assert 1 in jpeg_components
comp_Y = jpeg_components[1]
assert 2 in jpeg_components
comp_Cb = jpeg_components[2]
assert 3 in jpeg_components
comp_Cr = jpeg_components[3]
if (comp_Y, comp_Cb, comp_Cr) == (0x11, 0x11, 0x11):
jpeg_MODE = '444'
elif (comp_Y, comp_Cb, comp_Cr) == (0x21, 0x11, 0x11):
jpeg_MODE = '422'
elif (comp_Y, comp_Cb, comp_Cr) == (0x22, 0x11, 0x11):
jpeg_MODE = '420'
elif (comp_Y, comp_Cb, comp_Cr) == (0x41, 0x11, 0x11):
jpeg_MODE = '411'
else:
# TODO: 422-vertical, others???
# Is it possible to implement them?
print("Unsupported subsampling mode")
assert False
assert found_sof0
print(f"JPEG is {jpeg_W}x{jpeg_H} with subsampling {jpeg_MODE}")
if jpeg_MODE == '444' or jpeg_MODE == '400':
macroblock_W, macroblock_H = 8, 8
elif jpeg_MODE == '422':
macroblock_W, macroblock_H = 16, 8
elif jpeg_MODE == '420':
macroblock_W, macroblock_H = 16, 16
elif jpeg_MODE == '411':
macroblock_W, macroblock_H = 32, 8
else:
assert False
# FIXME: Exactly how much extra memory do we need to allocate?
surface_W = divroundup(jpeg_W // decode_scale, macroblock_W) * macroblock_W
surface_H = divroundup(jpeg_H // decode_scale, macroblock_H) * macroblock_H
if pixfmt in ['RGBA', 'BGRA']:
BYTESPP = 4
elif pixfmt in ['RGB565', 'YUV422-CbYCrY', 'YUV422-YCbYCr']:
BYTESPP = 2
elif pixfmt in ['YUV422-planar', 'YUV420-planar', 'YUV444-planar']:
BYTESPP = 1
else:
assert False
surface_stride = surface_W * BYTESPP
surface_sz = surface_stride*surface_H
if pixfmt == 'YUV422-planar':
P1_MULW = 1 # FIXME UGLY
P1_DIVW = 1
P1_DIVH = 1
elif pixfmt == 'YUV420-planar':
P1_MULW = 1
P1_DIVW = 1
P1_DIVH = 2
elif pixfmt == 'YUV444-planar':
P1_MULW = 2
P1_DIVW = 1
P1_DIVH = 1
if pixfmt in ['YUV422-planar', 'YUV420-planar', 'YUV444-planar']:
surface_P1_W = surface_W * P1_MULW // P1_DIVW
surface_P1_H = surface_H // P1_DIVH
surface_P1_stride = surface_P1_W
surface_P1_off = surface_sz
surface_sz += surface_P1_stride*surface_P1_H
else:
surface_P1_stride = 0
surface_P1_off = 0
input_mem_sz = align_up(len(jpeg_data))
print(f"Using size {input_mem_sz:08X} for JPEG data")
output_mem_sz = align_up(surface_sz)
print(f"Using size {output_mem_sz:08X} for output image")
else:
assert args.encode_subsampling in ['444', '422', '420', '400']
if args.encode_subsampling == '444' or args.encode_subsampling == '400':
macroblock_W, macroblock_H = 8, 8
elif args.encode_subsampling == '422':
macroblock_W, macroblock_H = 16, 8
elif args.encode_subsampling == '420':
macroblock_W, macroblock_H = 16, 16
else:
assert False
assert args.encode_pixelfmt in [
'RGB888',
'RGB101010',
'RGB565',
'YUV10',
'YUV-linear',
'YUV444-planar',
'YUV422-planar',
'YUV420-planar',
]
pixfmt = args.encode_pixelfmt
# Driver doesn't support this either
if pixfmt == 'YUV-linear' and args.encode_subsampling == '444':
print("WARNING: This combination does not appear to work!!!")
if pixfmt == 'YUV422-planar' and args.encode_subsampling == '444':
print("WARNING: This combination does not appear to work!!!")
if pixfmt == 'YUV420-planar' and args.encode_subsampling == '444':
print("WARNING: This combination does not appear to work!!!")
image_data = b''
image_data_P1 = b''
with Image.open(args.input) as im:
im_W, im_H = im.size
if pixfmt != 'YUV420-planar':
for y in range(im_H):
for x in range(im_W):
r, g, b = im.getpixel((x, y))
if pixfmt == 'RGB888':
image_data += struct.pack("BBBB", r, g, b, 255)
elif pixfmt == 'RGB101010':
image_data += struct.pack("<I", (r << 2) | (g << 12) | (b << 22))
elif pixfmt == 'RGB565':
image_data += struct.pack("<H", (r >> 3) | ((g >> 2) << 5) | ((b >> 3) << 11))
elif pixfmt == 'YUV10':
# absolute garbage color space conversion
# for demonstration purposes only
y_, u_, v_ = rgb2yuv(r, g, b)
image_data += struct.pack("<I", (y_ << 2) | (u_ << 12) | (v_ << 22))
elif pixfmt == 'YUV-linear':
# garbage color space conversion, garbage subsampling
# for demonstration purposes only
y_, u_, v_ = rgb2yuv(r, g, b)
if x & 1 == 0:
color = u_
else:
color = v_
image_data += struct.pack("BB", y_, color)
elif pixfmt == 'YUV444-planar':
# garbage color space conversion
# for demonstration purposes only
y_, u_, v_ = rgb2yuv(r, g, b)
image_data += struct.pack("B", y_)
image_data_P1 += struct.pack("BB", u_, v_)
elif pixfmt == 'YUV422-planar':
# garbage color space conversion, garbage subsampling
# for demonstration purposes only
y_, u_, v_ = rgb2yuv(r, g, b)
if x & 1 == 0:
color = u_
else:
color = v_
image_data += struct.pack("B", y_)
image_data_P1 += struct.pack("B", color)
else:
assert False
else:
for y in range(im_H):
for x in range(im_W):
r, g, b = im.getpixel((x, y))
# garbage color space conversion, garbage subsampling
# for demonstration purposes only
y_, u_, v_ = rgb2yuv(r, g, b)
if x & 1 == 0:
color = u_
else:
color = v_
image_data += struct.pack("B", y_)
if y & 1 == 0:
image_data_P1 += struct.pack("B", color)
if pixfmt in ['RGB888', 'RGB101010', 'YUV10']:
BYTESPP = 4
BYTESPP_P1 = 0
P1_DIVH = 1
elif pixfmt in ['RGB565', 'YUV-linear']:
BYTESPP = 2
BYTESPP_P1 = 0
P1_DIVH = 1
elif pixfmt == 'YUV444-planar':
BYTESPP = 1
BYTESPP_P1 = 2
P1_DIVH = 1
elif pixfmt == 'YUV422-planar':
BYTESPP = 1
BYTESPP_P1 = 1
P1_DIVH = 1
elif pixfmt == 'YUV420-planar':
BYTESPP = 1
BYTESPP_P1 = 1
P1_DIVH = 2
else:
assert False
surface_stride = im_W * BYTESPP
surface_sz = surface_stride * im_H
surface_P1_off = surface_sz
print(f"Plane 1 offset at {surface_P1_off:08X}")
surface_P1_stride = im_W * BYTESPP_P1
surface_sz += surface_P1_stride * im_H // P1_DIVH
input_mem_sz = align_up(surface_sz)
output_mem_sz = input_mem_sz
print(f"Using size {input_mem_sz:08X} for input image")
print(f"Using size {output_mem_sz:08X} for output data")
# Turn on the JPEG block
p.pmgr_adt_clocks_enable(f'/arm-io/dart-{args.which_jpeg}')
p.pmgr_adt_clocks_enable(f'/arm-io/{args.which_jpeg}')
dart = DART.from_adt(u, f'/arm-io/dart-{args.which_jpeg}')
dart.initialize()
jpeg_base, _ = u.adt[f'/arm-io/{args.which_jpeg}'].get_reg(0)
jpeg = JPEGRegs(u, jpeg_base)
def reset_block():
jpeg.MODE.val = 0x100
jpeg.MODE.val = 0x13e
set_default_regs()
jpeg.MODE.val = 0x17f
for _ in range(10000):
v = jpeg.REG_0x1004.val
if v == 0:
break
print(f"reset 1 -- {v}")
if (v := jpeg.REG_0x1004.val) != 0:
print(f"reset 1 failed! -- {v}")
assert False
jpeg.RST_INTERVAL.val = 1
for _ in range(2500):
v = jpeg.RST_INTERVAL.val
if v == 1:
break
print(f"reset 2 -- {v}")
if (v := jpeg.RST_INTERVAL.val) != 1:
print(f"reset 2 failed! -- {v}")
assert False
jpeg.RST_INTERVAL.val = 0
jpeg.ENABLE_RST_LOGGING.val = 0
jpeg.REG_0x1a8.val = 0
jpeg.REG_0x1ac.val = 0
jpeg.REG_0x1b0.val = 0
jpeg.REG_0x1b4.val = 0
jpeg.REG_0x1bc.val = 0
jpeg.REG_0x1c0.val = 0
jpeg.REG_0x1c4.val = 0
jpeg.REG_0x1c8.val = 0
jpeg.REG_0x1cc.val = 0
jpeg.REG_0x1d0.val = 0
jpeg.REG_0x1d4.val = 0
jpeg.MODE.val = 0x143
def set_default_regs(param1=0):
jpeg.REG_0x0.val = 0
jpeg.REG_0x0.val = 0
jpeg.REG_0x4.val = 0
jpeg.CODEC.val = 0
jpeg.REG_0x2c.val = 0
jpeg.REG_0x30.val = 0
jpeg.REG_0x34.val = 1
jpeg.REG_0x38.val = 1
jpeg.CHROMA_HALVE_H_TYPE1.val = 0
jpeg.CHROMA_HALVE_H_TYPE2.val = 0
jpeg.CHROMA_HALVE_V_TYPE1.val = 0
jpeg.CHROMA_HALVE_V_TYPE2.val = 0
jpeg.CHROMA_DOUBLE_H.val = 0
jpeg.CHROMA_QUADRUPLE_H.val = 0
jpeg.CHROMA_DOUBLE_V.val = 0
jpeg.PLANAR_CHROMA_HALVING.val = 0
jpeg.PX_USE_PLANE1.val = 0
jpeg.PX_TILES_W.val = 1
jpeg.PX_TILES_H.val = 1
jpeg.PX_PLANE0_WIDTH.val = 1
jpeg.PX_PLANE0_HEIGHT.val = 1
jpeg.PX_PLANE0_TILING_H.val = 1
jpeg.PX_PLANE0_TILING_V.val = 1
jpeg.PX_PLANE0_STRIDE.val = 1
jpeg.PX_PLANE1_WIDTH.val = 1
jpeg.PX_PLANE1_HEIGHT.val = 1
jpeg.PX_PLANE1_TILING_H.val = 1
jpeg.PX_PLANE1_TILING_V.val = 1
jpeg.PX_PLANE1_STRIDE.val = 1
jpeg.INPUT_START1.val = 0
jpeg.INPUT_START2.val = 0
jpeg.REG_0x94.val = 1
jpeg.REG_0x98.val = 1
jpeg.INPUT_END.val = 0xffffffff
jpeg.OUTPUT_START1.val = 0
jpeg.OUTPUT_START2.val = 0
jpeg.OUTPUT_END.val = 0xffffffff
for i in range(11):
jpeg.MATRIX_MULT[i].val = 0
for i in range(10):
jpeg.DITHER[i].val = 0xff
jpeg.ENCODE_PIXEL_FORMAT.val = 0
jpeg.ENCODE_COMPONENT0_POS.val = 0
jpeg.ENCODE_COMPONENT1_POS.val = 0
jpeg.ENCODE_COMPONENT2_POS.val = 0
jpeg.ENCODE_COMPONENT3_POS.val = 0
jpeg.CONVERT_COLOR_SPACE.val = 0
jpeg.REG_0x118.val = 0
jpeg.REG_0x11c.val = 0
jpeg.REG_0x120.val = 0
jpeg.TILING_ENABLE.val = 0
jpeg.TILING_PLANE0.val = 0
jpeg.TILING_PLANE1.val = 0
jpeg.DECODE_MACROBLOCKS_W.val = 0
jpeg.DECODE_MACROBLOCKS_H.val = 0
jpeg.SCALE_FACTOR.val = 0
jpeg.DECODE_PIXEL_FORMAT.val = 0
jpeg.YUV422_ORDER.val = 0
jpeg.RGBA_ORDER.val = 0
jpeg.RGBA_ALPHA.val = 0
jpeg.RIGHT_EDGE_PIXELS.val = 0
jpeg.BOTTOM_EDGE_PIXELS.val = 0
jpeg.RIGHT_EDGE_SAMPLES.val = 0
jpeg.BOTTOM_EDGE_SAMPLES.val = 0
# this is always done on the m1 max hwrev
jpeg.REG_0x1fc.val = 0
jpeg.REG_0x200.val = 0
jpeg.REG_0x204.val = 0
jpeg.REG_0x208.val = 0
jpeg.REG_0x214.val = 0
jpeg.REG_0x218.val = 0
jpeg.REG_0x21c.val = 0
jpeg.REG_0x220.val = 0
jpeg.REG_0x224.val = 0
jpeg.REG_0x228.val = 0
jpeg.REG_0x22c.val = 0
jpeg.REG_0x230.val = 0
jpeg.REG_0x234.val = 0x1f40
jpeg.REG_0x244.val = 0
jpeg.REG_0x248.val = 0
jpeg.REG_0x258.val = 0
jpeg.REG_0x25c.val = 0
jpeg.REG_0x23c.val = 0
jpeg.REG_0x240.val = 0
jpeg.REG_0x250.val = 0
jpeg.REG_0x254.val = 0
jpeg.REG_0x160.val = param1
jpeg.TIMEOUT.val = 0
jpeg.REG_0x20.val = 0xff
print(f"HW revision is {jpeg.HWREV}")
reset_block()
input_buf_phys = u.heap.memalign(0x4000, input_mem_sz)
output_buf_phys = u.heap.memalign(0x4000, output_mem_sz)
print(f"buffers (phys) {input_buf_phys:016X} {output_buf_phys:016X}")
input_buf_iova = dart.iomap(0, input_buf_phys, input_mem_sz)
output_buf_iova = dart.iomap(0, output_buf_phys, output_mem_sz)
print(f"buffers (iova) {input_buf_iova:08X} {output_buf_iova:08X}")
# dart.dump_all()
iface.writemem(input_buf_phys, b'\xAA' * input_mem_sz)
iface.writemem(output_buf_phys, b'\xAA' * output_mem_sz)
if args.decode:
iface.writemem(input_buf_phys, jpeg_data)
print("JPEG uploaded")
jpeg.REG_0x34 = 1
jpeg.REG_0x2c = 0
jpeg.REG_0x38 = 0
if jpeg_MODE == '444':
jpeg.CODEC.set(CODEC=E_CODEC._444)
elif jpeg_MODE == '400':
jpeg.CODEC.set(CODEC=E_CODEC._400)
elif jpeg_MODE == '422':
jpeg.CODEC.set(CODEC=E_CODEC._422)
elif jpeg_MODE == '420':
jpeg.CODEC.set(CODEC=E_CODEC._420)
elif jpeg_MODE == '411':
jpeg.CODEC.set(CODEC=E_CODEC._411)
else:
assert False
if pixfmt == 'RGBA' or pixfmt == 'BGRA':
jpeg.DECODE_PIXEL_FORMAT.set(FORMAT=E_DECODE_PIXEL_FORMAT.RGBA8888)
elif pixfmt == 'RGB565':
jpeg.DECODE_PIXEL_FORMAT.set(FORMAT=E_DECODE_PIXEL_FORMAT.RGB565)
elif pixfmt == 'YUV422-CbYCrY' or pixfmt == 'YUV422-YCbYCr':
jpeg.DECODE_PIXEL_FORMAT.set(FORMAT=E_DECODE_PIXEL_FORMAT.YUV422_linear)
elif pixfmt == 'YUV422-planar':
jpeg.DECODE_PIXEL_FORMAT.set(FORMAT=E_DECODE_PIXEL_FORMAT.YUV422_planar)
elif pixfmt == 'YUV420-planar':
jpeg.DECODE_PIXEL_FORMAT.set(FORMAT=E_DECODE_PIXEL_FORMAT.YUV420_planar)
elif pixfmt == 'YUV444-planar':
jpeg.DECODE_PIXEL_FORMAT.set(FORMAT=E_DECODE_PIXEL_FORMAT.YUV444_planar)
else:
assert False
if pixfmt in ['YUV422-planar', 'YUV420-planar', 'YUV444-planar']:
jpeg.PX_USE_PLANE1 = 1
jpeg.PX_PLANE1_WIDTH = jpeg_W * P1_MULW // P1_DIVW // decode_scale - 1
jpeg.PX_PLANE1_HEIGHT = jpeg_H // P1_DIVH // decode_scale - 1
else:
jpeg.PX_USE_PLANE1 = 0
jpeg.PX_PLANE0_WIDTH = jpeg_W*BYTESPP // decode_scale - 1
jpeg.PX_PLANE0_HEIGHT = jpeg_H // decode_scale - 1
jpeg.TIMEOUT = 266000000
jpeg.REG_0x94 = 0x1f
jpeg.REG_0x98 = 1
jpeg.DECODE_MACROBLOCKS_W = divroundup(jpeg_W, macroblock_W)
jpeg.DECODE_MACROBLOCKS_H = divroundup(jpeg_H, macroblock_H)
right_edge_px = \
jpeg_W - divroundup(jpeg_W, macroblock_W)*macroblock_W + macroblock_W
bot_edge_px = \
jpeg_H - divroundup(jpeg_H, macroblock_H)*macroblock_H + macroblock_H
# XXX changing this does not seem to do anything.
# Does it possibly affect scaling down?
jpeg.RIGHT_EDGE_PIXELS.val = right_edge_px
jpeg.BOTTOM_EDGE_PIXELS.val = bot_edge_px
jpeg.RIGHT_EDGE_SAMPLES.val = right_edge_px // (macroblock_W // 8)
jpeg.BOTTOM_EDGE_SAMPLES.val = bot_edge_px // (macroblock_H // 8)
jpeg.PX_TILES_H = divroundup(jpeg_H, macroblock_H)
# FIXME explain this
if pixfmt in ['RGBA', 'BGRA', 'RGB565', 'YUV444-planar']:
jpeg.PX_TILES_W = divroundup(jpeg_W // decode_scale, macroblock_W)
else:
jpeg.PX_TILES_W = divroundup(jpeg_W // decode_scale, max(macroblock_W, 16))
if pixfmt == 'RGBA' or pixfmt == 'BGRA':
if jpeg_MODE == '444' or jpeg_MODE == '400':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif jpeg_MODE == '422':
jpeg.PX_PLANE0_TILING_H = 8
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif jpeg_MODE == '420':
jpeg.PX_PLANE0_TILING_H = 8
jpeg.PX_PLANE0_TILING_V = 16 // decode_scale
jpeg.PX_PLANE1_TILING_H = 0
jpeg.PX_PLANE1_TILING_V = 0
elif jpeg_MODE == '411':
jpeg.PX_PLANE0_TILING_H = 16
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 0
jpeg.PX_PLANE1_TILING_V = 0
else:
assert False
elif pixfmt == 'RGB565':
if jpeg_MODE == '444' or jpeg_MODE == '400':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif jpeg_MODE == '422':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif jpeg_MODE == '420':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 16 // decode_scale
jpeg.PX_PLANE1_TILING_H = 0
jpeg.PX_PLANE1_TILING_V = 0
elif jpeg_MODE == '411':
jpeg.PX_PLANE0_TILING_H = 8
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 0
jpeg.PX_PLANE1_TILING_V = 0
else:
assert False
elif pixfmt == 'YUV422-CbYCrY' or pixfmt == 'YUV422-YCbYCr':
if jpeg_MODE == '444' or jpeg_MODE == '400':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif jpeg_MODE == '422':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif jpeg_MODE == '420':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 16 // decode_scale
jpeg.PX_PLANE1_TILING_H = 0
jpeg.PX_PLANE1_TILING_V = 0
elif jpeg_MODE == '411':
jpeg.PX_PLANE0_TILING_H = 8
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 0
jpeg.PX_PLANE1_TILING_V = 0
else:
assert False
elif pixfmt == 'YUV422-planar':
if jpeg_MODE == '444' or jpeg_MODE == '400':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 8 // decode_scale
elif jpeg_MODE == '422':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 8 // decode_scale
elif jpeg_MODE == '420':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 16 // decode_scale
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 16 // decode_scale
elif jpeg_MODE == '411':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 4
jpeg.PX_PLANE1_TILING_V = 8 // decode_scale
else:
assert False
elif pixfmt == 'YUV420-planar':
if jpeg_MODE == '444' or jpeg_MODE == '400':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 4 // decode_scale
elif jpeg_MODE == '422':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 4 // decode_scale
elif jpeg_MODE == '420':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 16 // decode_scale
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 8 // decode_scale
elif jpeg_MODE == '411':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 4
jpeg.PX_PLANE1_TILING_V = 4 // decode_scale
else:
assert False
elif pixfmt == 'YUV444-planar':
if jpeg_MODE == '444' or jpeg_MODE == '400':
jpeg.PX_PLANE0_TILING_H = 1
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 8 // decode_scale
elif jpeg_MODE == '422':
# The driver doesn't use this, but guessing seems to be fine?
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 4
jpeg.PX_PLANE1_TILING_V = 8 // decode_scale
elif jpeg_MODE == '420':
# The driver doesn't use this, but guessing seems to be fine?
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 16 // decode_scale
jpeg.PX_PLANE1_TILING_H = 4
jpeg.PX_PLANE1_TILING_V = 16 // decode_scale
elif jpeg_MODE == '411':
# The driver doesn't use this, but guessing seems to be fine?
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 8 // decode_scale
jpeg.PX_PLANE1_TILING_H = 8
jpeg.PX_PLANE1_TILING_V = 8 // decode_scale
else:
assert False
else:
assert False
if pixfmt in ['RGBA', 'BGRA', 'RGB565', 'YUV444-planar']:
if jpeg_MODE in ['422', '420']:
jpeg.CHROMA_DOUBLE_H = 1
if jpeg_MODE == '411':
jpeg.CHROMA_QUADRUPLE_H = 1
if jpeg_MODE == '420':
jpeg.CHROMA_DOUBLE_V = 1
elif pixfmt in ["YUV422-CbYCrY", "YUV422-YCbYCr", "YUV422-planar"]:
if jpeg_MODE == '444':
jpeg.CHROMA_HALVE_H_TYPE1 = 1
if jpeg_MODE == '411':
jpeg.CHROMA_DOUBLE_H = 1
if jpeg_MODE == '420':
jpeg.CHROMA_DOUBLE_V = 1
elif pixfmt in ["YUV420-planar"]:
if jpeg_MODE == '444':
jpeg.CHROMA_HALVE_H_TYPE1 = 1
if jpeg_MODE in ['444', '422', '411']:
jpeg.CHROMA_HALVE_V_TYPE1 = 1
if jpeg_MODE == '411':
jpeg.CHROMA_DOUBLE_H = 1
else:
assert False
jpeg.MATRIX_MULT[0].val = 0x100
jpeg.MATRIX_MULT[1].val = 0x0
jpeg.MATRIX_MULT[2].val = 0x167
jpeg.MATRIX_MULT[3].val = 0x100
jpeg.MATRIX_MULT[4].val = 0xffffffa8
jpeg.MATRIX_MULT[5].val = 0xffffff49
jpeg.MATRIX_MULT[6].val = 0x100
jpeg.MATRIX_MULT[7].val = 0x1c6
jpeg.MATRIX_MULT[8].val = 0x0
jpeg.MATRIX_MULT[9].val = 0x0
jpeg.MATRIX_MULT[10].val = 0xffffff80
jpeg.RGBA_ALPHA = args.decode_rgba_alpha
jpeg.RGBA_ORDER = pixfmt == "RGBA"
jpeg.YUV422_ORDER = pixfmt == "YUV422-YCbYCr"
if decode_scale == 1:
jpeg.SCALE_FACTOR.set(SCALE=E_SCALE.DIV1)
elif decode_scale == 2:
jpeg.SCALE_FACTOR.set(SCALE=E_SCALE.DIV2)
elif decode_scale == 4:
jpeg.SCALE_FACTOR.set(SCALE=E_SCALE.DIV4)
elif decode_scale == 8:
jpeg.SCALE_FACTOR.set(SCALE=E_SCALE.DIV8)
else:
assert False
jpeg.INPUT_START1 = input_buf_iova
jpeg.INPUT_START2 = 0xdeadbeef
jpeg.INPUT_END = input_buf_iova + input_mem_sz
jpeg.OUTPUT_START1 = output_buf_iova
jpeg.OUTPUT_START2 = output_buf_iova + surface_P1_off
jpeg.OUTPUT_END = output_buf_iova + output_mem_sz
jpeg.PX_PLANE0_STRIDE = surface_stride
jpeg.PX_PLANE1_STRIDE = surface_P1_stride
jpeg.REG_0x1ac = 0x0
jpeg.REG_0x1b0 = 0x0
jpeg.REG_0x1b4 = 0x0
jpeg.REG_0x1bc = 0x0
jpeg.REG_0x1c0 = 0x0
jpeg.REG_0x1c4 = 0x0
jpeg.REG_0x118 = 0x0
jpeg.REG_0x11c = 0x1
jpeg.MODE = 0x177
jpeg.REG_0x1028 = 0x400
jpeg.JPEG_IO_FLAGS = 0x3f
jpeg.REG_0x0 = 0x1
jpeg.REG_0x1004 = 0x1
# FIXME: we don't actually know when it's done
time.sleep(1)
print(jpeg.STATUS.reg)
print(jpeg.PERFCOUNTER.reg)
output_data = iface.readmem(output_buf_phys, output_mem_sz)
if args.raw_output is not None:
with open(args.raw_output, 'wb') as f:
f.write(output_data)
# Just for demonstration purposes, wrangle everything back into RGB
with Image.new(
mode='RGBA',
size=(jpeg_W // decode_scale, jpeg_H // decode_scale)) as im:
if pixfmt in ["RGBA", "BGRA", "RGB565"]:
for y in range(jpeg_H // decode_scale):
for x in range(jpeg_W // decode_scale):
block = output_data[
y*surface_stride + x*BYTESPP:
y*surface_stride + (x+1)*BYTESPP]
if pixfmt == "RGBA":
r, g, b, a = block
elif pixfmt == "BGRA":
b, g, r, a = block
elif pixfmt == "RGB565":
rgb = struct.unpack("<H", block)[0]
b = (rgb & 0b11111) << 3
g = ((rgb >> 5) & 0b111111) << 2
r = ((rgb >> 11) & 0b11111) << 3
a = 255
else:
assert False
im.putpixel((x, y), (r, g, b, a))
elif pixfmt in ["YUV422-CbYCrY", "YUV422-YCbYCr"]:
for y in range(jpeg_H // decode_scale):
for x in range(0, jpeg_W // decode_scale, 2):
block = output_data[
y*surface_stride + x*BYTESPP:
y*surface_stride + (x+2)*BYTESPP]
if pixfmt == "YUV422-CbYCrY":
cb, y0, cr, y1 = block
elif pixfmt == "YUV422-YCbYCr":
y0, cb, y1, cr = block
r0, g0, b0 = yuv2rgb(y0, cb, cr)
r1, g1, b1 = yuv2rgb(y1, cb, cr)
im.putpixel((x, y), (r0, g0, b0, 255))
# XXX this really needs some fixing
if x+1 < jpeg_W // decode_scale:
im.putpixel((x+1, y), (r1, g1, b1, 255))
elif pixfmt == "YUV422-planar":
for y in range(jpeg_H // decode_scale):
for x in range(jpeg_W // decode_scale):
y_ = output_data[y*surface_stride + x]
cb = output_data[surface_P1_off + y*surface_P1_stride + x&~1]
cr = output_data[surface_P1_off + y*surface_P1_stride + (x&~1)+1]
r, g, b = yuv2rgb(y_, cb, cr)
im.putpixel((x, y), (r, g, b, 255))
elif pixfmt == "YUV420-planar":
for y in range(jpeg_H // decode_scale):
for x in range(jpeg_W // decode_scale):
y_ = output_data[y*surface_stride + x]
cb = output_data[surface_P1_off + (y//2)*surface_P1_stride + x&~1]
cr = output_data[surface_P1_off + (y//2)*surface_P1_stride + (x&~1)+1]
r, g, b = yuv2rgb(y_, cb, cr)
im.putpixel((x, y), (r, g, b, 255))
elif pixfmt == "YUV444-planar":
for y in range(jpeg_H // decode_scale):
for x in range(jpeg_W // decode_scale):
y_ = output_data[y*surface_stride + x]
cb = output_data[surface_P1_off + y*surface_P1_stride + x*2]
cr = output_data[surface_P1_off + y*surface_P1_stride + x*2+1]
r, g, b = yuv2rgb(y_, cb, cr)
im.putpixel((x, y), (r, g, b, 255))
else:
assert False
im.save(args.output)
if args.encode:
iface.writemem(input_buf_phys, image_data)
iface.writemem(input_buf_phys + surface_P1_off, image_data_P1)
print("Pixel data uploaded")
jpeg.MODE = 0x17f
jpeg.REG_0x38 = 0x1 # if not set nothing happens
jpeg.REG_0x2c = 0x1 # if not set only header is output
jpeg.REG_0x34 = 0x0 # if set output is a JPEG but weird with no footer
if args.encode_subsampling == '444':
jpeg.CODEC.set(CODEC=E_CODEC._444)
elif args.encode_subsampling == '422':
jpeg.CODEC.set(CODEC=E_CODEC._422)
elif args.encode_subsampling == '420':
jpeg.CODEC.set(CODEC=E_CODEC._420)
elif args.encode_subsampling == '400':
jpeg.CODEC.set(CODEC=E_CODEC._400)
else:
assert False
if BYTESPP_P1 != 0:
jpeg.PX_USE_PLANE1 = 1
jpeg.PX_PLANE1_WIDTH = im_W*BYTESPP_P1 - 1
jpeg.PX_PLANE1_HEIGHT = im_H // P1_DIVH - 1
else:
jpeg.PX_USE_PLANE1 = 0
jpeg.PX_PLANE1_WIDTH = 0xffffffff
jpeg.PX_PLANE1_HEIGHT = 0xffffffff
jpeg.PX_PLANE0_WIDTH = im_W*BYTESPP - 1
jpeg.PX_PLANE0_HEIGHT = im_H - 1
jpeg.TIMEOUT = 266000000
jpeg.PX_TILES_W = divroundup(im_W, macroblock_W)
jpeg.PX_TILES_H = divroundup(im_H, macroblock_H)
if pixfmt in ['RGB888', 'RGB101010', 'YUV10']:
if args.encode_subsampling == '444' or args.encode_subsampling == '400':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif args.encode_subsampling == '422':
jpeg.PX_PLANE0_TILING_H = 8
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif args.encode_subsampling == '420':
jpeg.PX_PLANE0_TILING_H = 8
jpeg.PX_PLANE0_TILING_V = 16
jpeg.PX_PLANE1_TILING_H = 0
jpeg.PX_PLANE1_TILING_V = 0
else:
assert False
elif pixfmt == 'RGB565':
if args.encode_subsampling == '444' or args.encode_subsampling == '400':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif args.encode_subsampling == '422':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif args.encode_subsampling == '420':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 16
jpeg.PX_PLANE1_TILING_H = 0
jpeg.PX_PLANE1_TILING_V = 0
else:
assert False
elif pixfmt == 'YUV-linear':
if args.encode_subsampling == '444' or args.encode_subsampling == '400':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif args.encode_subsampling == '422':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 1
elif args.encode_subsampling == '420':
jpeg.PX_PLANE0_TILING_H = 4
jpeg.PX_PLANE0_TILING_V = 16
jpeg.PX_PLANE1_TILING_H = 0
jpeg.PX_PLANE1_TILING_V = 0
else:
assert False
elif pixfmt == 'YUV444-planar':
if args.encode_subsampling == '444' or args.encode_subsampling == '400':
jpeg.PX_PLANE0_TILING_H = 1
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 8
elif args.encode_subsampling == '422':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 4
jpeg.PX_PLANE1_TILING_V = 8
elif args.encode_subsampling == '420':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 16
jpeg.PX_PLANE1_TILING_H = 4
jpeg.PX_PLANE1_TILING_V = 16
else:
assert False
elif pixfmt == 'YUV422-planar':
if args.encode_subsampling == '444' or args.encode_subsampling == '400':
jpeg.PX_PLANE0_TILING_H = 1
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 8
elif args.encode_subsampling == '422':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 8
elif args.encode_subsampling == '420':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 16
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 16
else:
assert False
elif pixfmt == 'YUV420-planar':
if args.encode_subsampling == '444' or args.encode_subsampling == '400':
jpeg.PX_PLANE0_TILING_H = 1
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 1
jpeg.PX_PLANE1_TILING_V = 4
elif args.encode_subsampling == '422':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 8
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 4
elif args.encode_subsampling == '420':
jpeg.PX_PLANE0_TILING_H = 2
jpeg.PX_PLANE0_TILING_V = 16
jpeg.PX_PLANE1_TILING_H = 2
jpeg.PX_PLANE1_TILING_V = 8
else:
assert False
else:
assert False
jpeg.PX_PLANE0_STRIDE = surface_stride
jpeg.PX_PLANE1_STRIDE = surface_P1_stride
if pixfmt in ['RGB888', 'RGB101010', 'RGB565', 'YUV10', 'YUV444-planar']:
if args.encode_subsampling in ['422', '420']:
jpeg.CHROMA_HALVE_H_TYPE1 = 1
if args.encode_subsampling == '420':
jpeg.CHROMA_HALVE_V_TYPE1 = 1
elif pixfmt in ['YUV-linear', 'YUV422-planar']:
if args.encode_subsampling == '420':
jpeg.CHROMA_HALVE_V_TYPE1 = 1
elif pixfmt == 'YUV420-planar':
if args.encode_subsampling in ['422', '444']:
jpeg.CHROMA_DOUBLE_V = 1
else:
assert False
# none of this seems to affect anything????
jpeg.REG_0x94 = 0xc # c/2 for 444; 8/2 for 422; 3/1 for 411; b/2 for 400
jpeg.REG_0x98 = 0x2
jpeg.REG_0x20c = im_W
jpeg.REG_0x210 = im_H
if pixfmt in ['RGB888', 'RGB101010', 'RGB565']:
jpeg.CONVERT_COLOR_SPACE = 1
jpeg.MATRIX_MULT[0].val = 0x4d
jpeg.MATRIX_MULT[1].val = 0x96
jpeg.MATRIX_MULT[2].val = 0x1d
jpeg.MATRIX_MULT[3].val = 0xffffffd5
jpeg.MATRIX_MULT[4].val = 0xffffffab
jpeg.MATRIX_MULT[5].val = 0x80
jpeg.MATRIX_MULT[6].val = 0x80
jpeg.MATRIX_MULT[7].val = 0xffffff95
jpeg.MATRIX_MULT[8].val = 0xffffffeb
jpeg.MATRIX_MULT[9].val = 0x0
jpeg.MATRIX_MULT[10].val = 0x80
if pixfmt == 'RGB888':
jpeg.ENCODE_PIXEL_FORMAT.set(FORMAT=E_ENCODE_PIXEL_FORMAT.RGB888)
elif pixfmt == 'RGB101010':
jpeg.ENCODE_PIXEL_FORMAT.set(FORMAT=E_ENCODE_PIXEL_FORMAT.RGB101010)
elif pixfmt == 'RGB565':
jpeg.ENCODE_PIXEL_FORMAT.set(FORMAT=E_ENCODE_PIXEL_FORMAT.RGB565)
elif pixfmt == 'YUV10':
jpeg.ENCODE_PIXEL_FORMAT.set(FORMAT=E_ENCODE_PIXEL_FORMAT.YUV10_linear)
elif pixfmt == 'YUV-linear':
jpeg.ENCODE_PIXEL_FORMAT.set(FORMAT=E_ENCODE_PIXEL_FORMAT.YUV_linear)
elif pixfmt in ['YUV444-planar', 'YUV422-planar', 'YUV420-planar']:
jpeg.ENCODE_PIXEL_FORMAT.set(FORMAT=E_ENCODE_PIXEL_FORMAT.YUV_planar)
else:
assert False
if pixfmt == 'YUV-linear':
jpeg.ENCODE_COMPONENT0_POS = 0
jpeg.ENCODE_COMPONENT1_POS = 1
jpeg.ENCODE_COMPONENT2_POS = 3
jpeg.ENCODE_COMPONENT3_POS = 2
elif pixfmt in ['YUV422-planar', 'YUV420-planar', 'YUV444-planar']:
jpeg.ENCODE_COMPONENT0_POS = 0
jpeg.ENCODE_COMPONENT1_POS = 0
jpeg.ENCODE_COMPONENT2_POS = 1
jpeg.ENCODE_COMPONENT3_POS = 3
else:
jpeg.ENCODE_COMPONENT0_POS = 0
jpeg.ENCODE_COMPONENT1_POS = 1
jpeg.ENCODE_COMPONENT2_POS = 2
jpeg.ENCODE_COMPONENT3_POS = 3
jpeg.INPUT_START1 = input_buf_iova
jpeg.INPUT_START2 = input_buf_iova + surface_P1_off
jpeg.INPUT_END = input_buf_iova + input_mem_sz + 7 # NOTE +7
jpeg.OUTPUT_START1 = output_buf_iova
jpeg.OUTPUT_START2 = 0xdeadbeef
jpeg.OUTPUT_END = output_buf_iova + output_mem_sz
jpeg.REG_0x118 = 0x1
jpeg.REG_0x11c = 0x0
jpeg.ENABLE_RST_LOGGING = args.encode_rst_interval is not None
jpeg.MODE = 0x16f
if args.encode_subsampling == '444':
jpeg_subsampling = E_JPEG_IO_FLAGS_SUBSAMPLING._444
elif args.encode_subsampling == '422':
jpeg_subsampling = E_JPEG_IO_FLAGS_SUBSAMPLING._422
elif args.encode_subsampling == '420':
jpeg_subsampling = E_JPEG_IO_FLAGS_SUBSAMPLING._420
elif args.encode_subsampling == '400':
jpeg_subsampling = E_JPEG_IO_FLAGS_SUBSAMPLING._400
else:
assert False
jpeg.JPEG_IO_FLAGS.set(
OUTPUT_8BYTE_CHUNKS_CORRECTLY=1,
OUTPUT_MACROBLOCKS_UNFLIPPED_H=1,
SUBSAMPLING_MODE=jpeg_subsampling
)
jpeg.JPEG_WIDTH = im_W
jpeg.JPEG_HEIGHT = im_H
if args.encode_rst_interval is not None:
jpeg.RST_INTERVAL = args.encode_rst_interval
else:
jpeg.RST_INTERVAL = 0
jpeg.JPEG_OUTPUT_FLAGS = 0
jpeg.QTBL[0].val = 0xa06e64a0
jpeg.QTBL[1].val = 0xf0ffffff
jpeg.QTBL[2].val = 0x78788cbe
jpeg.QTBL[3].val = 0xffffffff
jpeg.QTBL[4].val = 0x8c82a0f0
jpeg.QTBL[5].val = 0xffffffff
jpeg.QTBL[6].val = 0x8caadcff
jpeg.QTBL[7].val = 0xffffffff
jpeg.QTBL[8].val = 0xb4dcffff
jpeg.QTBL[9].val = 0xffffffff
jpeg.QTBL[10].val = 0xf0ffffff
jpeg.QTBL[11].val = 0xffffffff
jpeg.QTBL[12].val = 0xffffffff
jpeg.QTBL[13].val = 0xffffffff
jpeg.QTBL[14].val = 0xffffffff
jpeg.QTBL[15].val = 0xffffffff
jpeg.QTBL[16].val = 0xaab4f0ff
jpeg.QTBL[17].val = 0xffffffff
jpeg.QTBL[18].val = 0xb4d2ffff
jpeg.QTBL[19].val = 0xffffffff
jpeg.QTBL[20].val = 0xf0ffffff
jpeg.QTBL[21].val = 0xffffffff
jpeg.QTBL[22].val = 0xffffffff
jpeg.QTBL[23].val = 0xffffffff
jpeg.QTBL[24].val = 0xffffffff
jpeg.QTBL[25].val = 0xffffffff
jpeg.QTBL[26].val = 0xffffffff
jpeg.QTBL[27].val = 0xffffffff
jpeg.QTBL[28].val = 0xffffffff
jpeg.QTBL[29].val = 0xffffffff
jpeg.QTBL[30].val = 0xffffffff
jpeg.QTBL[31].val = 0xffffffff
jpeg.QTBL[32].val = 0x01010201
jpeg.QTBL[33].val = 0x01020202
jpeg.QTBL[34].val = 0x02030202
jpeg.QTBL[35].val = 0x03030604
jpeg.QTBL[36].val = 0x03030303
jpeg.QTBL[37].val = 0x07050804
jpeg.QTBL[38].val = 0x0608080a
jpeg.QTBL[39].val = 0x0908070b
jpeg.QTBL[40].val = 0x080a0e0d
jpeg.QTBL[41].val = 0x0b0a0a0c
jpeg.QTBL[42].val = 0x0a08080b
jpeg.QTBL[43].val = 0x100c0c0d
jpeg.QTBL[44].val = 0x0f0f0f0f
jpeg.QTBL[45].val = 0x090b1011
jpeg.QTBL[46].val = 0x0f0e110d
jpeg.QTBL[47].val = 0x0e0e0e01
jpeg.QTBL[48].val = 0x04040405
jpeg.QTBL[49].val = 0x04050905
jpeg.QTBL[50].val = 0x05090f0a
jpeg.QTBL[51].val = 0x080a0f1a
jpeg.QTBL[52].val = 0x13090913
jpeg.QTBL[53].val = 0x1a1a1a1a
jpeg.QTBL[54].val = 0x0d1a1a1a
jpeg.QTBL[55].val = 0x1a1a1a1a
jpeg.QTBL[56].val = 0x1a1a1a1a
jpeg.QTBL[57].val = 0x1a1a1a1a
jpeg.QTBL[58].val = 0x1a1a1a1a
jpeg.QTBL[59].val = 0x1a1a1a1a
jpeg.QTBL[60].val = 0x1a1a1a1a
jpeg.QTBL[61].val = 0x1a1a1a1a
jpeg.QTBL[62].val = 0x1a1a1a1a
jpeg.QTBL[63].val = 0x1a1a1a1a
jpeg.HUFFMAN_TABLE.val = 0x3c
jpeg.QTBL_SEL.val = 0xff
jpeg.REG_0x0.val = 0x1
jpeg.REG_0x1004.val = 0x1
# FIXME: we don't actually know when it's done
time.sleep(1)
print(jpeg.STATUS.reg)
print(jpeg.PERFCOUNTER.reg)
jpeg_out_sz = jpeg.COMPRESSED_BYTES.val
print(f"JPEG output is {jpeg_out_sz} bytes")
rst_log_n = jpeg.RST_LOG_ENTRIES.val
for i in range(rst_log_n):
print(f"RST log[{i}] = 0x{jpeg.RSTLOG[i].val:X}")
output_data = iface.readmem(output_buf_phys, output_mem_sz)
if args.raw_output is not None:
with open(args.raw_output, 'wb') as f:
f.write(output_data)
with open(args.output, 'wb') as f:
f.write(output_data[:jpeg_out_sz])