ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_jpeg_sw_decode.c
Go to the documentation of this file.
1
30
31#include <stdint.h> // ra8-keep-include: `uint8_t` used directly
32#include <string.h>
33
34#include "ra8_attributes.h" // ra8-keep-include: `RA8_INTERNAL` and `RA8_PRIV` used directly
35#include "ra8_check.h"
36#include "ra8_err.h" // ra8-keep-include: `ra8_err_t` used directly
37#include "ra8_jpeg_sw.h"
39
41static const char* s_tag = "JPEG_SW";
42
43/* ------------------------------------------------------------------ */
44/* Decoder */
45/* ------------------------------------------------------------------ */
46
47/* The decoder context (`ra8_jpeg_dec_ctx_t`) and the marker/scan
48 * primitives below are declared in `ra8_jpeg_sw_internal.h` so the
49 * streaming driver (`ra8_jpeg_sw_stream.c`) can reuse them over its
50 * sliding window; this unit keeps their definitions plus the
51 * whole-buffer `ra8_jpeg_sw_decode()` driver. */
52
55{
56 if (d->cursor + 2U > d->src_len) {
58 }
59 uint16_t len = internal_read_be16(&d->src[d->cursor]);
60 if (len < 2U || (uint32_t)len > d->src_len - d->cursor) {
62 }
63 d->cursor += len;
64 return k_ra8_ok;
65}
66
69{
70 if (d->cursor + 2U > d->src_len) {
72 }
73 uint16_t len = internal_read_be16(&d->src[d->cursor]);
74 if (len < 2U || (uint32_t)len > d->src_len - d->cursor) {
76 }
77 uint32_t end = d->cursor + len;
78 d->cursor += 2U;
79 while (d->cursor < end) {
80 uint8_t pq_tq = d->src[d->cursor];
81 d->cursor++;
82 uint8_t pq = (uint8_t)(pq_tq >> k_ra8_jpeg_nibble_shift);
83 uint8_t tq = (uint8_t)(pq_tq & k_ra8_jpeg_nibble_mask);
84 if (tq >= (uint8_t)k_ra8_jpeg_quant_tabs || pq != 0U) {
85 return k_ra8_err_not_supported; /* 16-bit precision not supported. */
86 }
87 if (d->cursor + (uint32_t)k_ra8_jpeg_block_size > end) {
89 }
90 for (uint8_t i = 0U; i < (uint8_t)k_ra8_jpeg_block_size; i++) {
91 d->qtab[tq][s_zigzag[i]] = d->src[d->cursor];
92 d->cursor++;
93 }
94 }
95 return k_ra8_ok;
96}
97
125{
126 uint8_t tc_th = d->src[d->cursor];
127 d->cursor++;
128 uint8_t tc = (uint8_t)(tc_th >> k_ra8_jpeg_nibble_shift);
129 uint8_t th = (uint8_t)(tc_th & k_ra8_jpeg_nibble_mask);
130 if (tc >= (uint8_t)k_ra8_jpeg_huff_classes || th >= (uint8_t)k_ra8_jpeg_huff_ids) {
132 }
133 if (d->cursor + (uint32_t)k_ra8_jpeg_huff_lengths > end) {
135 }
136 ra8_jpeg_htab_t* h = (tc == 0U) ? &d->hdc[th] : &d->hac[th];
137 uint16_t total = 0U;
138 for (uint8_t i = 0U; i < (uint8_t)k_ra8_jpeg_huff_lengths; i++) {
139 h->bits[i] = d->src[d->cursor];
140 d->cursor++;
141 total = (uint16_t)(total + h->bits[i]);
142 }
143 if (total > (uint16_t)k_ra8_jpeg_huff_max) {
145 }
146 if (d->cursor + total > end) {
148 }
149 for (uint16_t i = 0U; i < total; i++) {
150 h->vals[i] = d->src[d->cursor];
151 d->cursor++;
152 }
154 return k_ra8_ok;
155}
156
159{
160 if (d->cursor + 2U > d->src_len) {
162 }
163 uint16_t len = internal_read_be16(&d->src[d->cursor]);
164 if (len < 2U || (uint32_t)len > d->src_len - d->cursor) {
166 }
167 uint32_t end = d->cursor + len;
168 d->cursor += 2U;
169 while (d->cursor < end) {
171 if (e != k_ra8_ok) {
172 return e;
173 }
174 }
175 return k_ra8_ok;
176}
177
199{
200 d->hmax = 0U;
201 d->vmax = 0U;
202 for (uint8_t i = 0U; i < d->ncomp; i++) {
203 d->comp_id[i] = d->src[*s];
204 (*s)++;
205 uint8_t hv = d->src[*s];
206 (*s)++;
207 d->comp_h[i] = (uint8_t)(hv >> k_ra8_jpeg_nibble_shift);
208 d->comp_v[i] = (uint8_t)(hv & k_ra8_jpeg_nibble_mask);
209 d->comp_qid[i] = d->src[*s];
210 (*s)++;
211 if (d->comp_h[i] > d->hmax) {
212 d->hmax = d->comp_h[i];
213 }
214 if (d->comp_v[i] > d->vmax) {
215 d->vmax = d->comp_v[i];
216 }
217 }
218}
219
244{
245 /* Only 4:4:4 (1,1,1) and 4:2:0 (2,1,1) accepted. */
246 if (d->ncomp == 3U) {
247 bool is_444 = (d->hmax == 1U && d->vmax == 1U);
248 bool is_420 = (d->hmax == 2U && d->vmax == 2U && d->comp_h[1] == 1U && d->comp_v[1] == 1U &&
249 d->comp_h[2] == 1U && d->comp_v[2] == 1U);
250 if (!is_444 && !is_420) {
252 }
253 }
254 return k_ra8_ok;
255}
256
259{
260 if (d->cursor + 2U > d->src_len) {
262 }
263 uint16_t len = internal_read_be16(&d->src[d->cursor]);
264 if (len < 8U || (uint32_t)len > d->src_len - d->cursor) {
266 }
267 uint32_t s = d->cursor + 2U;
268 uint8_t precision = d->src[s];
269 s++;
270 if (precision != 8U) {
272 }
273 d->height = internal_read_be16(&d->src[s]);
274 s += 2U;
275 d->width = internal_read_be16(&d->src[s]);
276 s += 2U;
277 d->ncomp = d->src[s];
278 s++;
279 if (d->ncomp != 1U && d->ncomp != 3U) {
281 }
282 if (((uint32_t)d->ncomp * 3U) + (s - d->cursor) > (uint32_t)len) {
284 }
286 d->cursor += len;
288}
289
292{
293 if (d->cursor + 2U > d->src_len) {
295 }
296 uint16_t len = internal_read_be16(&d->src[d->cursor]);
297 if (len < 6U || (uint32_t)len > d->src_len - d->cursor) {
299 }
300 uint32_t s = d->cursor + 2U;
301 uint8_t ns = d->src[s];
302 s++;
303 if (ns != d->ncomp) {
305 }
306 for (uint8_t i = 0U; i < ns; i++) {
307 uint8_t cs = d->src[s];
308 s++;
309 uint8_t tdta = d->src[s];
310 s++;
311 uint8_t idx = i;
312 for (uint8_t j = 0U; j < d->ncomp; j++) {
313 if (d->comp_id[j] == cs) {
314 idx = j;
315 break;
316 }
317 }
318 d->comp_dc_id[idx] = (uint8_t)(tdta >> k_ra8_jpeg_nibble_shift);
319 d->comp_ac_id[idx] = (uint8_t)(tdta & k_ra8_jpeg_nibble_mask);
320 if (d->comp_dc_id[idx] >= (uint8_t)k_ra8_jpeg_huff_ids ||
321 d->comp_ac_id[idx] >= (uint8_t)k_ra8_jpeg_huff_ids) {
323 }
324 }
325 /* Skip Ss/Se/AhAl (3 bytes). */
326 d->cursor += len;
327 return k_ra8_ok;
328}
329
360{
361 uint8_t k = 1U;
362 while (k < (uint8_t)k_ra8_jpeg_block_size) {
363 int32_t rs = priv_jpeg_sw_htab_decode(br, &d->hac[d->comp_ac_id[ci]]);
364 if (rs < 0) {
366 }
367 uint8_t rrrr = (uint8_t)(rs >> k_ra8_jpeg_nibble_shift);
368 uint8_t ssss = (uint8_t)(rs & k_ra8_jpeg_nibble_mask);
369 if (ssss == 0U) {
370 if (rrrr == k_jpeg_nibble_mask) {
371 k = (uint8_t)(k + 16U); /* ZRL: 16 zero coeffs. */
372 continue;
373 }
374 break; /* EOB. */
375 }
376 k = (uint8_t)(k + rrrr);
377 if (k >= (uint8_t)k_ra8_jpeg_block_size) {
379 }
380 int32_t v = priv_jpeg_sw_br_get_bits(br, ssss);
381 if (v < 0) {
383 }
384 v = priv_jpeg_sw_huff_extend(v, ssss);
385 outblk[s_zigzag[k]] = v * (int32_t)d->qtab[d->comp_qid[ci]][s_zigzag[k]];
386 k++;
387 }
388 return k_ra8_ok;
389}
390
394 uint8_t ci,
395 int32_t* outblk)
396{
397 for (uint8_t i = 0U; i < (uint8_t)k_ra8_jpeg_block_size; i++) {
398 outblk[i] = 0;
399 }
400 /* DC. */
401 int32_t t = priv_jpeg_sw_htab_decode(br, &d->hdc[d->comp_dc_id[ci]]);
402 if (t < 0) {
404 }
405 int32_t r = priv_jpeg_sw_br_get_bits(br, (uint8_t)t);
406 /* A zero-width Huffman value requests no bits, so the bit reader cannot
407 * return its exhausted sentinel when t == 0. */
408 // mcdc-deactivated: t == 0 requests no bits, so r < 0 requires t != 0; the operands cannot independently vary.
409 if (r < 0 && t != 0) {
411 }
412 int32_t diff = priv_jpeg_sw_huff_extend(r, (uint8_t)t);
413 d->comp_dc_pred[ci] += diff;
414 outblk[0] = d->comp_dc_pred[ci] * (int32_t)d->qtab[d->comp_qid[ci]][0];
415
416 /* AC. */
417 return internal_dec_block_ac(d, br, ci, outblk);
418}
419
420/* ------------------------------------------------------------------ */
421/* Public API: decode */
422/* ------------------------------------------------------------------ */
423
425RA8_PRIV void priv_jpeg_sw_idct_into(int32_t* coeffs, uint8_t* tile)
426{
427 priv_jpeg_sw_idct8x8(coeffs);
428 for (uint8_t i = 0U; i < (uint8_t)k_ra8_jpeg_block_size; i++) {
429 int32_t v = coeffs[i] + (int32_t)k_ra8_jpeg_level_offset;
430 tile[i] = internal_clamp_u8(v);
431 }
432}
433
456RA8_INTERNAL static void internal_dec_copy_block_to_tile(const uint8_t* blk,
457 uint8_t* y_tile,
458 uint8_t bx,
459 uint8_t by,
460 uint16_t mcu_w_px)
461{
462 for (uint8_t r = 0U; r < (uint8_t)k_ra8_jpeg_block_dim; r++) {
463 for (uint8_t c = 0U; c < (uint8_t)k_ra8_jpeg_block_dim; c++) {
464 uint16_t ty = (uint16_t)((by * (uint16_t)k_ra8_jpeg_block_dim) + r);
465 uint16_t tx = (uint16_t)((bx * (uint16_t)k_ra8_jpeg_block_dim) + c);
466 y_tile[(ty * mcu_w_px) + tx] = blk[(r * (uint8_t)k_ra8_jpeg_block_dim) + c];
467 }
468 }
469}
470
474 uint8_t* y_tile,
475 uint16_t mcu_w_px)
476{
477 int32_t coeffs[(uint32_t)k_ra8_jpeg_block_size];
478 for (uint8_t by = 0U; by < d->vmax; by++) {
479 for (uint8_t bx = 0U; bx < d->hmax; bx++) {
480 ra8_err_t e = priv_jpeg_sw_block(d, br, 0U, coeffs);
481 if (e != k_ra8_ok) {
482 return e;
483 }
484 uint8_t blk[(uint32_t)k_ra8_jpeg_block_size];
485 priv_jpeg_sw_idct_into(coeffs, blk);
486 internal_dec_copy_block_to_tile(blk, y_tile, bx, by, mcu_w_px);
487 }
488 }
489 return k_ra8_ok;
490}
491
495 uint8_t* cb_tile,
496 uint8_t* cr_tile)
497{
498 int32_t coeffs[(uint32_t)k_ra8_jpeg_block_size];
499 ra8_err_t e = priv_jpeg_sw_block(d, br, 1U, coeffs);
500 if (e != k_ra8_ok) {
501 return e;
502 }
503 priv_jpeg_sw_idct_into(coeffs, cb_tile);
504 e = priv_jpeg_sw_block(d, br, 2U, coeffs);
505 if (e != k_ra8_ok) {
506 return e;
507 }
508 priv_jpeg_sw_idct_into(coeffs, cr_tile);
509 return k_ra8_ok;
510}
511
543 const uint8_t* y_tile,
544 const uint8_t* cb_tile,
545 const uint8_t* cr_tile,
546 uint16_t mx,
547 uint16_t my,
548 uint16_t mcu_w_px,
549 uint16_t mcu_h_px,
550 uint8_t* out_buf)
551{
552 for (uint16_t r = 0U; r < mcu_h_px; r++) {
553 uint16_t py = (uint16_t)((my * mcu_h_px) + r);
554 if (py >= d->height) {
555 break;
556 }
557 for (uint16_t c = 0U; c < mcu_w_px; c++) {
558 uint16_t px = (uint16_t)((mx * mcu_w_px) + c);
559 if (px >= d->width) {
560 break;
561 }
562 int32_t y = (int32_t)y_tile[(r * mcu_w_px) + c];
563 int32_t cb;
564 int32_t cr;
565 if (d->ncomp == 3U) {
566 uint16_t cr_x = (uint16_t)(c / d->hmax);
567 uint16_t cr_y = (uint16_t)(r / d->vmax);
568 cb = (int32_t)cb_tile[(cr_y * (uint16_t)k_ra8_jpeg_block_dim) + cr_x];
569 cr = (int32_t)cr_tile[(cr_y * (uint16_t)k_ra8_jpeg_block_dim) + cr_x];
570 } else {
571 cb = (int32_t)k_ra8_jpeg_level_offset;
572 cr = (int32_t)k_ra8_jpeg_level_offset;
573 }
574 uint32_t idx =
575 (((uint32_t)py * (uint32_t)d->width) + (uint32_t)px) * (uint32_t)k_ra8_jpeg_rgb_components;
576 priv_jpeg_sw_ycc_to_rgb(y, cb, cr, &out_buf[idx], &out_buf[idx + 1U], &out_buf[idx + 2U]);
577 }
578 }
579}
580
615 uint8_t* y_tile,
616 uint8_t* cb_tile,
617 uint8_t* cr_tile,
618 uint16_t mx,
619 uint16_t my,
620 uint16_t mcu_w_px,
621 uint16_t mcu_h_px,
622 uint8_t* out_buf)
623{
624 ra8_err_t e = priv_jpeg_sw_mcu_y(d, br, y_tile, mcu_w_px);
625 if (e != k_ra8_ok) {
626 return e;
627 }
628 if (d->ncomp == 3U) {
629 e = priv_jpeg_sw_mcu_chroma(d, br, cb_tile, cr_tile);
630 if (e != k_ra8_ok) {
631 return e;
632 }
633 }
634 internal_dec_emit_mcu_rgb(d, y_tile, cb_tile, cr_tile, mx, my, mcu_w_px, mcu_h_px, out_buf);
635 return k_ra8_ok;
636}
637
658{
659 br->buf = d->src;
660 br->len = d->src_len;
661 br->pos = d->cursor;
662 br->acc = 0U;
663 br->nbits = 0U;
664 br->had_eoi = 0U;
665 for (uint8_t i = 0U; i < (uint8_t)k_ra8_jpeg_max_comps; i++) {
666 d->comp_dc_pred[i] = 0;
667 }
668}
669
697internal_dec_decode_scan(ra8_jpeg_dec_ctx_t* d, uint8_t* out_buf, uint32_t out_buf_len)
698{
699 uint32_t need = (uint32_t)d->width * (uint32_t)d->height * (uint32_t)k_ra8_jpeg_rgb_components;
700 if (out_buf_len < need) {
702 }
703
706
707 /*
708 * Cross-function invariant: priv_jpeg_sw_parse_sof0() only returns
709 * success for the 4:4:4 and 4:2:0 chroma layouts (and grayscale), all
710 * of which set hmax and vmax to a non-zero value.
711 * The clang static analyzer (scan-build, core.DivideZero) cannot follow
712 * the cross-function invariant, so re-state it here as an assertion to
713 * make the property locally provable to the analyzer and to NASA Power-
714 * of-10 Rule 5 readers.
715 */
716 RA8_ASSERT(d->hmax > 0U, "JPEG decoder hmax must be positive");
717 RA8_ASSERT(d->vmax > 0U, "JPEG decoder vmax must be positive");
718
719 uint16_t mcu_w_px = (uint16_t)((uint16_t)k_ra8_jpeg_block_dim * d->hmax);
720 uint16_t mcu_h_px = (uint16_t)((uint16_t)k_ra8_jpeg_block_dim * d->vmax);
721 uint16_t mcus_x = (uint16_t)(((d->width + mcu_w_px) - 1U) / mcu_w_px);
722 uint16_t mcus_y = (uint16_t)(((d->height + mcu_h_px) - 1U) / mcu_h_px);
723
724 uint8_t y_tile[(uint32_t)k_ra8_jpeg_mcu_max_dim * (uint32_t)k_ra8_jpeg_mcu_max_dim];
725 uint8_t cb_tile[(uint32_t)k_ra8_jpeg_block_size];
726 uint8_t cr_tile[(uint32_t)k_ra8_jpeg_block_size];
727
728 for (uint16_t my = 0U; my < mcus_y; my++) {
729 for (uint16_t mx = 0U; mx < mcus_x; mx++) {
731 &br,
732 y_tile,
733 cb_tile,
734 cr_tile,
735 mx,
736 my,
737 mcu_w_px,
738 mcu_h_px,
739 out_buf);
740 if (e != k_ra8_ok) {
741 return e;
742 }
743 }
744 }
745 d->cursor = br.pos;
746 return k_ra8_ok;
747}
748
777 uint16_t mk,
778 bool got_sof,
780{
781 if (mk == (uint16_t)k_ra8_jpeg_marker_dqt) {
782 return priv_jpeg_sw_parse_dqt(d);
783 }
784 if (mk == (uint16_t)k_ra8_jpeg_marker_dht) {
785 return priv_jpeg_sw_parse_dht(d);
786 }
787 if (mk == (uint16_t)k_ra8_jpeg_marker_sos) {
788 if (!got_sof) {
790 }
792 if (e != k_ra8_ok) {
793 return e;
794 }
795 *action = k_ra8_jpeg_dec_scan;
796 return k_ra8_ok;
797 }
798 if (mk == (uint16_t)k_ra8_jpeg_marker_eoi) {
799 *action = k_ra8_jpeg_dec_eoi;
800 return k_ra8_ok;
801 }
802 if (mk >= (uint16_t)k_ra8_jpeg_marker_rst0 && mk <= (uint16_t)k_ra8_jpeg_marker_rst7) {
803 /* Standalone marker, no length. */
804 return k_ra8_ok;
805 }
807}
808
811 bool* got_sof,
813{
814 *action = k_ra8_jpeg_dec_continue;
815 if (d->src[d->cursor] != (uint8_t)k_ra8_jpeg_marker_byte) {
817 }
818 while (d->cursor < d->src_len && d->src[d->cursor] == (uint8_t)k_ra8_jpeg_marker_byte) {
819 d->cursor++;
820 }
821 if (d->cursor >= d->src_len) {
823 }
824 uint8_t m = d->src[d->cursor];
825 d->cursor++;
826 uint16_t mk = (uint16_t)(k_jpeg_marker_ff00 | m);
827
828 if (mk == (uint16_t)k_ra8_jpeg_marker_sof0) {
830 if (e != k_ra8_ok) {
831 return e;
832 }
833 *got_sof = true;
834 return k_ra8_ok;
835 }
836 if (mk >= k_jpeg_marker_sof1 && mk <= k_jpeg_marker_sof_hi &&
837 mk != (uint16_t)k_ra8_jpeg_marker_dht && mk != k_jpeg_marker_jpg) {
839 }
840 return internal_dec_dispatch_tail(d, mk, *got_sof, action);
841}
842
872 uint8_t* out_buf,
873 uint32_t out_buf_len,
874 uint16_t* out_w,
875 uint16_t* out_h)
876{
877 bool got_sof = false;
878 while (d->cursor < d->src_len) {
880 ra8_err_t e = priv_jpeg_sw_dispatch(d, &got_sof, &action);
881 if (e != k_ra8_ok) {
882 return e;
883 }
884 if (action == k_ra8_jpeg_dec_scan) {
885 *out_w = d->width;
886 *out_h = d->height;
887 return internal_dec_decode_scan(d, out_buf, out_buf_len);
888 }
889 if (action == k_ra8_jpeg_dec_eoi) {
890 break;
891 }
892 }
894}
895
896ra8_err_t ra8_jpeg_sw_decode(const uint8_t* jpeg_buf,
897 uint32_t jpeg_len,
898 uint8_t* out_buf,
899 uint32_t out_buf_len,
900 uint16_t* out_w,
901 uint16_t* out_h)
902{
903 RA8_CHECK_NULL_PTR(jpeg_buf, s_tag, "jpeg_buf is NULL");
904 RA8_CHECK_NULL_PTR(out_buf, s_tag, "out_buf is NULL");
905 RA8_CHECK_NULL_PTR(out_w, s_tag, "out_w is NULL");
906 RA8_CHECK_NULL_PTR(out_h, s_tag, "out_h is NULL");
907 if (jpeg_len < 4U) {
909 }
910
911 /* Decoder context is large (4 Huffman tables + 2 quant tables);
912 * allocate as `static` so it doesn't blow the stack budget the
913 * project enforces via `-Wstack-usage`. The codec is documented
914 * as not thread-safe, so the static is fine. */
915 static ra8_jpeg_dec_ctx_t s_d;
916 ra8_jpeg_dec_ctx_t* d = &s_d;
917 memset(d, 0, sizeof(*d));
918 d->src = jpeg_buf;
919 d->src_len = jpeg_len;
920
921 if (internal_read_be16(jpeg_buf) != (uint16_t)k_ra8_jpeg_marker_soi) {
923 }
924 d->cursor = 2U;
925
926 return internal_dec_run(d, out_buf, out_buf_len, out_w, out_h);
927}
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_ASSERT(condition, message)
Runtime invariant check.
Definition ra8_check.h:123
#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 * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
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).
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.
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).
Pure-software baseline JPEG (ISO/IEC 10918-1 / ITU-T T.81) codec.
static void internal_dec_scan_begin(ra8_jpeg_dec_ctx_t *d, ra8_jpeg_bitreader_t *br)
Prime the bit reader and reset the DC predictors for a scan.
ra8_err_t priv_jpeg_sw_parse_sof0(ra8_jpeg_dec_ctx_t *d)
Implementation of priv_jpeg_sw_parse_sof0() – T.81 B.2.2 frame header.
static ra8_err_t internal_dec_decode_scan(ra8_jpeg_dec_ctx_t *d, uint8_t *out_buf, uint32_t out_buf_len)
Decode the whole entropy-coded segment, MCU by MCU.
ra8_err_t priv_jpeg_sw_dispatch(ra8_jpeg_dec_ctx_t *d, bool *got_sof, ra8_jpeg_dec_marker_action_t *action)
Implementation of priv_jpeg_sw_dispatch() – marker extraction + routing.
static ra8_err_t internal_dec_parse_dht_one(ra8_jpeg_dec_ctx_t *d, uint32_t end)
Parse one (TcTh, BITS, HUFFVAL) table out of a DHT segment.
static ra8_err_t internal_dec_dispatch_tail(ra8_jpeg_dec_ctx_t *d, uint16_t mk, bool got_sof, ra8_jpeg_dec_marker_action_t *action)
Handle a non-SOF marker in the decode dispatch chain.
ra8_err_t priv_jpeg_sw_mcu_y(ra8_jpeg_dec_ctx_t *d, ra8_jpeg_bitreader_t *br, uint8_t *y_tile, uint16_t mcu_w_px)
Implementation of priv_jpeg_sw_mcu_y() – hmax*vmax luma block loop.
static ra8_err_t internal_dec_run(ra8_jpeg_dec_ctx_t *d, uint8_t *out_buf, uint32_t out_buf_len, uint16_t *out_w, uint16_t *out_h)
Marker-walk driver for the whole-buffer decode.
static void internal_dec_parse_sof0_components(ra8_jpeg_dec_ctx_t *d, uint32_t *s)
Read the per-component id/sampling/quant fields of an SOF0.
static void internal_dec_emit_mcu_rgb(const ra8_jpeg_dec_ctx_t *d, const uint8_t *y_tile, const uint8_t *cb_tile, const uint8_t *cr_tile, uint16_t mx, uint16_t my, uint16_t mcu_w_px, uint16_t mcu_h_px, uint8_t *out_buf)
Convert one MCU's reconstructed YCbCr tiles into output RGB pixels.
static ra8_err_t internal_dec_block_ac(ra8_jpeg_dec_ctx_t *d, ra8_jpeg_bitreader_t *br, uint8_t ci, int32_t *outblk)
Run-length decode the 63 AC coefficients of one block.
static void internal_dec_copy_block_to_tile(const uint8_t *blk, uint8_t *y_tile, uint8_t bx, uint8_t by, uint16_t mcu_w_px)
Copy one reconstructed 8x8 luma block into its Y-tile slot.
ra8_err_t priv_jpeg_sw_parse_dht(ra8_jpeg_dec_ctx_t *d)
Implementation of priv_jpeg_sw_parse_dht() – T.81 B.2.4.2 record loop.
static ra8_err_t internal_dec_decode_mcu(ra8_jpeg_dec_ctx_t *d, ra8_jpeg_bitreader_t *br, uint8_t *y_tile, uint8_t *cb_tile, uint8_t *cr_tile, uint16_t mx, uint16_t my, uint16_t mcu_w_px, uint16_t mcu_h_px, uint8_t *out_buf)
Decode one MCU (luma + optional chroma) and emit its RGB pixels.
ra8_err_t ra8_jpeg_sw_decode(const uint8_t *jpeg_buf, uint32_t jpeg_len, uint8_t *out_buf, uint32_t out_buf_len, uint16_t *out_w, uint16_t *out_h)
Decode a baseline JPEG stream into packed RGB888.
void priv_jpeg_sw_idct_into(int32_t *coeffs, uint8_t *tile)
Implementation of priv_jpeg_sw_idct_into() – IDCT + level shift + clamp.
ra8_err_t priv_jpeg_sw_block(ra8_jpeg_dec_ctx_t *d, ra8_jpeg_bitreader_t *br, uint8_t ci, int32_t *outblk)
Implementation of priv_jpeg_sw_block() – T.81 F.2.2 DC diff + AC run-length.
ra8_err_t priv_jpeg_sw_skip_segment(ra8_jpeg_dec_ctx_t *d)
Implementation of priv_jpeg_sw_skip_segment() – bounds-checked cursor hop.
ra8_err_t priv_jpeg_sw_parse_dqt(ra8_jpeg_dec_ctx_t *d)
Implementation of priv_jpeg_sw_parse_dqt() – T.81 B.2.4.1 de-zigzag parse.
ra8_err_t priv_jpeg_sw_mcu_chroma(ra8_jpeg_dec_ctx_t *d, ra8_jpeg_bitreader_t *br, uint8_t *cb_tile, uint8_t *cr_tile)
Implementation of priv_jpeg_sw_mcu_chroma() – one Cb then one Cr block.
ra8_err_t priv_jpeg_sw_parse_sos(ra8_jpeg_dec_ctx_t *d)
Implementation of priv_jpeg_sw_parse_sos() – T.81 B.2.3 selector binding.
static ra8_err_t internal_dec_check_chroma_layout(const ra8_jpeg_dec_ctx_t *d)
Accept only the 4:4:4 and 4:2:0 3-component chroma layouts.
Module-private declarations shared across the software JPEGcodec translation units.
@ k_ra8_jpeg_marker_dht
Define Huffman table.
@ k_ra8_jpeg_marker_rst7
Restart 7.
@ k_ra8_jpeg_marker_eoi
End of image.
@ k_ra8_jpeg_marker_sof0
Baseline DCT, Huffman.
@ k_ra8_jpeg_marker_rst0
Restart 0.
@ k_ra8_jpeg_marker_soi
Start of image.
@ k_ra8_jpeg_marker_dqt
Define quantization table.
@ k_ra8_jpeg_marker_sos
Start of scan.
@ k_ra8_jpeg_level_offset
RA8 JPEG level offset.
@ k_ra8_jpeg_nibble_shift
RA8 JPEG nibble shift.
@ k_ra8_jpeg_nibble_mask
RA8 JPEG nibble mask.
@ k_ra8_jpeg_rgb_components
RA8 JPEG RGB components.
@ 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_nibble_mask
JPEG nibble mask.
@ k_ra8_jpeg_huff_ids
Luma + chroma table id.
@ k_ra8_jpeg_mcu_max_dim
4:2:0 MCU is 16x16 luma px.
@ k_ra8_jpeg_block_size
Coefficients per block.
@ k_ra8_jpeg_block_dim
8x8 DCT block edge.
@ k_ra8_jpeg_huff_classes
DC + AC.
@ k_ra8_jpeg_marker_byte
RA8 JPEG marker byte.
@ k_ra8_jpeg_max_comps
YCbCr or grayscale only.
@ k_ra8_jpeg_quant_tabs
One luma + one chroma table.
@ k_ra8_jpeg_huff_max
Max symbols per Huffman table.
static const uint8_t s_zigzag[64]
Zig-zag de-interleave order (T.81 Figure 5).
static uint8_t internal_clamp_u8(int32_t v)
Clamp v to the unsigned 8-bit pixel range.
@ k_jpeg_marker_ff00
JPEG marker ff00.
@ k_jpeg_marker_jpg
JPEG marker jpg.
@ k_jpeg_marker_sof1
JPEG marker sof1.
@ k_jpeg_marker_sof_hi
JPEG marker sof hi.
ra8_jpeg_dec_marker_action_t
Result of priv_jpeg_sw_dispatch(): what the driver does next.
@ k_ra8_jpeg_dec_eoi
EOI reached; the driver should stop with an error.
@ k_ra8_jpeg_dec_continue
Keep scanning markers.
@ k_ra8_jpeg_dec_scan
SOS reached; the driver should run its scan loop.
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.
Decoder state shared by the whole-buffer and streaming drivers.
int32_t comp_dc_pred[k_ra8_jpeg_max_comps]
DC predictors (scan state).
ra8_jpeg_htab_t hac[k_ra8_jpeg_huff_ids]
AC Huffman tables.
uint16_t qtab[k_ra8_jpeg_quant_tabs][k_ra8_jpeg_block_size]
Dequant tables.
uint8_t comp_qid[k_ra8_jpeg_max_comps]
Quant-table selector.
uint8_t comp_dc_id[k_ra8_jpeg_max_comps]
DC Huffman selector.
uint16_t height
Image height from SOF0, pixels.
uint8_t vmax
Max vertical sampling factor.
uint32_t src_len
Length of src in bytes.
uint8_t comp_v[k_ra8_jpeg_max_comps]
Vertical sampling.
uint32_t cursor
Parse cursor into src.
uint8_t ncomp
1 grayscale, 3 YCbCr.
ra8_jpeg_htab_t hdc[k_ra8_jpeg_huff_ids]
DC Huffman tables.
uint16_t width
Image width from SOF0, pixels.
uint8_t comp_h[k_ra8_jpeg_max_comps]
Horizontal sampling.
uint8_t comp_id[k_ra8_jpeg_max_comps]
Component identifiers.
uint8_t comp_ac_id[k_ra8_jpeg_max_comps]
AC Huffman selector.
uint8_t hmax
Max horizontal sampling factor.
const uint8_t * src
Byte slice the parsers read from.
Decoded Huffman table – 256 entries indexed by symbol order.
uint8_t vals[k_ra8_jpeg_huff_max]
Symbol order.
uint8_t bits[k_ra8_jpeg_huff_lengths]
BITS list.