ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
jof_produce.c
Go to the documentation of this file.
1
23
24#include "jof_produce.h"
25
26#include <stddef.h>
27#include <stdint.h>
28#include <string.h>
29
30#include "jof.h"
31#include "jof_internal.h"
32#include "ra8_attributes.h"
33#include "ra8_check.h"
34#include "ra8_compress.h"
35#include "ra8_err.h"
36#include "ra8_jpeg_sw.h"
37#include "ra8_log.h"
38#include "ra8_webp.h"
39
41static const char* const s_tag = "jof_prod";
42
63
65typedef enum : uint8_t {
71
81
83static const uint8_t s_prod_webp_riff[k_jof_magic_len] = {'R', 'I', 'F', 'F'};
84
86static const uint8_t s_prod_webp_webp[k_jof_magic_len] = {'W', 'E', 'B', 'P'};
87
89RA8_PRIV void* priv_jof_bump_take(jof_bump_t* bump, size_t len)
90{
91 if ((bump == nullptr) || (len == 0U)) {
92 return nullptr;
93 }
94 const size_t mask = (size_t)k_jof_bump_align - 1U;
95 const size_t aligned = (bump->off + mask) & ~mask;
96 if ((aligned > bump->cap) || (len > (bump->cap - aligned))) {
97 return nullptr;
98 }
99 bump->off = aligned + len;
100 return &bump->base[aligned];
101}
102
103/* ---------------------------------------------------------------------------
104 * Little-endian field writers + sink accounting.
105 * ---------------------------------------------------------------------------
106 */
107
121RA8_INTERNAL static void internal_wr_u16(uint8_t* buf, uint16_t v)
122{
123 buf[0] = (uint8_t)(v & (uint16_t)k_jof_byte_mask);
124 buf[1] = (uint8_t)((uint32_t)v >> k_jof_le_sh8);
125}
126
140RA8_INTERNAL static void internal_wr_u32(uint8_t* buf, uint32_t v)
141{
142 buf[0] = (uint8_t)(v & (uint32_t)k_jof_byte_mask);
143 buf[1] = (uint8_t)((v >> k_jof_le_sh8) & (uint32_t)k_jof_byte_mask);
144 buf[2] = (uint8_t)((v >> k_jof_le_sh16) & (uint32_t)k_jof_byte_mask);
145 buf[3] = (uint8_t)((v >> k_jof_le_sh24) & (uint32_t)k_jof_byte_mask);
146}
147
166RA8_INTERNAL static ra8_err_t internal_sink(jof_prod_state_t* st, const uint8_t* buf, size_t len)
167{
168 if ((uint64_t)len > ((uint64_t)UINT32_MAX - (uint64_t)st->written)) {
170 }
171 const ra8_err_t err = st->cfg->sink(st->cfg->sink_ctx, buf, len);
172 if (err != k_ra8_ok) {
173 return err;
174 }
175 st->written += (uint32_t)len;
176 return k_ra8_ok;
177}
178
179/* ---------------------------------------------------------------------------
180 * Prefix-replay pull adapter.
181 * ---------------------------------------------------------------------------
182 */
183
184RA8_PRIV ra8_err_t priv_jof_prefix_pull(void* ctx, uint8_t* buf, size_t cap, size_t* got)
185{
187 if (pfx->pos < pfx->head_len) {
188 const size_t left = pfx->head_len - pfx->pos;
189 const size_t take = (cap < left) ? cap : left;
190 (void)memcpy(buf, &pfx->head[pfx->pos], take);
191 pfx->pos += take;
192 *got = take;
193 return k_ra8_ok;
194 }
195 return pfx->inner(pfx->inner_ctx, buf, cap, got);
196}
197
198/* ---------------------------------------------------------------------------
199 * Geometry + band accumulation + tile flush.
200 * ---------------------------------------------------------------------------
201 */
202
219{
220 uint8_t hdr[k_jof_hdr_bytes] = {};
221 hdr[0] = 'J';
222 hdr[1] = 'O';
223 hdr[2] = 'F';
224 hdr[3] = '1';
229 hdr[k_jof_ofs_bpp] = st->bpp;
230 hdr[k_jof_ofs_codec] = st->cfg->codec;
232 return internal_sink(st, hdr, sizeof(hdr));
233}
234
252{
253 const uint16_t tw = st->cfg->tile_w;
254 const uint16_t th = st->cfg->tile_h;
255 const uint64_t band_bytes = (uint64_t)st->w * (uint64_t)th * (uint64_t)st->bpp;
256 const uint32_t tw_eff = (tw < st->w) ? tw : st->w;
257 const uint32_t th_eff = (th < st->h) ? th : st->h;
258 const uint64_t stage_bytes = (uint64_t)tw_eff * (uint64_t)th_eff * (uint64_t)st->bpp;
259 // mcdc-deactivated: stage_bytes = tw_eff*th_eff*bpp with tw_eff <= w and th_eff <= tile_h, so stage_bytes <= w*tile_h*bpp = band_bytes always; the stage-overflow arm cannot flip independently of the band arm (which apps/shared_libs/jof/tests/src/test_jof_produce_guards.c drives true via a 32768-wide RGBA source and a 65535-tall tile).
260 if ((band_bytes > (uint64_t)UINT32_MAX) || (stage_bytes > (uint64_t)UINT32_MAX)) {
262 }
263 st->band = priv_jof_bump_take(st->bump, (size_t)band_bytes);
264 st->stage = priv_jof_bump_take(st->bump, (size_t)stage_bytes);
265 st->idx = priv_jof_bump_take(st->bump, (size_t)st->tile_count * (size_t)k_jof_index_entry);
266 if ((st->band == nullptr) || (st->stage == nullptr) || (st->idx == nullptr)) {
268 }
269 if (st->cfg->codec == (uint8_t)k_jof_codec_deflate) {
270 st->cmp_cap = jof_stored_bound((uint32_t)stage_bytes);
271 st->cmp = priv_jof_bump_take(st->bump, (size_t)st->cmp_cap);
272 if (st->cmp == nullptr) {
274 }
275 }
276 return k_ra8_ok;
277}
278
301RA8_PRIV ra8_err_t priv_jof_on_geom(void* ctx, uint16_t width, uint16_t height, uint8_t channels)
302{
304 if (st->geom_done != 0U) {
306 }
307 if ((width == 0U) || (width > st->cap_w) || (height == 0U) || (height > st->cap_h)) {
309 }
310 const uint32_t cols = ((uint32_t)width + st->cfg->tile_w - 1U) / st->cfg->tile_w;
311 const uint32_t rows = ((uint32_t)height + st->cfg->tile_h - 1U) / st->cfg->tile_h;
312 if ((cols * rows) > (uint32_t)k_jof_max_tiles) {
314 }
315 st->w = width;
316 st->h = height;
317 st->bpp = channels;
318 st->tile_cols = (uint16_t)cols;
319 st->tile_rows = (uint16_t)rows;
320 st->tile_count = cols * rows;
322 if (err != k_ra8_ok) {
323 return err;
324 }
325 err = internal_emit_header(st);
326 if (err != k_ra8_ok) {
327 return err;
328 }
329 st->geom_done = 1U;
330 return k_ra8_ok;
331}
332
355{
356 const uint8_t* out_bytes = st->stage;
357 uint32_t out_len = payload;
358 if (st->cfg->codec == (uint8_t)k_jof_codec_deflate) {
359 uint32_t clen = 0U;
360 if (ra8_compress(st->stage, payload, st->cmp, st->cmp_cap, st->dfl, st->dfl_len, &clen) !=
361 k_ra8_ok) {
363 }
364 out_bytes = st->cmp;
365 out_len = clen;
366 }
367 uint8_t* entry = &st->idx[(size_t)st->tiles_done * (size_t)k_jof_index_entry];
369 internal_wr_u32(&entry[k_jof_idx_ofs_length], out_len);
370 const ra8_err_t err = internal_sink(st, out_bytes, (size_t)out_len);
371 if (err != k_ra8_ok) {
372 return err;
373 }
374 st->tiles_done++;
375 return k_ra8_ok;
376}
377
397{
398 const uint32_t stride = (uint32_t)st->w * (uint32_t)st->bpp;
399 for (uint32_t tx = 0U; tx < (uint32_t)st->tile_cols; tx++) {
400 const uint32_t x0 = tx * (uint32_t)st->cfg->tile_w;
401 const uint32_t tw = (((uint32_t)st->w - x0) < (uint32_t)st->cfg->tile_w)
402 ? ((uint32_t)st->w - x0)
403 : (uint32_t)st->cfg->tile_w;
404 const uint32_t row_bytes = tw * (uint32_t)st->bpp;
405 for (uint32_t r = 0U; r < th; r++) {
406 (void)memcpy(&st->stage[(size_t)r * (size_t)row_bytes],
407 &st->band[((size_t)r * (size_t)stride) + ((size_t)x0 * (size_t)st->bpp)],
408 (size_t)row_bytes);
409 }
410 const ra8_err_t err = internal_encode_tile(st, row_bytes * th);
411 if (err != k_ra8_ok) {
412 return err;
413 }
414 }
415 return k_ra8_ok;
416}
417
419 const uint8_t* px,
420 uint16_t width,
421 uint16_t y0,
422 uint16_t nrows,
423 uint8_t channels)
424{
426 RA8_CHECK_NULL_PTR(px, s_tag, "px must not be nullptr");
427 if ((st->geom_done == 0U) || (width != st->w) || (channels != st->bpp)) {
429 }
430 // mcdc-deactivated: row-ordering contract guard; the PNG scanline assembler emits exactly one row per call at y0 == rows_done and the JPEG stripe walker emits edge-clamped nrows >= 1 at strictly increasing MCU-row origins, so zero/duplicated/overshooting deliveries are not constructible from a public-API source.
431 if ((nrows == 0U) || ((uint32_t)y0 != st->rows_seen) ||
432 (((uint32_t)y0 + (uint32_t)nrows) > (uint32_t)st->h)) {
434 }
435 const uint32_t stride = (uint32_t)st->w * (uint32_t)st->bpp;
436 const uint8_t* src = px;
437 uint32_t left = nrows;
438 while (left > 0U) {
439 const uint32_t room = (uint32_t)st->cfg->tile_h - st->band_fill;
440 const uint32_t take = (left < room) ? left : room;
441 (void)memcpy(&st->band[(size_t)st->band_fill * (size_t)stride],
442 src,
443 (size_t)take * (size_t)stride);
444 st->band_fill += take;
445 st->rows_seen += take;
446 src = &src[(size_t)take * (size_t)stride];
447 left -= take;
448 if (st->band_fill == (uint32_t)st->cfg->tile_h) {
449 const ra8_err_t err = internal_flush_band(st, st->band_fill);
450 if (err != k_ra8_ok) {
451 return err;
452 }
453 st->band_fill = 0U;
454 }
455 }
456 return k_ra8_ok;
457}
458
484 uint16_t width,
485 uint16_t height,
486 uint8_t channels,
487 uint16_t stripe_rows,
488 uint8_t** out_stripe,
489 uint32_t* out_stripe_cap)
490{
492 const ra8_err_t err = priv_jof_on_geom(ctx, width, height, channels);
493 if (err != k_ra8_ok) {
494 return err;
495 }
496 const uint32_t cap = (uint32_t)width * (uint32_t)stripe_rows * (uint32_t)channels;
497 uint8_t* buf = priv_jof_bump_take(st->bump, (size_t)cap);
498 if (buf == nullptr) {
500 }
501 *out_stripe = buf;
502 *out_stripe_cap = cap;
503 return k_ra8_ok;
504}
505
506/* ---------------------------------------------------------------------------
507 * Trailer emission + entry point.
508 * ---------------------------------------------------------------------------
509 */
510
529{
530 if (st->tiles_done != st->tile_count) {
532 }
533 const uint32_t index_off = st->written;
534 ra8_err_t err = internal_sink(st, st->idx, (size_t)st->tile_count * (size_t)k_jof_index_entry);
535 if (err != k_ra8_ok) {
536 return err;
537 }
538 uint8_t ftr[k_jof_footer_bytes] = {};
539 internal_wr_u32(&ftr[k_jof_ftr_index_off], index_off);
542 ftr[k_jof_ftr_magic] = 'J';
543 ftr[k_jof_ftr_magic + 1U] = 'O';
544 ftr[k_jof_ftr_magic + 2U] = 'F';
545 ftr[k_jof_ftr_magic + 3U] = 'E';
546 err = internal_sink(st, ftr, sizeof(ftr));
547 if (err != k_ra8_ok) {
548 return err;
549 }
550 out_info->width = st->w;
551 out_info->height = st->h;
552 out_info->tile_w = st->cfg->tile_w;
553 out_info->tile_h = st->cfg->tile_h;
554 out_info->tile_cols = st->tile_cols;
555 out_info->tile_rows = st->tile_rows;
556 out_info->bpp = st->bpp;
557 out_info->codec = st->cfg->codec;
558 out_info->tile_count = st->tile_count;
559 out_info->index_off = index_off;
560 out_info->total_size = st->written;
561 return k_ra8_ok;
562}
563
580{
581 if ((cfg->tile_w == 0U) || (cfg->tile_h == 0U)) {
583 }
584 if (cfg->codec > (uint8_t)k_jof_codec_deflate) {
586 }
587 return k_ra8_ok;
588}
589
590uint32_t jof_work_bytes(uint16_t max_width, uint16_t max_height, uint16_t tile_w, uint16_t tile_h)
591{
592 if ((max_width == 0U) || ((uint32_t)max_width > (uint32_t)k_jof_max_dim) || (max_height == 0U) ||
593 ((uint32_t)max_height > (uint32_t)k_jof_max_dim)) {
594 return 0U;
595 }
596 if ((tile_w == 0U) || (tile_h == 0U)) {
597 return 0U;
598 }
599 const uint64_t cols = ((uint64_t)max_width + tile_w - 1U) / tile_w;
600 const uint64_t rows = ((uint64_t)max_height + tile_h - 1U) / tile_h;
601 if ((cols * rows) > (uint64_t)k_jof_max_tiles) {
602 return 0U;
603 }
604 const uint64_t bpp = (uint64_t)k_jof_bpp_max;
605 const uint64_t jpeg_set =
607 ((uint64_t)max_width * (uint64_t)k_ra8_jpeg_sw_stream_mcu_rows_max * 3U);
608 const uint64_t png_set = (uint64_t)sizeof(tinfl_decompressor) + (uint64_t)k_jof_png_ring +
609 (uint64_t)k_jof_png_inbuf + (3U * ((uint64_t)max_width * bpp)) + 2U;
610 const uint64_t dec_set = (jpeg_set > png_set) ? jpeg_set : png_set;
611 const uint64_t band = (uint64_t)max_width * (uint64_t)tile_h * bpp;
612 const uint64_t tw_eff =
613 ((uint64_t)tile_w < (uint64_t)max_width) ? (uint64_t)tile_w : (uint64_t)max_width;
614 const uint64_t th_eff =
615 ((uint64_t)tile_h < (uint64_t)max_height) ? (uint64_t)tile_h : (uint64_t)max_height;
616 const uint64_t stage = tw_eff * th_eff * bpp;
617 const uint64_t cmp = (uint64_t)jof_stored_bound((uint32_t)stage);
618 const uint64_t index_bytes = cols * rows * (uint64_t)k_jof_index_entry;
619 const uint64_t dfl = (uint64_t)k_ra8_compress_scratch_bytes;
620 const uint64_t total =
621 dec_set + band + stage + cmp + index_bytes + dfl + (uint64_t)k_jof_carve_slack;
622 if ((stage > (uint64_t)UINT32_MAX) || (total > (uint64_t)UINT32_MAX)) {
623 return 0U;
624 }
625 return (uint32_t)total;
626}
627
647 const jof_produce_cfg_t* cfg)
648{
649 (void)memset(st, 0, sizeof(*st));
650 st->cfg = cfg;
651 st->bump_store = (jof_bump_t){.base = cfg->work, .cap = cfg->work_cap, .off = 0U};
652 st->bump = &st->bump_store;
653 st->cap_w = ((cfg->max_width != 0U) && ((uint32_t)cfg->max_width < (uint32_t)k_jof_max_dim))
654 ? cfg->max_width
655 : (uint16_t)k_jof_max_dim;
656 st->cap_h = ((cfg->max_height != 0U) && ((uint32_t)cfg->max_height < (uint32_t)k_jof_max_dim))
657 ? cfg->max_height
658 : (uint16_t)k_jof_max_dim;
659 if (cfg->codec == (uint8_t)k_jof_codec_deflate) {
661 st->dfl = priv_jof_bump_take(st->bump, (size_t)st->dfl_len);
662 if (st->dfl == nullptr) {
664 }
665 }
666 return k_ra8_ok;
667}
668
687{
688 size_t head_len = 0U;
689 while (head_len < (size_t)k_jof_sniff_bytes) {
690 size_t got = 0U;
691 const ra8_err_t err =
692 cfg->pull(cfg->pull_ctx, &head[head_len], (size_t)k_jof_sniff_bytes - head_len, &got);
693 if (err != k_ra8_ok) {
694 return err;
695 }
696 if (got == 0U) {
697 return k_ra8_err_protocol_error; /* too short to be a JPEG/PNG */
698 }
699 head_len += got;
700 }
701 return k_ra8_ok;
702}
703
728{
729 if ((head[0] == (uint8_t)k_jof_jpeg_soi_first) && (head[1] == (uint8_t)k_jof_jpeg_soi_second)) {
730 uint8_t* window = priv_jof_bump_take(st->bump, (size_t)k_ra8_jpeg_sw_stream_min_window);
731 if (window == nullptr) {
733 }
735 pfx,
736 window,
740 st);
741 }
742 if (memcmp(head, s_prod_png_sig, sizeof(s_prod_png_sig)) == 0) {
744 pfx,
745 st->bump,
746 st->cap_w,
747 st->cap_h,
750 st);
751 }
752 if ((memcmp(head, s_prod_webp_riff, sizeof(s_prod_webp_riff)) == 0) &&
754 return priv_jof_webp_transcode(st, pfx);
755 }
756 return k_ra8_err_not_supported; /* not a JPEG/PNG/WebP source */
757}
758
774RA8_INTERNAL static uint32_t internal_rd_be32(const uint8_t* buf)
775{
776 return ((uint32_t)buf[0] << k_jof_le_sh24) | ((uint32_t)buf[1] << k_jof_le_sh16) |
777 ((uint32_t)buf[2] << k_jof_le_sh8) | (uint32_t)buf[3];
778}
779
796RA8_INTERNAL static bool internal_is_webp(const uint8_t* data)
797{
798 return (memcmp(data, s_prod_webp_riff, sizeof(s_prod_webp_riff)) == 0) &&
800}
801
823internal_png_dims(const uint8_t* data, size_t len, uint32_t* out_w, uint32_t* out_h)
824{
825 if (len < (size_t)k_jof_png_ihdr_end) {
826 return k_ra8_err_not_supported; /* IHDR truncated */
827 }
828 *out_w = internal_rd_be32(&data[k_jof_png_ihdr_w]);
829 *out_h = internal_rd_be32(&data[k_jof_png_ihdr_h]);
830 return k_ra8_ok;
831}
832
864internal_probe_sniff(const uint8_t* data, size_t len, uint16_t* out_w, uint16_t* out_h)
865{
866 if (len < (size_t)k_jof_sniff_bytes) {
867 return k_ra8_err_not_supported; /* too short to carry any accepted magic */
868 }
869 uint32_t w = 0U;
870 uint32_t h = 0U;
871 if ((data[0] == (uint8_t)k_jof_jpeg_soi_first) && (data[1] == (uint8_t)k_jof_jpeg_soi_second)) {
872 return ra8_jpeg_sw_get_dimensions(data, (uint32_t)len, out_w, out_h);
873 }
874 if (memcmp(data, s_prod_png_sig, sizeof(s_prod_png_sig)) == 0) {
875 const ra8_err_t rc = internal_png_dims(data, len, &w, &h);
876 if (rc != k_ra8_ok) {
877 return rc;
878 }
879 } else if (internal_is_webp(data)) {
880 const ra8_err_t rc = ra8_webp_get_info(data, len, &w, &h);
881 if (rc != k_ra8_ok) {
882 return rc;
883 }
884 } else {
885 return k_ra8_err_not_supported; /* not a JPEG/PNG/WebP source */
886 }
887 if ((w == 0U) || (h == 0U) || (w > (uint32_t)k_jof_max_dim) || (h > (uint32_t)k_jof_max_dim)) {
889 }
890 *out_w = (uint16_t)w;
891 *out_h = (uint16_t)h;
892 return k_ra8_ok;
893}
894
895ra8_err_t jof_probe_dims(const uint8_t* data, size_t len, uint16_t* out_w, uint16_t* out_h)
896{
897 RA8_CHECK_NULL_PTR(data, s_tag, "data must not be nullptr");
898 RA8_CHECK_NULL_PTR(out_w, s_tag, "out_w must not be nullptr");
899 RA8_CHECK_NULL_PTR(out_h, s_tag, "out_h must not be nullptr");
900 return internal_probe_sniff(data, len, out_w, out_h);
901}
902
922{
923 // mcdc-deactivated: post-decode contract guard; both in-tree decoders return success only after the geometry hook fired and every declared row was delivered (short/hostile streams abort inside the decoder), so neither condition can be flipped through the public producer entry.
924 if ((st->geom_done == 0U) || (st->rows_seen != (uint32_t)st->h)) {
925 return k_ra8_err_validation_failed; /* decoder under-delivered */
926 }
927 if (st->band_fill > 0U) {
928 const ra8_err_t err = internal_flush_band(st, st->band_fill);
929 if (err != k_ra8_ok) {
930 return err;
931 }
932 st->band_fill = 0U;
933 }
934 return internal_finish(st, out_info);
935}
936
954 const jof_info_t* out_info)
955{
956 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg must not be nullptr");
957 RA8_CHECK_NULL_PTR(out_info, s_tag, "out_info must not be nullptr");
958 RA8_CHECK_NULL_PTR(cfg->pull, s_tag, "cfg->pull must not be nullptr");
959 RA8_CHECK_NULL_PTR(cfg->sink, s_tag, "cfg->sink must not be nullptr");
960 RA8_CHECK_NULL_PTR(cfg->work, s_tag, "cfg->work must not be nullptr");
961 return k_ra8_ok;
962}
963
965{
966 static jof_prod_state_t s_prod;
967 ra8_err_t err = internal_produce_args_ok(cfg, out_info);
968 if (err != k_ra8_ok) {
969 return err;
970 }
971 err = internal_check_cfg(cfg);
972 if (err != k_ra8_ok) {
973 return err;
974 }
975 jof_prod_state_t* st = &s_prod;
976 err = internal_init_state(st, cfg);
977 if (err != k_ra8_ok) {
978 return err;
979 }
980 uint8_t head[k_jof_sniff_bytes] = {};
981 err = internal_sniff_head(cfg, head);
982 if (err != k_ra8_ok) {
983 return err;
984 }
985 jof_prefix_pull_t pfx = {
986 .head = head,
987 .head_len = sizeof(head),
988 .pos = 0U,
989 .inner = cfg->pull,
990 .inner_ctx = cfg->pull_ctx,
991 };
992 err = internal_dispatch(st, head, &pfx);
993 if (err != k_ra8_ok) {
994 return err;
995 }
996 return internal_epilogue(st, out_info);
997}
@ k_jof_le_sh16
16-bit shift.
Definition jof.c:43
@ k_jof_le_sh24
24-bit shift.
Definition jof.c:44
@ k_jof_le_sh8
8-bit shift.
Definition jof.c:42
JOF band-tile atlas: the display-native normalized image format (#231, shared with the longstrip scro...
@ k_jof_ofs_tile_count
Header: u32 tile count.
Definition jof.h:155
@ k_jof_index_entry
Bytes per tile-index entry.
Definition jof.h:145
@ k_jof_magic_len
Magic string length (both ends).
Definition jof.h:146
@ k_jof_footer_bytes
Footer length.
Definition jof.h:144
@ k_jof_ftr_total_size
Footer: u32 total atlas size.
Definition jof.h:159
@ k_jof_hdr_bytes
Header length.
Definition jof.h:143
@ k_jof_ftr_magic
Footer: magic "JOFE".
Definition jof.h:160
@ k_jof_ftr_index_off
Footer: u32 index offset.
Definition jof.h:157
@ k_jof_ofs_tile_h
Header: u16 tile height.
Definition jof.h:151
@ k_jof_ofs_codec
Header: u8 tile codec.
Definition jof.h:153
@ k_jof_idx_ofs_length
Index entry: u32 tile length.
Definition jof.h:162
@ k_jof_ofs_height
Header: u16 image height.
Definition jof.h:149
@ k_jof_ofs_tile_w
Header: u16 tile width.
Definition jof.h:150
@ k_jof_ofs_width
Header: u16 image width.
Definition jof.h:148
@ k_jof_ftr_tile_count
Footer: u32 tile count.
Definition jof.h:158
@ k_jof_ofs_bpp
Header: u8 bytes per pixel.
Definition jof.h:152
@ k_jof_idx_ofs_offset
Index entry: u32 tile offset.
Definition jof.h:161
@ k_jof_bpp_max
Max bytes per pixel.
Definition jof.h:178
@ k_jof_max_dim
Max image width/height, pixels.
Definition jof.h:176
@ k_jof_max_tiles
Max tiles per atlas.
Definition jof.h:177
@ k_jof_codec_deflate
Tile stream is one raw-DEFLATE run.
Definition jof.h:192
uint32_t jof_stored_bound(uint32_t raw_bytes)
Worst-case stored-tile byte bound for scratch/cell sizing.
Definition jof.c:439
Module-private seams shared by the producer translation units.
ra8_err_t priv_jof_on_geom(void *ctx, uint16_t width, uint16_t height, uint8_t channels)
Bind the source geometry: validate caps, carve buffers, emit header.
@ k_jof_bump_align
Every carve is 8-byte aligned.
@ k_jof_carve_slack
Alignment slack folded into every arena sizing.
ra8_err_t priv_jof_on_rows(void *ctx, const uint8_t *px, uint16_t width, uint16_t y0, uint16_t nrows, uint8_t channels)
Row sink shared by every decoder arm: accumulate, flush full bands.
ra8_err_t priv_jof_png_rows(jof_pull_fn pull, void *pull_ctx, jof_bump_t *bump, uint16_t max_w, uint16_t max_h, jof_geom_fn on_geom, jof_rows_fn on_rows, void *cb_ctx)
Streaming PNG scanline decode: pull bytes in, emit rows in order.
Definition jof_png.c:579
ra8_err_t priv_jof_webp_transcode(jof_prod_state_t *st, jof_prefix_pull_t *pfx)
Transcode a WebP source into the JOF tile path (whole-frame, #290).
ra8_err_t priv_jof_prefix_pull(void *ctx, uint8_t *buf, size_t cap, size_t *got)
Pull adapter: replay the sniffed head, then delegate to the source.
static ra8_err_t internal_check_cfg(const jof_produce_cfg_t *cfg)
Validate the caller configuration's non-pointer invariants.
static ra8_err_t internal_sniff_head(const jof_produce_cfg_t *cfg, uint8_t *head)
Pull the sniff head (both formats need at least these bytes).
ra8_err_t priv_jof_on_geom(void *ctx, uint16_t width, uint16_t height, uint8_t channels)
Bind the source geometry: validate caps, carve buffers, emit header.
static ra8_err_t internal_finish(jof_prod_state_t *st, jof_info_t *out_info)
Emit the tile index and footer, then fill the caller's info.
jof_png_signature_t
Fixed non-ASCII bytes in the PNG signature.
Definition jof_produce.c:65
@ k_jof_png_sig_cr
Carriage return byte.
Definition jof_produce.c:67
@ k_jof_png_sig_sub
DOS EOF byte.
Definition jof_produce.c:69
@ k_jof_png_sig_lf
Line feed byte.
Definition jof_produce.c:68
@ k_jof_png_sig_high
High-bit signature byte.
Definition jof_produce.c:66
static ra8_err_t internal_carve_pixel_path(jof_prod_state_t *st)
Carve the band, stage, index and compressed-tile buffers.
static ra8_err_t internal_produce_args_ok(const jof_produce_cfg_t *cfg, const jof_info_t *out_info)
Reject any NULL jof_produce argument or seam.
void * priv_jof_bump_take(jof_bump_t *bump, size_t len)
Implementation of priv_jof_bump_take() – aligned linear carve.
Definition jof_produce.c:89
static ra8_err_t internal_emit_header(jof_prod_state_t *st)
Serialize + sink the 32-byte JOF header from the bound geometry.
static const uint8_t s_prod_webp_riff[k_jof_magic_len]
WebP RIFF container tag (source head bytes 0..3).
Definition jof_produce.c:83
ra8_err_t priv_jof_on_rows(void *ctx, const uint8_t *px, uint16_t width, uint16_t y0, uint16_t nrows, uint8_t channels)
Row sink shared by every decoder arm: accumulate, flush full bands.
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.
static ra8_err_t internal_probe_sniff(const uint8_t *data, size_t len, uint16_t *out_w, uint16_t *out_h)
Sniff the container, read its declared geometry and range-check it.
static ra8_err_t internal_epilogue(jof_prod_state_t *st, jof_info_t *out_info)
Post-decode checks, final band flush and trailer emission.
static ra8_err_t internal_png_dims(const uint8_t *data, size_t len, uint32_t *out_w, uint32_t *out_h)
Read the pixel geometry out of a PNG IHDR chunk.
jof_prod_const_t
Producer sizing and sniffing constants.
Definition jof_produce.c:47
@ k_jof_byte_mask
Low-byte mask.
Definition jof_produce.c:55
@ k_jof_png_ihdr_h
PNG IHDR height field offset (big-endian).
Definition jof_produce.c:60
@ k_jof_jpeg_soi_second
JPEG SOI second byte.
Definition jof_produce.c:51
@ k_jof_png_ring
PNG inflate ring carve (bytes).
Definition jof_produce.c:53
@ k_jof_png_inbuf
PNG input-buffer carve (bytes).
Definition jof_produce.c:54
@ k_jof_png_ihdr_w
PNG IHDR width field offset (big-endian).
Definition jof_produce.c:59
@ k_jof_webp_fourcc_ofs
Offset of the "WEBP" fourCC.
Definition jof_produce.c:52
@ k_jof_png_sig_len
PNG signature length.
Definition jof_produce.c:49
@ k_jof_png_ihdr_end
Bytes needed to read both IHDR fields.
Definition jof_produce.c:61
@ k_jof_jpeg_soi_first
JPEG SOI first byte.
Definition jof_produce.c:50
@ k_jof_sniff_bytes
Magic bytes pulled up front (WebP needs 12).
Definition jof_produce.c:48
static ra8_err_t internal_jpeg_geom(void *ctx, uint16_t width, uint16_t height, uint8_t channels, uint16_t stripe_rows, uint8_t **out_stripe, uint32_t *out_stripe_cap)
JPEG geometry adapter: bind geometry, then carve the MCU stripe.
static ra8_err_t internal_encode_tile(jof_prod_state_t *st, uint32_t payload)
Encode one packed tile payload and append it to the atlas.
static ra8_err_t internal_flush_band(jof_prod_state_t *st, uint32_t th)
Cut the accumulated band into tiles and append each to the atlas.
static void internal_wr_u16(uint8_t *buf, uint16_t v)
Store a uint16 little-endian at buf.
static const uint8_t s_prod_png_sig[k_jof_png_sig_len]
PNG signature for source sniffing (mirrors the PNG decoder unit).
Definition jof_produce.c:73
static void internal_wr_u32(uint8_t *buf, uint32_t v)
Store a uint32 little-endian at buf.
static ra8_err_t internal_sink(jof_prod_state_t *st, const uint8_t *buf, size_t len)
Append bytes to the caller sink, tracking the atlas offset.
static ra8_err_t internal_dispatch(jof_prod_state_t *st, const uint8_t *head, jof_prefix_pull_t *pfx)
Dispatch the sniffed source to the matching decoder.
static const uint8_t s_prod_webp_webp[k_jof_magic_len]
WebP form-type fourCC (source head bytes 8..11).
Definition jof_produce.c:86
static bool internal_is_webp(const uint8_t *data)
True if the sniff window carries the WebP RIFF container magic.
static ra8_err_t internal_init_state(jof_prod_state_t *st, const jof_produce_cfg_t *cfg)
Reset the transcode state and carve the deflate scratch.
static uint32_t internal_rd_be32(const uint8_t *buf)
Read a big-endian uint32 (PNG stores its IHDR fields big-endian).
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).
ra8_err_t priv_jof_prefix_pull(void *ctx, uint8_t *buf, size_t cap, size_t *got)
Pull adapter: replay the sniffed head, then delegate to the source.
Import-time transcode producer: JPEG/PNG/WebP -> JOF band-tile atlas in bounded RAM (#231,...
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
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).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
App-domain DEFLATE compress / decompress (zero-heap, firmware-safe).
@ k_ra8_compress_scratch_bytes
Minimum compress scratch size (one miniz tdefl_compressor).
ra8_err_t ra8_compress(const uint8_t *src, uint32_t src_len, uint8_t *out, uint32_t out_cap, void *scratch, uint32_t scratch_len, uint32_t *out_len)
Raw-DEFLATE compress src into out.
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_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_err_validation_failed
Validation rule failed (caller-supplied invariant not satisfied).
Definition ra8_err.h:459
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_protocol_error
Protocol-level error (e.g.
Definition ra8_err.h:429
@ 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
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
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.
Pure-software baseline JPEG (ISO/IEC 10918-1 / ITU-T T.81) codec.
@ k_ra8_jpeg_sw_stream_mcu_rows_max
Max rows per stripe (4:2:0).
@ k_ra8_jpeg_sw_stream_min_window
Minimum window bytes.
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.
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...
Lightweight Logging Interface for ra8-firmware.
Zero-heap WebP (VP8 / VP8L) decode facade over the vendored libwebp.
ra8_err_t ra8_webp_get_info(const uint8_t *data, size_t size, uint32_t *out_w, uint32_t *out_h)
Read a WebP header's pixel dimensions without decoding the body.
Definition ra8_webp.c:33
Linear (bump) allocator over the caller's work arena.
size_t off
First free byte.
uint8_t * base
Arena base (caller's work buffer).
size_t cap
Arena capacity, bytes.
Parsed + validated geometry of one JOF atlas.
Definition jof.h:208
uint8_t bpp
Bytes per pixel (1, 3 or 4).
Definition jof.h:215
uint8_t codec
jof_codec_t member.
Definition jof.h:216
uint16_t tile_w
Tile width, pixels.
Definition jof.h:211
uint16_t width
Image width, pixels.
Definition jof.h:209
uint32_t index_off
Absolute byte offset of the tile index.
Definition jof.h:218
uint16_t tile_rows
Ceil(height / tile_h) tile rows.
Definition jof.h:214
uint16_t tile_h
Tile height, pixels.
Definition jof.h:212
uint32_t tile_count
Total tiles (== cols * rows).
Definition jof.h:217
uint16_t height
Image height, pixels.
Definition jof.h:210
uint32_t total_size
Whole atlas byte length (footer included).
Definition jof.h:219
uint16_t tile_cols
Ceil(width / tile_w) tile columns.
Definition jof.h:213
Pull adapter that replays the sniffed head bytes, then delegates.
size_t head_len
Sniffed byte count.
const uint8_t * head
Sniffed bytes to replay.
size_t pos
Replay cursor.
void * inner_ctx
Context for the source.
jof_pull_fn inner
Real source.
Whole transcode state (module-static instance in the producer TU).
uint32_t tiles_done
Tiles encoded + recorded so far.
uint32_t cmp_cap
Capacity of cmp.
uint32_t written
Atlas bytes sunk so far.
uint8_t * cmp
One encoded tile (deflate codec).
uint8_t geom_done
1 once geometry was bound.
uint32_t band_fill
Rows currently in the band.
jof_bump_t bump_store
Arena allocator state.
const jof_produce_cfg_t * cfg
Caller configuration.
uint8_t * idx
Tile index bytes (8 per tile).
uint8_t * stage
One packed tile payload.
uint8_t bpp
Output bytes per pixel.
uint16_t w
Source width, pixels.
uint16_t cap_h
Effective height cap.
uint16_t tile_cols
Tile grid columns.
uint32_t rows_seen
Decoded rows accumulated so far.
uint32_t dfl_len
Scratch length (0 for raw codec).
uint16_t tile_rows
Tile grid rows.
uint32_t tile_count
Total tiles (cols * rows).
jof_bump_t * bump
Arena allocator (owned).
uint8_t * dfl
Deflate compressor scratch.
uint8_t * band
One tile row of decoded pixels.
uint16_t h
Source height, pixels.
uint16_t cap_w
Effective width cap.
Producer configuration: source, sink, tile geometry and work arena.
uint16_t max_width
Width budget cap (0 = format cap).
void * pull_ctx
Context for pull.
uint8_t codec
jof_codec_t member.
uint16_t max_height
Height budget cap (0 = format cap).
jof_sink_fn sink
Atlas byte sink (append-only).
jof_pull_fn pull
Encoded-source byte stream.
void * sink_ctx
Context for sink.
uint16_t tile_h
Tile height, pixels (>= 1).
size_t work_cap
Arena size; see jof_work_bytes().
uint16_t tile_w
Tile width, pixels (>= 1).