Skip to content

Commit ad72180

Browse files
committed
samples: video: tcpserversink: sync with capture sample
Sync with video capture sample. Signed-off-by: Hugues Fruchet <[email protected]>
1 parent 613b697 commit ad72180

File tree

2 files changed

+214
-2
lines changed

2 files changed

+214
-2
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
mainmenu "TCP camera streaming sample application"
5+
6+
menu "Video capture configuration"
7+
8+
config VIDEO_SOURCE_CROP_LEFT
9+
int "Crop area left value"
10+
default 0
11+
help
12+
Left value of the crop area within the video source.
13+
14+
config VIDEO_SOURCE_CROP_TOP
15+
int "Crop area top value"
16+
default 0
17+
help
18+
Top value of the crop area within the video source.
19+
20+
config VIDEO_SOURCE_CROP_WIDTH
21+
int "Crop area width value"
22+
default 0
23+
help
24+
Width value of the crop area within the video source.
25+
If set to 0, the crop is not applied.
26+
27+
config VIDEO_SOURCE_CROP_HEIGHT
28+
int "Crop area height value"
29+
default 0
30+
help
31+
Height value of the crop area within the video source.
32+
If set to 0, the crop is not applied.
33+
34+
config VIDEO_FRAME_HEIGHT
35+
int "Height of the video frame"
36+
default 0
37+
help
38+
Height of the video frame. If set to 0, the default height is used.
39+
40+
config VIDEO_FRAME_WIDTH
41+
int "Width of the video frame"
42+
default 0
43+
help
44+
Width of the video frame. If set to 0, the default width is used.
45+
46+
config VIDEO_PIXEL_FORMAT
47+
string "Pixel format of the video frame"
48+
help
49+
Pixel format of the video frame. If not set, the default pixel format is used.
50+
51+
config VIDEO_CTRL_HFLIP
52+
bool "Mirror the video frame horizontally"
53+
help
54+
If set, mirror the video frame horizontally
55+
56+
config VIDEO_CTRL_VFLIP
57+
bool "Mirror the video frame vertically"
58+
help
59+
If set, mirror the video frame vertically
60+
61+
endmenu
62+
63+
source "Kconfig.zephyr"

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

Lines changed: 151 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
/*
22
* Copyright (c) 2019 Linaro Limited
3+
* Copyright 2025 NXP
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
67

78
#include <zephyr/device.h>
89
#include <zephyr/drivers/video.h>
10+
#include <zephyr/drivers/video-controls.h>
911
#include <zephyr/kernel.h>
1012
#include <zephyr/logging/log.h>
1113
#include <zephyr/net/socket.h>
@@ -36,11 +38,22 @@ int main(void)
3638
socklen_t client_addr_len = sizeof(client_addr);
3739
struct video_buffer *buffers[2];
3840
struct video_buffer *vbuf = &(struct video_buffer){};
39-
int i, ret, sock, client;
41+
int ret, sock, client;
4042
struct video_format fmt;
4143
struct video_caps caps;
44+
struct video_frmival frmival;
45+
struct video_frmival_enum fie;
4246
enum video_buf_type type = VIDEO_BUF_TYPE_OUTPUT;
4347
const struct device *video_dev;
48+
#if (CONFIG_VIDEO_SOURCE_CROP_WIDTH && CONFIG_VIDEO_SOURCE_CROP_HEIGHT) || \
49+
CONFIG_VIDEO_FRAME_HEIGHT || CONFIG_VIDEO_FRAME_WIDTH
50+
struct video_selection sel = {
51+
.type = VIDEO_BUF_TYPE_OUTPUT,
52+
};
53+
#endif
54+
size_t bsize;
55+
int i = 0;
56+
int err;
4457

4558
video_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_camera));
4659
if (!device_is_ready(video_dev)) {
@@ -80,6 +93,17 @@ int main(void)
8093
return 0;
8194
}
8295

96+
LOG_INF("- Capabilities:");
97+
while (caps.format_caps[i].pixelformat) {
98+
const struct video_format_cap *fcap = &caps.format_caps[i];
99+
/* fourcc to string */
100+
LOG_INF(" %s width [%u; %u; %u] height [%u; %u; %u]",
101+
VIDEO_FOURCC_TO_STR(fcap->pixelformat),
102+
fcap->width_min, fcap->width_max, fcap->width_step,
103+
fcap->height_min, fcap->height_max, fcap->height_step);
104+
i++;
105+
}
106+
83107
/* Get default/native format */
84108
fmt.type = type;
85109
if (video_get_format(video_dev, &fmt)) {
@@ -95,9 +119,134 @@ int main(void)
95119
return 0;
96120
}
97121

122+
/* Set the crop setting if necessary */
123+
#if CONFIG_VIDEO_SOURCE_CROP_WIDTH && CONFIG_VIDEO_SOURCE_CROP_HEIGHT
124+
sel.target = VIDEO_SEL_TGT_CROP;
125+
sel.rect.left = CONFIG_VIDEO_SOURCE_CROP_LEFT;
126+
sel.rect.top = CONFIG_VIDEO_SOURCE_CROP_TOP;
127+
sel.rect.width = CONFIG_VIDEO_SOURCE_CROP_WIDTH;
128+
sel.rect.height = CONFIG_VIDEO_SOURCE_CROP_HEIGHT;
129+
if (video_set_selection(video_dev, &sel)) {
130+
LOG_ERR("Unable to set selection crop");
131+
return 0;
132+
}
133+
LOG_INF("Selection crop set to (%u,%u)/%ux%u",
134+
sel.rect.left, sel.rect.top, sel.rect.width, sel.rect.height);
135+
#endif
136+
137+
#if CONFIG_VIDEO_FRAME_HEIGHT || CONFIG_VIDEO_FRAME_WIDTH
138+
#if CONFIG_VIDEO_FRAME_HEIGHT
139+
fmt.height = CONFIG_VIDEO_FRAME_HEIGHT;
140+
#endif
141+
142+
#if CONFIG_VIDEO_FRAME_WIDTH
143+
fmt.width = CONFIG_VIDEO_FRAME_WIDTH;
144+
#endif
145+
146+
/*
147+
* Check (if possible) if targeted size is same as crop
148+
* and if compose is necessary
149+
*/
150+
sel.target = VIDEO_SEL_TGT_CROP;
151+
err = video_get_selection(video_dev, &sel);
152+
if (err < 0 && err != -ENOSYS) {
153+
LOG_ERR("Unable to get selection crop");
154+
return 0;
155+
}
156+
157+
if (err == 0 && (sel.rect.width != fmt.width || sel.rect.height != fmt.height)) {
158+
sel.target = VIDEO_SEL_TGT_COMPOSE;
159+
sel.rect.left = 0;
160+
sel.rect.top = 0;
161+
sel.rect.width = fmt.width;
162+
sel.rect.height = fmt.height;
163+
err = video_set_selection(video_dev, &sel);
164+
if (err < 0 && err != -ENOSYS) {
165+
LOG_ERR("Unable to set selection compose");
166+
return 0;
167+
}
168+
}
169+
#endif
170+
171+
if (strcmp(CONFIG_VIDEO_PIXEL_FORMAT, "")) {
172+
fmt.pixelformat = VIDEO_FOURCC_FROM_STR(CONFIG_VIDEO_PIXEL_FORMAT);
173+
}
174+
175+
LOG_INF("- Video format: %s %ux%u",
176+
VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width, fmt.height);
177+
178+
if (video_set_format(video_dev, &fmt)) {
179+
LOG_ERR("Unable to set format");
180+
return 0;
181+
}
182+
183+
if (!video_get_frmival(video_dev, &frmival)) {
184+
LOG_INF("- Default frame rate : %f fps",
185+
1.0 * frmival.denominator / frmival.numerator);
186+
}
187+
188+
LOG_INF("- Supported frame intervals for the default format:");
189+
memset(&fie, 0, sizeof(fie));
190+
fie.format = &fmt;
191+
while (video_enum_frmival(video_dev, &fie) == 0) {
192+
if (fie.type == VIDEO_FRMIVAL_TYPE_DISCRETE) {
193+
LOG_INF(" %u/%u", fie.discrete.numerator, fie.discrete.denominator);
194+
} else {
195+
LOG_INF(" [min = %u/%u; max = %u/%u; step = %u/%u]",
196+
fie.stepwise.min.numerator, fie.stepwise.min.denominator,
197+
fie.stepwise.max.numerator, fie.stepwise.max.denominator,
198+
fie.stepwise.step.numerator, fie.stepwise.step.denominator);
199+
}
200+
fie.index++;
201+
}
202+
203+
/* Get supported controls */
204+
LOG_INF("- Supported controls:");
205+
const struct device *last_dev = NULL;
206+
struct video_ctrl_query cq = {.dev = video_dev, .id = VIDEO_CTRL_FLAG_NEXT_CTRL};
207+
208+
while (!video_query_ctrl(&cq)) {
209+
if (cq.dev != last_dev) {
210+
last_dev = cq.dev;
211+
LOG_INF("\t\tdevice: %s", cq.dev->name);
212+
}
213+
video_print_ctrl(&cq);
214+
cq.id |= VIDEO_CTRL_FLAG_NEXT_CTRL;
215+
}
216+
217+
/* Set controls */
218+
struct video_control ctrl = {.id = VIDEO_CID_HFLIP, .val = 1};
219+
int tp_set_ret = -ENOTSUP;
220+
221+
if (IS_ENABLED(CONFIG_VIDEO_CTRL_HFLIP)) {
222+
video_set_ctrl(video_dev, &ctrl);
223+
}
224+
225+
if (IS_ENABLED(CONFIG_VIDEO_CTRL_VFLIP)) {
226+
ctrl.id = VIDEO_CID_VFLIP;
227+
video_set_ctrl(video_dev, &ctrl);
228+
}
229+
230+
if (IS_ENABLED(CONFIG_TEST)) {
231+
ctrl.id = VIDEO_CID_TEST_PATTERN;
232+
tp_set_ret = video_set_ctrl(video_dev, &ctrl);
233+
}
234+
235+
/* Size to allocate for each buffer */
236+
if (caps.min_line_count == LINE_COUNT_HEIGHT) {
237+
bsize = fmt.pitch * fmt.height;
238+
} else {
239+
bsize = fmt.pitch * caps.min_line_count;
240+
}
241+
98242
/* Alloc Buffers */
99243
for (i = 0; i < ARRAY_SIZE(buffers); i++) {
100-
buffers[i] = video_buffer_alloc(fmt.pitch * fmt.height, K_FOREVER);
244+
/*
245+
* For some hardwares, such as the PxP used on i.MX RT1170 to do image rotation,
246+
* buffer alignment is needed in order to achieve the best performance
247+
*/
248+
buffers[i] = video_buffer_aligned_alloc(bsize, CONFIG_VIDEO_BUFFER_POOL_ALIGN,
249+
K_FOREVER);
101250
if (buffers[i] == NULL) {
102251
LOG_ERR("Unable to alloc video buffer");
103252
return 0;

0 commit comments

Comments
 (0)