Skip to content

Commit a0908b1

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 58daa7c commit a0908b1

File tree

2 files changed

+123
-1
lines changed

2 files changed

+123
-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: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,113 @@ static ssize_t sendall(int sock, const void *buf, size_t len)
3131
return 0;
3232
}
3333

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

357+
#if DT_HAS_CHOSEN(zephyr_videoenc)
358+
if (configure_encoder()) {
359+
LOG_ERR("Unable to configure video encoder");
360+
return 0;
361+
}
362+
#endif
363+
256364
/* Connection loop */
257365
do {
258366
printk("TCP: Waiting for client...\n");
@@ -288,10 +396,17 @@ int main(void)
288396
return 0;
289397
}
290398

291-
printk("\rSending frame %d\n", i++);
399+
#if DT_HAS_CHOSEN(zephyr_videoenc)
400+
encode_frame(vbuf, &vbuf_out);
292401

402+
printk("\rSending compressed frame %d (size=%d bytes)\n", i++, vbuf_out->bytesused);
403+
/* Send compressed video buffer to TCP client */
404+
ret = sendall(client, vbuf_out->buffer, vbuf_out->bytesused);
405+
#else
406+
printk("\rSending frame %d\n", i++);
293407
/* Send video buffer to TCP client */
294408
ret = sendall(client, vbuf->buffer, vbuf->bytesused);
409+
#endif
295410
if (ret && ret != -EAGAIN) {
296411
/* client disconnected */
297412
printk("\nTCP: Client disconnected %d\n", ret);

0 commit comments

Comments
 (0)