Skip to content

Commit d8f04bf

Browse files
committed
samples: video: tcpserversink: video compression support
Add video compression support to lowerize network bandwidth. To visualise camera content on host PC, use GStreamer command line: $> gst-launch-1.0 tcpclientsrc host=<board ip address> port=5000 ! decodebin ! autovideosink sync=false Signed-off-by: Hugues Fruchet <[email protected]>
1 parent 8016c5c commit d8f04bf

File tree

3 files changed

+173
-1
lines changed

3 files changed

+173
-1
lines changed

samples/drivers/video/tcpserversink/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ config VIDEO_CTRL_VFLIP
6868
help
6969
If set, mirror the video frame vertically
7070

71+
config VIDEO_ENCODED_PIXEL_FORMAT
72+
string "Pixel format of the encoded frame"
73+
help
74+
Pixel format of the encoded frame.
75+
7176
endmenu
7277

7378
source "Kconfig.zephyr"

samples/drivers/video/tcpserversink/README.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ Example with gstreamer:
7171
7272
For video software generator, the default resolution should be width=320 and height=160.
7373

74+
When using compression support, use this GStreamer command line:
75+
76+
.. code-block:: console
77+
78+
gst-launch-1.0 tcpclientsrc host=192.0.2.1 port=5000 \
79+
! queue ! decodebin ! queue ! fpsdisplaysink sync=false
80+
7481
References
7582
**********
7683

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

Lines changed: 161 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,149 @@ static ssize_t sendall(int sock, const void *buf, size_t len)
3333
return 0;
3434
}
3535

36+
#if DT_HAS_CHOSEN(zephyr_videoenc)
37+
const struct device *encoder_dev = NULL;
38+
39+
int configure_encoder()
40+
{
41+
struct video_buffer *buffer;
42+
struct video_format fmt;
43+
struct video_caps caps;
44+
uint32_t size;
45+
int i = 0;
46+
47+
encoder_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_videoenc));
48+
if (!device_is_ready(encoder_dev)) {
49+
LOG_ERR("%s: encoder video device not ready.",
50+
encoder_dev->name);
51+
return -1;
52+
}
53+
54+
/* Get capabilities */
55+
caps.type = VIDEO_BUF_TYPE_OUTPUT;
56+
if (video_get_caps(encoder_dev, &caps)) {
57+
LOG_ERR("Unable to retrieve video capabilities");
58+
return -1;
59+
}
60+
61+
LOG_INF("- Capabilities:");
62+
while (caps.format_caps[i].pixelformat) {
63+
const struct video_format_cap *fcap = &caps.format_caps[i];
64+
/* fourcc to string */
65+
LOG_INF(" %s width [%u; %u; %u] height [%u; %u; %u]",
66+
VIDEO_FOURCC_TO_STR(fcap->pixelformat),
67+
fcap->width_min, fcap->width_max, fcap->width_step,
68+
fcap->height_min, fcap->height_max, fcap->height_step);
69+
i++;
70+
}
71+
72+
/* Get default/native format */
73+
fmt.type = VIDEO_BUF_TYPE_OUTPUT;
74+
if (video_get_format(encoder_dev, &fmt)) {
75+
LOG_ERR("Unable to retrieve video format");
76+
return -1;
77+
}
78+
79+
printk("Video encoder device detected, format: %s %ux%u\n",
80+
VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width, fmt.height);
81+
82+
#if CONFIG_VIDEO_FRAME_HEIGHT
83+
fmt.height = CONFIG_VIDEO_FRAME_HEIGHT;
84+
#endif
85+
86+
#if CONFIG_VIDEO_FRAME_WIDTH
87+
fmt.width = CONFIG_VIDEO_FRAME_WIDTH;
88+
#endif
89+
90+
/* Set output format */
91+
if (strcmp(CONFIG_VIDEO_ENCODED_PIXEL_FORMAT, "")) {
92+
fmt.pixelformat = VIDEO_FOURCC_FROM_STR(CONFIG_VIDEO_ENCODED_PIXEL_FORMAT);
93+
}
94+
95+
LOG_INF("- Video encoded format: %s %ux%u",
96+
VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width, fmt.height);
97+
98+
fmt.type = VIDEO_BUF_TYPE_OUTPUT;
99+
if (video_set_format(encoder_dev, &fmt)) {
100+
LOG_ERR("Unable to set format");
101+
return -1;
102+
}
103+
104+
/* Alloc output buffer */
105+
size = fmt.sizeimage;
106+
if (size == 0) {
107+
LOG_ERR("Encoder driver must set sizeimage");
108+
return -1;
109+
}
110+
buffer = video_buffer_aligned_alloc(size, CONFIG_VIDEO_BUFFER_POOL_ALIGN,
111+
K_FOREVER);
112+
if (buffer == NULL) {
113+
LOG_ERR("Unable to alloc compressed video buffer size=%d", size);
114+
return -1;
115+
}
116+
buffer->type = VIDEO_BUF_TYPE_OUTPUT;
117+
video_enqueue(encoder_dev, buffer);
118+
119+
/* Set input format */
120+
if (strcmp(CONFIG_VIDEO_PIXEL_FORMAT, "")) {
121+
fmt.pixelformat = VIDEO_FOURCC_FROM_STR(CONFIG_VIDEO_PIXEL_FORMAT);
122+
}
123+
124+
LOG_INF("- Video input format: %s %ux%u",
125+
VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width, fmt.height);
126+
127+
fmt.type = VIDEO_BUF_TYPE_INPUT;
128+
if (video_set_format(encoder_dev, &fmt)) {
129+
LOG_ERR("Unable to set input format");
130+
return 0;
131+
}
132+
133+
/* Start video encoder */
134+
if (video_stream_start(encoder_dev, VIDEO_BUF_TYPE_INPUT)) {
135+
LOG_ERR("Unable to start video encoder (input)");
136+
return -1;
137+
}
138+
if (video_stream_start(encoder_dev, VIDEO_BUF_TYPE_OUTPUT)) {
139+
LOG_ERR("Unable to start video encoder (output)");
140+
return -1;
141+
}
142+
143+
return 0;
144+
}
145+
146+
int encode_frame(struct video_buffer *in, struct video_buffer **out)
147+
{
148+
int ret;
149+
150+
in->type = VIDEO_BUF_TYPE_INPUT;
151+
video_enqueue(encoder_dev, in);
152+
153+
(*out)->type = VIDEO_BUF_TYPE_OUTPUT;
154+
ret = video_dequeue(encoder_dev, out, K_FOREVER);
155+
if (ret) {
156+
LOG_ERR("Unable to dequeue encoder buf");
157+
return ret;
158+
}
159+
160+
return 0;
161+
}
162+
163+
void stop_encoder(void)
164+
{
165+
if (video_stream_stop(encoder_dev, VIDEO_BUF_TYPE_OUTPUT))
166+
LOG_ERR("Unable to stop encoder");
167+
}
168+
#endif
169+
36170
int main(void)
37171
{
38172
struct sockaddr_in addr, client_addr;
39173
socklen_t client_addr_len = sizeof(client_addr);
40174
struct video_buffer *buffers[CONFIG_VIDEO_CAPTURE_N_BUFFERING];
41175
struct video_buffer *vbuf = &(struct video_buffer){};
176+
#if DT_HAS_CHOSEN(zephyr_videoenc)
177+
struct video_buffer *vbuf_out = &(struct video_buffer){};
178+
#endif
42179
int ret, sock, client;
43180
struct video_format fmt;
44181
struct video_caps caps;
@@ -267,6 +404,13 @@ int main(void)
267404

268405
printk("TCP: Accepted connection\n");
269406

407+
#if DT_HAS_CHOSEN(zephyr_videoenc)
408+
if (configure_encoder()) {
409+
LOG_ERR("Unable to configure video encoder");
410+
return 0;
411+
}
412+
#endif
413+
270414
/* Enqueue Buffers */
271415
for (i = 0; i < ARRAY_SIZE(buffers); i++) {
272416
video_enqueue(video_dev, buffers[i]);
@@ -290,16 +434,27 @@ int main(void)
290434
return 0;
291435
}
292436

293-
printk("\rSending frame %d\n", i++);
437+
#if DT_HAS_CHOSEN(zephyr_videoenc)
438+
encode_frame(vbuf, &vbuf_out);
294439

440+
printk("\rSending compressed frame %d (size=%d bytes)\n", i++, vbuf_out->bytesused);
441+
/* Send compressed video buffer to TCP client */
442+
ret = sendall(client, vbuf_out->buffer, vbuf_out->bytesused);
443+
444+
vbuf_out->type = VIDEO_BUF_TYPE_OUTPUT;
445+
video_enqueue(encoder_dev, vbuf_out);
446+
#else
447+
printk("\rSending frame %d\n", i++);
295448
/* Send video buffer to TCP client */
296449
ret = sendall(client, vbuf->buffer, vbuf->bytesused);
450+
#endif
297451
if (ret && ret != -EAGAIN) {
298452
/* client disconnected */
299453
printk("\nTCP: Client disconnected %d\n", ret);
300454
close(client);
301455
}
302456

457+
vbuf->type = VIDEO_BUF_TYPE_INPUT;
303458
(void)video_enqueue(video_dev, vbuf);
304459
} while (!ret);
305460

@@ -309,8 +464,13 @@ int main(void)
309464
return 0;
310465
}
311466

467+
#if DT_HAS_CHOSEN(zephyr_videoenc)
468+
stop_encoder();
469+
#endif
470+
312471
/* Flush remaining buffers */
313472
do {
473+
vbuf->type = VIDEO_BUF_TYPE_INPUT;
314474
ret = video_dequeue(video_dev, &vbuf, K_NO_WAIT);
315475
} while (!ret);
316476

0 commit comments

Comments
 (0)