| /*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 |
| // |
| |
| #include "_highgui.h" |
| #include <android/log.h> |
| #include <errno.h> |
| #include <netdb.h> |
| #include <unistd.h> |
| |
| #define LOGV(...) __android_log_print(ANDROID_LOG_SILENT, LOG_TAG, __VA_ARGS__) |
| #define LOG_TAG "CVJNI" |
| |
| #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; |
| } |