Skip to content

Commit b0e4c92

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 34ad61a commit b0e4c92

File tree

3 files changed

+180
-1
lines changed

3 files changed

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

268409
LOG_INF("TCP: Accepted connection");
269410

411+
#if DT_HAS_CHOSEN(zephyr_videoenc)
412+
if (configure_encoder()) {
413+
LOG_ERR("Unable to configure video encoder");
414+
return 0;
415+
}
416+
#endif
417+
270418
/* Enqueue Buffers */
271419
for (i = 0; i < ARRAY_SIZE(buffers); i++) {
272420
video_enqueue(video_dev, buffers[i]);
@@ -290,16 +438,28 @@ int main(void)
290438
return 0;
291439
}
292440

293-
LOG_INF("Sending frame %d", i++);
441+
#if DT_HAS_CHOSEN(zephyr_videoenc)
442+
encode_frame(vbuf, &vbuf_out);
294443

444+
LOG_INF("Sending compressed frame %d (size=%d bytes)", i++,
445+
vbuf_out->bytesused);
446+
/* Send compressed video buffer to TCP client */
447+
ret = sendall(client, vbuf_out->buffer, vbuf_out->bytesused);
448+
449+
vbuf_out->type = VIDEO_BUF_TYPE_OUTPUT;
450+
video_enqueue(encoder_dev, vbuf_out);
451+
#else
452+
LOG_INF("Sending frame %d", i++);
295453
/* Send video buffer to TCP client */
296454
ret = sendall(client, vbuf->buffer, vbuf->bytesused);
455+
#endif
297456
if (ret && ret != -EAGAIN) {
298457
/* client disconnected */
299458
LOG_ERR("TCP: Client disconnected %d", ret);
300459
close(client);
301460
}
302461

462+
vbuf->type = VIDEO_BUF_TYPE_INPUT;
303463
(void)video_enqueue(video_dev, vbuf);
304464
} while (!ret);
305465

@@ -309,8 +469,13 @@ int main(void)
309469
return 0;
310470
}
311471

472+
#if DT_HAS_CHOSEN(zephyr_videoenc)
473+
stop_encoder();
474+
#endif
475+
312476
/* Flush remaining buffers */
313477
do {
478+
vbuf->type = VIDEO_BUF_TYPE_INPUT;
314479
ret = video_dequeue(video_dev, &vbuf, K_NO_WAIT);
315480
} while (!ret);
316481

0 commit comments

Comments
 (0)