ipro7_jpeg_decode¶
以軟體(TJpgDec)把 JPEG 解碼成 RGB565/RGB888,附格式探測、內建測試圖與主機端工具;IPRO7 的 MJPEG 硬體只能編碼
| 項目 | 內容 |
|---|---|
| 原始碼 | apps/multimedia/ipro7_jpeg_decode |
| 板卡與設定 | Reef(defconfig_reef);.config 為 IPRO7AI EVK |
| 主控台 | UART 921600 |
| 建置 | Reef:make -C apps/multimedia/ipro7_jpeg_decode DEFCONFIG=defconfig_reef |
在 Reef 上執行¶
這是 Reef 設定中唯一主控台為 921600 baud 的應用。
-
建置
映像在
apps/multimedia/ipro7_jpeg_decode/build_reef/build_out/ipro7_jpeg_decode_IPRO7.bin,測試圖已連結在內。 -
燒錄:進入下載模式,在 IntelProCube 目錄執行
./ipro_iot_tool_macos --chipname ipro7 --chip-variant IPRO7AI \ --port /dev/cu.usbserial-XXXX --baudrate 921600 \ --firmware <SDK>/apps/multimedia/ipro7_jpeg_decode/build_reef/build_out/ipro7_jpeg_decode_IPRO7.bin確認
[All Success]後按一下 SW2。 -
執行:以 921600 baud 開啟主控台。開機印出
ipro7_jpeg_decode: JPEG -> RGB565 / RGB888, ...;輸入jdec run all,最後一行為... failed -> ALL PASS。jdec list列出測試圖與預期結果。
README¶
README 原文
以下是應用隨附的 README(SDK V2.2.1),保留原文、未翻譯;只替換了不適合公開的內容。
Decode a JPEG picture into RGB565 or RGB888 pixels on IPRO7 with a software decoder, and check the result.
IPRO7's MJPEG hardware block is supported for encoding only. hal_mjdec.h exists in
the SDK, but on IPRO7 the decoder never completes a frame (no frame-done interrupt, no
output), so JPEG pictures are decoded on the CPU, by TJpgDec R0.03 (BSD-style licence, see
the header of tjpgd/tjpgd.c). The decoder sources are in tjpgd/ because the SDK
release packages do not carry components/3rdparty/tjpgdec; tjpgd.c / tjpgd.h are that
component's files unchanged, tjpgdcnf.h selects 24-bit output. To use it in your own
project copy jdec_rgb.c, jdec_rgb.h and tjpgd/.
What the wrapper adds to TJpgDec¶
| Topic | TJpgDec on its own | jdec_rgb |
|---|---|---|
| Unsupported file | JDR_FMT1 / JDR_FMT3 after the decoder has started |
jdec_probe() names the reason first (progressive, CMYK, 4:1:1, truncated, ...) |
| Colour order | writes B, G, R; with JD_FORMAT 1 its "RGB565" is really BGR565 |
true RGB565 (LE or BE) or RGB888, whatever JD_FORMAT is |
| Camera MJPEG frame without DHT | fails (JDR_FMT1) |
standard Huffman tables inserted |
| Output | callback per MCU block | whole picture into a buffer (jdec_decode) or per block (jdec_decode_blocks) |
| Output size with scaling | to be worked out | jdec_out_dims() / jdec_out_size() |
API¶
#include "jdec_rgb.h"
jdec_info_t info;
int err = jdec_probe(jpg, len, &info); /* can it be decoded, how big is it? */
if (err != JDEC_OK) {
printf("%s\r\n", jdec_strerror(err));
return;
}
uint32_t size = jdec_out_size(&info, JDEC_RGB565, 0); /* scale 0..3 = 1/1, 1/2, 1/4, 1/8 */
uint8_t *rgb = pvPortMalloc(size); /* PSRAM when CONFIG_USE_PSRAM=y */
err = jdec_decode(jpg, len, JDEC_RGB565, 0, rgb, size, &info);
Formats: JDEC_RGB565 (uint16_t, R in bits 15..11, little-endian), JDEC_RGB565_BE
(same value, high byte first, as SPI LCD controllers expect), JDEC_RGB888 (R, G, B bytes).
For an LCD, jdec_decode_blocks() passes each decoded block (at most 16 x 16 pixels) to a
callback, so no frame buffer is needed; a callback writing into its own buffer must keep
x + w and y + h within jdec_out_dims(). The decoder allocates an 8 KB work area per
call (16 KB with JD_FASTDECODE 2; typically 3.5 KB / 9.7 KB is used, 5.4 KB for a valid file
at the format limits); the input JPEG can be anywhere the CPU can read, flash included.
jdec_out_size() returns 0 when the picture cannot be decoded or needs 4 GB or more.
Accepted: baseline (SOF0) Huffman JPEG, grey or YCbCr 4:4:4 / 4:2:2 / 4:2:0, 8-bit tables,
any size, EXIF / ICC / other APPn segments, restart markers, missing DHT.
Rejected: progressive, other SOF types (extended, lossless, arithmetic), 12-bit, 4:1:1 / 4:4:0,
CMYK / RGB-coded, 16-bit quantisation tables, files without EOI.
host/jpeg_check.py photo.jpg [--fix out.jpg] checks a file on the PC and converts it if needed.
Build and flash¶
make -C apps/multimedia/ipro7_jpeg_decode # IPRO7AI EVK, console 921600
make -C apps/multimedia/ipro7_jpeg_decode DEFCONFIG=defconfig_reef # IPRO7AI Reef (build_reef/)
Needs PSRAM (CONFIG_USE_PSRAM=y) for the output buffers. Image: 482 KB flash (360 KB of
it test JPEGs), 41 KB OCRAM. With CMake 3.18 or later jdec_rgb.c and tjpgd/tjpgd.c are
compiled at -O2 (about 1.9x faster than the SDK's -Os, same output); older CMake keeps -Os.
Shell¶
| Command | |
|---|---|
jdec list |
built-in test images and what is expected of each |
jdec info <n\|rx> |
what jdec_probe() reports |
jdec mem |
stack and heap used around a few decodes |
jdec run <n\|all> [565\|565be\|888] [scale] [blocks] |
decode, check, time |
jdec dump <n\|rx> [565\|888] [scale] |
print the pixels as base64 |
jdec rx <bytes>, jdec put <base64>, jdec go [fmt] [scale] |
receive a JPEG over the console and decode it |
Checks on the built-in images: the output hash must equal that of the same decoder built on
the PC (=host, bit-exact), and the RGB mean of every 16 x 16 block (64 x 64 above 640
pixels wide) must be within 10 of libjpeg.
Host tools (Python 3, pyserial, Pillow, numpy):
python3 host/jdec_host.py -p /dev/cu.usbmodemXXXX02 upload photo.jpg --go 565
python3 host/jdec_host.py -p /dev/cu.usbmodemXXXX02 dump rx --fmt 888 -o board.png --ref photo.jpg
python3 host/run_host_tests.py # decoder + wrapper on the PC against libjpeg (needs cc, djpeg)
python3 host/make_test_jpegs.py # regenerate test_images.c (needs cc, djpeg, jpegtran)
Results (IPRO7AI Reef, CPU 192 MHz, 2026-10-30)¶
jdec run all with 565, 888, 565be, and 565 / 888 in block mode: 14 / 14 PASS each; all 11
decodable images bit-exact with the PC build; 3 rejected with the expected reason
(progressive, CMYK, truncated). Against libjpeg (RGB888, PC build): PSNR 44.7-45.3 dB on the
test images (grey 49.6 dB); a 640 x 480 photo-like JPEG with EXIF + ICC sent over the console:
46.2 dB. With JD_FORMAT 1 (16-bit, as components/3rdparty/tjpgdec) RGB888 is expanded
from 16 bits: 38.3-39.1 dB. host/run_host_tests.py runs on an AddressSanitizer +
UndefinedBehaviorSanitizer build and decodes damaged copies of the test images; 1500 of them
(3000 decodes) gave no memory error, and host/jpeg_check.py agreed with jdec_probe() on all.
Stack: about 1 KB at peak (decode plus printf); heap back to the same value after each decode.
Decode time, output to PSRAM, code in flash:
| Picture | RGB565 -O2 |
RGB888 -O2 |
RGB565 -Os |
RGB888 -Os |
|---|---|---|---|---|
| 320 x 240 4:2:0 | 53 ms | 53 ms | 95 ms | 91 ms |
| 320 x 240 4:2:2 / 4:4:4 / grey | 58 / 67 / 50 ms | 57 / 66 / 48 ms | 110 ms (4:4:4) | |
| 640 x 480 4:2:0 | 204 ms | |||
| 1280 x 720 4:2:0 | 571 ms | 564 ms | ||
| 1920 x 1080 4:2:0 | 1.27 s | 1.25 s | 2.41 s | 2.31 s |
| 1920 x 1080 at 1/2, 1/4, 1/8 | 1.08 s, 1.03 s, 0.45 s |
-O2 applies with CMake 3.18 or later (see CMakeLists.txt). Block mode adds 3-4 %.
JD_FASTDECODE 2 (16 KB work area) saved a further 5 % in a test with the 16-bit build; it is
left at 1. -fwrapv keeps corrupt data from causing undefined behaviour in the decoder's
integer IDCT (it costs 3-5 % on RGB888).