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