ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_export_jof.c
Go to the documentation of this file.
1
30
31#include <stdio.h>
32#include <string.h>
33
34#include "jof.h"
35#include "jof_produce.h"
36#include "mdl_export.h"
37#include "mdl_export_internal.h"
38#include "ra8_attributes.h"
39#include "ra8_err.h"
40
49typedef enum : uint16_t {
52
67
68typedef enum : uint32_t {
69 k_jof_source_cap = 16U * 1024U * 1024U,
70 k_jof_work_cap = 16U * 1024U * 1024U,
71 k_jof_webp_work_cap = 64U * 1024U * 1024U,
73
75static const uint8_t s_jof_webp_riff[k_jof_webp_tag_len] = {'R', 'I', 'F', 'F'};
76
78static const uint8_t s_jof_webp_webp[k_jof_webp_tag_len] = {'W', 'E', 'B', 'P'};
79
98RA8_INTERNAL static bool internal_jof_is_webp(const uint8_t* data, size_t len)
99{
100 if ((data == nullptr) || (len < (size_t)k_jof_webp_head_len)) {
101 return false;
102 }
103 return (memcmp(&data[k_jof_webp_riff_ofs], s_jof_webp_riff, sizeof(s_jof_webp_riff)) == 0) &&
105}
106
108typedef struct {
109 const uint8_t* data;
110 size_t len;
111 size_t pos;
113
131RA8_INTERNAL static ra8_err_t internal_jof_pull(void* ctx, uint8_t* buf, size_t cap, size_t* got)
132{
134 size_t n = s->len - s->pos;
135 if (n > cap) {
136 n = cap;
137 }
138 memcpy(buf, s->data + s->pos, n);
139 s->pos += n;
140 *got = n;
141 return k_ra8_ok;
142}
143
162RA8_INTERNAL static ra8_err_t internal_jof_sink(void* ctx, const uint8_t* buf, size_t len)
163{
164 if (len > UINT32_MAX) {
166 }
167 return priv_mdl_export_output_write((mdl_export_output_t*)ctx, buf, (uint32_t)len);
168}
169
199 size_t slen,
200 uint16_t w,
201 uint16_t h,
202 uint8_t** out_work,
203 size_t* out_cap,
205{
206 *out_work = nullptr;
207 *out_cap = 0U;
208 if (!internal_jof_is_webp(src, slen)) {
209 return k_ra8_ok;
210 }
211 const uint32_t need = jof_webp_work_bytes(w, h, (uint32_t)slen);
212 if ((need == 0U) || ((size_t)need > (size_t)k_jof_webp_work_cap)) {
214 }
215 uint8_t* mem = (uint8_t*)mdl_export_workspace_take(ws, (size_t)need, 16U);
216 if (mem == nullptr) {
218 }
219 *out_work = mem;
220 *out_cap = (size_t)need;
221 return k_ra8_ok;
222}
223
259 size_t slen,
260 uint16_t w,
261 uint16_t h,
262 uint16_t tile_h,
263 uint32_t work_cap,
264 mdl_export_output_t* output,
266{
267 if ((size_t)work_cap > (size_t)k_jof_work_cap) {
269 }
270 uint8_t* work = (uint8_t*)mdl_export_workspace_take(ws, (size_t)work_cap, 16U);
271 if (work == nullptr) {
273 }
274 uint8_t* webp_work = nullptr;
275 size_t webp_cap = 0U;
276 const ra8_err_t carve_rc = internal_jof_carve_webp(src, slen, w, h, &webp_work, &webp_cap, ws);
277 if (carve_rc != k_ra8_ok) {
278 return carve_rc;
279 }
280 jof_pull_ctx_t pull = {.data = src, .len = slen, .pos = 0U};
282 .pull_ctx = &pull,
283 .sink = internal_jof_sink,
284 .sink_ctx = output,
285 .tile_w = w,
286 .tile_h = tile_h,
287 .codec = (uint8_t)k_jof_codec_deflate,
288 .max_width = w,
289 .max_height = h,
290 .work = work,
291 .work_cap = work_cap,
292 .webp_work = webp_work,
293 .webp_work_cap = webp_cap};
294 jof_info_t info = {};
295 const ra8_err_t rc = jof_produce(&cfg, &info);
296 return rc;
297}
298
324 const char* in_path,
326 uint8_t** out_src,
327 size_t* out_slen)
328{
329 fw_fs_stat_t stat = {};
330 ra8_err_t rc = fw_fs_stat(&storage->fs->names, in_path, &stat);
331 if (rc != k_ra8_ok) {
332 return rc;
333 }
334 if (!stat.exists) {
335 return k_ra8_err_not_found;
336 }
337 if ((stat.type != k_fw_fs_node_file) || (stat.size_bytes == 0U)) {
339 }
340 if (stat.size_bytes > (uint64_t)k_jof_source_cap) {
342 }
343 uint8_t* src = (uint8_t*)mdl_export_workspace_take(ws, (size_t)stat.size_bytes, 16U);
344 if (src == nullptr) {
346 }
347 rc = priv_mdl_export_source_slurp(storage, in_path, src, (size_t)stat.size_bytes, out_slen);
348 if (rc != k_ra8_ok) {
349 return rc;
350 }
351 *out_src = src;
352 return k_ra8_ok;
353}
354
378 const char* in_path,
379 const char* out_path,
381{
382 uint8_t* src = nullptr;
383 size_t slen = 0U;
384 ra8_err_t rc = internal_jof_load_source(storage, in_path, ws, &src, &slen);
385 if (rc != k_ra8_ok) {
386 return rc;
387 }
388 uint16_t w = 0U;
389 uint16_t h = 0U;
390 /* Probe through the producer's own dispatch, so every format the producer can
391 * decode (JPEG, PNG, WebP) is a format this exporter can size and write. */
392 if (jof_probe_dims(src, slen, &w, &h) != k_ra8_ok) {
394 }
395 const uint16_t tile_h = (h < (uint16_t)k_jof_band_h) ? h : (uint16_t)k_jof_band_h;
396 const uint32_t work_cap = jof_work_bytes(w, h, w, tile_h);
397 if (work_cap == 0U) {
399 }
400 /* Produce into the storage transaction's borrowed stage; canonical
401 * validation must pass before the transaction publishes this page. */
402 mdl_export_output_t output = {};
403 rc = priv_mdl_export_output_begin(&output, storage, out_path, k_mdl_format_jof);
404 if (rc == k_ra8_ok) {
405 rc = internal_jof_produce_page(src, slen, w, h, tile_h, work_cap, &output, ws);
406 }
407 if ((rc != k_ra8_ok) && output.writer.transaction.active) {
408 const ra8_err_t aborted = priv_mdl_export_output_abort(&output);
409 return (aborted == k_ra8_ok) ? rc : aborted;
410 }
411 bool published = false;
412 return (rc == k_ra8_ok) ? priv_mdl_export_output_commit(&output, ws, &published) : rc;
413}
414
416 const char* dir,
417 const char names[][k_name_max],
418 size_t count,
420{
421 const size_t page_mark = ws->used;
422 ra8_err_t rc = k_ra8_ok;
423 for (size_t i = 0U; (rc == k_ra8_ok) && (i < count); ++i) {
424 char in_path[k_fw_fs_path_cap];
425 char stem[k_name_max];
426 char out_path[k_fw_fs_path_cap];
427 rc = priv_mdl_export_path_join(in_path, sizeof(in_path), dir, names[i]);
428 memcpy(stem, names[i], k_name_max);
429 char* dot = strrchr(stem, '.');
430 if (dot != nullptr) {
431 *dot = '\0';
432 }
433 char output_leaf[k_name_max];
434 const int written = snprintf(output_leaf, sizeof(output_leaf), "%s.jof", stem);
435 if ((rc == k_ra8_ok) && priv_mdl_export_snprintf_fit(written, sizeof(output_leaf))) {
436 rc = priv_mdl_export_path_join(out_path, sizeof(out_path), dir, output_leaf);
437 } else if (rc == k_ra8_ok) {
439 }
440 ws->used = page_mark;
441 if (rc == k_ra8_ok) {
442 rc = internal_jof_one(storage, in_path, out_path, ws);
443 }
444 }
445 return rc;
446}
ra8_err_t fw_fs_stat(const fw_fs_namespace_t *names, const char *path, fw_fs_stat_t *out)
Query a path; a miss is success with out->exists == false.
Definition fw_if_fs.c:480
@ k_fw_fs_node_file
Regular byte stream.
@ k_fw_fs_path_cap
Largest portable path including its NUL.
JOF band-tile atlas: the display-native normalized image format (#231, shared with the longstrip scro...
@ k_jof_codec_deflate
Tile stream is one raw-DEFLATE run.
Definition jof.h:192
@ k_jof_webp_fourcc_ofs
Offset of the "WEBP" fourCC.
Definition jof_produce.c:52
Import-time transcode producer: JPEG/PNG/WebP -> JOF band-tile atlas in bounded RAM (#231,...
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.
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).
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.
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).
Package a downloaded chapter folder into a reader-openable container.
void * mdl_export_workspace_take(mdl_export_workspace_t *ws, size_t bytes, size_t alignment)
Reserve aligned bytes from an exporter arena.
struct mdl_export_workspace mdl_export_workspace_t
Caller-owned bounded arena for all exporter scratch state.
Module-private contracts shared by chapter export writers.
@ k_name_max
Maximum entry-name bytes.
bool priv_mdl_export_snprintf_fit(int written, size_t cap)
Report whether an snprintf result fit its destination.
ra8_err_t priv_mdl_export_path_join(char *out, size_t capacity, const char *directory, const char *leaf)
Join a canonical directory and leaf without truncation.
ra8_err_t priv_mdl_export_output_abort(mdl_export_output_t *output)
Abort one unpublished export stage, retaining cleanup failure.
ra8_err_t priv_mdl_export_output_commit(mdl_export_output_t *output, mdl_export_workspace_t *workspace, bool *out_published)
Structurally validate and publish one completed export stage.
ra8_err_t priv_mdl_export_output_begin(mdl_export_output_t *output, mdl_storage_t *storage, const char *destination, mdl_format_t format)
Bind a validated publication transaction to one destination.
ra8_err_t priv_mdl_export_output_write(mdl_export_output_t *output, const uint8_t *bytes, uint32_t length)
Append one complete byte span to an active export stage.
ra8_err_t priv_mdl_export_source_slurp(mdl_storage_t *storage, const char *path, uint8_t *destination, size_t capacity, size_t *out_length)
Read one complete bounded portable source into caller storage.
static const uint8_t s_jof_webp_riff[k_jof_webp_tag_len]
WebP RIFF container tag (page head bytes 0..3).
static bool internal_jof_is_webp(const uint8_t *data, size_t len)
Test whether a page's bytes carry the WebP RIFF container head.
static ra8_err_t internal_jof_load_source(mdl_storage_t *storage, const char *in_path, mdl_export_workspace_t *ws, uint8_t **out_src, size_t *out_slen)
Stat, bound-check, arena-claim, and slurp one source image.
ra8_err_t priv_mdl_export_jof(mdl_storage_t *storage, const char *dir, const char names[][k_name_max], size_t count, mdl_export_workspace_t *ws)
Convert every page in a chapter directory to a sibling .jof atlas.
static const uint8_t s_jof_webp_webp[k_jof_webp_tag_len]
WebP form-type fourCC (page head bytes 8..11).
static ra8_err_t internal_jof_produce_page(const uint8_t *src, size_t slen, uint16_t w, uint16_t h, uint16_t tile_h, uint32_t work_cap, mdl_export_output_t *output, mdl_export_workspace_t *ws)
Produce one page's atlas into an already-open output file.
static ra8_err_t internal_jof_pull(void *ctx, uint8_t *buf, size_t cap, size_t *got)
Copy the next encoded source span into a producer buffer.
static ra8_err_t internal_jof_carve_webp(const uint8_t *src, size_t slen, uint16_t w, uint16_t h, uint8_t **out_work, size_t *out_cap, mdl_export_workspace_t *ws)
Carve the whole-frame WebP work arena for a WebP page (no-op otherwise).
static ra8_err_t internal_jof_sink(void *ctx, const uint8_t *buf, size_t len)
Append producer output bytes to the active publication transaction.
mdl_jof_geom_t
JOF atlas tiling geometry for a long-strip page.
@ k_jof_band_h
Tile-band height in pixels.
mdl_jof_webp_t
WebP container-head offsets for the whole-frame-arena decision.
@ k_jof_webp_head_len
Bytes needed to sniff both fourCCs.
@ k_jof_webp_riff_ofs
Offset of the "RIFF" fourCC.
@ k_jof_webp_tag_len
Length of one fourCC tag.
static ra8_err_t internal_jof_one(mdl_storage_t *storage, const char *in_path, const char *out_path, mdl_export_workspace_t *ws)
Transcode one JPEG, PNG, or WebP page to a JOF band atlas.
mdl_jof_workspace_t
Hard memory ceilings for the non-reentrant transcode workspace.
@ k_jof_webp_work_cap
Maximum WebP frame workspace.
@ k_jof_work_cap
Maximum streaming work bytes.
@ k_jof_source_cap
Maximum encoded source bytes.
@ k_mdl_format_jof
Native JOF tile atlas per page (.jof).
Definition mdl_format.h:43
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Error Code Definitions for ra8-firmware.
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_not_found
Requested item not found (lookup / search missed).
Definition ra8_err.h:173
@ 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
int memcmp(const void *a, const void *b, size_t n)
Compare bytes in two memory areas.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
char * strrchr(const char *s, int c)
Locate last occurrence of character in string.
Result of a portable metadata query.
uint64_t size_bytes
File length; zero for a directory.
bool exists
False means a clean lookup miss.
fw_fs_node_type_t type
Kind of node at the path.
fw_fs_namespace_t names
Namespace operations.
bool active
Begin succeeded.
Parsed + validated geometry of one JOF atlas.
Definition jof.h:208
Producer configuration: source, sink, tile geometry and work arena.
Pull cursor over an in-RAM encoded image.
size_t len
Total length.
size_t pos
Read cursor.
const uint8_t * data
Encoded bytes.
One validated staged publication, including random ZIP backfill.
mdl_storage_txn_t writer
Active storage transaction.
size_t used
Current allocation high edge.
Definition mdl_export.h:220
One non-reentrant downloader filesystem dependency bundle.
Definition mdl_storage.h:40
const fw_fs_t * fs
Injected portable filesystem.
Definition mdl_storage.h:41
fw_fs_transaction_t transaction
Active private filesystem stage.
Definition mdl_storage.h:60