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

Pure-software baseline JPEG codec: shared entropy/DSP primitives plus the get-dimensions public API. More...

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

Go to the source code of this file.

Functions

static void internal_br_fill (ra8_jpeg_bitreader_t *br)
 Refill acc until at least 16 bits are available.
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.
static void internal_htab_build_lookup (ra8_jpeg_htab_t *h)
 Build the F.2.2.3 mincode/maxcode/valptr decode tables.
void priv_jpeg_sw_htab_build (ra8_jpeg_htab_t *h)
 Build canonical code/size and mincode/maxcode tables.
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_huff_extend (int32_t v, uint8_t n)
 Decode a signed n-bit DCT coefficient (T.81 F.1.2.1.3).
static void internal_inv_dct_1d_norm (const int32_t *in, int32_t *out)
 1-D inverse DCT pass with JPEG normalization folded in.
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.
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 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.
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 decoding.

Variables

static const char * s_tag = "JPEG_SW"
 Component log tag.

Detailed Description

Pure-software baseline JPEG codec: shared entropy/DSP primitives plus the get-dimensions public API.

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

Implements the codec primitives shared by both the decoder and the encoder – the big-endian bit reader, the canonical Huffman tables, the inverse DCT and the BT.601 YCbCr->RGB colour conversion – and the lightweight ra8_jpeg_sw_get_dimensions() public API, which only walks the marker chain to the SOF0 frame header.

The decoder-driver half (marker parser, MCU scan loop and ra8_jpeg_sw_decode()) lives in ra8_jpeg_sw_decode.c; the encoder (forward DCT, quantization, Huffman code emission and ra8_jpeg_sw_encode()) lives in ra8_jpeg_sw_encode.c. Every symbol referenced by more than one of those units – the C23 typed-enum constant blocks, the shared DSP look-up tables, the inline byte helpers, the bit-reader / Huffman-table types and the prototypes for the primitives defined here – lives in ra8_jpeg_sw_internal.h.

The reference codec for the decoder is the C99 reformulation of "TJpgDec" by ChaN; both halves have been re-implemented here from scratch in this project's style and naming conventions; no third-party code is copied.

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

MVE / Helium acceleration:

  • The colour-conversion (ycc_to_rgb_row) row loop is wrapped in #ifdef __ARM_FEATURE_MVE and uses arm_mve.h intrinsics on the Cortex-M85 target. The fallback scalar implementation is bit-exact with the vector version and is the path the host unit tests exercise.

Definition in file ra8_jpeg_sw.c.

Function Documentation

◆ internal_br_fill()

void internal_br_fill ( ra8_jpeg_bitreader_t * br)
static

Refill acc until at least 16 bits are available.

Pulls bytes from the entropy stream into the 32-bit accumulator, unstuffing 0xFF 0x00 sequences per T.81 F.1.2.3 and stopping when a real marker is reached (rewinds two bytes so the caller can inspect it).

Parameters
[in,out]brBit reader (state mutated in place).
Precondition
br is non-NULL.
br->buf and br->len describe a valid byte slice.
Postcondition
br->nbits is >= 24 OR br->had_eoi is set.
br->pos advances past consumed payload bytes.
Note
Internal helper; not thread-safe.
Since
0.1.0

Definition at line 83 of file ra8_jpeg_sw.c.

References ra8_jpeg_bitreader_t::acc, ra8_jpeg_bitreader_t::buf, ra8_jpeg_bitreader_t::had_eoi, k_jpeg_reservoir_lo, k_ra8_jpeg_byte_shift, k_ra8_jpeg_marker_byte, ra8_jpeg_bitreader_t::len, ra8_jpeg_bitreader_t::nbits, ra8_jpeg_bitreader_t::pos, and RA8_INTERNAL.

Referenced by priv_jpeg_sw_br_get_bits(), and priv_jpeg_sw_htab_decode().

◆ internal_dims_next_marker()

ra8_err_t internal_dims_next_marker ( const uint8_t * jpeg_buf,
uint32_t jpeg_len,
uint32_t * i,
uint16_t * out_mk )
static

Advance past 0xFF pad bytes and read one marker code.

Implements the T.81 sec B.1.1.2 "Markers" scan step of the ra8_jpeg_sw_get_dimensions() walk: verifies the cursor sits on a 0xFF prefix, skips any run of 0xFF fill bytes, and returns the 0xFFxx marker code assembled from the byte that follows. The cursor is left one past the marker's low byte.

Parameters
[in]jpeg_bufJPEG byte stream.
[in]jpeg_lenTotal stream length in bytes.
[in,out]iParse cursor (advanced past the marker).
[out]out_mkReceives the 0xFFxx marker code.
Returns
ra8_err_t Error code.
Return values
k_ra8_okMarker code stored in *out_mk.
k_ra8_err_protocol_errorCursor not on 0xFF, or the stream ends inside the pad run.
Precondition
jpeg_buf, i and out_mk are non-NULL (caller-checked).
*i < jpeg_len (enforced by the caller's loop bound).
Postcondition
On success *i points at the first byte after the marker.
On error *i is unspecified; the caller aborts the walk.
Note
Internal helper; not thread-safe.
Since
0.1.0

Definition at line 453 of file ra8_jpeg_sw.c.

References k_jpeg_byte_mask, k_ra8_err_protocol_error, k_ra8_jpeg_byte_shift, k_ra8_jpeg_marker_byte, and k_ra8_ok.

Referenced by internal_dims_step().

◆ internal_dims_parse_sof0()

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

Extract width/height from an SOF0 payload (T.81 sec B.2.2).

Reads the precision byte and the two big-endian dimension fields of the SOF0 frame header whose length field starts at i, rejecting non-8-bit precision and zero dimensions exactly as the previous monolithic ra8_jpeg_sw_get_dimensions() body did.

Parameters
[in]jpeg_bufJPEG byte stream.
[in]iOffset of the SOF0 segment-length field.
[in]seglenValidated segment length (>= 2, in bounds).
[out]out_wReceives the image width in pixels.
[out]out_hReceives the image height in pixels.
Returns
ra8_err_t Error code.
Return values
k_ra8_okDimensions stored.
k_ra8_err_protocol_errorSegment too short or zero dimension.
k_ra8_err_not_supportedSample precision is not 8-bit.
Precondition
seglen was bounds-checked against the stream by the caller.
out_w and out_h are non-NULL (caller-checked).
Postcondition
On success *out_w and *out_h are non-zero.
No global state is touched.
Note
Internal helper; not thread-safe.
Since
0.1.0

Definition at line 499 of file ra8_jpeg_sw.c.

References internal_read_be16(), k_jpeg_sof_dims_off, k_ra8_err_not_supported, k_ra8_err_protocol_error, k_ra8_ok, and RA8_INTERNAL.

Referenced by internal_dims_step().

◆ internal_dims_step()

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

One step of the dimension walk: read a marker, handle it.

Loop body of ra8_jpeg_sw_get_dimensions(): reads the next marker via internal_dims_next_marker(), skips standalone SOI/EOI codes, validates the segment length, extracts the dimensions on SOF0 (setting *done), rejects unsupported SOFn frames, and otherwise advances the cursor past the segment.

Parameters
[in]jpeg_bufJPEG byte stream.
[in]jpeg_lenTotal stream length in bytes.
[in,out]iParse cursor (advances).
[out]doneSet true when SOF0 delivered the dimensions.
[out]out_wReceives the image width on SOF0.
[out]out_hReceives the image height on SOF0.
Returns
ra8_err_t Error code.
Return values
k_ra8_okStep handled; check *done.
k_ra8_err_protocol_errorMalformed marker / length field.
k_ra8_err_not_supportedUnsupported SOFn or precision.
Precondition
*i + 4 <= jpeg_len (caller's loop bound).
All pointers are non-NULL (public API validated them).
Postcondition
On success with *done false, *i advanced past the segment.
On success with *done true, the dimensions are stored.
Note
Internal helper; not thread-safe.
Since
0.1.0

Definition at line 550 of file ra8_jpeg_sw.c.

References internal_dims_next_marker(), internal_dims_parse_sof0(), internal_read_be16(), k_jpeg_marker_jpg, k_jpeg_marker_sof_hi, k_jpeg_marker_sof_lo, k_ra8_err_not_supported, k_ra8_err_protocol_error, k_ra8_jpeg_marker_dht, k_ra8_jpeg_marker_eoi, k_ra8_jpeg_marker_sof0, k_ra8_jpeg_marker_soi, k_ra8_ok, and RA8_INTERNAL.

Referenced by ra8_jpeg_sw_get_dimensions().

◆ internal_htab_build_lookup()

void internal_htab_build_lookup ( ra8_jpeg_htab_t * h)
static

Build the F.2.2.3 mincode/maxcode/valptr decode tables.

Second phase of priv_jpeg_sw_htab_build(): walks the BITS list and the canonical huffcode array produced by the Annex C phase and derives, per code length, the smallest code (mincode), the largest code (maxcode, -1 for unused lengths) and the index of the first symbol of that length (valptr) exactly as T.81 Annex F.2.2.3 "Decoder tables" specifies.

Parameters
[in,out]hHuffman table (huffcode/bits in, lookup tables out).
Precondition
h is non-NULL.
h->huffcode was populated by the Annex C canonical build.
Postcondition
h->mincode/h->maxcode/h->valptr are populated.
h->maxcode[i] is -1 for every length with zero codes.
Note
Internal helper; not thread-safe.
Since
0.1.0

Definition at line 176 of file ra8_jpeg_sw.c.

References ra8_jpeg_htab_t::bits, ra8_jpeg_htab_t::huffcode, k_ra8_jpeg_huff_lengths, ra8_jpeg_htab_t::maxcode, ra8_jpeg_htab_t::mincode, RA8_INTERNAL, and ra8_jpeg_htab_t::valptr.

Referenced by priv_jpeg_sw_htab_build().

◆ internal_inv_dct_1d_norm()

void internal_inv_dct_1d_norm ( const int32_t * in,
int32_t * out )
static

1-D inverse DCT pass with JPEG normalization folded in.

Computes y[n] = sum_k sqrt(2/N)*C(k)*Y[k]*cos((2n+1)*k*pi/16). Pre-multiplies each Y[k] by the Q14 weight before the cosine accumulation so the cosine terms stay symmetrical with the forward pass.

Parameters
[in]inSee declaration: const int32_t* in.
[out]outSee declaration: int32_t* out.
Precondition
Module/state preconditions hold (see function body).
Module/state preconditions hold (see function body).
Postcondition
Documented side effects are visible on success.
Documented side effects are visible on success.
Note
Not thread-safe; the caller must serialise concurrent access.
Since
0.1.0

Definition at line 338 of file ra8_jpeg_sw.c.

References k_jpeg_idct_p2_bias_sh, k_jpeg_q14_shift, k_ra8_jpeg_block_dim, RA8_INTERNAL, s_dct_cos_q14, and s_dct_w_q14.

Referenced by priv_jpeg_sw_idct8x8().

◆ priv_jpeg_sw_br_get_bits()

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.

Calls internal_br_fill to top off the accumulator, then drains n MSBs as a non-negative integer.

Parameters
[in,out]brBit reader (state mutated in place).
[in]nNumber of bits to consume (0..16).
Returns
Decoded bit pattern, or -1 on stream underflow.
Return values
>=0n-bit unsigned value drained from the accumulator.
-1Underflow / EOI before n bits were available.
Precondition
br is non-NULL.
n <= 16 (caller-enforced).
Postcondition
br->nbits decreases by n on success.
Accumulator is masked to its remaining bits.
Note
Internal helper; not thread-safe.
Since
0.1.0

Definition at line 134 of file ra8_jpeg_sw.c.

References ra8_jpeg_bitreader_t::acc, internal_br_fill(), ra8_jpeg_bitreader_t::nbits, and RA8_PRIV.

Referenced by internal_dec_block_ac(), priv_jpeg_sw_block(), and priv_jpeg_sw_htab_decode().

◆ priv_jpeg_sw_htab_build()

void priv_jpeg_sw_htab_build ( ra8_jpeg_htab_t * h)

Build canonical code/size and mincode/maxcode tables.

Implements T.81 Annex C "Generation of size table" + "Generation of code table" plus the Annex F.2.2.3 mincode/maxcode/valptr tables used by the symbol decoder. Defined in ra8_jpeg_sw.c; the parser unit calls it from dec_parse_dht().

Parameters
[in,out]hHuffman table (BITS / VALS in, derived tables out).
Precondition
h is non-NULL.
h->bits and h->vals populated from the JPEG DHT marker.
Postcondition
h->huffcode, h->huffsize, h->mincode, h->maxcode and h->valptr are populated.
h->total reflects the symbol count.
Note
Internal helper; not thread-safe.
Since
0.1.0

Definition at line 192 of file ra8_jpeg_sw.c.

References ra8_jpeg_htab_t::bits, ra8_jpeg_htab_t::huffcode, ra8_jpeg_htab_t::huffsize, internal_htab_build_lookup(), k_ra8_jpeg_huff_lengths, RA8_PRIV, and ra8_jpeg_htab_t::total.

Referenced by internal_dec_parse_dht_one().

◆ priv_jpeg_sw_htab_decode()

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.

Single-bit greedy lookup per T.81 F.2.2.3 "Decoder code-length algorithm". Returns -1 on stream underflow or table miss.

Parameters
[in,out]brBit reader (state mutated in place).
[in]hPre-built canonical Huffman table.
Returns
Decoded symbol or -1 on error.
Return values
>=0Symbol value from h->vals.
-1Stream underflow or table miss.
Precondition
br and h non-NULL.
h was previously populated by priv_jpeg_sw_htab_build.
Postcondition
br advances by the consumed code length on success.
No table state is mutated.
Note
Internal helper; not thread-safe.
Since
0.1.0

Definition at line 250 of file ra8_jpeg_sw.c.

References internal_br_fill(), k_ra8_jpeg_huff_lengths, ra8_jpeg_htab_t::mincode, ra8_jpeg_bitreader_t::nbits, priv_jpeg_sw_br_get_bits(), RA8_PRIV, ra8_jpeg_htab_t::total, ra8_jpeg_htab_t::valptr, and ra8_jpeg_htab_t::vals.

Referenced by internal_dec_block_ac(), and priv_jpeg_sw_block().

◆ priv_jpeg_sw_huff_extend()

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

Extends a non-negative n-bit pattern into the signed range documented at T.81 Figure F.12 "EXTEND". A leading-zero pattern is treated as the negative of the symmetric positive value.

Parameters
[in]vNon-negative bit pattern from the bit reader.
[in]nNumber of significant bits.
Returns
Signed coefficient.
Return values
0..(1<<n)-1v had its high bit set (positive value).
-(1<<n)+1..0v had its high bit clear (negative value).
Precondition
v is in 0..(1 << n) - 1.
n <= 16 (caller-enforced from JPEG stream).
Postcondition
Return value is in (-(1<<n))+1 .. (1<<n)-1.
No global state is mutated.
Note
Pure helper; safe from any context.
Since
0.1.0

Definition at line 305 of file ra8_jpeg_sw.c.

References RA8_PRIV.

Referenced by internal_dec_block_ac(), and priv_jpeg_sw_block().

◆ priv_jpeg_sw_idct8x8()

void priv_jpeg_sw_idct8x8 ( int32_t * block)

Full 8x8 inverse DCT, in place.

Two-pass separable IDCT (rows then columns) using the shared Q14 cosine basis. Defined in ra8_jpeg_sw.c; the parser unit calls it from dec_idct_into().

Parameters
[in,out]block64-entry row-major coefficient block, IDCTed in place.
Precondition
block is non-NULL with at least 64 writable int32 slots.
block holds dequantized DCT coefficients.
Postcondition
block holds the reconstructed spatial samples.
No global state is touched.
Note
Internal helper; not thread-safe.
Since
0.1.0

Definition at line 352 of file ra8_jpeg_sw.c.

References internal_inv_dct_1d_norm(), k_ra8_jpeg_block_dim, k_ra8_jpeg_block_size, and RA8_PRIV.

Referenced by priv_jpeg_sw_idct_into().

◆ priv_jpeg_sw_ycc_to_rgb()

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

MVE-accelerated path is enabled when __ARM_FEATURE_MVE is defined (Cortex-M85 target). Host tests run the scalar path.

Parameters
[in,out]cbSee function signature.
[in,out]crSee function signature.
[in,out]out_bSee function signature.
[in,out]out_gSee function signature.
[in,out]out_rSee function signature.
[in,out]ySee function signature.
Precondition
Module has been initialized.
Caller has validated arguments.
Postcondition
Side effects bounded to documented state.
State reflects operation result.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 402 of file ra8_jpeg_sw.c.

References internal_clamp_u8(), k_ra8_jpeg_cb_b, k_ra8_jpeg_cb_g, k_ra8_jpeg_cr_g, k_ra8_jpeg_cr_r, k_ra8_jpeg_level_offset, k_ra8_jpeg_yuv_shift, and RA8_PRIV.

Referenced by internal_dec_emit_mcu_rgb(), and internal_js_emit_mcu().

◆ ra8_jpeg_sw_get_dimensions()

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

Parse the SOF0 marker of a JPEG stream and report its image dimensions without performing entropy decoding.

Walks the marker chain looking for T.81 sec B.2.2 "Frame header syntax" (SOF0 = 0xFFC0). On match the 16-bit big-endian Y (height) and X (width) fields are returned. This is the cheap way to size an output buffer before calling ra8_jpeg_sw_decode().

Algorithm:

  1. Verify the stream begins with the SOI marker (0xFFD8).
  2. Walk segment headers, skipping their payloads.
  3. Stop at SOF0; reject SOF1..SOF15 (non-baseline).
  4. Read 8-bit precision, 16-bit Y, 16-bit X.
Parameters
[in]jpeg_bufPointer to the JPEG byte stream (not NULL).
[in]jpeg_lenLength of jpeg_buf in bytes (must be >= 4).
[out]out_wReceives image width in pixels (not NULL).
[out]out_hReceives image height in pixels (not NULL).
Returns
ra8_err_t error code.
Return values
k_ra8_okDimensions written to *out_w, *out_h.
k_ra8_err_null_ptrAny pointer argument was NULL.
k_ra8_err_invalid_sizejpeg_len smaller than the SOI marker (2 bytes).
k_ra8_err_protocol_errorStream lacks SOI, lacks SOF0, or a marker length field overflows the buffer.
k_ra8_err_not_supportedSOF marker is non-baseline (e.g. progressive 0xFFC2, lossless 0xFFC3, arithmetic 0xFFC9+).
Precondition
jpeg_buf references at least jpeg_len valid bytes.
The caller will not modify jpeg_buf for the duration of this call.
Postcondition
On k_ra8_ok both *out_w and *out_h are non-zero.
On any error neither output is modified.
Note
Thread-safe: the function reads only its arguments and has no internal state.
Example:
uint16_t w, h;
if (ra8_jpeg_sw_get_dimensions(buf, len, &w, &h) == k_ra8_ok) {
printf("%u x %u\n", w, h);
}
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
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...
See also
ra8_jpeg_sw_decode Full decode that also returns dimensions.
Since
0.1.0

Definition at line 587 of file ra8_jpeg_sw.c.

References internal_dims_step(), internal_read_be16(), k_ra8_err_invalid_size, k_ra8_err_protocol_error, k_ra8_jpeg_marker_soi, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by internal_probe_sniff().

Variable Documentation

◆ s_tag

const char* s_tag = "JPEG_SW"
static

Component log tag.

Definition at line 54 of file ra8_jpeg_sw.c.