Skip to content

Commit dd5b12a

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

File tree

2 files changed

+215
-2
lines changed

2 files changed

+215
-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: 152 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,24 @@ 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+
#if CONFIG_VIDEO_FRAME_HEIGHT || CONFIG_VIDEO_FRAME_WIDTH
57+
int err;
58+
#endif
4459

4560
video_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_camera));
4661
if (!device_is_ready(video_dev)) {
@@ -80,6 +95,16 @@ int main(void)
8095
return 0;
8196
}
8297

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

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

0 commit comments

Comments
 (0)