ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_jpeg_sw_stream.c File Reference

Streaming baseline JPEG decoder: bounded-RAM MCU-row stripes (#231). More...

#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_jpeg_sw.h"
#include "ra8_jpeg_sw_internal.h"
#include "ra8_log.h"
Include dependency graph for ra8_jpeg_sw_stream.c:

Go to the source code of this file.

Data Structures

struct  ra8_jpeg_stream_state_t
 Whole streaming-decode state: source window + geometry + stripe. More...

Enumerations

enum  ra8_jpeg_stream_const_t : uint16_t {
  k_ra8_jpeg_stream_max_markers = 1024U ,
  k_ra8_jpeg_stream_soi_bytes = 2U ,
  k_ra8_jpeg_stream_gray_ch = 1U ,
  k_ra8_jpeg_stream_rgb_ch = 3U
}
 Streaming-driver bounds (loop caps and phase sizes). More...

Functions

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_slide (ra8_jpeg_stream_state_t *st, uint32_t consumed)
 Discard consumed leading window bytes and refill.
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_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_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_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.
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.
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.

Variables

static const char * s_tag = "JPEG_SW"
 Component log tag.
static ra8_jpeg_stream_state_t s_js
 Module-static streaming state (codec documented not thread-safe).

Detailed Description

Streaming baseline JPEG decoder: bounded-RAM MCU-row stripes (#231).

Tag
[Ring 4 / Domain] {World: NS}

Implements ra8_jpeg_sw_decode_stripes(): the same baseline (8-bit, sequential, Huffman) decode as ra8_jpeg_sw_decode(), but the compressed input arrives through a pull callback into a caller-owned sliding window and the decoded output leaves through a stripe callback one MCU row at a time – resident RAM is window + one stripe, independent of image size.

The marker parsers, the per-block entropy decoder and the MCU block helpers are shared with the whole-buffer driver (ra8_jpeg_sw_decode.c) via ra8_jpeg_sw_internal.h; this unit adds only the window management (slide + refill around the shared ra8_jpeg_bitreader_t) and the emit-into-stripe pixel stage.

Spec citations are tagged T.81 sec X.Y "..." and refer to ITU-T Recommendation T.81 (1992) | ISO/IEC 10918-1.

Since
0.1.0

Definition in file ra8_jpeg_sw_stream.c.

Enumeration Type Documentation

◆ ra8_jpeg_stream_const_t

enum ra8_jpeg_stream_const_t : uint16_t

Streaming-driver bounds (loop caps and phase sizes).

Enumerator
k_ra8_jpeg_stream_max_markers 

Marker-segment dispatch cap.

k_ra8_jpeg_stream_soi_bytes 

SOI marker size.

k_ra8_jpeg_stream_gray_ch 

Grayscale output channels.

k_ra8_jpeg_stream_rgb_ch 

Colour output channels.

Definition at line 47 of file ra8_jpeg_sw_stream.c.

Function Documentation

◆ internal_js_begin()

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 )
static

Bind the source, prime the window and consume the SOI marker.

Resets the module-static state, fills the window once, and verifies the stream begins with the SOI marker.

Parameters
[in,out]stStreaming state (reset + bound).
[in]pullSequential byte source.
[in]pull_ctxContext for pull.
[in]windowSliding window buffer.
[in]window_capWindow capacity, bytes.
[in]on_rowsStripe sink.
[in]cb_ctxConsumer context.
Returns
Result code.
Return values
k_ra8_okSOI consumed; marker walk may start.
k_ra8_err_invalid_sizeThe source is shorter than a marker.
k_ra8_err_protocol_errorThe stream does not begin with SOI.
otherPropagated from the pull callback.
Precondition
The public entry validated every pointer.
window covers window_cap bytes.
Postcondition
On success the window sits right after the SOI marker.
On error the decode aborts.
Note
Not thread-safe.
Since
0.1.0

Definition at line 469 of file ra8_jpeg_sw_stream.c.

References ra8_jpeg_stream_state_t::cb_ctx, internal_js_refill(), internal_js_slide(), internal_read_be16(), k_ra8_err_invalid_size, k_ra8_err_protocol_error, k_ra8_jpeg_marker_soi, k_ra8_jpeg_stream_soi_bytes, k_ra8_ok, memset(), ra8_jpeg_stream_state_t::on_rows, ra8_jpeg_stream_state_t::pull, ra8_jpeg_stream_state_t::pull_ctx, RA8_INTERNAL, ra8_jpeg_stream_state_t::win, ra8_jpeg_stream_state_t::win_cap, and ra8_jpeg_stream_state_t::win_len.

Referenced by ra8_jpeg_sw_decode_stripes().

◆ internal_js_bind_geometry()

ra8_err_t internal_js_bind_geometry ( ra8_jpeg_stream_state_t * st,
ra8_jpeg_sw_geom_fn on_geom )
static

Validate the SOF0 geometry and fire the consumer geometry callback.

Computes the MCU grid, asks the consumer for its stripe buffer, and checks the buffer covers one full stripe. The channel count is 1 for grayscale sources and 3 (RGB888) otherwise.

Parameters
[in,out]stStreaming state (geometry fields written).
[in]on_geomConsumer geometry callback.
Returns
Result code.
Return values
k_ra8_okGeometry accepted; stripe bound.
k_ra8_err_invalid_sizeThe supplied stripe buffer is too small.
k_ra8_err_null_ptrThe consumer supplied a NULL stripe.
otherThe consumer aborted the decode.
Precondition
st->dec holds a successfully parsed SOF0 (hmax/vmax non-zero).
on_geom is non-NULL.
Postcondition
On success st->stripe/stripe_cap/grid fields are set.
On any error the decode aborts.
Note
Not thread-safe.
Since
0.1.0

Definition at line 166 of file ra8_jpeg_sw_stream.c.

References ra8_jpeg_stream_state_t::cb_ctx, ra8_jpeg_stream_state_t::channels, ra8_jpeg_stream_state_t::dec, ra8_jpeg_dec_ctx_t::height, ra8_jpeg_dec_ctx_t::hmax, k_ra8_err_invalid_size, k_ra8_jpeg_block_dim, k_ra8_jpeg_stream_gray_ch, k_ra8_jpeg_stream_rgb_ch, k_ra8_ok, ra8_jpeg_stream_state_t::mcu_h, ra8_jpeg_stream_state_t::mcu_w, ra8_jpeg_stream_state_t::mcus_x, ra8_jpeg_stream_state_t::mcus_y, ra8_jpeg_dec_ctx_t::ncomp, RA8_CHECK_NULL_PTR, RA8_INTERNAL, s_tag, ra8_jpeg_stream_state_t::stripe, ra8_jpeg_stream_state_t::stripe_cap, ra8_jpeg_dec_ctx_t::vmax, and ra8_jpeg_dec_ctx_t::width.

Referenced by internal_js_parse_markers().

◆ internal_js_decode_mcu()

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 )
static

Decode + emit one MCU: margin slide, luma, chroma, stripe write.

Keeps the window margin ahead of the bit reader, then reuses the shared block decoders and the stripe emit stage.

Parameters
[in,out]stStreaming state.
[in,out]brBit reader over the window.
[in]y_tileLuma tile scratch (mcu_w * mcu_h bytes).
[in,out]cb_tileCb tile scratch (64 bytes).
[in,out]cr_tileCr tile scratch (64 bytes).
[in]mxMCU column index.
[in]rowsValid rows in this stripe.
Returns
Result code.
Return values
k_ra8_okMCU decoded and emitted into the stripe.
k_ra8_err_protocol_errorEntropy stream corrupt / truncated.
otherPropagated from the pull callback.
Precondition
The geometry and tables are bound (post internal_js_parse_markers()).
All three tile buffers are writable.
Postcondition
br advanced past one MCU's blocks.
On error the scan aborts.
Note
Not thread-safe.
Since
0.1.0

Definition at line 365 of file ra8_jpeg_sw_stream.c.

References ra8_jpeg_stream_state_t::dec, internal_js_emit_mcu(), internal_js_scan_margin(), k_ra8_ok, ra8_jpeg_stream_state_t::mcu_w, ra8_jpeg_dec_ctx_t::ncomp, priv_jpeg_sw_mcu_chroma(), priv_jpeg_sw_mcu_y(), and RA8_INTERNAL.

Referenced by internal_js_scan().

◆ internal_js_emit_mcu()

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 )
static

Emit one decoded MCU's visible pixels into the stripe buffer.

Streaming twin of the whole-buffer driver's emit stage: rows are stripe-local (r counts from the top of the current MCU row), columns clamp at the image's right edge, and grayscale sources copy Y directly instead of running the colour transform.

Parameters
[in]stStreaming state (stripe + geometry).
[in]y_tileReconstructed luma tile (mcu_w * mcu_h).
[in]cb_tileReconstructed Cb tile (64 bytes; colour only).
[in]cr_tileReconstructed Cr tile (64 bytes; colour only).
[in]mxMCU column index.
[in]rowsValid rows in this stripe (edge stripes are short).
Precondition
st->stripe covers one full stripe (bound at geometry time).
rows <= st->mcu_h.
Postcondition
The MCU's visible pixels are packed into the stripe.
No decoder state is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 275 of file ra8_jpeg_sw_stream.c.

References ra8_jpeg_stream_state_t::channels, ra8_jpeg_stream_state_t::dec, ra8_jpeg_dec_ctx_t::hmax, k_ra8_jpeg_block_dim, k_ra8_jpeg_stream_gray_ch, ra8_jpeg_stream_state_t::mcu_w, priv_jpeg_sw_ycc_to_rgb(), RA8_INTERNAL, ra8_jpeg_stream_state_t::stripe, ra8_jpeg_dec_ctx_t::vmax, and ra8_jpeg_dec_ctx_t::width.

Referenced by internal_js_decode_mcu().

◆ internal_js_parse_markers()

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 )
static

Walk marker segments until SOS, firing the geometry callback.

Each iteration slides the consumed bytes off, refills the window (so any single segment, <= 65539 bytes, is fully materialised), and dispatches one marker through the shared parser. Bounded by k_ra8_jpeg_stream_max_markers dispatches (NASA Rule 2).

Parameters
[in,out]stStreaming state.
[in]on_geomConsumer geometry callback.
[out]out_scan_posWindow offset of the entropy-coded data.
Returns
Result code.
Return values
k_ra8_okSOS reached; scan may start.
k_ra8_err_protocol_errorMalformed stream / EOI before SOS / marker budget exhausted.
k_ra8_err_not_supportedNon-baseline stream.
otherPropagated from pull / the callback.
Precondition
The SOI marker has already been consumed.
st->win has been refilled once.
Postcondition
On success the geometry callback fired exactly once.
On any error the decode aborts.
Note
Not thread-safe.
Since
0.1.0

Definition at line 216 of file ra8_jpeg_sw_stream.c.

References ra8_jpeg_dec_ctx_t::cursor, ra8_jpeg_stream_state_t::dec, internal_js_bind_geometry(), internal_js_slide(), k_ra8_err_protocol_error, k_ra8_jpeg_dec_continue, k_ra8_jpeg_dec_eoi, k_ra8_jpeg_dec_scan, k_ra8_jpeg_stream_max_markers, k_ra8_ok, priv_jpeg_sw_dispatch(), RA8_INTERNAL, ra8_jpeg_dec_ctx_t::src, ra8_jpeg_dec_ctx_t::src_len, ra8_jpeg_stream_state_t::win, and ra8_jpeg_stream_state_t::win_len.

Referenced by ra8_jpeg_sw_decode_stripes().

◆ internal_js_refill()

ra8_err_t internal_js_refill ( ra8_jpeg_stream_state_t * st)
static

Top the window up from the pull source until full or EOF.

Each non-EOF pull delivers at least one byte, so the loop is bounded by the window capacity (NASA Rule 2).

Parameters
[in,out]stStreaming state (window mutates).
Returns
Result code.
Return values
k_ra8_okWindow is full or the source hit EOF.
otherPropagated from the pull callback.
Precondition
st->win covers st->win_cap bytes.
st->win_len <= st->win_cap.
Postcondition
st->win_len == st->win_cap or st->eof == 1 (on success).
On error the window content below win_len is still valid.
Note
Not thread-safe.
Since
0.1.0

Definition at line 105 of file ra8_jpeg_sw_stream.c.

References ra8_jpeg_stream_state_t::eof, k_ra8_ok, ra8_jpeg_stream_state_t::pull, ra8_jpeg_stream_state_t::pull_ctx, RA8_INTERNAL, ra8_jpeg_stream_state_t::win, ra8_jpeg_stream_state_t::win_cap, and ra8_jpeg_stream_state_t::win_len.

Referenced by internal_js_begin(), and internal_js_slide().

◆ internal_js_scan()

ra8_err_t internal_js_scan ( ra8_jpeg_stream_state_t * st,
uint32_t scan_pos )
static

Decode the whole entropy-coded scan, one MCU row per stripe.

Outer loops are bounded by the SOF0-derived MCU grid (NASA Rule 2). Each MCU row fills the stripe buffer, then the stripe callback fires with the row's true (edge-clamped) height.

Parameters
[in,out]stStreaming state.
[in]scan_posWindow offset of the entropy-coded data.
Returns
Result code.
Return values
k_ra8_okEvery stripe emitted.
k_ra8_err_protocol_errorEntropy stream corrupt / truncated.
otherPropagated from pull / the stripe sink.
Precondition
internal_js_parse_markers() succeeded (geometry + tables bound).
scan_pos <= st->win_len.
Postcondition
On success mcus_y stripes were emitted in order.
On any error emission stops at the failing stripe.
Note
Not thread-safe.
Since
0.1.0

Definition at line 409 of file ra8_jpeg_sw_stream.c.

References ra8_jpeg_stream_state_t::cb_ctx, ra8_jpeg_stream_state_t::channels, ra8_jpeg_dec_ctx_t::comp_dc_pred, ra8_jpeg_stream_state_t::dec, ra8_jpeg_dec_ctx_t::height, internal_js_decode_mcu(), k_ra8_jpeg_block_size, k_ra8_jpeg_max_comps, k_ra8_jpeg_mcu_max_dim, k_ra8_ok, ra8_jpeg_stream_state_t::mcu_h, ra8_jpeg_stream_state_t::mcus_x, ra8_jpeg_stream_state_t::mcus_y, ra8_jpeg_stream_state_t::on_rows, RA8_INTERNAL, ra8_jpeg_stream_state_t::stripe, ra8_jpeg_dec_ctx_t::width, ra8_jpeg_stream_state_t::win, and ra8_jpeg_stream_state_t::win_len.

Referenced by ra8_jpeg_sw_decode_stripes().

◆ internal_js_scan_margin()

ra8_err_t internal_js_scan_margin ( ra8_jpeg_stream_state_t * st,
ra8_jpeg_bitreader_t * br )
static

Keep the entropy window topped up ahead of the bit reader.

Slides the already-consumed bytes (br->pos) off the window and refills whenever fewer than the scan margin remain unread, then rebases the bit reader onto the slid window. The accumulator bits survive the rebase untouched.

Parameters
[in,out]stStreaming state (window mutates).
[in,out]brBit reader over the window (rebased in place).
Returns
Result code.
Return values
k_ra8_okThe reader has margin bytes or the source hit EOF.
otherPropagated from the pull callback.
Precondition
br->buf == st->win and br->pos <= st->win_len.
st->win_cap >= k_ra8_jpeg_sw_stream_min_window.
Postcondition
br->len == st->win_len and br->pos is rebased.
On error the scan aborts.
Note
Not thread-safe.
Since
0.1.0

Definition at line 328 of file ra8_jpeg_sw_stream.c.

References ra8_jpeg_stream_state_t::eof, internal_js_slide(), k_ra8_jpeg_sw_stream_scan_margin, k_ra8_ok, ra8_jpeg_bitreader_t::len, ra8_jpeg_bitreader_t::pos, RA8_INTERNAL, and ra8_jpeg_stream_state_t::win_len.

Referenced by internal_js_decode_mcu().

◆ internal_js_slide()

ra8_err_t internal_js_slide ( ra8_jpeg_stream_state_t * st,
uint32_t consumed )
static

Discard consumed leading window bytes and refill.

Memmoves the unread tail to the window head, then tops the window up.

Parameters
[in,out]stStreaming state (window mutates).
[in]consumedBytes to drop from the window head.
Returns
Result code.
Return values
k_ra8_okThe window slid and refilled (or EOF).
otherPropagated from the pull callback.
Precondition
consumed <= st->win_len.
st->win covers st->win_cap bytes.
Postcondition
The former byte at consumed is now at offset 0.
st->win_len reflects the slide plus any refill.
Note
Not thread-safe.
Since
0.1.0

Definition at line 138 of file ra8_jpeg_sw_stream.c.

References internal_js_refill(), memmove(), RA8_INTERNAL, ra8_jpeg_stream_state_t::win, and ra8_jpeg_stream_state_t::win_len.

Referenced by internal_js_begin(), internal_js_parse_markers(), and internal_js_scan_margin().

◆ ra8_jpeg_sw_decode_stripes()

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 )
nodiscard

Decode a baseline JPEG in bounded RAM, one MCU-row stripe at a time.

The streaming counterpart of ra8_jpeg_sw_decode() for images whose whole decoded frame cannot be resident (#231). Input arrives through pull into the caller's sliding window (the resident compressed footprint); output leaves through on_rows one MCU row at a time (8 rows for 4:4:4/grayscale, 16 for 4:2:0), so the resident decoded footprint is one stripe – both independent of the image size. Between the two callbacks a transcoder can tile, convert, or compress each stripe with the whole image never in memory.

Same format envelope as ra8_jpeg_sw_decode(): baseline sequential Huffman, 8-bit, grayscale or YCbCr 4:4:4 / 4:2:0; progressive and restart-marker streams are rejected. Grayscale sources emit 1 channel, colour sources 3 (packed RGB888). One additional streaming-only bound: a run of more than the window size of consecutive 0xFF fill bytes is rejected as malformed rather than buffered unboundedly.

Parameters
[in]pullSequential byte source (non-NULL).
[in]pull_ctxContext for pull.
[in]windowSliding compressed-input window buffer.
[in]window_capWindow capacity; >= k_ra8_jpeg_sw_stream_min_window.
[in]on_geomGeometry callback (non-NULL; supplies the stripe).
[in]on_rowsStripe sink (non-NULL).
[in]cb_ctxContext passed to both callbacks.
Returns
ra8_err_t Error code.
Return values
k_ra8_okWhole image decoded and emitted.
k_ra8_err_null_ptrpull, window, on_geom, or on_rows is NULL.
k_ra8_err_invalid_sizewindow_cap below the minimum, or the supplied stripe buffer too small.
k_ra8_err_protocol_errorMalformed / truncated JPEG stream.
k_ra8_err_not_supportedNon-baseline stream (progressive, 12-bit, exotic chroma layout).
otherPropagated from pull / the callbacks.
Precondition
window holds window_cap writable bytes.
pull delivers the stream strictly in order, once.
Postcondition
On success every image row was emitted exactly once, in order.
On any error emission stops; already-emitted rows stay valid.
Note
Not thread-safe (module-static decoder context, like ra8_jpeg_sw_decode()).
See also
ra8_jpeg_sw_decode() Whole-buffer decode for small images.
Since
0.1.0

Definition at line 497 of file ra8_jpeg_sw_stream.c.

References internal_js_begin(), internal_js_parse_markers(), internal_js_scan(), k_ra8_err_invalid_size, k_ra8_jpeg_sw_stream_min_window, k_ra8_ok, RA8_CHECK_NULL_PTR, s_js, and s_tag.

Referenced by internal_dispatch().

Variable Documentation

◆ s_js

Module-static streaming state (codec documented not thread-safe).

Definition at line 88 of file ra8_jpeg_sw_stream.c.

Referenced by ra8_jpeg_sw_decode_stripes().

◆ s_tag

const char* s_tag = "JPEG_SW"
static

Component log tag.

Definition at line 41 of file ra8_jpeg_sw_stream.c.