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