Skip to content

Commit ce9469b

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

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,28 @@ 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
59+
const struct device *last_dev = NULL;
60+
struct video_ctrl_query cq = {.id = VIDEO_CTRL_FLAG_NEXT_CTRL};
61+
struct video_control ctrl = {.id = VIDEO_CID_HFLIP, .val = 1};
62+
int tp_set_ret = -ENOTSUP;
4463

4564
video_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_camera));
4665
if (!device_is_ready(video_dev)) {
@@ -80,6 +99,16 @@ int main(void)
8099
return 0;
81100
}
82101

102+
LOG_INF("- Capabilities:");
103+
while (caps.format_caps[i].pixelformat) {
104+
const struct video_format_cap *fcap = &caps.format_caps[i];
105+
/* fourcc to string */
106+
LOG_INF(" %s width [%u; %u; %u] height [%u; %u; %u]",
107+
VIDEO_FOURCC_TO_STR(fcap->pixelformat), fcap->width_min, fcap->width_max,
108+
fcap->width_step, fcap->height_min, fcap->height_max, fcap->height_step);
109+
i++;
110+
}
111+
83112
/* Get default/native format */
84113
fmt.type = type;
85114
if (video_get_format(video_dev, &fmt)) {
@@ -95,9 +124,129 @@ int main(void)
95124
return 0;
96125
}
97126

127+
/* Set the crop setting if necessary */
128+
#if CONFIG_VIDEO_SOURCE_CROP_WIDTH && CONFIG_VIDEO_SOURCE_CROP_HEIGHT
129+
sel.target = VIDEO_SEL_TGT_CROP;
130+
sel.rect.left = CONFIG_VIDEO_SOURCE_CROP_LEFT;
131+
sel.rect.top = CONFIG_VIDEO_SOURCE_CROP_TOP;
132+
sel.rect.width = CONFIG_VIDEO_SOURCE_CROP_WIDTH;
133+
sel.rect.height = CONFIG_VIDEO_SOURCE_CROP_HEIGHT;
134+
if (video_set_selection(video_dev, &sel)) {
135+
LOG_ERR("Unable to set selection crop");
136+
return 0;
137+
}
138+
LOG_INF("Selection crop set to (%u,%u)/%ux%u", sel.rect.left, sel.rect.top, sel.rect.width,
139+
sel.rect.height);
140+
#endif
141+
142+
#if CONFIG_VIDEO_FRAME_HEIGHT || CONFIG_VIDEO_FRAME_WIDTH
143+
#if CONFIG_VIDEO_FRAME_HEIGHT
144+
fmt.height = CONFIG_VIDEO_FRAME_HEIGHT;
145+
#endif
146+
147+
#if CONFIG_VIDEO_FRAME_WIDTH
148+
fmt.width = CONFIG_VIDEO_FRAME_WIDTH;
149+
#endif
150+
151+
/*
152+
* Check (if possible) if targeted size is same as crop
153+
* and if compose is necessary
154+
*/
155+
sel.target = VIDEO_SEL_TGT_CROP;
156+
err = video_get_selection(video_dev, &sel);
157+
if (err < 0 && err != -ENOSYS) {
158+
LOG_ERR("Unable to get selection crop");
159+
return 0;
160+
}
161+
162+
if (err == 0 && (sel.rect.width != fmt.width || sel.rect.height != fmt.height)) {
163+
sel.target = VIDEO_SEL_TGT_COMPOSE;
164+
sel.rect.left = 0;
165+
sel.rect.top = 0;
166+
sel.rect.width = fmt.width;
167+
sel.rect.height = fmt.height;
168+
err = video_set_selection(video_dev, &sel);
169+
if (err < 0 && err != -ENOSYS) {
170+
LOG_ERR("Unable to set selection compose");
171+
return 0;
172+
}
173+
}
174+
#endif
175+
176+
if (strcmp(CONFIG_VIDEO_PIXEL_FORMAT, "")) {
177+
fmt.pixelformat = VIDEO_FOURCC_FROM_STR(CONFIG_VIDEO_PIXEL_FORMAT);
178+
}
179+
180+
LOG_INF("- Video format: %s %ux%u", VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width,
181+
fmt.height);
182+
183+
if (video_set_format(video_dev, &fmt)) {
184+
LOG_ERR("Unable to set format");
185+
return 0;
186+
}
187+
188+
if (!video_get_frmival(video_dev, &frmival)) {
189+
LOG_INF("- Default frame rate : %f fps",
190+
1.0 * frmival.denominator / frmival.numerator);
191+
}
192+
193+
LOG_INF("- Supported frame intervals for the default format:");
194+
memset(&fie, 0, sizeof(fie));
195+
fie.format = &fmt;
196+
while (video_enum_frmival(video_dev, &fie) == 0) {
197+
if (fie.type == VIDEO_FRMIVAL_TYPE_DISCRETE) {
198+
LOG_INF(" %u/%u", fie.discrete.numerator, fie.discrete.denominator);
199+
} else {
200+
LOG_INF(" [min = %u/%u; max = %u/%u; step = %u/%u]",
201+
fie.stepwise.min.numerator, fie.stepwise.min.denominator,
202+
fie.stepwise.max.numerator, fie.stepwise.max.denominator,
203+
fie.stepwise.step.numerator, fie.stepwise.step.denominator);
204+
}
205+
fie.index++;
206+
}
207+
208+
/* Get supported controls */
209+
LOG_INF("- Supported controls:");
210+
cq.dev = video_dev;
211+
while (!video_query_ctrl(&cq)) {
212+
if (cq.dev != last_dev) {
213+
last_dev = cq.dev;
214+
LOG_INF("\t\tdevice: %s", cq.dev->name);
215+
}
216+
video_print_ctrl(&cq);
217+
cq.id |= VIDEO_CTRL_FLAG_NEXT_CTRL;
218+
}
219+
220+
/* Set controls */
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)