/*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to this license. // If you do not agree to this license, do not download, install, // copy or use the software. // // // Intel License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2008, Nils Hasler, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of Intel Corporation may not be used to endorse or promote products // derived from this software without specific prior written permission. // // This software is provided by the copyright holders and contributors "as is" and // any express or implied warranties, including, but not limited to, the implied // warranties of merchantability and fitness for a particular purpose are disclaimed. // In no event shall the Intel Corporation or contributors be liable for any direct, // indirect, incidental, special, exemplary, or consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. // //M*/ // Author: Bill McCord // // Intuitive Automata // // capture video from a socket connection // #define LOG_TAG "CVJNI" #define LOGV(...) __android_log_print(ANDROID_LOG_SILENT, LOG_TAG, __VA_ARGS__) #include "_highgui.h" #include <android/log.h> #include <errno.h> #include <netdb.h> #include <unistd.h> #ifdef NDEBUG #define CV_WARN(message) #else #define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__) #endif #define IMAGE( i, x, y, n ) *(( unsigned char * )(( i )->imageData \ + ( x ) * sizeof( unsigned char ) * 3 \ + ( y ) * ( i )->widthStep ) + ( n )) class CVCapture_Socket : public CvCapture { public: CVCapture_Socket() { pAddrInfo = 0; width = 0; height = 0; readBufSize = 0; readBuf = 0; frame = 0; } virtual ~CVCapture_Socket() { close(); } virtual bool open(const char* _address, const char* _port, int _width, int _height); virtual void close(); virtual double getProperty(int); virtual bool setProperty(int, double); virtual bool grabFrame(); virtual IplImage* retrieveFrame(); protected: struct addrinfo *pAddrInfo; int width; // the width of the images received over the socket int height; // the height of the images received over the socket long readBufSize; // the length of the read buffer char *readBuf; // the read buffer IplImage* frame; }; // The open method simply initializes some variables we will need later. bool CVCapture_Socket::open(const char* _address, const char* _port, int _width, int _height) { // Free the addrinfo if it was allocated. if (pAddrInfo) { freeaddrinfo(pAddrInfo); pAddrInfo = 0; } // Check the easy stuff first. width = _width; height = _height; if (width <= 0 || height <= 0) { LOGV("Invalid width or height!"); return false; } // Setup a new addrinfo to support a streaming socket at the given address and port. struct addrinfo hints; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICHOST; int error = getaddrinfo(_address, _port, &hints, &pAddrInfo); if (error) { char buffer[100]; sprintf(buffer, "getaddrinfo error: %s", gai_strerror(error)); LOGV("%s", buffer); freeaddrinfo(pAddrInfo); pAddrInfo = 0; return false; } readBufSize = width * height * sizeof(int); readBuf = (char*)malloc(readBufSize); if (!readBuf) { LOGV("out of memory error"); freeaddrinfo(pAddrInfo); pAddrInfo = 0; return false; } return true; } // Close cleans up all of our state and cached data. void CVCapture_Socket::close() { LOGV("Setting simple vars to 0"); width = 0; height = 0; readBufSize = 0; LOGV("Freeing Addr Info"); if (pAddrInfo) { freeaddrinfo(pAddrInfo); pAddrInfo = 0; } LOGV("Freeing Buffer"); if (readBuf) { free(readBuf); readBuf = 0; } LOGV("Releasing Image"); if (frame) { cvReleaseImage( &frame ); frame = 0; } LOGV("Done closing Capture Socket"); } // Helper to load pixels from a byte stream received over a socket. static IplImage* loadPixels(char* pixels, int width, int height) { int x, y, pos, int_size = sizeof(int); IplImage *img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3); for ( y = 0; y < height; y++ ) { pos = y * width * int_size; for ( x = 0; x < width; x++, pos += int_size ) { // blue IMAGE( img, x, y, 0 ) = pixels[pos + 3] & 0xFF; // green IMAGE( img, x, y, 1 ) = pixels[pos + 2] & 0xFF; // red IMAGE( img, x, y, 2 ) = pixels[pos + 1] & 0xFF; } } return img; } // Grabs a frame (image) from a socket. bool CVCapture_Socket::grabFrame() { // First ensure that our addrinfo and read buffer are allocated. if (pAddrInfo == 0 || readBuf == 0) { LOGV("You haven't opened the socket capture yet!"); return false; } // Establish the socket. int sockd = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, pAddrInfo->ai_protocol); if (sockd < 0 || errno != 0) { char buffer[100]; sprintf(buffer, "Failed to create socket, errno = %d", errno); LOGV("%s", buffer); ::close(sockd); return false; } // Now connect to the socket. if (connect(sockd, pAddrInfo->ai_addr, pAddrInfo->ai_addrlen) < 0 || errno != 0) { char buffer[100]; sprintf(buffer, "socket connection errorno = %d", errno); LOGV("%s", buffer); ::close(sockd); return false; } // Release the image if it hasn't been already because we are going to overwrite it. if (frame) { cvReleaseImage( &frame ); frame = 0; } // Read the socket until we have filled the data with the space allocated OR run // out of data which we treat as an error. long read_count, total_read = 0; while (total_read < readBufSize) { read_count = read(sockd, &readBuf[total_read], readBufSize); if (read_count <= 0 || errno != 0) { char buffer[100]; sprintf(buffer, "socket read errorno = %d", errno); LOGV("%s", buffer); break; } total_read += read_count; } // If we read all of the data we expected, we will load the frame from the pixels. if (total_read == readBufSize) { frame = loadPixels(readBuf, width, height); } else { LOGV("full read of pixels failed"); } // Close the socket and return the frame! ::close(sockd); return frame != 0; } IplImage* CVCapture_Socket::retrieveFrame() { return frame; } double CVCapture_Socket::getProperty(int id) { LOGV("unknown/unhandled property"); return 0; } bool CVCapture_Socket::setProperty(int id, double value) { LOGV("unknown/unhandled property"); return false; } CvCapture* cvCreateCameraCapture_Socket( const char *address, const char *port, int width, int height ) { CVCapture_Socket* capture = new CVCapture_Socket; if ( capture-> open(address, port, width, height) ) return capture; delete capture; return 0; }