1 /*
2 * Copyright (c) 2019 Linaro Limited
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/device.h>
8 #include <zephyr/drivers/video.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/net/socket.h>
12
13 LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL);
14
15 #define MY_PORT 5000
16 #define MAX_CLIENT_QUEUE 1
17
sendall(int sock,const void * buf,size_t len)18 static ssize_t sendall(int sock, const void *buf, size_t len)
19 {
20 while (len) {
21 ssize_t out_len = send(sock, buf, len, 0);
22
23 if (out_len < 0) {
24 return out_len;
25 }
26 buf = (const char *)buf + out_len;
27 len -= out_len;
28 }
29
30 return 0;
31 }
32
main(void)33 int main(void)
34 {
35 struct sockaddr_in addr, client_addr;
36 socklen_t client_addr_len = sizeof(client_addr);
37 struct video_buffer *buffers[2];
38 struct video_buffer *vbuf = &(struct video_buffer){};
39 int i, ret, sock, client;
40 struct video_format fmt;
41 struct video_caps caps;
42 enum video_buf_type type = VIDEO_BUF_TYPE_OUTPUT;
43 const struct device *video_dev;
44
45 video_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_camera));
46 if (!device_is_ready(video_dev)) {
47 LOG_ERR("%s: video device not ready.", video_dev->name);
48 return 0;
49 }
50
51 /* Prepare Network */
52 (void)memset(&addr, 0, sizeof(addr));
53 addr.sin_family = AF_INET;
54 addr.sin_port = htons(MY_PORT);
55
56 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
57 if (sock < 0) {
58 LOG_ERR("Failed to create TCP socket: %d", errno);
59 return 0;
60 }
61
62 ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
63 if (ret < 0) {
64 LOG_ERR("Failed to bind TCP socket: %d", errno);
65 close(sock);
66 return 0;
67 }
68
69 ret = listen(sock, MAX_CLIENT_QUEUE);
70 if (ret < 0) {
71 LOG_ERR("Failed to listen on TCP socket: %d", errno);
72 close(sock);
73 return 0;
74 }
75
76 /* Get capabilities */
77 caps.type = type;
78 if (video_get_caps(video_dev, &caps)) {
79 LOG_ERR("Unable to retrieve video capabilities");
80 return 0;
81 }
82
83 /* Get default/native format */
84 fmt.type = type;
85 if (video_get_format(video_dev, &fmt)) {
86 LOG_ERR("Unable to retrieve video format");
87 return 0;
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 if (caps.min_line_count != LINE_COUNT_HEIGHT) {
94 LOG_ERR("Partial framebuffers not supported by this sample");
95 return 0;
96 }
97
98 /* Alloc Buffers */
99 for (i = 0; i < ARRAY_SIZE(buffers); i++) {
100 buffers[i] = video_buffer_alloc(fmt.pitch * fmt.height, K_FOREVER);
101 if (buffers[i] == NULL) {
102 LOG_ERR("Unable to alloc video buffer");
103 return 0;
104 }
105 buffers[i]->type = type;
106 }
107
108 /* Connection loop */
109 do {
110 printk("TCP: Waiting for client...\n");
111
112 client = accept(sock, (struct sockaddr *)&client_addr, &client_addr_len);
113 if (client < 0) {
114 printk("Failed to accept: %d\n", errno);
115 return 0;
116 }
117
118 printk("TCP: Accepted connection\n");
119
120 /* Enqueue Buffers */
121 for (i = 0; i < ARRAY_SIZE(buffers); i++) {
122 video_enqueue(video_dev, buffers[i]);
123 }
124
125 /* Start video capture */
126 if (video_stream_start(video_dev, type)) {
127 LOG_ERR("Unable to start video");
128 return 0;
129 }
130
131 printk("Stream started\n");
132
133 /* Capture loop */
134 i = 0;
135 vbuf->type = type;
136 do {
137 ret = video_dequeue(video_dev, &vbuf, K_FOREVER);
138 if (ret) {
139 LOG_ERR("Unable to dequeue video buf");
140 return 0;
141 }
142
143 printk("\rSending frame %d\n", i++);
144
145 /* Send video buffer to TCP client */
146 ret = sendall(client, vbuf->buffer, vbuf->bytesused);
147 if (ret && ret != -EAGAIN) {
148 /* client disconnected */
149 printk("\nTCP: Client disconnected %d\n", ret);
150 close(client);
151 }
152
153 (void)video_enqueue(video_dev, vbuf);
154 } while (!ret);
155
156 /* stop capture */
157 if (video_stream_stop(video_dev, type)) {
158 LOG_ERR("Unable to stop video");
159 return 0;
160 }
161
162 /* Flush remaining buffers */
163 do {
164 ret = video_dequeue(video_dev, &vbuf, K_NO_WAIT);
165 } while (!ret);
166
167 } while (1);
168 }
169