Skip to content

Commit e5aaab5

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 81bc8e5 commit e5aaab5

File tree

3 files changed

+198
-1
lines changed

3 files changed

+198
-1
lines changed

samples/drivers/video/tcpserversink/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ 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+
default VIDEO_PIX_FMT_H264
74+
help
75+
Compression format used by the video encoder if enabled.
76+
If not set defaults to H264 video bitstream with startcodes.
77+
7178
endmenu
7279

7380
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: 184 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,171 @@ 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;
38+
39+
int configure_encoder(void)
40+
{
41+
struct video_buffer *buffer;
42+
struct video_format fmt;
43+
struct video_caps caps;
44+
uint32_t size;
45+
int i;
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.", encoder_dev->name);
50+
return -1;
51+
}
52+
53+
/* Get capabilities */
54+
caps.type = VIDEO_BUF_TYPE_INPUT;
55+
if (video_get_caps(encoder_dev, &caps)) {
56+
LOG_ERR("Unable to retrieve video capabilities");
57+
return -1;
58+
}
59+
60+
LOG_INF("- Encoder input capabilities:");
61+
i = 0;
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), fcap->width_min, fcap->width_max,
67+
fcap->width_step, fcap->height_min, fcap->height_max, fcap->height_step);
68+
i++;
69+
}
70+
71+
caps.type = VIDEO_BUF_TYPE_OUTPUT;
72+
if (video_get_caps(encoder_dev, &caps)) {
73+
LOG_ERR("Unable to retrieve video capabilities");
74+
return -1;
75+
}
76+
77+
LOG_INF("- Encoder output capabilities:");
78+
i = 0;
79+
while (caps.format_caps[i].pixelformat) {
80+
const struct video_format_cap *fcap = &caps.format_caps[i];
81+
/* fourcc to string */
82+
LOG_INF(" %s width [%u; %u; %u] height [%u; %u; %u]",
83+
VIDEO_FOURCC_TO_STR(fcap->pixelformat), fcap->width_min, fcap->width_max,
84+
fcap->width_step, fcap->height_min, fcap->height_max, fcap->height_step);
85+
i++;
86+
}
87+
88+
/* Get default/native format */
89+
fmt.type = VIDEO_BUF_TYPE_OUTPUT;
90+
if (video_get_format(encoder_dev, &fmt)) {
91+
LOG_ERR("Unable to retrieve video format");
92+
return -1;
93+
}
94+
95+
LOG_INF("Video encoder device detected, format: %s %ux%u",
96+
VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width, fmt.height);
97+
98+
#if CONFIG_VIDEO_FRAME_HEIGHT
99+
fmt.height = CONFIG_VIDEO_FRAME_HEIGHT;
100+
#endif
101+
102+
#if CONFIG_VIDEO_FRAME_WIDTH
103+
fmt.width = CONFIG_VIDEO_FRAME_WIDTH;
104+
#endif
105+
106+
/* Set output format */
107+
if (strcmp(CONFIG_VIDEO_ENCODED_PIXEL_FORMAT, "")) {
108+
fmt.pixelformat = VIDEO_FOURCC_FROM_STR(CONFIG_VIDEO_ENCODED_PIXEL_FORMAT);
109+
}
110+
111+
LOG_INF("- Video encoded format: %s %ux%u", VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width,
112+
fmt.height);
113+
114+
fmt.type = VIDEO_BUF_TYPE_OUTPUT;
115+
if (video_set_format(encoder_dev, &fmt)) {
116+
LOG_ERR("Unable to set format");
117+
return -1;
118+
}
119+
120+
/* Alloc output buffer */
121+
size = fmt.sizeimage;
122+
if (size == 0) {
123+
LOG_ERR("Encoder driver must set sizeimage");
124+
return -1;
125+
}
126+
127+
buffer = video_buffer_aligned_alloc(size, CONFIG_VIDEO_BUFFER_POOL_ALIGN, K_FOREVER);
128+
if (buffer == NULL) {
129+
LOG_ERR("Unable to alloc compressed video buffer size=%d", size);
130+
return -1;
131+
}
132+
133+
buffer->type = VIDEO_BUF_TYPE_OUTPUT;
134+
video_enqueue(encoder_dev, buffer);
135+
136+
/* Set input format */
137+
if (strcmp(CONFIG_VIDEO_PIXEL_FORMAT, "")) {
138+
fmt.pixelformat = VIDEO_FOURCC_FROM_STR(CONFIG_VIDEO_PIXEL_FORMAT);
139+
}
140+
141+
LOG_INF("- Video input format: %s %ux%u", VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width,
142+
fmt.height);
143+
144+
fmt.type = VIDEO_BUF_TYPE_INPUT;
145+
if (video_set_format(encoder_dev, &fmt)) {
146+
LOG_ERR("Unable to set input format");
147+
return -1;
148+
}
149+
150+
/* Start video encoder */
151+
if (video_stream_start(encoder_dev, VIDEO_BUF_TYPE_INPUT)) {
152+
LOG_ERR("Unable to start video encoder (input)");
153+
return -1;
154+
}
155+
if (video_stream_start(encoder_dev, VIDEO_BUF_TYPE_OUTPUT)) {
156+
LOG_ERR("Unable to start video encoder (output)");
157+
return -1;
158+
}
159+
160+
return 0;
161+
}
162+
163+
int encode_frame(struct video_buffer *in, struct video_buffer **out)
164+
{
165+
int ret;
166+
167+
in->type = VIDEO_BUF_TYPE_INPUT;
168+
video_enqueue(encoder_dev, in);
169+
170+
(*out)->type = VIDEO_BUF_TYPE_OUTPUT;
171+
ret = video_dequeue(encoder_dev, out, K_FOREVER);
172+
if (ret) {
173+
LOG_ERR("Unable to dequeue encoder buf");
174+
return ret;
175+
}
176+
177+
return 0;
178+
}
179+
180+
void stop_encoder(void)
181+
{
182+
if (video_stream_stop(encoder_dev, VIDEO_BUF_TYPE_OUTPUT)) {
183+
LOG_ERR("Unable to stop encoder (output)");
184+
}
185+
186+
if (video_stream_stop(encoder_dev, VIDEO_BUF_TYPE_INPUT)) {
187+
LOG_ERR("Unable to stop encoder (input)");
188+
}
189+
}
190+
#endif
191+
36192
int main(void)
37193
{
38194
struct sockaddr_in addr, client_addr;
39195
socklen_t client_addr_len = sizeof(client_addr);
40196
struct video_buffer *buffers[CONFIG_VIDEO_CAPTURE_N_BUFFERING];
41197
struct video_buffer *vbuf = &(struct video_buffer){};
198+
#if DT_HAS_CHOSEN(zephyr_videoenc)
199+
struct video_buffer *vbuf_out = &(struct video_buffer){};
200+
#endif
42201
int ret, sock, client;
43202
struct video_format fmt;
44203
struct video_caps caps;
@@ -267,6 +426,13 @@ int main(void)
267426

268427
LOG_INF("TCP: Accepted connection");
269428

429+
#if DT_HAS_CHOSEN(zephyr_videoenc)
430+
if (configure_encoder()) {
431+
LOG_ERR("Unable to configure video encoder");
432+
return 0;
433+
}
434+
#endif
435+
270436
/* Enqueue Buffers */
271437
for (i = 0; i < ARRAY_SIZE(buffers); i++) {
272438
video_enqueue(video_dev, buffers[i]);
@@ -290,16 +456,28 @@ int main(void)
290456
return 0;
291457
}
292458

293-
LOG_INF("Sending frame %d", i++);
459+
#if DT_HAS_CHOSEN(zephyr_videoenc)
460+
encode_frame(vbuf, &vbuf_out);
461+
462+
LOG_INF("Sending compressed frame %d (size=%d bytes)", i++,
463+
vbuf_out->bytesused);
464+
/* Send compressed video buffer to TCP client */
465+
ret = sendall(client, vbuf_out->buffer, vbuf_out->bytesused);
294466

467+
vbuf_out->type = VIDEO_BUF_TYPE_OUTPUT;
468+
video_enqueue(encoder_dev, vbuf_out);
469+
#else
470+
LOG_INF("Sending frame %d", i++);
295471
/* Send video buffer to TCP client */
296472
ret = sendall(client, vbuf->buffer, vbuf->bytesused);
473+
#endif
297474
if (ret && ret != -EAGAIN) {
298475
/* client disconnected */
299476
LOG_ERR("TCP: Client disconnected %d", ret);
300477
close(client);
301478
}
302479

480+
vbuf->type = VIDEO_BUF_TYPE_INPUT;
303481
(void)video_enqueue(video_dev, vbuf);
304482
} while (!ret);
305483

@@ -309,8 +487,13 @@ int main(void)
309487
return 0;
310488
}
311489

490+
#if DT_HAS_CHOSEN(zephyr_videoenc)
491+
stop_encoder();
492+
#endif
493+
312494
/* Flush remaining buffers */
313495
do {
496+
vbuf->type = VIDEO_BUF_TYPE_INPUT;
314497
ret = video_dequeue(video_dev, &vbuf, K_NO_WAIT);
315498
} while (!ret);
316499

0 commit comments

Comments
 (0)