Skip to content

Commit a83b615

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 7ab4cee commit a83b615

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
@@ -26,6 +26,20 @@ LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL);
2626
#error No camera chosen in devicetree. Missing "--shield" or "--snippet video-sw-generator" flag?
2727
#endif
2828

29+
int __weak video_transform_setup(struct video_format in_fmt, struct video_format *out_fmt)
30+
{
31+
*out_fmt = in_fmt;
32+
33+
return 0;
34+
}
35+
36+
int __weak video_transform_process(struct video_buffer *in_buf, struct video_buffer **out_buf)
37+
{
38+
*out_buf = in_buf;
39+
40+
return 0;
41+
}
42+
2943
#if DT_HAS_CHOSEN(zephyr_display)
3044
static inline int display_setup(const struct device *const display_dev, const uint32_t pixfmt)
3145
{
@@ -91,10 +105,12 @@ static inline void video_display_frame(const struct device *const display_dev,
91105

92106
int main(void)
93107
{
94-
struct video_buffer *buffers[CONFIG_VIDEO_BUFFER_POOL_NUM_MAX];
108+
struct video_buffer *buffers[2];
95109
struct video_buffer *vbuf = &(struct video_buffer){};
110+
struct video_buffer *transformed_buf = &(struct video_buffer){};
96111
const struct device *video_dev;
97112
struct video_format fmt;
113+
struct video_format transformed_fmt;
98114
struct video_caps caps;
99115
struct video_frmival frmival;
100116
struct video_frmival_enum fie;
@@ -262,6 +278,13 @@ int main(void)
262278
tp_set_ret = video_set_ctrl(video_dev, &ctrl);
263279
}
264280

281+
/* Set up transformation */
282+
err = video_transform_setup(fmt, &transformed_fmt);
283+
if (err) {
284+
LOG_ERR("Unable to set up transformation");
285+
return 0;
286+
}
287+
265288
#if DT_HAS_CHOSEN(zephyr_display)
266289
const struct device *const display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
267290

@@ -270,7 +293,7 @@ int main(void)
270293
return 0;
271294
}
272295

273-
err = display_setup(display_dev, fmt.pixelformat);
296+
err = display_setup(display_dev, transformed_fmt.pixelformat);
274297
if (err) {
275298
LOG_ERR("Unable to set up display");
276299
return err;
@@ -328,8 +351,15 @@ int main(void)
328351
}
329352
#endif
330353

354+
/* Do transformation */
355+
err = video_transform_process(vbuf, &transformed_buf);
356+
if (err) {
357+
LOG_ERR("Unable to transform video frame");
358+
return 0;
359+
}
360+
331361
#if DT_HAS_CHOSEN(zephyr_display)
332-
video_display_frame(display_dev, vbuf, fmt);
362+
video_display_frame(display_dev, transformed_buf, transformed_fmt);
333363
#endif
334364

335365
err = video_enqueue(video_dev, vbuf);

0 commit comments

Comments
 (0)