Skip to content

Commit 135cc7f

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 c508165 commit 135cc7f

File tree

2 files changed

+137
-1
lines changed

2 files changed

+137
-1
lines changed

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: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL);
1616
#define MY_PORT 5000
1717
#define MAX_CLIENT_QUEUE 1
1818

19+
/* Assuming that video encoder will at least compress to this ratio */
20+
#define ESTIMATED_COMPRESSION_RATIO 10
21+
1922
static ssize_t sendall(int sock, const void *buf, size_t len)
2023
{
2124
while (len) {
@@ -31,12 +34,118 @@ static ssize_t sendall(int sock, const void *buf, size_t len)
3134
return 0;
3235
}
3336

37+
#if DT_HAS_CHOSEN(zephyr_videoenc)
38+
const struct device *encoder_dev = NULL;
39+
40+
int configure_encoder()
41+
{
42+
struct video_buffer *buffer;
43+
struct video_format fmt;
44+
struct video_caps caps;
45+
enum video_buf_type type = VIDEO_BUF_TYPE_OUTPUT;
46+
uint32_t size;
47+
48+
encoder_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_videoenc));
49+
if (!device_is_ready(encoder_dev)) {
50+
LOG_ERR("%s: encoder video device not ready.",
51+
encoder_dev->name);
52+
return -1;
53+
}
54+
LOG_INF("Encoder video device: %s", encoder_dev->name);
55+
56+
/* Get capabilities */
57+
caps.type = type;
58+
if (video_get_caps(encoder_dev, &caps)) {
59+
LOG_ERR("Unable to retrieve video capabilities");
60+
return -1;
61+
}
62+
63+
/* Get default/native format */
64+
fmt.type = type;
65+
if (video_get_format(encoder_dev, &fmt)) {
66+
LOG_ERR("Unable to retrieve video format");
67+
return -1;
68+
}
69+
70+
#if CONFIG_VIDEO_FRAME_HEIGHT
71+
fmt.height = CONFIG_VIDEO_FRAME_HEIGHT;
72+
#endif
73+
74+
#if CONFIG_VIDEO_FRAME_WIDTH
75+
fmt.width = CONFIG_VIDEO_FRAME_WIDTH;
76+
#endif
77+
78+
if (strcmp(CONFIG_VIDEO_PIXEL_FORMAT, "")) {
79+
fmt.pixelformat = VIDEO_FOURCC_FROM_STR(CONFIG_VIDEO_PIXEL_FORMAT);
80+
}
81+
82+
LOG_INF("- Video format: %s %ux%u",
83+
VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width, fmt.height);
84+
85+
if (video_set_format(encoder_dev, &fmt)) {
86+
LOG_ERR("Unable to set format");
87+
return -1;
88+
}
89+
90+
printk("Video device detected, format: %s %ux%u\n",
91+
VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width, fmt.height);
92+
93+
/* Alloc output buffer */
94+
size = fmt.width * fmt.height / ESTIMATED_COMPRESSION_RATIO;
95+
buffer = video_buffer_aligned_alloc(size, CONFIG_VIDEO_BUFFER_POOL_ALIGN,
96+
K_FOREVER);
97+
if (buffer == NULL) {
98+
LOG_ERR("Unable to alloc compressed video buffer size=%d", size);
99+
return -1;
100+
}
101+
buffer->type = type;
102+
video_enqueue(encoder_dev, buffer);
103+
104+
/* Start video capture */
105+
if (video_stream_start(encoder_dev, type)) {
106+
LOG_ERR("Unable to start video");
107+
return -1;
108+
}
109+
110+
return 0;
111+
}
112+
113+
int encode_frame(struct video_buffer *in, struct video_buffer **out)
114+
{
115+
struct video_buffer vbuf_in;
116+
int ret;
117+
118+
vbuf_in = *in;/* Do not override capture video buffer */
119+
120+
vbuf_in.type = VIDEO_BUF_TYPE_INPUT;
121+
video_enqueue(encoder_dev, &vbuf_in);
122+
123+
(*out)->type = VIDEO_BUF_TYPE_OUTPUT;
124+
ret = video_dequeue(encoder_dev, out, K_FOREVER);
125+
if (ret) {
126+
LOG_ERR("Unable to dequeue encoder buf");
127+
return ret;
128+
}
129+
130+
return 0;
131+
}
132+
133+
void stop_encoder(void)
134+
{
135+
if (video_stream_stop(encoder_dev, VIDEO_BUF_TYPE_OUTPUT))
136+
LOG_ERR("Unable to stop encoder");
137+
}
138+
#endif
139+
34140
int main(void)
35141
{
36142
struct sockaddr_in addr, client_addr;
37143
socklen_t client_addr_len = sizeof(client_addr);
38144
struct video_buffer *buffers[2];
39145
struct video_buffer *vbuf = &(struct video_buffer){};
146+
#if DT_HAS_CHOSEN(zephyr_videoenc)
147+
struct video_buffer *vbuf_out = &(struct video_buffer){};
148+
#endif
40149
int ret, sock, client;
41150
struct video_format fmt;
42151
struct video_caps caps;
@@ -265,6 +374,13 @@ int main(void)
265374

266375
printk("TCP: Accepted connection\n");
267376

377+
#if DT_HAS_CHOSEN(zephyr_videoenc)
378+
if (configure_encoder()) {
379+
LOG_ERR("Unable to configure video encoder");
380+
return 0;
381+
}
382+
#endif
383+
268384
/* Enqueue Buffers */
269385
for (i = 0; i < ARRAY_SIZE(buffers); i++) {
270386
video_enqueue(video_dev, buffers[i]);
@@ -288,10 +404,19 @@ int main(void)
288404
return 0;
289405
}
290406

291-
printk("\rSending frame %d\n", i++);
407+
#if DT_HAS_CHOSEN(zephyr_videoenc)
408+
encode_frame(vbuf, &vbuf_out);
409+
410+
printk("\rSending compressed frame %d (size=%d bytes)\n", i++, vbuf_out->bytesused);
411+
/* Send compressed video buffer to TCP client */
412+
ret = sendall(client, vbuf_out->buffer, vbuf_out->bytesused);
292413

414+
video_enqueue(encoder_dev, vbuf_out);
415+
#else
416+
printk("\rSending frame %d\n", i++);
293417
/* Send video buffer to TCP client */
294418
ret = sendall(client, vbuf->buffer, vbuf->bytesused);
419+
#endif
295420
if (ret && ret != -EAGAIN) {
296421
/* client disconnected */
297422
printk("\nTCP: Client disconnected %d\n", ret);
@@ -307,6 +432,10 @@ int main(void)
307432
return 0;
308433
}
309434

435+
#if DT_HAS_CHOSEN(zephyr_videoenc)
436+
stop_encoder();
437+
#endif
438+
310439
/* Flush remaining buffers */
311440
do {
312441
ret = video_dequeue(video_dev, &vbuf, K_NO_WAIT);

0 commit comments

Comments
 (0)