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