ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_jpeg_sw_stream.c
Go to the documentation of this file.
1
28
29#include <stddef.h>
30#include <stdint.h>
31#include <string.h>
32
33#include "ra8_attributes.h"
34#include "ra8_check.h"
35#include "ra8_err.h"
36#include "ra8_jpeg_sw.h"
38#include "ra8_log.h"
39
41static const char* s_tag = "JPEG_SW";
42
53
65typedef struct {
67 void* pull_ctx;
68 uint8_t* win;
69 uint32_t win_cap;
70 uint32_t win_len;
71 uint8_t eof;
72
74 void* cb_ctx;
75
76 uint8_t* stripe;
77 uint32_t stripe_cap;
78 uint8_t channels;
79 uint16_t mcu_w;
80 uint16_t mcu_h;
81 uint16_t mcus_x;
82 uint16_t mcus_y;
83
86
89
106{
107 while ((st->eof == 0U) && (st->win_len < st->win_cap)) {
108 size_t got = 0U;
109 const ra8_err_t err =
110 st->pull(st->pull_ctx, &st->win[st->win_len], (size_t)(st->win_cap - st->win_len), &got);
111 if (err != k_ra8_ok) {
112 return err;
113 }
114 if (got == 0U) {
115 st->eof = 1U;
116 } else {
117 st->win_len += (uint32_t)got;
118 }
119 }
120 return k_ra8_ok;
121}
122
139{
140 if (consumed > 0U) {
141 (void)memmove(st->win, &st->win[consumed], (size_t)(st->win_len - consumed));
142 st->win_len -= consumed;
143 }
144 return internal_js_refill(st);
145}
146
167 ra8_jpeg_sw_geom_fn on_geom)
168{
169 const ra8_jpeg_dec_ctx_t* d = &st->dec;
170 st->channels =
171 (d->ncomp == 1U) ? (uint8_t)k_ra8_jpeg_stream_gray_ch : (uint8_t)k_ra8_jpeg_stream_rgb_ch;
172 st->mcu_w = (uint16_t)((uint16_t)k_ra8_jpeg_block_dim * d->hmax);
173 st->mcu_h = (uint16_t)((uint16_t)k_ra8_jpeg_block_dim * d->vmax);
174 st->mcus_x = (uint16_t)((d->width + st->mcu_w - 1U) / st->mcu_w);
175 st->mcus_y = (uint16_t)((d->height + st->mcu_h - 1U) / st->mcu_h);
176
177 uint8_t* stripe = nullptr;
178 uint32_t stripe_cap = 0U;
179 const ra8_err_t err =
180 on_geom(st->cb_ctx, d->width, d->height, st->channels, st->mcu_h, &stripe, &stripe_cap);
181 if (err != k_ra8_ok) {
182 return err;
183 }
184 RA8_CHECK_NULL_PTR(stripe, s_tag, "geometry callback supplied a NULL stripe");
185 const uint32_t need = (uint32_t)d->width * (uint32_t)st->mcu_h * (uint32_t)st->channels;
186 if (stripe_cap < need) {
188 }
189 st->stripe = stripe;
190 st->stripe_cap = stripe_cap;
191 return k_ra8_ok;
192}
193
217 ra8_jpeg_sw_geom_fn on_geom,
218 uint32_t* out_scan_pos)
219{
220 bool got_sof = false;
221 bool geom_done = false;
222 for (uint16_t iter = 0U; iter < (uint16_t)k_ra8_jpeg_stream_max_markers; iter++) {
223 if (st->win_len == 0U) {
224 return k_ra8_err_protocol_error; /* stream ended before SOS */
225 }
226 st->dec.src = st->win;
227 st->dec.src_len = st->win_len;
228 st->dec.cursor = 0U;
230 ra8_err_t err = priv_jpeg_sw_dispatch(&st->dec, &got_sof, &action);
231 if (err != k_ra8_ok) {
232 return err;
233 }
234 if (got_sof && !geom_done) {
235 err = internal_js_bind_geometry(st, on_geom);
236 if (err != k_ra8_ok) {
237 return err;
238 }
239 geom_done = true;
240 }
241 if (action == k_ra8_jpeg_dec_scan) {
242 *out_scan_pos = st->dec.cursor;
243 return k_ra8_ok;
244 }
245 if (action == k_ra8_jpeg_dec_eoi) {
246 return k_ra8_err_protocol_error; /* EOI before any scan */
247 }
248 err = internal_js_slide(st, st->dec.cursor);
249 if (err != k_ra8_ok) {
250 return err;
251 }
252 }
253 return k_ra8_err_protocol_error; /* marker budget exhausted (hostile stream) */
254}
255
276 const uint8_t* y_tile,
277 const uint8_t* cb_tile,
278 const uint8_t* cr_tile,
279 uint16_t mx,
280 uint16_t rows)
281{
282 const ra8_jpeg_dec_ctx_t* d = &st->dec;
283 const uint32_t stride = (uint32_t)d->width * (uint32_t)st->channels;
284 for (uint16_t r = 0U; r < rows; r++) {
285 for (uint16_t c = 0U; c < st->mcu_w; c++) {
286 const uint32_t px = ((uint32_t)mx * (uint32_t)st->mcu_w) + (uint32_t)c;
287 if (px >= (uint32_t)d->width) {
288 break;
289 }
290 const int32_t y = (int32_t)y_tile[((uint32_t)r * (uint32_t)st->mcu_w) + (uint32_t)c];
291 if (st->channels == (uint8_t)k_ra8_jpeg_stream_gray_ch) {
292 st->stripe[((uint32_t)r * stride) + px] = (uint8_t)y;
293 continue;
294 }
295 const uint16_t cx = (uint16_t)(c / d->hmax);
296 const uint16_t cy = (uint16_t)(r / d->vmax);
297 const int32_t cb = (int32_t)cb_tile[((uint32_t)cy * (uint32_t)k_ra8_jpeg_block_dim) + cx];
298 const int32_t cr = (int32_t)cr_tile[((uint32_t)cy * (uint32_t)k_ra8_jpeg_block_dim) + cx];
299 const uint32_t idx = ((uint32_t)r * stride) + (px * (uint32_t)st->channels);
301 cb,
302 cr,
303 &st->stripe[idx],
304 &st->stripe[idx + 1U],
305 &st->stripe[idx + 2U]);
306 }
307 }
308}
309
330{
331 if ((st->eof == 0U) && ((st->win_len - br->pos) < (uint32_t)k_ra8_jpeg_sw_stream_scan_margin)) {
332 const uint32_t shift = br->pos;
333 const ra8_err_t err = internal_js_slide(st, shift);
334 if (err != k_ra8_ok) {
335 return err;
336 }
337 br->pos = 0U;
338 br->len = st->win_len;
339 }
340 return k_ra8_ok;
341}
342
367 uint8_t* y_tile,
368 uint8_t* cb_tile,
369 uint8_t* cr_tile,
370 uint16_t mx,
371 uint16_t rows)
372{
374 if (err != k_ra8_ok) {
375 return err;
376 }
377 err = priv_jpeg_sw_mcu_y(&st->dec, br, y_tile, st->mcu_w);
378 if (err != k_ra8_ok) {
379 return err;
380 }
381 if (st->dec.ncomp == 3U) {
382 err = priv_jpeg_sw_mcu_chroma(&st->dec, br, cb_tile, cr_tile);
383 if (err != k_ra8_ok) {
384 return err;
385 }
386 }
387 internal_js_emit_mcu(st, y_tile, cb_tile, cr_tile, mx, rows);
388 return k_ra8_ok;
389}
390
410{
411 ra8_jpeg_dec_ctx_t* d = &st->dec;
413 .buf = st->win,
414 .len = st->win_len,
415 .pos = scan_pos,
416 .acc = 0U,
417 .nbits = 0U,
418 .had_eoi = 0U,
419 };
420 for (uint8_t i = 0U; i < (uint8_t)k_ra8_jpeg_max_comps; i++) {
421 d->comp_dc_pred[i] = 0;
422 }
423 uint8_t y_tile[(uint32_t)k_ra8_jpeg_mcu_max_dim * (uint32_t)k_ra8_jpeg_mcu_max_dim] = {};
424 uint8_t cb_tile[(uint32_t)k_ra8_jpeg_block_size] = {};
425 uint8_t cr_tile[(uint32_t)k_ra8_jpeg_block_size] = {};
426
427 for (uint16_t my = 0U; my < st->mcus_y; my++) {
428 const uint32_t y0 = (uint32_t)my * (uint32_t)st->mcu_h;
429 const uint32_t left = (uint32_t)d->height - y0;
430 const uint16_t rows = (uint16_t)((left < (uint32_t)st->mcu_h) ? left : (uint32_t)st->mcu_h);
431 for (uint16_t mx = 0U; mx < st->mcus_x; mx++) {
432 const ra8_err_t err = internal_js_decode_mcu(st, &br, y_tile, cb_tile, cr_tile, mx, rows);
433 if (err != k_ra8_ok) {
434 return err;
435 }
436 }
437 const ra8_err_t err =
438 st->on_rows(st->cb_ctx, st->stripe, d->width, (uint16_t)y0, rows, st->channels);
439 if (err != k_ra8_ok) {
440 return err;
441 }
442 }
443 return k_ra8_ok;
444}
445
471 void* pull_ctx,
472 uint8_t* window,
473 uint32_t window_cap,
474 ra8_jpeg_sw_rows_fn on_rows,
475 void* cb_ctx)
476{
477 (void)memset(st, 0, sizeof(*st));
478 st->pull = pull;
479 st->pull_ctx = pull_ctx;
480 st->win = window;
481 st->win_cap = window_cap;
482 st->on_rows = on_rows;
483 st->cb_ctx = cb_ctx;
485 if (err != k_ra8_ok) {
486 return err;
487 }
488 if (st->win_len < (uint32_t)k_ra8_jpeg_stream_soi_bytes) {
490 }
491 if (internal_read_be16(st->win) != (uint16_t)k_ra8_jpeg_marker_soi) {
493 }
495}
496
498 void* pull_ctx,
499 uint8_t* window,
500 uint32_t window_cap,
501 ra8_jpeg_sw_geom_fn on_geom,
502 ra8_jpeg_sw_rows_fn on_rows,
503 void* cb_ctx)
504{
505 RA8_CHECK_NULL_PTR(pull, s_tag, "pull must not be nullptr");
506 RA8_CHECK_NULL_PTR(window, s_tag, "window must not be nullptr");
507 RA8_CHECK_NULL_PTR(on_geom, s_tag, "on_geom must not be nullptr");
508 RA8_CHECK_NULL_PTR(on_rows, s_tag, "on_rows must not be nullptr");
509 if (window_cap < (uint32_t)k_ra8_jpeg_sw_stream_min_window) {
511 }
513 ra8_err_t err = internal_js_begin(st, pull, pull_ctx, window, window_cap, on_rows, cb_ctx);
514 if (err != k_ra8_ok) {
515 return err;
516 }
517 uint32_t scan_pos = 0U;
518 err = internal_js_parse_markers(st, on_geom, &scan_pos);
519 if (err != k_ra8_ok) {
520 return err;
521 }
522 return internal_js_scan(st, scan_pos);
523}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#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_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 * memmove(void *dst, const void *src, size_t n)
Copy memory area between potentially overlapping regions.
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).
Pure-software baseline JPEG (ISO/IEC 10918-1 / ITU-T T.81) codec.
@ k_ra8_jpeg_sw_stream_scan_margin
Refill trigger, bytes.
@ k_ra8_jpeg_sw_stream_min_window
Minimum window bytes.
ra8_err_t(* ra8_jpeg_sw_pull_fn)(void *ctx, uint8_t *buf, size_t cap, size_t *got)
Forward byte source for the streaming decoder (DIP seam).
ra8_err_t(* ra8_jpeg_sw_rows_fn)(void *ctx, const uint8_t *px, uint16_t width, uint16_t y0, uint16_t nrows, uint8_t channels)
Stripe sink: receives each completed run of decoded pixel rows.
ra8_err_t(* ra8_jpeg_sw_geom_fn)(void *ctx, uint16_t width, uint16_t height, uint8_t channels, uint16_t stripe_rows, uint8_t **out_stripe, uint32_t *out_stripe_cap)
Geometry callback: fires once, right after SOF0 parses.
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.
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.
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.
Module-private declarations shared across the software JPEGcodec translation units.
@ k_ra8_jpeg_marker_soi
Start of image.
static uint16_t internal_read_be16(const uint8_t *p)
Read a 16-bit big-endian word from p.
@ 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_max_comps
YCbCr or grayscale only.
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.
static ra8_err_t internal_js_scan(ra8_jpeg_stream_state_t *st, uint32_t scan_pos)
Decode the whole entropy-coded scan, one MCU row per stripe.
ra8_jpeg_stream_const_t
Streaming-driver bounds (loop caps and phase sizes).
@ k_ra8_jpeg_stream_soi_bytes
SOI marker size.
@ k_ra8_jpeg_stream_max_markers
Marker-segment dispatch cap.
@ k_ra8_jpeg_stream_rgb_ch
Colour output channels.
@ k_ra8_jpeg_stream_gray_ch
Grayscale output channels.
static ra8_err_t internal_js_begin(ra8_jpeg_stream_state_t *st, ra8_jpeg_sw_pull_fn pull, void *pull_ctx, uint8_t *window, uint32_t window_cap, ra8_jpeg_sw_rows_fn on_rows, void *cb_ctx)
Bind the source, prime the window and consume the SOI marker.
ra8_err_t ra8_jpeg_sw_decode_stripes(ra8_jpeg_sw_pull_fn pull, void *pull_ctx, uint8_t *window, uint32_t window_cap, ra8_jpeg_sw_geom_fn on_geom, ra8_jpeg_sw_rows_fn on_rows, void *cb_ctx)
Decode a baseline JPEG in bounded RAM, one MCU-row stripe at a time.
static ra8_err_t internal_js_slide(ra8_jpeg_stream_state_t *st, uint32_t consumed)
Discard consumed leading window bytes and refill.
static ra8_err_t internal_js_parse_markers(ra8_jpeg_stream_state_t *st, ra8_jpeg_sw_geom_fn on_geom, uint32_t *out_scan_pos)
Walk marker segments until SOS, firing the geometry callback.
static void internal_js_emit_mcu(const ra8_jpeg_stream_state_t *st, const uint8_t *y_tile, const uint8_t *cb_tile, const uint8_t *cr_tile, uint16_t mx, uint16_t rows)
Emit one decoded MCU's visible pixels into the stripe buffer.
static ra8_err_t internal_js_refill(ra8_jpeg_stream_state_t *st)
Top the window up from the pull source until full or EOF.
static ra8_err_t internal_js_scan_margin(ra8_jpeg_stream_state_t *st, ra8_jpeg_bitreader_t *br)
Keep the entropy window topped up ahead of the bit reader.
static ra8_err_t internal_js_bind_geometry(ra8_jpeg_stream_state_t *st, ra8_jpeg_sw_geom_fn on_geom)
Validate the SOF0 geometry and fire the consumer geometry callback.
static ra8_jpeg_stream_state_t s_js
Module-static streaming state (codec documented not thread-safe).
static ra8_err_t internal_js_decode_mcu(ra8_jpeg_stream_state_t *st, ra8_jpeg_bitreader_t *br, uint8_t *y_tile, uint8_t *cb_tile, uint8_t *cr_tile, uint16_t mx, uint16_t rows)
Decode + emit one MCU: margin slide, luma, chroma, stripe write.
Lightweight Logging Interface for ra8-firmware.
Big-endian bit reader over an entropy-coded segment.
uint32_t len
Total bytes.
uint32_t pos
Read cursor.
Decoder state shared by the whole-buffer and streaming drivers.
int32_t comp_dc_pred[k_ra8_jpeg_max_comps]
DC predictors (scan state).
uint16_t height
Image height from SOF0, pixels.
uint8_t vmax
Max vertical sampling factor.
uint32_t src_len
Length of src in bytes.
uint32_t cursor
Parse cursor into src.
uint8_t ncomp
1 grayscale, 3 YCbCr.
uint16_t width
Image width from SOF0, pixels.
uint8_t hmax
Max horizontal sampling factor.
const uint8_t * src
Byte slice the parsers read from.
Whole streaming-decode state: source window + geometry + stripe.
uint32_t win_len
Valid bytes currently in the window.
uint8_t eof
1 once the source reported EOF.
ra8_jpeg_sw_rows_fn on_rows
Stripe sink.
uint32_t win_cap
Window capacity, bytes.
ra8_jpeg_sw_pull_fn pull
Sequential byte source.
uint8_t * win
Sliding window base.
uint32_t stripe_cap
Stripe buffer capacity, bytes.
void * cb_ctx
Consumer context for both callbacks.
uint8_t * stripe
Consumer stripe buffer (geometry cb).
uint8_t channels
Output channels (1 or 3).
ra8_jpeg_dec_ctx_t dec
Shared decoder tables + parse state.
uint16_t mcus_x
MCU columns.
uint16_t mcu_w
MCU width, pixels.
uint16_t mcu_h
MCU height, pixels (== stripe rows).
void * pull_ctx
Context for pull.