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

Pure-software baseline JPEG (ISO/IEC 10918-1 / ITU-T T.81) codec. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_err.h"
Include dependency graph for ra8_jpeg_sw.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

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

Enumerations

enum  ra8_jpeg_sw_pixfmt_t : uint8_t { k_ra8_jpeg_sw_pixfmt_rgb888 = 0U }
 Output pixel layout produced by ra8_jpeg_sw_decode(). More...
enum  ra8_jpeg_sw_quality_t : uint8_t {
  k_ra8_jpeg_sw_quality_min = 1U ,
  k_ra8_jpeg_sw_quality_low = 50U ,
  k_ra8_jpeg_sw_quality_default = 75U ,
  k_ra8_jpeg_sw_quality_high = 90U ,
  k_ra8_jpeg_sw_quality_max = 100U
}
 Convenience quality presets for ra8_jpeg_sw_encode(). More...
enum  ra8_jpeg_sw_stream_limits_t : uint32_t {
  k_ra8_jpeg_sw_stream_min_window = 131072U ,
  k_ra8_jpeg_sw_stream_scan_margin = 32768U
}
 Sizing floors for the streaming stripe decoder. More...
enum  ra8_jpeg_sw_stream_geom_t : uint8_t { k_ra8_jpeg_sw_stream_mcu_rows_max = 16U }
 Stripe geometry constant exposed for consumer buffer sizing. More...

Functions

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.
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.
ra8_err_t ra8_jpeg_sw_encode (const uint8_t *rgb_buf, uint16_t width, uint16_t height, uint8_t quality, uint8_t *out_buf, uint32_t out_buf_len, uint32_t *out_len)
 Encode a packed RGB888 frame as a baseline JPEG.
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.

Detailed Description

Pure-software baseline JPEG (ISO/IEC 10918-1 / ITU-T T.81) codec.

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

The RA8D2 has no hardware JPEG block. This module implements a software baseline JPEG codec (8-bit precision, sequential DCT, Huffman entropy coding) for two pixel layouts:

  • Grayscale (1 component, Y only).
  • YCbCr 4:2:0 (3 components, the dominant layout in real-world JPEG-from-camera files).

Decoder input is accepted with both 4:2:0 and 4:4:4 chroma subsampling so that round-trip tests against known files still succeed; encoder output is fixed at 4:2:0 (or grayscale-only when quality is negative – see ra8_jpeg_sw_encode()).

Out of scope:

  • Progressive, hierarchical, lossless and arithmetic-coded modes.
  • 12-bit precision.
  • JFIF / Exif metadata round-tripping (the encoder emits a minimal APP0 JFIF header so common viewers accept the output).
  • Restart markers (RST0..RST7) – decoder tolerates them, encoder does not emit them.

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

Definition in file ra8_jpeg_sw.h.

Typedef Documentation

◆ ra8_jpeg_sw_geom_fn

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

The consumer learns the image dimensions and channel count (1 = grayscale, 3 = RGB) before any pixel decodes, sizes its own buffers, and hands back the stripe buffer the decoder will fill: at least width * (8 * vmax) * channels bytes, where 8 * vmax is 8 for 4:4:4/grayscale and 16 for 4:2:0. Sizing for k_ra8_jpeg_sw_stream_mcu_rows_max rows always suffices. Returning any error aborts the decode with that code (the fail-closed "image too large for my budget" hook).

Parameters
[in]ctxConsumer context.
[in]widthImage width, pixels (>= 1).
[in]heightImage height, pixels (>= 1).
[in]channelsOutput channels per pixel (1 or 3).
[in]stripe_rowsRows per stripe the decoder will emit (8/16).
[out]out_stripeReceives the consumer's stripe buffer.
[out]out_stripe_capReceives that buffer's capacity, bytes.
Returns
k_ra8_ok to continue; any error aborts the decode.
Since
0.1.0

Definition at line 335 of file ra8_jpeg_sw.h.

◆ ra8_jpeg_sw_pull_fn

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

Strictly sequential: each call appends the next bytes of the JPEG stream. *got == 0 signals a clean end of stream; any error return aborts the decode with that code. An EPUB entry cursor (ra8_epub_entry_read) matches this shape directly.

Parameters
[in]ctxSource-specific context.
[out]bufDestination buffer (cap writable bytes).
[in]capCapacity of buf.
[out]gotBytes delivered this call (0 = end of stream).
Returns
k_ra8_ok on success; any error aborts the decode.
Since
0.1.0

Definition at line 310 of file ra8_jpeg_sw.h.

◆ ra8_jpeg_sw_rows_fn

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

Rows are tightly packed at width * channels bytes per row, top-to-bottom, and each stripe is emitted exactly once in order (y0 strictly increasing). The pixels live in the stripe buffer the geometry callback supplied and are only valid for the duration of the call. Returning any error aborts the decode with that code.

Parameters
[in]ctxConsumer context.
[in]pxStripe pixels (nrows * width * channels bytes).
[in]widthRow width, pixels.
[in]y0Image row of the stripe's first row.
[in]nrowsRows in this stripe (edge stripes are shorter).
[in]channelsBytes per pixel (1 or 3).
Returns
k_ra8_ok to continue; any error aborts the decode.
Since
0.1.0

Definition at line 363 of file ra8_jpeg_sw.h.

Enumeration Type Documentation

◆ ra8_jpeg_sw_pixfmt_t

enum ra8_jpeg_sw_pixfmt_t : uint8_t

Output pixel layout produced by ra8_jpeg_sw_decode().

The decoder always emits packed RGB888 (3 bytes per pixel, R-G-B order, no row padding) regardless of the source colour space. This enum exists for symmetry with the encoder and to make future expansion (RGB565, YUV planar) explicit.

Enumerator
k_ra8_jpeg_sw_pixfmt_rgb888 

24-bit packed R,G,B per pixel.

Definition at line 59 of file ra8_jpeg_sw.h.

◆ ra8_jpeg_sw_quality_t

enum ra8_jpeg_sw_quality_t : uint8_t

Convenience quality presets for ra8_jpeg_sw_encode().

The quality argument to ra8_jpeg_sw_encode() is a plain integer in [1, 100]. These named constants document the recommended operating points; callers may pass any value in range.

Enumerator
k_ra8_jpeg_sw_quality_min 

Lowest legal quality.

k_ra8_jpeg_sw_quality_low 

IJG default lower bound.

k_ra8_jpeg_sw_quality_default 

IJG cjpeg default.

k_ra8_jpeg_sw_quality_high 

Visually lossless on photos.

k_ra8_jpeg_sw_quality_max 

Largest legal quality.

Definition at line 73 of file ra8_jpeg_sw.h.

◆ ra8_jpeg_sw_stream_geom_t

enum ra8_jpeg_sw_stream_geom_t : uint8_t

Stripe geometry constant exposed for consumer buffer sizing.

Since
0.1.0
Enumerator
k_ra8_jpeg_sw_stream_mcu_rows_max 

Max rows per stripe (4:2:0).

Definition at line 376 of file ra8_jpeg_sw.h.

◆ ra8_jpeg_sw_stream_limits_t

enum ra8_jpeg_sw_stream_limits_t : uint32_t

Sizing floors for the streaming stripe decoder.

The sliding window must always be able to materialise one whole marker segment (a segment length field is 16-bit, so <= 65537 bytes with its marker) AND keep a comfortable entropy-decode margin ahead of the bit reader between refills; 128 KiB covers both with 2x headroom. The scan margin is the refill trigger: the window slides whenever fewer bytes than this remain unread before an MCU decode.

Since
0.1.0
Enumerator
k_ra8_jpeg_sw_stream_min_window 

Minimum window bytes.

k_ra8_jpeg_sw_stream_scan_margin 

Refill trigger, bytes.

Definition at line 289 of file ra8_jpeg_sw.h.

Function Documentation

◆ ra8_jpeg_sw_decode()

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

Decode a baseline JPEG stream into packed RGB888.

Performs full entropy decoding, dequantization, inverse DCT and YCbCr-to-RGB colour conversion (ITU-T T.871 JFIF colour conversion). The output buffer must be at least width * height * 3 bytes; the actual size is reported via *out_w and *out_h.

Supported source formats:

  • Grayscale: 1 component, no subsampling.
  • YCbCr: 3 components, 4:4:4 (H1V1,H1V1,H1V1), 4:2:0 (H2V2,H1V1,H1V1).

Algorithm (per MCU):

  1. Decode Huffman-coded DC/AC coefficients per block.
  2. Dequantize against the per-component quantization table.
  3. Apply the IDCT (T.81 Annex A.3.3 8x8 inverse DCT).
  4. Upsample chroma to luma resolution where required.
  5. YCbCr -> RGB and store row-major into out_buf.
Parameters
[in]jpeg_bufPointer to the JPEG byte stream.
[in]jpeg_lenLength of jpeg_buf in bytes.
[out]out_bufDestination buffer for RGB888 pixels.
[in]out_buf_lenCapacity of out_buf in bytes.
[out]out_wReceives image width in pixels.
[out]out_hReceives image height in pixels.
Returns
ra8_err_t error code.
Return values
k_ra8_okDecoded successfully.
k_ra8_err_null_ptrAny pointer argument was NULL.
k_ra8_err_protocol_errorMalformed JPEG stream.
k_ra8_err_not_supportedProgressive / arithmetic / 12-bit / unsupported chroma layout.
k_ra8_err_invalid_sizeout_buf_len < width*height*3.
Precondition
jpeg_buf and out_buf reference disjoint memory.
Image dimensions in the SOF0 marker are non-zero.
Postcondition
On success *out_w * *out_h * 3 <= out_buf_len.
On any error out_buf contents are unspecified but the caller's stack is unaffected.
Note
Thread-safe (re-entrant): all state lives on the caller's stack.
Warning
The decoder does not stream – the entire JPEG must be buffered in memory before the call. For typical RA8D2 camera frames (<= 256 KiB) this is fine.
See also
ra8_jpeg_sw_get_dimensions Lightweight dimension probe.
ra8_jpeg_sw_encode Inverse operation.
Since
0.1.0

Definition at line 896 of file ra8_jpeg_sw_decode.c.

References ra8_jpeg_dec_ctx_t::cursor, internal_dec_run(), internal_read_be16(), k_ra8_err_invalid_size, k_ra8_err_protocol_error, k_ra8_jpeg_marker_soi, memset(), RA8_CHECK_NULL_PTR, s_tag, ra8_jpeg_dec_ctx_t::src, and ra8_jpeg_dec_ctx_t::src_len.

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

◆ ra8_jpeg_sw_encode()

ra8_err_t ra8_jpeg_sw_encode ( const uint8_t * rgb_buf,
uint16_t width,
uint16_t height,
uint8_t quality,
uint8_t * out_buf,
uint32_t out_buf_len,
uint32_t * out_len )
nodiscard

Encode a packed RGB888 frame as a baseline JPEG.

Emits an SOI / APP0(JFIF 1.01) / DQT / SOF0 / DHT / SOS / compressed-data / EOI byte stream. Quantization tables are the T.81 Annex K.1 "Quantization table examples" luma and chroma tables, scaled by the IJG quality formula (scale = 5000/q for q < 50, 200 - 2q for q >= 50). Huffman tables are the T.81 Annex K.3.3 "Typical Huffman tables for 8-bit precision luminance and chrominance" reference tables, included verbatim via DHT segments rather than being optimized per image.

Colour space: input is interpreted as sRGB and converted to YCbCr per ITU-R BT.601, then chroma is averaged 4:1 to produce 4:2:0 subsampling. Width and height are padded to a multiple of 16 internally; the SOF0 marker still records the requested unpadded dimensions so decoders crop correctly.

Parameters
[in]rgb_bufSource pixels, 3 bytes per pixel (R, G, B), width * height * 3 total.
[in]widthImage width in pixels (1..0xFFFF).
[in]heightImage height in pixels (1..0xFFFF).
[in]qualityQuality factor in [k_ra8_jpeg_sw_quality_min, k_ra8_jpeg_sw_quality_max].
[out]out_bufDestination buffer for the JPEG bytes.
[in]out_buf_lenCapacity of out_buf.
[out]out_lenReceives the encoded byte count.
Returns
ra8_err_t error code.
Return values
k_ra8_okEncoded; *out_len <= out_buf_len.
k_ra8_err_null_ptrAny pointer argument was NULL.
k_ra8_err_invalid_argquality out of range, or width == 0, or height == 0.
k_ra8_err_invalid_sizeout_buf_len too small to hold the encoded stream (worst case is roughly width * height * 3).
Precondition
rgb_buf, out_buf and out_len are non-NULL.
out_buf capacity is at least width * height bytes for well-compressing inputs (caller should over-provision).
Postcondition
On success the bytes at out_buf[0..*out_len) form a valid JFIF 1.01 JPEG file.
On any error *out_len is set to 0.
Note
Thread-safe.
Example:
uint32_t produced;
ra8_err_t e = ra8_jpeg_sw_encode(rgb, 640, 480,
jpeg, sizeof jpeg, &produced);
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
@ k_ra8_jpeg_sw_quality_default
IJG cjpeg default.
Definition ra8_jpeg_sw.h:76
ra8_err_t ra8_jpeg_sw_encode(const uint8_t *rgb_buf, uint16_t width, uint16_t height, uint8_t quality, uint8_t *out_buf, uint32_t out_buf_len, uint32_t *out_len)
Encode a packed RGB888 frame as a baseline JPEG.
See also
ra8_jpeg_sw_decode Inverse operation.
Since
0.1.0

Definition at line 778 of file ra8_jpeg_sw_encode.c.

References ra8_jpeg_enc_ctx_t::cap, ra8_jpeg_enc_ctx_t::dst, internal_enc_run(), k_ra8_err_invalid_arg, k_ra8_jpeg_sw_quality_max, k_ra8_jpeg_sw_quality_min, k_ra8_ok, memset(), ra8_jpeg_enc_ctx_t::pos, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by internal_jpeg_sw_encode().

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