Skip to content

Commit 84476af

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 dae574f commit 84476af

File tree

3 files changed

+168
-1
lines changed

3 files changed

+168
-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: 156 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL);
1818
#define MY_PORT 5000
1919
#define MAX_CLIENT_QUEUE 1
2020

21+
/* Assuming that video encoder will at least compress to this ratio */
22+
#define ESTIMATED_COMPRESSION_RATIO 10
23+
2124
static ssize_t sendall(int sock, const void *buf, size_t len)
2225
{
2326
while (len) {
@@ -33,12 +36,141 @@ static ssize_t sendall(int sock, const void *buf, size_t len)
3336
return 0;
3437
}
3538

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

268400
printk("TCP: Accepted connection\n");
269401

402+
#if DT_HAS_CHOSEN(zephyr_videoenc)
403+
if (configure_encoder()) {
404+
LOG_ERR("Unable to configure video encoder");
405+
return 0;
406+
}
407+
#endif
408+
270409
/* Enqueue Buffers */
271410
for (i = 0; i < ARRAY_SIZE(buffers); i++) {
272411
video_enqueue(video_dev, buffers[i]);
@@ -290,16 +429,27 @@ int main(void)
290429
return 0;
291430
}
292431

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

435+
printk("\rSending compressed frame %d (size=%d bytes)\n", i++, vbuf_out->bytesused);
436+
/* Send compressed video buffer to TCP client */
437+
ret = sendall(client, vbuf_out->buffer, vbuf_out->bytesused);
438+
439+
vbuf_out->type = VIDEO_BUF_TYPE_OUTPUT;
440+
video_enqueue(encoder_dev, vbuf_out);
441+
#else
442+
printk("\rSending frame %d\n", i++);
295443
/* Send video buffer to TCP client */
296444
ret = sendall(client, vbuf->buffer, vbuf->bytesused);
445+
#endif
297446
if (ret && ret != -EAGAIN) {
298447
/* client disconnected */
299448
printk("\nTCP: Client disconnected %d\n", ret);
300449
close(client);
301450
}
302451

452+
vbuf->type = VIDEO_BUF_TYPE_INPUT;
303453
(void)video_enqueue(video_dev, vbuf);
304454
} while (!ret);
305455

@@ -309,8 +459,13 @@ int main(void)
309459
return 0;
310460
}
311461

462+
#if DT_HAS_CHOSEN(zephyr_videoenc)
463+
stop_encoder();
464+
#endif
465+
312466
/* Flush remaining buffers */
313467
do {
468+
vbuf->type = VIDEO_BUF_TYPE_INPUT;
314469
ret = video_dequeue(video_dev, &vbuf, K_NO_WAIT);
315470
} while (!ret);
316471

0 commit comments

Comments
 (0)