|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Import-time transcode producer: JPEG/PNG/WebP -> JOF band-tile atlas in bounded RAM (#231, #290 normalize-on-import). More...
Go to the source code of this file.
Data Structures | |
| struct | jof_produce_cfg_t |
| Producer configuration: source, sink, tile geometry and work arena. More... | |
Typedefs | |
| typedef ra8_err_t(* | jof_pull_fn) (void *ctx, uint8_t *buf, size_t cap, size_t *got) |
| Forward byte source for the producer (DIP seam). | |
| typedef ra8_err_t(* | jof_sink_fn) (void *ctx, const uint8_t *buf, size_t len) |
| Append-only byte sink for the produced atlas (DIP seam). | |
Functions | |
| uint32_t | jof_work_bytes (uint16_t max_width, uint16_t max_height, uint16_t tile_w, uint16_t tile_h) |
| Compute the work-arena size the producer needs for given caps. | |
| uint32_t | jof_webp_work_bytes (uint16_t max_width, uint16_t max_height, uint32_t max_src_bytes) |
| Compute the whole-frame webp_work arena a WebP source needs (#290). | |
| ra8_err_t | jof_probe_dims (const uint8_t *data, size_t len, uint16_t *out_w, uint16_t *out_h) |
| Read a source image's pixel dimensions without decoding its body. | |
| ra8_err_t | jof_produce (const jof_produce_cfg_t *cfg, jof_info_t *out_info) |
| Transcode one encoded JPEG/PNG/WebP source into a JOF atlas (#231, #290). | |
Import-time transcode producer: JPEG/PNG/WebP -> JOF band-tile atlas in bounded RAM (#231, #290 normalize-on-import).
jof_produce() turns an arbitrary encoded source image into the JOF atlas (jof.h) – the single on-device normalized format – so render time only ever touches one codec regardless of source. The tile codec is lossless DEFLATE (never a second lossy re-encode of the decoded pixels), so no source ever loses quality on import.
The streaming formats (JPEG, PNG) transcode in one forward pass with a constant RAM high-water: the source arrives through a pull callback (never held whole), the decoder emits pixel rows in bounded stripes (never the whole frame), a band accumulator gathers one tile row at a time, each tile is cut + intra-coded + appended to the sink, and the index/footer trail the data so the sink can be append-only (an SD file, a memstore over SDRAM). A page whose decoded size exceeds SDRAM transcodes without ever being resident – the memory ceiling is the caller's fixed work arena plus the caller's buffers. That ceiling is a function of max_width, tile_h and the tile count; it is independent of image height to within the 8-byte index entry each band adds, which is what makes an arbitrarily long longstrip importable. Width is not free: it scales the band, the tile stage and the compressed-tile bound together.
WebP (VP8 / VP8L, via the ra8_webp facade over libwebp) is inherently a whole-frame codec: its lossless mode uses 2-D backward references, so it cannot be decoded with a bounded output window the way JPEG/PNG stripe out. A WebP source is therefore normalized through the same JOF tile path but at a whole-frame memory cost: the caller supplies a second webp_work arena (sized by jof_webp_work_bytes()) that holds the compressed source, the decoded RGBA frame and libwebp's scratch. webp_work == NULL fail-closed rejects any WebP source as k_ra8_err_not_supported, so a streaming-only caller pays nothing. The JOF output is byte-identical to the atlas produced from a lossless PNG of the same pixels: import genuinely converges every source codec on one representation.
Resident working set (all carved from the caller's single work arena; jof_work_bytes() computes the exact requirement):
Sources: baseline JPEG (grayscale -> 1 bpp, colour -> 3 bpp RGB888), PNG (8-bit gray -> 1 bpp; RGB / palette -> 3 bpp; gray+alpha / RGBA / palette+tRNS -> 4 bpp) and WebP (VP8 lossy / VP8L lossless -> 4 bpp RGBA, when a webp_work arena is supplied). Anything else – progressive JPEG, 16-bit or interlaced PNG, other formats – is rejected fail-closed (k_ra8_err_not_supported); the caller falls back to the whole-decode path for images small enough to afford it. No downscaling, ever: output pixels are the decoded pixels, full resolution, lossless.
This is untrusted EPUB content: every source field is bounds-checked, all loops are capped, and any structural anomaly aborts the transcode with an error rather than a partial atlas being trusted. Zero heap: the producer allocates nothing – every byte of state lives in caller buffers.
The band accumulator is always full-width, so streaming does not depend on tile_w: narrow tiles are cut out of the same band. tile_w == width (band-tiles) is a reader optimisation – it makes the tile index the band index for an O(1) scroll seek – and it costs the writer, because the tile stage then grows to a whole band.
Definition in file jof_produce.h.
| typedef ra8_err_t(* jof_pull_fn) (void *ctx, uint8_t *buf, size_t cap, size_t *got) |
Forward byte source for the producer (DIP seam).
Strictly sequential, single pass: each call appends the next bytes of the encoded source image. *got == 0 signals a clean end of stream; any error return aborts the transcode with that code. An EPUB entry cursor (epub_entry_read) matches this shape directly.
| [in] | ctx | Source-specific context. |
| [out] | buf | Destination buffer (cap writable bytes). |
| [in] | cap | Capacity of buf. |
| [out] | got | Bytes delivered this call (0 = end of stream). |
Definition at line 111 of file jof_produce.h.
| typedef ra8_err_t(* jof_sink_fn) (void *ctx, const uint8_t *buf, size_t len) |
Append-only byte sink for the produced atlas (DIP seam).
Bytes arrive strictly in atlas order (header, tiles, index, footer); the sink never seeks. jof_memstore_sink() is the RAM-backed reference implementation; an ra8_fs file writer wraps ra8_fs_write identically. Any error return aborts the transcode with that code.
| [in] | ctx | Sink-specific context. |
| [in] | buf | Bytes to append. |
| [in] | len | Byte count. |
Definition at line 129 of file jof_produce.h.
|
nodiscard |
Read a source image's pixel dimensions without decoding its body.
Sniffs the same three magics jof_produce() dispatches on (JPEG SOI, PNG signature, WebP RIFF+WEBP) and returns the declared geometry from the matching header: the JPEG SOF, the PNG IHDR, or the WebP VP8/VP8L header via ra8_webp_get_info. Callers need this before producing, because the work-arena sizes and the tile width are all functions of the geometry – jof_work_bytes and jof_webp_work_bytes both take it as input.
The probe shares the producer's magic constants and accepts exactly the set the producer accepts, so "probe succeeded" and "produce will dispatch" cannot drift apart. A non-WebP RIFF (WAVE, AVI) is rejected rather than handed to the WebP reader.
| [in] | data | Encoded source bytes (non-NULL). |
| [in] | len | Readable byte count at data. |
| [out] | out_w | Receives the source width in pixels. |
| [out] | out_h | Receives the source height in pixels. |
| k_ra8_ok | Dimensions read; both outputs written. |
| k_ra8_err_null_ptr | data, out_w or out_h is NULL. |
| k_ra8_err_not_supported | Too short to sniff, header truncated, or the magic is not JPEG / PNG / WebP. |
| k_ra8_err_invalid_size | A dimension is zero or exceeds k_jof_max_dim. |
| other | Propagated from the per-format reader. |
data holds len readable bytes. out_w and out_h point at writable storage. Definition at line 895 of file jof_produce.c.
References internal_probe_sniff(), RA8_CHECK_NULL_PTR, and s_tag.
Referenced by internal_jof_one(), and jof_worker_convert().
|
nodiscard |
Transcode one encoded JPEG/PNG/WebP source into a JOF atlas (#231, #290).
Sniffs the source magic (JPEG SOI, PNG signature, or WebP RIFF/WEBP), then:
Either way the rows are accumulated into one band, each tile is cut + encoded through the configured (lossless) codec, and header / tiles / index / footer are appended to the sink in one forward pass. On success out_info describes the finished atlas exactly as jof_parse() would report it, and the atlas is byte-identical across source codecs that decode to the same pixels.
| [in] | cfg | Producer configuration (see the struct contract). |
| [out] | out_info | Receives the finished atlas geometry. |
| k_ra8_ok | Atlas fully written to the sink. |
| k_ra8_err_null_ptr | A required pointer in cfg is NULL. |
| k_ra8_err_invalid_arg | Zero tile geometry or unknown codec. |
| k_ra8_err_invalid_size | Source exceeds the budget caps, the grid exceeds the tile cap, or work / webp_work is too small (fail-closed). |
| k_ra8_err_not_supported | Source format not JPEG/PNG/WebP, a WebP source with no webp_work arena, a WebP axis over the 8192 cap, or an unsupported variant (progressive, interlaced, 16-bit, ...). |
| k_ra8_err_protocol_error | Malformed / truncated / hostile source structure. |
| k_ra8_err_validation_failed | Pixel-stream inconsistency (row count, inflate size, palette index). |
| other | Propagated from pull / sink. |
cfg->work covers work_cap bytes sized per jof_work_bytes(). cfg->pull delivers the encoded source strictly in order, once. Definition at line 964 of file jof_produce.c.
References internal_check_cfg(), internal_dispatch(), internal_epilogue(), internal_init_state(), internal_produce_args_ok(), internal_sniff_head(), k_jof_sniff_bytes, k_ra8_ok, jof_produce_cfg_t::pull, and jof_produce_cfg_t::pull_ctx.
Referenced by internal_jof_produce_page(), internal_produce(), mg_build_atlas(), ra8_fmt_jof_convert_stream(), and worker_produce_to_file().
|
nodiscard |
Compute the whole-frame webp_work arena a WebP source needs (#290).
A WebP transcode cannot stream (its lossless mode back-references the whole frame), so it holds three regions at once, all carved from webp_work: the compressed source (up to max_src_bytes), the decoded RGBA8888 frame (max_width * max_height * 4) and libwebp's decode scratch (a further whole-frame-scale allocation plus slack). Sizing with the same caps used in the produce config guarantees jof_produce() never fails on WebP arena exhaustion for an in-cap WebP source. This is separate from jof_work_bytes(): that arena stays small (the streaming tile path); only WebP-capable callers pay the whole-frame cost here.
| [in] | max_width | Largest WebP source width to support (>= 1). |
| [in] | max_height | Largest WebP source height to support (>= 1). |
| [in] | max_src_bytes | Largest compressed WebP byte length to support (>= 1). |
| 0 | A dimension is zero or exceeds the WebP per-axis cap (8192), the source-byte cap is zero, or the total exceeds the u32 arena cap. |
| >0 | Byte size to allocate for webp_work. |
max_src_bytes compressed bytes. Definition at line 54 of file jof_produce_webp.c.
References k_jof_carve_slack, k_jof_webp_bpp, k_jof_webp_scratch_mult, k_jof_webp_scratch_slack, and k_ra8_webp_max_dim.
Referenced by internal_jof_carve_webp(), ra8_fmt_jof_convert_requirements(), and worker_alloc_webp().
|
nodiscard |
Compute the work-arena size the producer needs for given caps.
Sums the worst of the two decoder carve sets (JPEG window + stripe vs PNG inflate state + ring + rows) with the band, tile stage, compressed-tile bound, deflate scratch and tile index for the given budget caps, plus per-carve alignment slack. Passing the same caps here and in the config guarantees jof_produce() never fails on arena exhaustion for an in-budget source.
| [in] | max_width | Largest source width to support (>= 1, <= cap). |
| [in] | max_height | Largest source height to support (>= 1, <= cap). |
| [in] | tile_w | Tile width the producer will use (>= 1). |
| [in] | tile_h | Tile height the producer will use (>= 1). |
| 0 | An argument was zero or exceeded k_jof_max_dim, or the tile grid would exceed k_jof_max_tiles. |
| >0 | Byte size to allocate for work. |
Definition at line 590 of file jof_produce.c.
References jof_stored_bound(), k_jof_bpp_max, k_jof_carve_slack, k_jof_index_entry, k_jof_max_dim, k_jof_max_tiles, k_jof_png_inbuf, k_jof_png_ring, k_ra8_compress_scratch_bytes, k_ra8_jpeg_sw_stream_mcu_rows_max, and k_ra8_jpeg_sw_stream_min_window.
Referenced by internal_jof_one(), jof_worker_convert(), mg_build_atlas(), ra8_fmt_jof_convert_requirements(), and ra8_fmt_jof_verify_requirements().