<alp/jpeg.h> — JPEG Encoder
Portable JPEG encoding of planar YUV frames, hardware-accelerated where the silicon has an encoder and software everywhere else. New in v0.14.0.
:::note Encoder only
There is no decode path in this header. <alp/jpeg.h> encodes; it does not decode. If you need to decode, that is outside this surface today.
:::
Header
#include <alp/jpeg.h>
Quick example
alp_jpeg_t *enc = alp_jpeg_open(&(alp_jpeg_config_t){
.engine_id = 0u,
.max_width = 640u,
.max_height = 480u,
});
if (enc == NULL) {
printk("jpeg open failed: %d\n", alp_last_error());
return;
}
const alp_jpeg_encode_req_t req = {
.width = 64u,
.height = 64u,
.format = ALP_PIXFMT_NV12,
.subsample = ALP_JPEG_SUBSAMPLE_420,
.quality = 80u,
.y_plane = y_buf, /* NOT in TCM — see below */
.y_stride = 64u,
.u_plane = uv_buf,
.u_stride = 64u,
.v_plane = NULL,
.v_stride = 0u,
};
size_t out_len = 0u;
alp_status_t rc = alp_jpeg_encode(enc, &req, out_buf, sizeof(out_buf), &out_len);
alp_jpeg_close(enc);
:::warning The hardware backend DMAs from your planes — keep them out of TCM
The hardware-accelerated backend reads the caller's planes by DMA directly, so those buffers must live in globally-addressable RAM. A TCM buffer is not DMA-reachable and yields ALP_ERR_NOSUPPORT — the encode never starts. This is the single most likely first-run failure on E8.
:::
Types
alp_jpeg_subsample_t
| Value | Numeric |
|---|---|
ALP_JPEG_SUBSAMPLE_400 | 0 |
ALP_JPEG_SUBSAMPLE_420 | 1 |
ALP_JPEG_SUBSAMPLE_422 | 2 |
alp_jpeg_config_t
| Field | Type | Notes |
|---|---|---|
engine_id | uint32_t | Which encoder engine to open. |
max_width | uint16_t | Largest frame width this handle will be asked to encode. |
max_height | uint16_t | Largest frame height this handle will be asked to encode. |
alp_jpeg_encode_req_t
Fields in header order:
| Field | Notes |
|---|---|
width / height | Frame geometry for this encode. |
format | alp_pixfmt_t — the input pixel format. |
subsample | Chroma subsampling for the output JPEG. |
quality | Encoder quality setting. |
y_plane / y_stride | Luma plane and its row stride. |
u_plane / u_stride | U (or interleaved UV, for NV12) plane and its row stride. |
v_plane / v_stride | V plane and its row stride. |
alp_jpeg_caps_t
| Field | Type | Notes |
|---|---|---|
hw_accelerated | bool | true when a hardware encoder is behind the handle. |
mjpeg_supported | bool | |
max_width / max_height | Largest geometry the backend will encode. | |
subsample_mask | Bitmask of the supported alp_jpeg_subsample_t values. | |
pixfmt_mask | Bitmask of the supported alp_pixfmt_t inputs. |
Query it with alp_jpeg_capabilities(handle, &caps) — note this class returns an alp_status_t and fills a caller-provided struct, rather than returning a const alp_capabilities_t * like the bus classes do.
New pixel formats
Two values were appended to alp_pixfmt_t in <alp/peripheral.h> for this class:
| Value | Numeric |
|---|---|
ALP_PIXFMT_YUV420_PLANAR | 4 |
ALP_PIXFMT_NV12 | 5 |
Existing values are unchanged — this is an ABI-safe append, and ALP_PIXFMT_ARGB8888 remains 3.
Functions
| Call | Returns |
|---|---|
alp_jpeg_open(const alp_jpeg_config_t *cfg) | alp_jpeg_t *, or NULL — read alp_last_error(). |
alp_jpeg_encode(h, const alp_jpeg_encode_req_t *req, void *out_buf, size_t out_cap, size_t *out_len) | alp_status_t; on ALP_OK, *out_len is the encoded byte count written into out_buf. |
alp_jpeg_capabilities(const alp_jpeg_t *h, alp_jpeg_caps_t *out) | alp_status_t; fills *out. |
alp_jpeg_close(h) | void. |
Errors
alp_jpeg_open() returns NULL and sets alp_last_error() to one of:
| Code | Meaning |
|---|---|
ALP_ERR_INVAL | Bad config. |
ALP_ERR_NOMEM | Allocation failed. |
ALP_ERR_NOT_PRESENT_ON_THIS_SOC | No encoder engine on this silicon. |
ALP_ERR_NOT_IMPLEMENTED | The selected backend is the stub. |
alp_jpeg_encode() returns:
| Code | Meaning |
|---|---|
ALP_ERR_INVAL | Bad argument. |
ALP_ERR_NOSUPPORT | Unsupported pixel format or subsampling — or a buffer that is not DMA-reachable on the hardware backend (the TCM case above). |
ALP_ERR_NOMEM | out_cap too small for the encoded frame. |
ALP_ERR_IO | Hardware fault. |
ALP_ERR_NOT_IMPLEMENTED | No encode path in the selected backend. |
ALP_ERR_NOT_READY | Handle or engine not ready. |
Backends
| Backend | Applies to | Status |
|---|---|---|
alif_hantro (priority 100, silicon_ref="alif:ensemble:e8") | Alif Ensemble E8 Hantro VC9000E hardware encoder, driven through the Zephyr video driver class; NV12 input only; gated on CONFIG_ALP_SDK_JPEG_ALIF_HANTRO | Bench-verified on real E1M-AEN801 (Ensemble E8) silicon: JPEG_SWREG0 reads back JPEG_HW_ID 0x90001000, hardware version 0x00c0c200; alp_jpeg_encode() returned rc=0 out_len=935 for a 64×64 NV12 frame, round-tripped through libjpeg to a correct image. |
sw_baseline (priority 50, silicon_ref="*") | Portable TooJpeg baseline encoder, 4:2:0 and 4:0:0 only | Software fallback; wins on every non-E8 SoM. |
zephyr_stub (priority 0) | Safety net | Returns ALP_ERR_NOT_IMPLEMENTED. |
See the selection rules for how priority and silicon_ref pick a row.
Practical consequence: on E8 with the Hantro row compiled in you get hardware encoding of NV12; anywhere else — and on E8 without CONFIG_ALP_SDK_JPEG_ALIF_HANTRO — the TooJpeg baseline encoder runs, and ALP_JPEG_SUBSAMPLE_422 is not available there.
ABI status
[ABI-EXPERIMENTAL] — new in v0.14.0. Encoder-only, one hardware backend, and a surface that may still move. Pin your SDK to a specific commit if you depend on it.
See also
<alp/peripheral.h>— error model,alp_last_error(), andalp_pixfmt_t<alp/camera.h>— where the frames you encode usually come from<alp/cap.h>— compile-time / runtime silicon gating<alp/backend.h>— why the software fallback wins off E8- API Overview — the full header index