Home | History | Annotate | Download | only in highgui
      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 #define LOG_TAG "CVJNI"
     51 #define LOGV(...) __android_log_print(ANDROID_LOG_SILENT, LOG_TAG, __VA_ARGS__)
     52 
     53 #include "_highgui.h"
     54 #include <android/log.h>
     55 #include <errno.h>
     56 #include <netdb.h>
     57 #include <unistd.h>
     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:
     72     CVCapture_Socket()
     73     {
     74 		pAddrInfo = 0;
     75 		width = 0;
     76 		height = 0;
     77 		readBufSize = 0;
     78 		readBuf = 0;
     79         frame = 0;
     80     }
     81 
     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.
    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.
    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.
    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.
    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 
    277 IplImage* CVCapture_Socket::retrieveFrame()
    278 {
    279     return frame;
    280 }
    281 
    282 double CVCapture_Socket::getProperty(int id)
    283 {
    284 	LOGV("unknown/unhandled property");
    285     return 0;
    286 }
    287 
    288 bool CVCapture_Socket::setProperty(int id, double value)
    289 {
    290     LOGV("unknown/unhandled property");
    291     return false;
    292 }
    293 
    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