1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2008, Nils Hasler, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41 
42 // Author: Bill McCord
43 //
44 //         Intuitive Automata
45 
46 //
47 // capture video from a socket connection
48 //
49 
50 #include "_highgui.h"
51 #include <android/log.h>
52 #include <errno.h>
53 #include <netdb.h>
54 #include <unistd.h>
55 
56 #define LOGV(...) __android_log_print(ANDROID_LOG_SILENT, LOG_TAG, __VA_ARGS__)
57 #define LOG_TAG "CVJNI"
58 
59 #ifdef NDEBUG
60 #define CV_WARN(message)
61 #else
62 #define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
63 #endif
64 
65 #define IMAGE( i, x, y, n )   *(( unsigned char * )(( i )->imageData      \
66                                     + ( x ) * sizeof( unsigned char ) * 3 \
67                                     + ( y ) * ( i )->widthStep ) + ( n ))
68 
69 class CVCapture_Socket : public CvCapture
70 {
71 public:
CVCapture_Socket()72     CVCapture_Socket()
73     {
74 		pAddrInfo = 0;
75 		width = 0;
76 		height = 0;
77 		readBufSize = 0;
78 		readBuf = 0;
79         frame = 0;
80     }
81 
~CVCapture_Socket()82     virtual ~CVCapture_Socket()
83     {
84         close();
85     }
86 
87     virtual bool open(const char* _address, const char* _port, int _width, int _height);
88     virtual void close();
89     virtual double getProperty(int);
90     virtual bool setProperty(int, double);
91     virtual bool grabFrame();
92     virtual IplImage* retrieveFrame();
93 
94 protected:
95 	struct addrinfo *pAddrInfo;
96 	int width; // the width of the images received over the socket
97 	int height; // the height of the images received over the socket
98 	long readBufSize; // the length of the read buffer
99 	char *readBuf; // the read buffer
100 
101     IplImage* frame;
102 };
103 
104 // The open method simply initializes some variables we will need later.
open(const char * _address,const char * _port,int _width,int _height)105 bool CVCapture_Socket::open(const char* _address, const char* _port, int _width, int _height)
106 {
107 	// Free the addrinfo if it was allocated.
108 	if (pAddrInfo)
109 	{
110 		freeaddrinfo(pAddrInfo);
111 		pAddrInfo = 0;
112 	}
113 
114 	// Check the easy stuff first.
115 	width = _width;
116 	height = _height;
117 	if (width <= 0 || height <= 0)
118 	{
119 		LOGV("Invalid width or height!");
120 		return false;
121 	}
122 
123 	// Setup a new addrinfo to support a streaming socket at the given address and port.
124 	struct addrinfo hints;
125 	memset(&hints, 0, sizeof hints);
126 	hints.ai_family = AF_UNSPEC;  // use IPv4 or IPv6, whichever
127 	hints.ai_socktype = SOCK_STREAM;
128 	hints.ai_flags = AI_NUMERICHOST;
129 
130 	int error = getaddrinfo(_address, _port, &hints, &pAddrInfo);
131 	if (error)
132 	{
133 		char buffer[100];
134 		sprintf(buffer, "getaddrinfo error: %s", gai_strerror(error));
135 		LOGV("%s", buffer);
136 		freeaddrinfo(pAddrInfo);
137 		pAddrInfo = 0;
138 		return false;
139 	}
140 
141 	readBufSize = width * height * sizeof(int);
142 	readBuf = (char*)malloc(readBufSize);
143 	if (!readBuf)
144 	{
145 		LOGV("out of memory error");
146 		freeaddrinfo(pAddrInfo);
147 		pAddrInfo = 0;
148 		return false;
149 	}
150 
151 	return true;
152 }
153 
154 // Close cleans up all of our state and cached data.
close()155 void CVCapture_Socket::close()
156 {
157 	LOGV("Setting simple vars to 0");
158 	width = 0;
159 	height = 0;
160 	readBufSize = 0;
161 
162 	LOGV("Freeing Addr Info");
163 	if (pAddrInfo)
164 	{
165 		freeaddrinfo(pAddrInfo);
166 		pAddrInfo = 0;
167 	}
168 
169 	LOGV("Freeing Buffer");
170 	if (readBuf)
171 	{
172 		free(readBuf);
173 		readBuf = 0;
174 	}
175 
176 	LOGV("Releasing Image");
177 	if (frame)
178 	{
179 		cvReleaseImage( &frame );
180 		frame = 0;
181 	}
182 
183 	LOGV("Done closing Capture Socket");
184 }
185 
186 // Helper to load pixels from a byte stream received over a socket.
loadPixels(char * pixels,int width,int height)187 static IplImage* loadPixels(char* pixels, int width, int height) {
188 
189 	int x, y, pos, int_size = sizeof(int);
190 	IplImage *img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
191 
192 	for ( y = 0; y < height; y++ ) {
193 		pos = y * width * int_size;
194         for ( x = 0; x < width; x++, pos += int_size ) {
195             // blue
196             IMAGE( img, x, y, 0 ) = pixels[pos + 3] & 0xFF;
197             // green
198             IMAGE( img, x, y, 1 ) = pixels[pos + 2] & 0xFF;
199             // red
200             IMAGE( img, x, y, 2 ) = pixels[pos + 1] & 0xFF;
201         }
202     }
203 
204 	return img;
205 }
206 
207 // Grabs a frame (image) from a socket.
grabFrame()208 bool CVCapture_Socket::grabFrame()
209 {
210 	// First ensure that our addrinfo and read buffer are allocated.
211 	if (pAddrInfo == 0 || readBuf == 0)
212 	{
213 		LOGV("You haven't opened the socket capture yet!");
214 		return false;
215 	}
216 
217 	// Establish the socket.
218 	int sockd = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, pAddrInfo->ai_protocol);
219 	if (sockd < 0 || errno != 0)
220 	{
221 		char buffer[100];
222 		sprintf(buffer, "Failed to create socket, errno = %d", errno);
223 		LOGV("%s", buffer);
224 		::close(sockd);
225 		return false;
226 	}
227 
228 	// Now connect to the socket.
229 	if (connect(sockd, pAddrInfo->ai_addr, pAddrInfo->ai_addrlen) < 0 || errno != 0)
230 	{
231 		char buffer[100];
232 		sprintf(buffer, "socket connection errorno = %d", errno);
233 		LOGV("%s", buffer);
234 		::close(sockd);
235 		return false;
236 	}
237 
238 	// Release the image if it hasn't been already because we are going to overwrite it.
239 	if (frame)
240 	{
241 		cvReleaseImage( &frame );
242 		frame = 0;
243 	}
244 
245 	// Read the socket until we have filled the data with the space allocated OR run
246 	// out of data which we treat as an error.
247 	long read_count, total_read = 0;
248 	while (total_read < readBufSize)
249 	{
250 		read_count = read(sockd, &readBuf[total_read], readBufSize);
251 		if (read_count <= 0 || errno != 0)
252 		{
253 			char buffer[100];
254 			sprintf(buffer, "socket read errorno = %d", errno);
255 			LOGV("%s", buffer);
256 			break;
257 		}
258 		total_read += read_count;
259 	}
260 
261 	// If we read all of the data we expected, we will load the frame from the pixels.
262 	if (total_read == readBufSize)
263 	{
264 		frame = loadPixels(readBuf, width, height);
265 	}
266 	else
267 	{
268 		LOGV("full read of pixels failed");
269 	}
270 
271 	// Close the socket and return the frame!
272 	::close(sockd);
273 
274     return frame != 0;
275 }
276 
retrieveFrame()277 IplImage* CVCapture_Socket::retrieveFrame()
278 {
279     return frame;
280 }
281 
getProperty(int id)282 double CVCapture_Socket::getProperty(int id)
283 {
284 	LOGV("unknown/unhandled property");
285     return 0;
286 }
287 
setProperty(int id,double value)288 bool CVCapture_Socket::setProperty(int id, double value)
289 {
290     LOGV("unknown/unhandled property");
291     return false;
292 }
293 
cvCreateCameraCapture_Socket(const char * address,const char * port,int width,int height)294 CvCapture* cvCreateCameraCapture_Socket( const char *address, const char *port, int width, int height )
295 {
296 	CVCapture_Socket* capture = new CVCapture_Socket;
297 	if ( capture-> open(address, port, width, height) )
298 		return capture;
299 
300 	delete capture;
301 	return 0;
302 }
303