Repository navigation
jpegio encodes, and decodes on the P4's JPEG engine (media Phase 2) - #41
Merged
Merged
Conversation
…ere), hardware decode on the P4, and a C API for cameraif JpegEncoder(quality, subsampling, *, hardware, exact).encode(buffer, w, h, *, format=RGB565|GRAY, stride, swap) -> bytes. Software is stb_image_write's JPEG writer generated into src/jpegenc/ by tools/make_jpegenc.py, reading pixels through a fetch callback. On the ESP32-P4 the JPEG engine encodes: by default from RGB888 widened as a display widens (the engine zero-fills RGB565, which caps a round trip near 33 dB), or with exact=False straight from the buffer (8-10 ms for 720x720). JpegDecoder(hardware=True) decodes on the engine where it can (whole image, buffer, scale 0) and falls back to TJpgDec otherwise; .hardware says which ran. The engine is asked for YUV 4:4:4 and converted with JFIF's full-range matrix here, because the driver's RGB path uses studio-range BT.601. jpegio_encode() in src/jpegio.h is the C API cameraif's capture_jpeg() calls. tests/test_jpegio_encode.py is the Phase 2 gate (thresholds fixed first); tests/check_encode_pil.py has Pillow read every encoded file back.
… as the corpus test does On the S3 the first gc.mem_free() after a collect wobbles by 1.4-3 KB (stale stack words pin blocks); 100 and 300 encodes land on the same collected number, so the check now looks for a trend, not before-vs-after.
bdbarnett
added a commit
that referenced
this pull request
Oct 19, 2026
…sing a fifth of itself (usbif#37) (#41) At high speed the audio data endpoint asked for a packet every 125 us. TinyUSB re-arms that endpoint from the MicroPython task, and whenever the interpreter took longer than a microframe the next packet was lost: 20 % for long stretches, a third under load. The pump played what arrived back to back, so music came out a major third or more sharp and rough at the splices. bInterval 4 at high speed gives one 196-byte packet per millisecond, the full-speed cadence, and eight times the room. Adds uac_pump_clock() (USB packets, I2S DMA bytes consumed) and uac_pump_tap() (the samples handed to I2S) and a board/host checker in tests/hardware that measures delivery and pitch without ears.
bdbarnett
added a commit
that referenced
this pull request
Oct 19, 2026
…41) (#43) test_jpegio_lvgl.py now fails when `import jpegio` after lv.init() registers nothing on linux, darwin or win32, naming MICROPY_MODULE_BUILTIN_INIT. The windows half needs #18, which turns the hook on in the PyDevices windows variant; the README says so and tells other windows builds to call register_lvgl_decoder().
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Media modules roadmap, Phase 2.
jpegio.JpegEncoder(quality, subsampling, *, hardware, exact): RGB565 or GRAY buffers to baseline JPEG. Software everywhere (stb_image_write's writer, generated intosrc/jpegenc/), the ESP32-P4's JPEG engine there. The engine zero-fills RGB565 (a round trip caps near 33 dB), so by default jpegio widens to RGB888 first;exact=Falselets it read the buffer directly (8-10 ms for 720x720).JpegDecoder(hardware=True)decodes on the engine where it can and falls back to TJpgDec;.hardwaresays which ran. The driver's RGB output is studio-range BT.601 (crushed blacks, clipped whites), so jpegio asks for YUV and converts with JFIF's full-range matrix.jpegio_encode()insrc/jpegio.h, the C API cameraif'scapture_jpeg()now calls (capture_jpeg() encodes through jpegio cameraif#10, pinned here).Gate, all four items met on hardware: P4 and S3 encodes read back by Pillow as their source (30/36 dB thresholds fixed first, planted faults rejected); hardware decode 40-44 dB from TJpgDec with means within 0.11 of the corpus reference; two threads encoding at once give identical bytes; cameraif's snapshot and MJPEG examples run unchanged on the panel's camera at 35.7 fps capture. Details in the anchor's media-modules-roadmap.md.