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