Skip to content

Enable mcux jpegdec and pngdec video driver#101883

Draft
KATE-WANG-NXP wants to merge 12 commits intozephyrproject-rtos:mainfrom
nxp-upstream:enable-mcux-jpegdec-video-driver
Draft

Enable mcux jpegdec and pngdec video driver#101883
KATE-WANG-NXP wants to merge 12 commits intozephyrproject-rtos:mainfrom
nxp-upstream:enable-mcux-jpegdec-video-driver

Conversation

@KATE-WANG-NXP
Copy link
Contributor

@KATE-WANG-NXP KATE-WANG-NXP commented Jan 7, 2026

  1. Update the supported pixel formats in display.h, to align with the ones in video,h
  2. Enable mcux jpegdec video driver
  3. Enable mcux pngdec video driver
  4. Update the video-sw-generator to support generating JPEG and PNG format frames, including two hard-encoded 320x160(default frame size) JPEG frames with color-bar pattern (normal and horizontally flipped) as static buffers.
  5. Update the DCNano display controller to support more pixel formats
  6. Add driver specific files in application layer to support the nxp jpegdec and pngdec as transform video components
  7. Enable the demo on RT700
@ngphibang
Copy link
Contributor

ngphibang commented Jan 7, 2026

No example in repo can be used to demo the driver usage, ...

Does the RT700-EVK supports a camera that can output jpeg (e.g. ov5640) so that we can demo on the capture sample ?
Otherwise, we can leverage the tcpserversink sample to be tcpserversrc sample which receive jpeg frame from gstreamer running on a PC ?

@avolmat-st
Copy link

No example in repo can be used to demo the driver usage, ...

Does the RT700-EVK supports a camera that can output jpeg (e.g. ov5640) so that we can demo on the capture sample ? Otherwise, we can leverage the tcpserversink sample to be tcpserversrc sample which receive jpeg frame from gstreamer running on a PC ?

Or maybe even just a display (either display api directly or LVGL based) of a fixed / hardcoded jpeg frame stored directly into the sample code, that would allow to very easily validate a jpeg decoding and can be reused for all other upcoming jpeg decoder
(on stm32n6 only the encoder direction has been implemented for the time being but decoder is also possible so we could also use such sample)

@ngphibang
Copy link
Contributor

No example in repo can be used to demo the driver usage, ...

Does the RT700-EVK supports a camera that can output jpeg (e.g. ov5640) so that we can demo on the capture sample ? Otherwise, we can leverage the tcpserversink sample to be tcpserversrc sample which receive jpeg frame from gstreamer running on a PC ?

Or maybe even just a display (either display api directly or LVGL based) of a fixed / hardcoded jpeg frame stored directly into the sample code, that would allow to very easily validate a jpeg decoding and can be reused for all other upcoming jpeg decoder
(on stm32n6 only the encoder direction has been implemented for the time being but decoder is also possible so we could also use such sample)

It will be much easier with libMP but currently I don't have enough bandwidth to implement jpegparse, jpegdec, tcpserversrc, tcpserversink and pull-push mode support ... :-)

@josuah
Copy link
Contributor

josuah commented Jan 7, 2026

fixed / hardcoded jpeg frame stored directly into the sample code

Stored in video-sw-generator? or a very basic video-sw-jpeg that repeats it in loop? This is a different use-case (simulate hardware that generates JPEG) than a libMP element.

@ngphibang
Copy link
Contributor

Stored in video-sw-generator is a good idea, jpeg will be a supported format like any other formats

@avolmat-st
Copy link

fixed / hardcoded jpeg frame stored directly into the sample code

Stored in video-sw-generator? or a very basic video-sw-jpeg that repeats it in loop? This is a different use-case (simulate hardware that generates JPEG) than a libMP element.

Excellent idea !!!

@KATE-WANG-NXP
Copy link
Contributor Author

No example in repo can be used to demo the driver usage, ...

Does the RT700-EVK supports a camera that can output jpeg (e.g. ov5640) so that we can demo on the capture sample ? Otherwise, we can leverage the tcpserversink sample to be tcpserversrc sample which receive jpeg frame from gstreamer running on a PC ?

We do not have a camera on RT700 that can output jpeg format frame, there is a PR in progress that introduces a usb camera device that can do that 728e508
although only RW612 is supported in this PR I think this can be expanded to other platforms too

Add support for compressed video formats (JPEG and PNG) in the software
video generator driver. This enables testing of compressed video formats
without requiring actual hardware.
The compressed formats only support a fixed 320x160 resolution and
provide two frames (normal and horizontally flipped) for testing.

Signed-off-by: Kate Wang <yumeng.wang@nxp.com>
Add support for NXP JPEG decoder hardware module. This driver provides
memory-to-memory (M2M) video transformation capability to decode JPEG
compressed images into raw pixel formats.

Key features:
- Supports JPEG input format (VIDEO_PIX_FMT_JPEG)
- Resolution support: 64x64 to 8192x8192 pixels (16-pixel step)
- Automatic format detection from JPEG header parsing
- No color space conversion (output format matches JPEG encoding)
- Interrupt-driven operation with input/output buffer queues
- Configurable output buffer pitch for flexible memory layouts

Signed-off-by: Kate Wang <yumeng.wang@nxp.com>
Add support for NXP PNG decoder hardware module. This driver provides
memory-to-memory (M2M) video transformation capability to decode PNG
compressed images into raw pixel formats.

Key features:
- Supports PNG input format (VIDEO_PIX_FMT_PNG)
- Resolution support: 1x1 to 1024x65535 pixels (1-pixel step)
- Fixed ABGR8888 output format (VIDEO_PIX_FMT_ABGR32)
- Interrupt-driven operation with input/output buffer queues
- 8-byte buffer alignment requirement

Signed-off-by: Kate Wang <yumeng.wang@nxp.com>
Add support for more pixel formats that are supported by the DCNano
on mimxrt700_evk:
- PIXEL_FORMAT_RGB_888: 24-bit RGB format with 8 bits per component
- PIXEL_FORMAT_BGR_888: 24-bit BGR format with 8 bits per component
- PIXEL_FORMAT_ABGR_8888: 32-bit ABGR with alpha channel
- PIXEL_FORMAT_RGBA_8888: 32-bit RGBA with alpha channel
- PIXEL_FORMAT_BGRA_8888: 32-bit BGRA with alpha channel

Signed-off-by: Kate Wang <yumeng.wang@nxp.com>
Add MCUX SDK driver component mappings for the JPEG and PNG decoder
drivers.

Signed-off-by: Kate Wang <yumeng.wang@nxp.com>
Add device tree nodes for the JPEG and PNG hardware decoder modules
on the RT7xx SoC.

Signed-off-by: Kate Wang <yumeng.wang@nxp.com>
Enable the JPEG and PNG hardware decoder modules on the mimxrt700_evk
board

Signed-off-by: Kate Wang <yumeng.wang@nxp.com>
Add support for NXP JPEG and PNG hardware decoders to the video capture
sample application for the mimxrt700_evk board.

Changes include:
- Add transform_nxp_jpegdec.c with JPEG decoder integration and optional
  software color space conversion from NV12 to RGB565
- Add transform_nxp_pngdec.c with PNG decoder integration supporting
  ABGR8888 output format
- Add board-specific configuration and overlay files for mimxrt700_evk
  to enable PNG decoder by default (JPEG decoder configuration available
  but commented out)
- Add Kconfig option VIDEO_NXP_JPEGDEC_CSC to enable software-based
  color space conversion for JPEG decoder output
- Update sample.yaml to include mimxrt700_evk test configurations with
  video-sw-generator snippet and rk055hdmipi4ma0 shield

Signed-off-by: Kate Wang <yumeng.wang@nxp.com>
@KATE-WANG-NXP KATE-WANG-NXP force-pushed the enable-mcux-jpegdec-video-driver branch from b218acb to babe8ba Compare February 2, 2026 09:35
@KATE-WANG-NXP KATE-WANG-NXP changed the title Enable mcux jpegdec video driver Feb 2, 2026
@KATE-WANG-NXP
Copy link
Contributor Author

Hi @ngphibang, I also enabled the nxp pngdec video driver and enabled it in the video capture example. Please have a test :-)
The pngdec can only output ABGR pixel format, which is supported by the DCNano on RT700 so I updated the DCNano lcdif driver as well.
Cmd:
west build -b mimxrt700_evk/mimxrt798s/cm33_cpu0 samples/drivers/video/capture --snippet video-sw-generator --shield rk055hdmipi4ma0
To test the jpegdec, samples/drivers/video/capture/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay and samples/drivers/video/capture/boards/mimxrt700_evk_mimxrt798s_cm33_cpu0.overlay needs to be updated.

struct mcux_jpegdec_data *data = dev->data;

*fmt = fmt->type == VIDEO_BUF_TYPE_INPUT ? data->m2m.in.fmt : data->m2m.out.fmt;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format->pitch and size is determined by the driver (the one who know if need padding or not) and should be return back to the application. You could take a look at other video drivers.
Also, could use video_estimate_fmt_size() helper to compute it.

Comment on lines +236 to +243
/* Update pitch value. */
data->m2m.out.fmt.pitch = fmt->pitch;
data->m2m.out.fmt.size = fmt->pitch * fmt->height;
if (data->m2m.out.fmt.pixelformat == VIDEO_PIX_FMT_NV12) {
data->m2m.out.fmt.size = fmt->pitch * fmt->height * 2U;
} else {
data->m2m.out.fmt.size = fmt->pitch * fmt->height;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Application just sets the pixelformat, width and height.
format->pitch and size is determined / decided by the driver (the one who know if need padding or not) and should be return back to the application. You could take a look at other video drivers.
video_estimate_fmt_size() helper can be used to compute it.

} else {
caps->format_caps = mcux_jpegdec_in_fmts;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buf_align is not merged yet, it's still under review

Copy link
Contributor

@JarmouniA JarmouniA left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Submit JPEGdec and PNGdec drivers in 2 separate PRs.
I honestly don't understand this desire to cram things that can be submitted independently in one huge unreviewable mess.

POWER_ApplyPD();
#endif

#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(jpegdec))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check by compatible


capabilities->y_resolution = config->dpi_config.panelHeight;
capabilities->x_resolution = config->dpi_config.panelWidth;
#if DT_ENUM_IDX_OR(DT_NODELABEL(lcdif), version, 0) == 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get by compatible

/**
* @code{.unparsed}
* | Aaaaaaaa Bbbbbbbb Gggggggg Rrrrrrrr | ...
* | Bbbbbbbb Gggggggg Rrrrrrrr Aaaaaaaa | ...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixes should not be in the same commit as additions.
Also the fix is kind of unrelated to the PR, so it should be submitted in a separate one.

@KATE-WANG-NXP KATE-WANG-NXP marked this pull request as draft February 9, 2026 03:09
@KATE-WANG-NXP
Copy link
Contributor Author

Submit JPEGdec and PNGdec drivers in 2 separate PRs. I honestly don't understand this desire to cram things that can be submitted independently in one huge unreviewable mess.

Sorry about that, I put it in the same PR for phibang to test on these m2m video components, I think I'll convert to draft then

Comment on lines +13 to +22
static uint8_t BYTECLIP(int val)
{
if (val < 0) {
return 0U;
} else if (val > 255) {
return 255U;
} else {
return (uint8_t)val;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using the well-known CLAMP(val, 0, 255) macro directly?

}
}

static void Convert_yuv420_to_rgb565(uint16_t width, uint16_t height, uint32_t yAddr,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might be interested in lower-case everywhere for function and variable names.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having an app_ prefix as done elsewhere also seems like a good idea, but maybe not critical.

Comment on lines +63 to +75
#ifdef CONFIG_VIDEO_NXP_JPEGDEC_CSC
if (ret < 0) {
return ret;
}

/* The transfromed format shall be RGB565 for display panel to show. */
out_fmt->pixelformat = VIDEO_PIX_FMT_RGB565;
out_fmt->pitch = out_fmt->width * 2U;

return 0;
#else
return ret;
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#ifdef THIS_PARTICULAR_DRIVER means that every driver will need custom application code.

Better use generic Kconfig's and fill them in each board prj.conf.

I think we need to discuss how to make this possible to be vendor-neutral, as this is not going to work at scale.

This is also one reason for #98514: reduce the amount of custom application code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, Linux support for compression engine goes a lot through Gstreamer, which is same use-case as libZMP.

Copy link
Contributor

@josuah josuah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misc discussions

Comment on lines +37 to +38
#define JPEG_FRAME_SIZE 0x522 /* Fixed size for each JPEG frame */
#define PNG_FRAME_SIZE 0x164 /* Fixed size for each PNG frame */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe better to get the size directly from the array by sizeof(jpeg_frame_buffers) / 2 ? This is less error-prone (as we don't need to manually count the array items and don't need to change the macro when the array changes).

};

/* Static JPEG frame buffers. 2 320x160 color-bar pattern frames, h-flipped. */
static uint8_t jpeg_frame_buffers[2U][JPEG_FRAME_SIZE] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be flatten to static uint8_t jpeg_frame_buffers[] = {...}; to avoid giving the size

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would even go with one frame per variable, making it very trivial and flexible: compressed formats typically give buffers of each different size.

Copy link
Contributor

@josuah josuah Feb 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or even better: I would recommend to not store the buffer directly as hex in the source as it is a lot more difficult to inspect the image this way, while .jpeg and .png file are easy to inspect and modify.

How about using this for generating the buffers?

  • xxd -i frame.jpeg >jpeg_frame.h
  • xxd -i frame_hflip.jpeg >jpeg_frame_hflip.h

See #101883 (comment) for an example of CMakeLists.txt integration. I can provide and test an example CMakeLists.txt snippet if that helps.

You can then include it from the middle of an array for instance.

/* Static JPEG frame buffers. */

static uint8_t jpeg_frame_buffer[] = {
#include "jpeg_frame.h"
};

static uint8_t jpeg_frame_hflip_buffer[] = {
#include "jpeg_frame_hflip.h"
};

/* Static PNG frame buffers. */

static uint8_t png_frame_buffer[] = {
#include "png_frame.h"
};

static uint8_t png_frame_hflip_buffer[] = {
#include "png_frame_hflip.h"
};

I removed the description as it is not given anymore, and now trivial to see what the buffer contain, or i.e. memcmp them if needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, all these are examples and suggestions, maybe you wished a different naming/implementation...


switch (pix_format) {
case VIDEO_PIX_FMT_JPEG:
frame = jpeg_frame_buffers[hflip ? 1U : 0U];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&jpeg_frame_buffers[(hflip ? 1U : 0U) * FRAME_SIZE] if the array is flatten

return 2;
}

static int video_sw_generator_fill_compressed(const struct device *const dev,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dev is not used.

return -ENOMEM;
}

/* Copy the JPEG frame data to the video buffer */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/* Copy the compressed frame data to the video buffer */

Comment on lines +302 to +311
#define VIDEO_SW_GENERATOR_FORMAT_CAP_COMPRESSED(pixfmt) \
{ \
.pixelformat = pixfmt, \
.width_min = DEFAULT_FRAME_WIDTH, \
.width_max = DEFAULT_FRAME_WIDTH, \
.height_min = DEFAULT_FRAME_HEIGHT, \
.height_max = DEFAULT_FRAME_HEIGHT, \
.width_step = 1, \
.height_step = 1, \
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be merged with VIDEO_SW_GENERATOR_FORMAT_CAP by:

.width_min = ((pixfmt) == VIDEO_PIX_FMT_JPEG || (pixfmt) == VIDEO_PIX_FMT_PNG) ? DEFAULT_FRAME_WIDTH : 64,

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this will need some glue to extract the JPEG frame width from the image, maybe some Kconfig like this to keep it simple:

  • CONFIG_VIDEO_SW_GENERATOR_JPEG_WIDTH
  • CONFIG_VIDEO_SW_GENERATOR_JPEG_HEIGHT
  • CONFIG_VIDEO_SW_GENERATOR_PNG_WIDTH
  • CONFIG_VIDEO_SW_GENERATOR_PNG_HEIGHT

This could be further extended with:

  • CONFIG_VIDEO_SW_GENERATOR_JPEG_FILE
  • CONFIG_VIDEO_SW_GENERATOR_JPEG_HFILP_FILE
  • CONFIG_VIDEO_SW_GENERATOR_PNG_FILE
  • CONFIG_VIDEO_SW_GENERATOR_PNG_HFLIP_FILE

Which default to the two files stored in-tree and their dimension, so that the user can specify an out-of-tree file if they want.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you wish some example Kconfig/CMakeLists.txt for it, I'd be glad to propose it if you appreciate this change.

Comment on lines +344 to +365
/* Special handling for JPEG and PNG formats */
if (fmt->pixelformat == VIDEO_PIX_FMT_JPEG) {
if (fmt->width != DEFAULT_FRAME_WIDTH || fmt->height != DEFAULT_FRAME_HEIGHT) {
LOG_ERR("JPEG format only supports %dx%d resolution", DEFAULT_FRAME_WIDTH,
DEFAULT_FRAME_HEIGHT);
return -EINVAL;
}
fmt->pitch = 0; /* JPEG doesn't have a pitch */
fmt->size = JPEG_FRAME_SIZE;
} else if (fmt->pixelformat == VIDEO_PIX_FMT_PNG) {
if (fmt->width != DEFAULT_FRAME_WIDTH || fmt->height != DEFAULT_FRAME_HEIGHT) {
LOG_ERR("PNG format only supports %dx%d resolution", DEFAULT_FRAME_WIDTH,
DEFAULT_FRAME_HEIGHT);
return -EINVAL;
}
fmt->pitch = 0; /* PNG doesn't have a pitch */
fmt->size = PNG_FRAME_SIZE;
} else {
ret = video_estimate_fmt_size(fmt);
if (ret < 0) {
return ret;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these code can be drop, just add two entries for JPEG and PNG in video_estimate_fmt_size() and it will be OK. If the estimation is a bit large, you can add to the end:

if (fmt->pixelformat == VIDEO_PIX_FMT_JPEG) {
    fmt->size = JPEG_FRAME_SIZE;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think after applying your own comment, it would become something like fmt->size = MAX(sizeof(jpeg_frame_1_buffer), sizeof(jpeg_frame_2_buffer))?

Comment on lines +345 to +350
if (fmt->pixelformat == VIDEO_PIX_FMT_JPEG) {
if (fmt->width != DEFAULT_FRAME_WIDTH || fmt->height != DEFAULT_FRAME_HEIGHT) {
LOG_ERR("JPEG format only supports %dx%d resolution", DEFAULT_FRAME_WIDTH,
DEFAULT_FRAME_HEIGHT);
return -EINVAL;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need because video_format_caps_index() already did the job.

};

/* Static JPEG frame buffers. 2 320x160 color-bar pattern frames, h-flipped. */
static uint8_t jpeg_frame_buffers[2U][JPEG_FRAME_SIZE] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would even go with one frame per variable, making it very trivial and flexible: compressed formats typically give buffers of each different size.

0xE0, 0x3B, 0x80, 0xF4, 0x74, 0x00, 0x02, 0x62, 0xA7, 0x26, 0x2C, 0xAD, 0x3C, 0xED, 0xBB,
0x7C, 0x96, 0xE1, 0xB5, 0xE3, 0xA0, 0x0C, 0xAA, 0xB6, 0x00, 0x08, 0x10, 0x0E, 0xE3, 0x38,
0xE8, 0x00, 0x02, 0x64, 0xA6, 0xA6, 0x4C, 0xAB, 0x3C, 0xED, 0xBB, 0x7C, 0x97, 0x21, 0x95,
0xE3, 0xA0, 0x0C, 0xAC, 0xB8, 0x00, 0x0F, 0xFF, 0xD9},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a relatively rare syntax for multi-line buffers in Zephyr, with the } on the same line as the rest.

I suppose clang-format did this. You can add a trailing , before the } to indicate clang-format to use the more frequent style of having } on its own line.

};

/* Static JPEG frame buffers. 2 320x160 color-bar pattern frames, h-flipped. */
static uint8_t jpeg_frame_buffers[2U][JPEG_FRAME_SIZE] = {
Copy link
Contributor

@josuah josuah Feb 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or even better: I would recommend to not store the buffer directly as hex in the source as it is a lot more difficult to inspect the image this way, while .jpeg and .png file are easy to inspect and modify.

How about using this for generating the buffers?

  • xxd -i frame.jpeg >jpeg_frame.h
  • xxd -i frame_hflip.jpeg >jpeg_frame_hflip.h

See #101883 (comment) for an example of CMakeLists.txt integration. I can provide and test an example CMakeLists.txt snippet if that helps.

You can then include it from the middle of an array for instance.

/* Static JPEG frame buffers. */

static uint8_t jpeg_frame_buffer[] = {
#include "jpeg_frame.h"
};

static uint8_t jpeg_frame_hflip_buffer[] = {
#include "jpeg_frame_hflip.h"
};

/* Static PNG frame buffers. */

static uint8_t png_frame_buffer[] = {
#include "png_frame.h"
};

static uint8_t png_frame_hflip_buffer[] = {
#include "png_frame_hflip.h"
};

I removed the description as it is not given anymore, and now trivial to see what the buffer contain, or i.e. memcmp them if needed.

Comment on lines +344 to +365
/* Special handling for JPEG and PNG formats */
if (fmt->pixelformat == VIDEO_PIX_FMT_JPEG) {
if (fmt->width != DEFAULT_FRAME_WIDTH || fmt->height != DEFAULT_FRAME_HEIGHT) {
LOG_ERR("JPEG format only supports %dx%d resolution", DEFAULT_FRAME_WIDTH,
DEFAULT_FRAME_HEIGHT);
return -EINVAL;
}
fmt->pitch = 0; /* JPEG doesn't have a pitch */
fmt->size = JPEG_FRAME_SIZE;
} else if (fmt->pixelformat == VIDEO_PIX_FMT_PNG) {
if (fmt->width != DEFAULT_FRAME_WIDTH || fmt->height != DEFAULT_FRAME_HEIGHT) {
LOG_ERR("PNG format only supports %dx%d resolution", DEFAULT_FRAME_WIDTH,
DEFAULT_FRAME_HEIGHT);
return -EINVAL;
}
fmt->pitch = 0; /* PNG doesn't have a pitch */
fmt->size = PNG_FRAME_SIZE;
} else {
ret = video_estimate_fmt_size(fmt);
if (ret < 0) {
return ret;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think after applying your own comment, it would become something like fmt->size = MAX(sizeof(jpeg_frame_1_buffer), sizeof(jpeg_frame_2_buffer))?

Comment on lines +302 to +311
#define VIDEO_SW_GENERATOR_FORMAT_CAP_COMPRESSED(pixfmt) \
{ \
.pixelformat = pixfmt, \
.width_min = DEFAULT_FRAME_WIDTH, \
.width_max = DEFAULT_FRAME_WIDTH, \
.height_min = DEFAULT_FRAME_HEIGHT, \
.height_max = DEFAULT_FRAME_HEIGHT, \
.width_step = 1, \
.height_step = 1, \
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this will need some glue to extract the JPEG frame width from the image, maybe some Kconfig like this to keep it simple:

  • CONFIG_VIDEO_SW_GENERATOR_JPEG_WIDTH
  • CONFIG_VIDEO_SW_GENERATOR_JPEG_HEIGHT
  • CONFIG_VIDEO_SW_GENERATOR_PNG_WIDTH
  • CONFIG_VIDEO_SW_GENERATOR_PNG_HEIGHT

This could be further extended with:

  • CONFIG_VIDEO_SW_GENERATOR_JPEG_FILE
  • CONFIG_VIDEO_SW_GENERATOR_JPEG_HFILP_FILE
  • CONFIG_VIDEO_SW_GENERATOR_PNG_FILE
  • CONFIG_VIDEO_SW_GENERATOR_PNG_HFLIP_FILE

Which default to the two files stored in-tree and their dimension, so that the user can specify an out-of-tree file if they want.

Comment on lines +302 to +311
#define VIDEO_SW_GENERATOR_FORMAT_CAP_COMPRESSED(pixfmt) \
{ \
.pixelformat = pixfmt, \
.width_min = DEFAULT_FRAME_WIDTH, \
.width_max = DEFAULT_FRAME_WIDTH, \
.height_min = DEFAULT_FRAME_HEIGHT, \
.height_max = DEFAULT_FRAME_HEIGHT, \
.width_step = 1, \
.height_step = 1, \
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you wish some example Kconfig/CMakeLists.txt for it, I'd be glad to propose it if you appreciate this change.

};

/* Static JPEG frame buffers. 2 320x160 color-bar pattern frames, h-flipped. */
static uint8_t jpeg_frame_buffers[2U][JPEG_FRAME_SIZE] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, all these are examples and suggestions, maybe you wished a different naming/implementation...

Copy link
Contributor

@josuah josuah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, I meant to comment, not to approve yet...

@josuah josuah self-requested a review February 15, 2026 22:07
Comment on lines +47 to +48
#define MCUX_JPEGDEC_HEIGHT_MIN 64U
#define MCUX_JPEGDEC_HEIGHT_MAX 0x2000U
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

height is same as width so these can be drop as you drop already the height_step

Comment on lines +432 to +440
if (caps->type == VIDEO_BUF_TYPE_OUTPUT) {
if (data->first_frame_rcv) {
/* Assign the format capability based on parsed JPEG header. */
mcux_jpegdec_out_fmts[0] = mcux_jpegdec_out_all_fmts[data->format_idx];
} else {
LOG_WRN("Output format can only be obtained after first input buffer "
"is received, use VIDEO_PIX_FMT_NV12 as default since it is mostly "
"used by JPEG.");
mcux_jpegdec_out_fmts[0] = mcux_jpegdec_out_all_fmts[0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

caps is the capability of the HW so here we should expose all output formats that the HW / driver can support. It does not depend on the first frame header.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment