Skip to content

Commit 73d951e

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

File tree

2 files changed

+216
-2
lines changed

2 files changed

+216
-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: 153 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,17 @@ 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),
104+
fcap->width_min, fcap->width_max, fcap->width_step,
105+
fcap->height_min, fcap->height_max, fcap->height_step);
106+
i++;
107+
}
108+
83109
/* Get default/native format */
84110
fmt.type = type;
85111
if (video_get_format(video_dev, &fmt)) {
@@ -95,9 +121,134 @@ int main(void)
95121
return 0;
96122
}
97123

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

0 commit comments

Comments
 (0)