ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_jpeg_sw.c
Go to the documentation of this file.
1
43
44#include "ra8_jpeg_sw.h"
45
46#include <stdint.h> // ra8-keep-include: `uint8_t` used directly
47
48#include "ra8_attributes.h" // ra8-keep-include: `RA8_INTERNAL` and `RA8_PRIV` used directly
49#include "ra8_check.h"
50#include "ra8_err.h" // ra8-keep-include: `ra8_err_t` used directly
52
54static const char* s_tag = "JPEG_SW";
55
56#ifdef __ARM_FEATURE_MVE
57#include <arm_mve.h>
58#endif
59
60/* ------------------------------------------------------------------ */
61/* Bit reader (decoder-side) */
62/* ------------------------------------------------------------------ */
63
84{
85 while (br->nbits <= k_jpeg_reservoir_lo && !br->had_eoi) {
86 if (br->pos >= br->len) {
87 br->had_eoi = 1U;
88 return;
89 }
90 uint8_t b = br->buf[br->pos];
91 br->pos++;
92 if (b == (uint8_t)k_ra8_jpeg_marker_byte) {
93 if (br->pos >= br->len) {
94 br->had_eoi = 1U;
95 return;
96 }
97 uint8_t s = br->buf[br->pos];
98 br->pos++;
99 if (s != 0U) {
100 /* A real marker; rewind so caller can inspect. */
101 br->pos -= 2U;
102 br->had_eoi = 1U;
103 return;
104 }
105 /* Stuffed 0xFF byte. */
106 }
107 br->acc = (br->acc << k_ra8_jpeg_byte_shift) | (uint32_t)b;
108 br->nbits = (uint8_t)(br->nbits + k_ra8_jpeg_byte_shift);
109 }
110}
111
135{
136 if (n == 0U) {
137 return 0;
138 }
139 if (br->nbits < n) {
141 if (br->nbits < n) {
142 return -1;
143 }
144 }
145 uint32_t v = (br->acc >> (br->nbits - n)) & ((1U << n) - 1U);
146 br->nbits = (uint8_t)(br->nbits - n);
147 br->acc &= (br->nbits == 0U) ? 0U : ((1U << br->nbits) - 1U);
148 return (int32_t)v;
149}
150
151/* ------------------------------------------------------------------ */
152/* Huffman tables */
153/* ------------------------------------------------------------------ */
154
177{
178 uint16_t j = 0U;
179 for (uint8_t i = 0U; i < (uint8_t)k_ra8_jpeg_huff_lengths; i++) {
180 if (h->bits[i] == 0U) {
181 h->maxcode[i] = -1;
182 } else {
183 h->valptr[i] = j;
184 h->mincode[i] = (int32_t)h->huffcode[j];
185 j = (uint16_t)((j + h->bits[i]) - 1U);
186 h->maxcode[i] = (int32_t)h->huffcode[j];
187 j++;
188 }
189 }
190}
191
193{
194 /* T.81 Annex C, "Generation of size table" + "Generation of code
195 * table". */
196 uint16_t k = 0U;
197 for (uint8_t i = 0U; i < (uint8_t)k_ra8_jpeg_huff_lengths; i++) {
198 for (uint8_t j = 0U; j < h->bits[i]; j++) {
199 h->huffsize[k] = (uint8_t)(i + 1U);
200 k++;
201 }
202 }
203 h->huffsize[k] = 0U;
204 h->total = k;
205
206 uint16_t code = 0U;
207 uint8_t si = (k > 0U) ? h->huffsize[0] : 0U;
208 uint16_t kk = 0U;
209 while (h->huffsize[kk] != 0U) {
210 while (h->huffsize[kk] == si) {
211 h->huffcode[kk] = code;
212 code++;
213 kk++;
214 }
215 if (h->huffsize[kk] == 0U) {
216 break;
217 }
218 do {
219 code = (uint16_t)(code << 1U);
220 si++;
221 } while (h->huffsize[kk] != si);
222 }
223
224 /* T.81 Annex F.2.2.3 mincode/maxcode/valptr build. */
226}
227
251{
253 if (br->nbits == 0U) {
254 return -1;
255 }
256 /* Single-bit greedy lookup per F.2.2.3 "Decoder code-length
257 * algorithm". */
258 int32_t code = priv_jpeg_sw_br_get_bits(br, 1U);
259 /* After br->nbits == 0 guard above, br->nbits >= 1; br_get_bits(br, 1)
260 * with nbits >= 1 always returns 0 or 1 without invoking internal_br_fill, so
261 * code < 0 is unreachable on any host input. */
262 if (code < 0) {
263 return -1; /* GCOVR_EXCL_LINE -- internal_br_receive(nbits>=1) returns 0 or 1 */
264 }
265 for (uint8_t i = 0U; i < (uint8_t)k_ra8_jpeg_huff_lengths; i++) {
266 if (code <= h->maxcode[i]) {
267 uint16_t j = (uint16_t)(h->valptr[i] + (uint16_t)(code - h->mincode[i]));
268 if (j >= h->total) {
269 return -1;
270 }
271 return (int32_t)h->vals[j];
272 }
273 int32_t bit = priv_jpeg_sw_br_get_bits(br, 1U);
274 if (bit < 0) {
275 return -1;
276 }
277 code = (code << 1) | bit;
278 }
279 return -1;
280}
281
305RA8_PRIV int32_t priv_jpeg_sw_huff_extend(int32_t v, uint8_t n)
306{
307 if (n == 0U) {
308 return 0;
309 }
310 int32_t vt = 1 << (n - 1U);
311 if (v < vt) {
312 v += ((int32_t)((uint32_t)-1 << n)) + 1;
313 }
314 return v;
315}
316
317/* ------------------------------------------------------------------ */
318/* Inverse DCT (decoder) */
319/* ------------------------------------------------------------------ */
320
338RA8_INTERNAL static void internal_inv_dct_1d_norm(const int32_t* in, int32_t* out)
339{
340 for (uint8_t n = 0U; n < (uint8_t)k_ra8_jpeg_block_dim; n++) {
341 int64_t s = 0;
342 for (uint8_t k = 0U; k < (uint8_t)k_ra8_jpeg_block_dim; k++) {
343 int64_t v = (int64_t)in[k] * (int64_t)s_dct_w_q14[k];
344 s += (v * (int64_t)s_dct_cos_q14[k][n]) >> k_jpeg_q14_shift;
345 }
346 int64_t r = (s + (1LL << k_jpeg_idct_p2_bias_sh)) >> k_jpeg_q14_shift;
347 out[n] = (int32_t)r;
348 }
349}
350
351/* Full 8x8 inverse DCT, in place -- see surrounding code and HUM citations. */
352RA8_PRIV void priv_jpeg_sw_idct8x8(int32_t* block)
353{
354 int32_t tmp[(uint32_t)k_ra8_jpeg_block_size];
355 int32_t row[(uint32_t)k_ra8_jpeg_block_dim];
356 int32_t col[(uint32_t)k_ra8_jpeg_block_dim];
357 int32_t out[(uint32_t)k_ra8_jpeg_block_dim];
358 for (uint8_t r = 0U; r < (uint8_t)k_ra8_jpeg_block_dim; r++) {
359 for (uint8_t c = 0U; c < (uint8_t)k_ra8_jpeg_block_dim; c++) {
360 row[c] = block[(r * (uint8_t)k_ra8_jpeg_block_dim) + c];
361 }
362 internal_inv_dct_1d_norm(row, out);
363 for (uint8_t c = 0U; c < (uint8_t)k_ra8_jpeg_block_dim; c++) {
364 tmp[(r * (uint8_t)k_ra8_jpeg_block_dim) + c] = out[c];
365 }
366 }
367 for (uint8_t c = 0U; c < (uint8_t)k_ra8_jpeg_block_dim; c++) {
368 for (uint8_t r = 0U; r < (uint8_t)k_ra8_jpeg_block_dim; r++) {
369 col[r] = tmp[(r * (uint8_t)k_ra8_jpeg_block_dim) + c];
370 }
371 internal_inv_dct_1d_norm(col, out);
372 for (uint8_t r = 0U; r < (uint8_t)k_ra8_jpeg_block_dim; r++) {
373 block[(r * (uint8_t)k_ra8_jpeg_block_dim) + c] = out[r];
374 }
375 }
376}
377
378/* ------------------------------------------------------------------ */
379/* Colour conversion (YCbCr -> RGB) */
380/* ------------------------------------------------------------------ */
381
403 int32_t cb,
404 int32_t cr,
405 uint8_t* out_r,
406 uint8_t* out_g,
407 uint8_t* out_b)
408{
409 cb -= (int32_t)k_ra8_jpeg_level_offset;
410 cr -= (int32_t)k_ra8_jpeg_level_offset;
411 int32_t r = y + (((int32_t)k_ra8_jpeg_cr_r * cr) >> k_ra8_jpeg_yuv_shift);
412 int32_t g = y + ((((int32_t)k_ra8_jpeg_cb_g * cb) + ((int32_t)k_ra8_jpeg_cr_g * cr)) >>
414 int32_t b = y + (((int32_t)k_ra8_jpeg_cb_b * cb) >> k_ra8_jpeg_yuv_shift);
415 *out_r = internal_clamp_u8(r);
416 *out_g = internal_clamp_u8(g);
417 *out_b = internal_clamp_u8(b);
418}
419
420/* ------------------------------------------------------------------ */
421/* Public API: get_dimensions */
422/* ------------------------------------------------------------------ */
423
453internal_dims_next_marker(const uint8_t* jpeg_buf, uint32_t jpeg_len, uint32_t* i, uint16_t* out_mk)
454{
455 if (jpeg_buf[*i] != (uint8_t)k_ra8_jpeg_marker_byte) {
457 }
458 /* Skip pad bytes. */
459 while (*i < jpeg_len && jpeg_buf[*i] == (uint8_t)k_ra8_jpeg_marker_byte) {
460 (*i)++;
461 }
462 if (*i >= jpeg_len) {
464 }
465 uint8_t m = jpeg_buf[*i];
466 *out_mk = (uint16_t)(((uint16_t)k_jpeg_byte_mask << k_ra8_jpeg_byte_shift) | m);
467 (*i)++;
468 return k_ra8_ok;
469}
470
499RA8_INTERNAL static ra8_err_t internal_dims_parse_sof0(const uint8_t* jpeg_buf,
500 uint32_t i,
501 uint16_t seglen,
502 uint16_t* out_w,
503 uint16_t* out_h)
504{
505 if (seglen < 8U) {
507 }
508 uint8_t precision = jpeg_buf[i + 2U];
509 if (precision != 8U) {
511 }
512 *out_h = internal_read_be16(&jpeg_buf[i + 3U]);
513 *out_w = internal_read_be16(&jpeg_buf[i + k_jpeg_sof_dims_off]);
514 if (*out_w == 0U || *out_h == 0U) {
516 }
517 return k_ra8_ok;
518}
519
550RA8_INTERNAL static ra8_err_t internal_dims_step(const uint8_t* jpeg_buf,
551 uint32_t jpeg_len,
552 uint32_t* i,
553 bool* done,
554 uint16_t* out_w,
555 uint16_t* out_h)
556{
557 uint16_t mk = 0U;
558 ra8_err_t e = internal_dims_next_marker(jpeg_buf, jpeg_len, i, &mk);
559 if (e != k_ra8_ok) {
560 return e;
561 }
562 if (mk == (uint16_t)k_ra8_jpeg_marker_soi || mk == (uint16_t)k_ra8_jpeg_marker_eoi) {
563 return k_ra8_ok;
564 }
565 if (*i + 2U > jpeg_len) {
567 }
568 uint16_t seglen = internal_read_be16(&jpeg_buf[*i]);
569 if (seglen < 2U || (uint32_t)seglen > jpeg_len - *i) {
571 }
572 if (mk == (uint16_t)k_ra8_jpeg_marker_sof0) {
573 e = internal_dims_parse_sof0(jpeg_buf, *i, seglen, out_w, out_h);
574 if (e == k_ra8_ok) {
575 *done = true;
576 }
577 return e;
578 }
579 if (mk >= k_jpeg_marker_sof_lo && mk <= k_jpeg_marker_sof_hi &&
580 mk != (uint16_t)k_ra8_jpeg_marker_dht && mk != k_jpeg_marker_jpg) {
582 }
583 *i += seglen;
584 return k_ra8_ok;
585}
586
587ra8_err_t ra8_jpeg_sw_get_dimensions(const uint8_t* jpeg_buf,
588 uint32_t jpeg_len,
589 uint16_t* out_w,
590 uint16_t* out_h)
591{
592 RA8_CHECK_NULL_PTR(jpeg_buf, s_tag, "jpeg_buf is NULL");
593 RA8_CHECK_NULL_PTR(out_w, s_tag, "out_w is NULL");
594 RA8_CHECK_NULL_PTR(out_h, s_tag, "out_h is NULL");
595 if (jpeg_len < 4U) {
597 }
598 if (internal_read_be16(jpeg_buf) != (uint16_t)k_ra8_jpeg_marker_soi) {
600 }
601 uint32_t i = 2U;
602 while (i + 4U <= jpeg_len) {
603 bool done = false;
604 ra8_err_t e = internal_dims_step(jpeg_buf, jpeg_len, &i, &done, out_w, out_h);
605 if (e != k_ra8_ok) {
606 return e;
607 }
608 if (done) {
609 return k_ra8_ok;
610 }
611 }
613}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_protocol_error
Protocol-level error (e.g.
Definition ra8_err.h:429
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
void priv_jpeg_sw_idct8x8(int32_t *block)
Full 8x8 inverse DCT, in place.
void priv_jpeg_sw_ycc_to_rgb(int32_t y, int32_t cb, int32_t cr, uint8_t *out_r, uint8_t *out_g, uint8_t *out_b)
Convert a YCbCr triple to RGB (BT.601, fixed-point).
static ra8_err_t internal_dims_next_marker(const uint8_t *jpeg_buf, uint32_t jpeg_len, uint32_t *i, uint16_t *out_mk)
Advance past 0xFF pad bytes and read one marker code.
int32_t priv_jpeg_sw_htab_decode(ra8_jpeg_bitreader_t *br, const ra8_jpeg_htab_t *h)
Decode one Huffman symbol from br using table h.
int32_t priv_jpeg_sw_br_get_bits(ra8_jpeg_bitreader_t *br, uint8_t n)
Pop n bits MSB-first; returns -1 on underflow.
ra8_err_t ra8_jpeg_sw_get_dimensions(const uint8_t *jpeg_buf, uint32_t jpeg_len, uint16_t *out_w, uint16_t *out_h)
Parse the SOF0 marker of a JPEG stream and report its image dimensions without performing entropy dec...
void priv_jpeg_sw_htab_build(ra8_jpeg_htab_t *h)
Build canonical code/size and mincode/maxcode tables.
int32_t priv_jpeg_sw_huff_extend(int32_t v, uint8_t n)
Decode a signed n-bit DCT coefficient (T.81 F.1.2.1.3).
static ra8_err_t internal_dims_step(const uint8_t *jpeg_buf, uint32_t jpeg_len, uint32_t *i, bool *done, uint16_t *out_w, uint16_t *out_h)
One step of the dimension walk: read a marker, handle it.
static ra8_err_t internal_dims_parse_sof0(const uint8_t *jpeg_buf, uint32_t i, uint16_t seglen, uint16_t *out_w, uint16_t *out_h)
Extract width/height from an SOF0 payload (T.81 sec B.2.2).
static void internal_inv_dct_1d_norm(const int32_t *in, int32_t *out)
1-D inverse DCT pass with JPEG normalization folded in.
static void internal_br_fill(ra8_jpeg_bitreader_t *br)
Refill acc until at least 16 bits are available.
Definition ra8_jpeg_sw.c:83
static void internal_htab_build_lookup(ra8_jpeg_htab_t *h)
Build the F.2.2.3 mincode/maxcode/valptr decode tables.
Pure-software baseline JPEG (ISO/IEC 10918-1 / ITU-T T.81) codec.
Module-private declarations shared across the software JPEGcodec translation units.
@ k_ra8_jpeg_marker_dht
Define Huffman table.
@ k_ra8_jpeg_marker_eoi
End of image.
@ k_ra8_jpeg_marker_sof0
Baseline DCT, Huffman.
@ k_ra8_jpeg_marker_soi
Start of image.
@ k_ra8_jpeg_level_offset
RA8 JPEG level offset.
@ k_ra8_jpeg_byte_shift
RA8 JPEG byte shift.
@ k_ra8_jpeg_yuv_shift
BT.601 fixed-point shift.
@ k_ra8_jpeg_huff_lengths
16 BITS-list slots.
static uint16_t internal_read_be16(const uint8_t *p)
Read a 16-bit big-endian word from p.
@ k_jpeg_idct_p2_bias_sh
JPEG idct p2 bias sh.
@ k_jpeg_q14_shift
JPEG q14 shift.
@ k_jpeg_byte_mask
JPEG byte mask.
@ k_jpeg_sof_dims_off
JPEG sof dims off.
@ k_jpeg_reservoir_lo
JPEG reservoir lo.
@ k_ra8_jpeg_block_size
Coefficients per block.
@ k_ra8_jpeg_block_dim
8x8 DCT block edge.
@ k_ra8_jpeg_marker_byte
RA8 JPEG marker byte.
static const int32_t s_dct_cos_q14[8][8]
Cosine table cos((2n+1)*k*pi/16) * 2^14, k = row, n = col.
@ k_ra8_jpeg_cr_r
1.40200.
@ k_ra8_jpeg_cb_b
1.77200.
@ k_ra8_jpeg_cb_g
RA8 JPEG cb g.
@ k_ra8_jpeg_cr_g
RA8 JPEG cr g.
static uint8_t internal_clamp_u8(int32_t v)
Clamp v to the unsigned 8-bit pixel range.
@ k_jpeg_marker_jpg
JPEG marker jpg.
@ k_jpeg_marker_sof_hi
JPEG marker sof hi.
@ k_jpeg_marker_sof_lo
JPEG marker sof lo.
static const int32_t s_dct_w_q14[8]
sqrt(2/N)*C(k) DCT normalization weights, Q14.
Big-endian bit reader over an entropy-coded segment.
uint32_t acc
Bit accumulator.
uint32_t len
Total bytes.
uint8_t nbits
Bits valid in acc (0..32).
const uint8_t * buf
Byte stream.
uint32_t pos
Read cursor.
uint8_t had_eoi
Set when an end marker is consumed.
Decoded Huffman table – 256 entries indexed by symbol order.
uint16_t valptr[k_ra8_jpeg_huff_lengths]
Valptr.
uint16_t huffcode[k_ra8_jpeg_huff_max]
Code per symbol.
int32_t maxcode[k_ra8_jpeg_huff_lengths]
Maxcode.
int32_t mincode[k_ra8_jpeg_huff_lengths]
Mincode.
uint8_t vals[k_ra8_jpeg_huff_max]
Symbol order.
uint8_t bits[k_ra8_jpeg_huff_lengths]
BITS list.
uint8_t huffsize[k_ra8_jpeg_huff_max]
Code length.