Skip to content

Commit babe8ba

Browse files
committed
samples: drivers: video: capture: Add NXP JPEG and PNG decoder support
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>
1 parent 9e187a4 commit babe8ba

File tree

7 files changed

+177
-0
lines changed

7 files changed

+177
-0
lines changed

‎samples/drivers/video/capture/Kconfig‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ config VIDEO_TRANSFORM
7878
If set, the video frame will go through some m2m transforms defined in
7979
transform_${CONFIG_VIDEO_TRANSFORM}.c
8080

81+
if VIDEO_MCUX_JPEGDEC
82+
rsource "boards/Kconfig.nxp_jpegdec"
83+
endif
84+
8185
endmenu
8286

8387
source "Kconfig.zephyr"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright 2026 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config VIDEO_NXP_JPEGDEC_CSC
5+
bool "Convert pixel format NV12 to RGB565"
6+
default y
7+
help
8+
Use software implemented CSC function to convert
9+
the NV12 pixel format to RGB565 for the display driver
10+
to use
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#
2+
# Copyright 2026 NXP
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
# CONFIG_VIDEO_PIXEL_FORMAT="JPEG"
8+
# CONFIG_VIDEO_TRANSFORM="nxp_jpegdec"
9+
CONFIG_VIDEO_PIXEL_FORMAT="PNG "
10+
CONFIG_VIDEO_TRANSFORM="nxp_pngdec"
11+
CONFIG_VIDEO_FRAME_WIDTH=320
12+
CONFIG_VIDEO_FRAME_HEIGHT=160
13+
CONFIG_VIDEO_BUFFER_POOL_HEAP_SIZE=400000
14+
CONFIG_DCACHE=n
15+
CONFIG_VIDEO_CAM_NUM_BUFS=1
16+
CONFIG_HEAP_MEM_POOL_SIZE=103000
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* Copyright 2026 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
*/
7+
8+
/ {
9+
chosen {
10+
zephyr,videodec = &pngdec;
11+
};
12+
};

‎samples/drivers/video/capture/sample.yaml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ tests:
1414
- platform:frdm_mcxn236/mcxn236:SHIELD="dvp_20pin_ov7670;lcd_par_s035_8080"
1515
- platform:stm32h7b3i_dk:SHIELD="st_b_cams_omv_mb1683"
1616
- platform:ek_ra8d1/r7fa8d1bhecbd:SHIELD="dvp_20pin_ov7670;rtkmipilcdb00000be"
17+
- platform:mimxrt700_evk/mimxrt798s/cm33_cpu0:SNIPPET="video-sw-generator":SHIELD="rk055hdmipi4ma0"
1718
extra_configs:
1819
- CONFIG_FPU=y
1920
harness: console
@@ -36,6 +37,7 @@ tests:
3637
- esp32s3_eye/esp32s3/procpu
3738
- stm32h7b3i_dk
3839
- ek_ra8d1/r7fa8d1bhecbd
40+
- mimxrt700_evk
3941
depends_on: video
4042
integration_platforms:
4143
- mimxrt1064_evk/mimxrt1064
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright 2026 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/device.h>
9+
#include <zephyr/drivers/video.h>
10+
#include "transform.h"
11+
12+
#ifdef CONFIG_VIDEO_NXP_JPEGDEC_CSC
13+
static uint8_t BYTECLIP(int val)
14+
{
15+
if (val < 0) {
16+
return 0U;
17+
} else if (val > 255) {
18+
return 255U;
19+
} else {
20+
return (uint8_t)val;
21+
}
22+
}
23+
24+
static void Convert_yuv420_to_rgb565(uint16_t width, uint16_t height, uint32_t yAddr,
25+
uint32_t uvAddr, uint32_t rgbAddr)
26+
{
27+
uint16_t *rgb = (void *)rgbAddr;
28+
int16_t r, g, b;
29+
uint8_t R, G, B, y, u, v;
30+
31+
uint16_t i, j;
32+
33+
for (i = 0U; i < height; i++) {
34+
for (j = 0U; j < width; j++) {
35+
y = *(((uint8_t *)yAddr) + width * i + j);
36+
u = *(((uint8_t *)uvAddr) + width * (i / 2) + j - (j % 2));
37+
v = *(((uint8_t *)uvAddr) + width * (i / 2) + j + 1 - (j % 2));
38+
r = y + 1402 * (v - 128) / 1000;
39+
g = y - (344 * (u - 128) + 714 * (v - 128)) / 1000;
40+
b = y + 1772 * (u - 128) / 1000;
41+
R = BYTECLIP(r);
42+
G = BYTECLIP(g);
43+
B = BYTECLIP(b);
44+
*rgb++ = (uint16_t)((((uint16_t)R & 0xF8) << 8U) |
45+
(((uint16_t)G & 0xFC) << 3U) |
46+
(((uint16_t)B & 0xF8) >> 3U));
47+
}
48+
}
49+
}
50+
#endif
51+
52+
int app_setup_video_transform(const struct device *const transform_dev, struct video_format in_fmt,
53+
struct video_format *const out_fmt, struct video_buffer **out_buf)
54+
{
55+
out_fmt->pixelformat = VIDEO_PIX_FMT_NV12; /* Decoder output format shall be NV12 */
56+
out_fmt->width = CONFIG_VIDEO_FRAME_WIDTH;
57+
out_fmt->height = CONFIG_VIDEO_FRAME_HEIGHT;
58+
out_fmt->pitch = out_fmt->width;
59+
out_fmt->size = out_fmt->width * out_fmt->height * 2U;
60+
61+
int ret = setup_video_transform(transform_dev, in_fmt, out_fmt, out_buf);
62+
63+
#ifdef CONFIG_VIDEO_NXP_JPEGDEC_CSC
64+
if (ret < 0) {
65+
return ret;
66+
}
67+
68+
/* The transfromed format shall be RGB565 for display panel to show. */
69+
out_fmt->pixelformat = VIDEO_PIX_FMT_RGB565;
70+
out_fmt->pitch = out_fmt->width * 2U;
71+
72+
return 0;
73+
#else
74+
return ret;
75+
#endif
76+
}
77+
78+
int app_transform_frame(const struct device *const transform_dev, struct video_buffer *in_buf,
79+
struct video_buffer **out_buf)
80+
{
81+
int ret = transform_frame(transform_dev, in_buf, out_buf);
82+
83+
#ifdef CONFIG_VIDEO_NXP_JPEGDEC_CSC
84+
if (ret < 0) {
85+
return ret;
86+
}
87+
88+
/* Change the decoded NV12 2-p pixel to RGB565 for display to show. */
89+
uint8_t *rgb565 = k_aligned_alloc(CONFIG_VIDEO_BUFFER_POOL_ALIGN, (*out_buf)->bytesused);
90+
91+
Convert_yuv420_to_rgb565(CONFIG_VIDEO_FRAME_WIDTH, CONFIG_VIDEO_FRAME_HEIGHT,
92+
(uint32_t)(*out_buf)->buffer,
93+
(uint32_t)((*out_buf)->buffer +
94+
CONFIG_VIDEO_FRAME_WIDTH * CONFIG_VIDEO_FRAME_HEIGHT),
95+
(uint32_t)rgb565);
96+
97+
memcpy((*out_buf)->buffer, rgb565,
98+
CONFIG_VIDEO_FRAME_WIDTH * CONFIG_VIDEO_FRAME_HEIGHT * 2U);
99+
100+
return 0;
101+
#else
102+
return ret;
103+
#endif
104+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2026 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/device.h>
9+
#include <zephyr/drivers/video.h>
10+
#include "transform.h"
11+
12+
13+
int app_setup_video_transform(const struct device *const transform_dev, struct video_format in_fmt,
14+
struct video_format *const out_fmt, struct video_buffer **out_buf)
15+
{
16+
out_fmt->pixelformat = VIDEO_PIX_FMT_ABGR32; /* Decoder output format shall be ABGR8888 */
17+
out_fmt->width = CONFIG_VIDEO_FRAME_WIDTH;
18+
out_fmt->height = CONFIG_VIDEO_FRAME_HEIGHT;
19+
out_fmt->pitch = out_fmt->width * 4;
20+
out_fmt->size = out_fmt->pitch * out_fmt->height;
21+
22+
return setup_video_transform(transform_dev, in_fmt, out_fmt, out_buf);
23+
}
24+
25+
int app_transform_frame(const struct device *const transform_dev, struct video_buffer *in_buf,
26+
struct video_buffer **out_buf)
27+
{
28+
return transform_frame(transform_dev, in_buf, out_buf);
29+
}

0 commit comments

Comments
 (0)