Skip to content

Commit 972cb73

Browse files
committed
samples: video: capture: Add support for m2m transformation
Sometimnes, additional transforms needs to be applied on the video frame to be able to display it correctly on the LCD. This is to add support for such a transformation. This also adds a 90-degree image rotation using PxP m2m device on i.MX RT1170 as an example of such usecase. Signed-off-by: Phi Bang Nguyen <phibang.nguyen@nxp.com>
1 parent 4776d28 commit 972cb73

File tree

5 files changed

+150
-4
lines changed

5 files changed

+150
-4
lines changed

samples/drivers/video/capture/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@ project(video_capture)
66

77
FILE(GLOB app_sources src/*.c)
88
target_sources(app PRIVATE ${app_sources})
9+
10+
if(CONFIG_VIDEO_TRANSFORM)
11+
target_sources(app PRIVATE boards/${BOARD}/transform.c)
12+
endif()

samples/drivers/video/capture/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ config VIDEO_CTRL_VFLIP
5858
help
5959
If set, mirror the video frame vertically
6060

61+
config VIDEO_TRANSFORM
62+
bool "Perform some m2m transforms on the video frame"
63+
help
64+
If set, the video frame will go through some m2m transforms before being displayed
65+
6166
endmenu
6267

6368
source "Kconfig.zephyr"
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/device.h>
8+
#include <zephyr/drivers/video.h>
9+
#include <zephyr/drivers/video-controls.h>
10+
11+
#include <zephyr/logging/log.h>
12+
13+
LOG_MODULE_REGISTER(transform, CONFIG_LOG_DEFAULT_LEVEL);
14+
15+
static const struct device *transform_dev;
16+
static struct video_buffer *transformed_buffer;
17+
18+
int video_transform_setup(struct video_format in_fmt, struct video_format *out_fmt)
19+
{
20+
int ret;
21+
transform_dev = DEVICE_DT_GET(DT_NODELABEL(pxp));
22+
struct video_control ctrl = {.id = VIDEO_CID_ROTATE, .val = 90};
23+
24+
out_fmt->pixelformat = in_fmt.pixelformat;
25+
out_fmt->width = in_fmt.height;
26+
out_fmt->height = in_fmt.width;
27+
out_fmt->type = VIDEO_BUF_TYPE_OUTPUT;
28+
29+
/* Set input and output formats */
30+
in_fmt.type = VIDEO_BUF_TYPE_INPUT;
31+
ret = video_set_format(transform_dev, &in_fmt);
32+
if (ret) {
33+
LOG_ERR("Unable to set input format");
34+
return ret;
35+
}
36+
37+
ret = video_set_format(transform_dev, out_fmt);
38+
if (ret) {
39+
LOG_ERR("Unable to set output format");
40+
return ret;
41+
}
42+
43+
/* Set controls */
44+
video_set_ctrl(transform_dev, &ctrl);
45+
46+
/* Allocate a buffer for output queue */
47+
transformed_buffer = video_buffer_aligned_alloc(in_fmt.pitch * in_fmt.height,
48+
CONFIG_VIDEO_BUFFER_POOL_ALIGN, K_FOREVER);
49+
50+
if (transformed_buffer == NULL) {
51+
LOG_ERR("Unable to alloc video buffer");
52+
return -ENOMEM;
53+
}
54+
55+
return 0;
56+
}
57+
58+
int video_transform_process(struct video_buffer *in_buf, struct video_buffer **out_buf)
59+
{
60+
int err;
61+
struct video_buffer *transformed_buf = &(struct video_buffer){};
62+
/* Store the input buffer type to recover later */
63+
enum video_buf_type in_buf_type = in_buf->type;
64+
65+
in_buf->type = VIDEO_BUF_TYPE_INPUT;
66+
err = video_enqueue(transform_dev, in_buf);
67+
if (err) {
68+
LOG_ERR("Unable to enqueue input buffer");
69+
return err;
70+
}
71+
72+
transformed_buffer->type = VIDEO_BUF_TYPE_OUTPUT;
73+
err = video_enqueue(transform_dev, transformed_buffer);
74+
if (err) {
75+
LOG_ERR("Unable to enqueue output buffer");
76+
return err;
77+
}
78+
79+
/* Same start for both input and output */
80+
if (video_stream_start(transform_dev, VIDEO_BUF_TYPE_INPUT)) {
81+
LOG_ERR("Unable to start PxP");
82+
return 0;
83+
}
84+
85+
/* Dequeue input and output buffers */
86+
err = video_dequeue(transform_dev, &in_buf, K_FOREVER);
87+
if (err) {
88+
LOG_ERR("Unable to dequeue PxP video buf in");
89+
return err;
90+
}
91+
92+
transformed_buf->type = VIDEO_BUF_TYPE_OUTPUT;
93+
err = video_dequeue(transform_dev, &transformed_buf, K_FOREVER);
94+
if (err) {
95+
LOG_ERR("Unable to dequeue PxP video buf out");
96+
return err;
97+
}
98+
99+
*out_buf = transformed_buf;
100+
101+
/* Keep the input buffer intact */
102+
in_buf->type = in_buf_type;
103+
104+
return 0;
105+
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=3686800
1+
CONFIG_VIDEO_TRANSFORM=y
2+
CONFIG_VIDEO_BUFFER_POOL_SZ_MAX=6530200
3+
CONFIG_VIDEO_BUFFER_POOL_NUM_MAX=3

samples/drivers/video/capture/src/main.c

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@ LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);
2222
LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL);
2323
#endif
2424

25+
int __weak video_transform_setup(struct video_format in_fmt, struct video_format *out_fmt)
26+
{
27+
*out_fmt = in_fmt;
28+
29+
return 0;
30+
}
31+
32+
int __weak video_transform_process(struct video_buffer *in_buf, struct video_buffer **out_buf)
33+
{
34+
*out_buf = in_buf;
35+
36+
return 0;
37+
}
38+
2539
#if DT_HAS_CHOSEN(zephyr_display)
2640
static inline int display_setup(const struct device *const display_dev, const uint32_t pixfmt)
2741
{
@@ -87,10 +101,12 @@ static inline void video_display_frame(const struct device *const display_dev,
87101

88102
int main(void)
89103
{
90-
struct video_buffer *buffers[CONFIG_VIDEO_BUFFER_POOL_NUM_MAX];
104+
struct video_buffer *buffers[2];
91105
struct video_buffer *vbuf = &(struct video_buffer){};
106+
struct video_buffer *transformed_buf = &(struct video_buffer){};
92107
const struct device *video_dev;
93108
struct video_format fmt;
109+
struct video_format transformed_fmt;
94110
struct video_caps caps;
95111
struct video_frmival frmival;
96112
struct video_frmival_enum fie;
@@ -257,6 +273,13 @@ int main(void)
257273
video_set_ctrl(video_dev, &ctrl);
258274
}
259275

276+
/* Set up transformation */
277+
err = video_transform_setup(fmt, &transformed_fmt);
278+
if (err) {
279+
LOG_ERR("Unable to set up transformation");
280+
return 0;
281+
}
282+
260283
#if DT_HAS_CHOSEN(zephyr_display)
261284
const struct device *const display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
262285

@@ -265,7 +288,7 @@ int main(void)
265288
return 0;
266289
}
267290

268-
err = display_setup(display_dev, fmt.pixelformat);
291+
err = display_setup(display_dev, transformed_fmt.pixelformat);
269292
if (err) {
270293
LOG_ERR("Unable to set up display");
271294
return err;
@@ -321,8 +344,15 @@ int main(void)
321344
}
322345
#endif
323346

347+
/* Do transformation */
348+
err = video_transform_process(vbuf, &transformed_buf);
349+
if (err) {
350+
LOG_ERR("Unable to transform video frame");
351+
return 0;
352+
}
353+
324354
#if DT_HAS_CHOSEN(zephyr_display)
325-
video_display_frame(display_dev, vbuf, fmt);
355+
video_display_frame(display_dev, transformed_buf, transformed_fmt);
326356
#endif
327357

328358
err = video_enqueue(video_dev, vbuf);

0 commit comments

Comments
 (0)