PageRenderTime 27ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/jni/otherlibs/highgui/cvcap_socket.cpp

http://github.com/billmccord/OpenCV-Android
C++ | 302 lines | 199 code | 39 blank | 64 comment | 29 complexity | 490794ec9ce9719960c3d8a6112ff80c MD5 | raw file
Possible License(s): BSD-3-Clause
  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. // Author: Bill McCord
  42. //
  43. // Intuitive Automata
  44. //
  45. // capture video from a socket connection
  46. //
  47. #include "_highgui.h"
  48. #include <android/log.h>
  49. #include <errno.h>
  50. #include <netdb.h>
  51. #include <unistd.h>
  52. #define LOGV(...) __android_log_print(ANDROID_LOG_SILENT, LOG_TAG, __VA_ARGS__)
  53. #define LOG_TAG "CVJNI"
  54. #ifdef NDEBUG
  55. #define CV_WARN(message)
  56. #else
  57. #define CV_WARN(message) fprintf(stderr, "warning: %s (%s:%d)\n", message, __FILE__, __LINE__)
  58. #endif
  59. #define IMAGE( i, x, y, n ) *(( unsigned char * )(( i )->imageData \
  60. + ( x ) * sizeof( unsigned char ) * 3 \
  61. + ( y ) * ( i )->widthStep ) + ( n ))
  62. class CVCapture_Socket : public CvCapture
  63. {
  64. public:
  65. CVCapture_Socket()
  66. {
  67. pAddrInfo = 0;
  68. width = 0;
  69. height = 0;
  70. readBufSize = 0;
  71. readBuf = 0;
  72. frame = 0;
  73. }
  74. virtual ~CVCapture_Socket()
  75. {
  76. close();
  77. }
  78. virtual bool open(const char* _address, const char* _port, int _width, int _height);
  79. virtual void close();
  80. virtual double getProperty(int);
  81. virtual bool setProperty(int, double);
  82. virtual bool grabFrame();
  83. virtual IplImage* retrieveFrame();
  84. protected:
  85. struct addrinfo *pAddrInfo;
  86. int width; // the width of the images received over the socket
  87. int height; // the height of the images received over the socket
  88. long readBufSize; // the length of the read buffer
  89. char *readBuf; // the read buffer
  90. IplImage* frame;
  91. };
  92. // The open method simply initializes some variables we will need later.
  93. bool CVCapture_Socket::open(const char* _address, const char* _port, int _width, int _height)
  94. {
  95. // Free the addrinfo if it was allocated.
  96. if (pAddrInfo)
  97. {
  98. freeaddrinfo(pAddrInfo);
  99. pAddrInfo = 0;
  100. }
  101. // Check the easy stuff first.
  102. width = _width;
  103. height = _height;
  104. if (width <= 0 || height <= 0)
  105. {
  106. LOGV("Invalid width or height!");
  107. return false;
  108. }
  109. // Setup a new addrinfo to support a streaming socket at the given address and port.
  110. struct addrinfo hints;
  111. memset(&hints, 0, sizeof hints);
  112. hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
  113. hints.ai_socktype = SOCK_STREAM;
  114. hints.ai_flags = AI_NUMERICHOST;
  115. int error = getaddrinfo(_address, _port, &hints, &pAddrInfo);
  116. if (error)
  117. {
  118. char buffer[100];
  119. sprintf(buffer, "getaddrinfo error: %s", gai_strerror(error));
  120. LOGV(buffer);
  121. freeaddrinfo(pAddrInfo);
  122. pAddrInfo = 0;
  123. return false;
  124. }
  125. readBufSize = width * height * sizeof(int);
  126. readBuf = (char*)malloc(readBufSize);
  127. if (!readBuf)
  128. {
  129. LOGV("out of memory error");
  130. freeaddrinfo(pAddrInfo);
  131. pAddrInfo = 0;
  132. return false;
  133. }
  134. return true;
  135. }
  136. // Close cleans up all of our state and cached data.
  137. void CVCapture_Socket::close()
  138. {
  139. LOGV("Setting simple vars to 0");
  140. width = 0;
  141. height = 0;
  142. readBufSize = 0;
  143. LOGV("Freeing Addr Info");
  144. if (pAddrInfo)
  145. {
  146. freeaddrinfo(pAddrInfo);
  147. pAddrInfo = 0;
  148. }
  149. LOGV("Freeing Buffer");
  150. if (readBuf)
  151. {
  152. free(readBuf);
  153. readBuf = 0;
  154. }
  155. LOGV("Releasing Image");
  156. if (frame)
  157. {
  158. cvReleaseImage( &frame );
  159. frame = 0;
  160. }
  161. LOGV("Done closing Capture Socket");
  162. }
  163. // Helper to load pixels from a byte stream received over a socket.
  164. static IplImage* loadPixels(char* pixels, int width, int height) {
  165. int x, y, pos, int_size = sizeof(int);
  166. IplImage *img = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 3);
  167. for ( y = 0; y < height; y++ ) {
  168. pos = y * width * int_size;
  169. for ( x = 0; x < width; x++, pos += int_size ) {
  170. // blue
  171. IMAGE( img, x, y, 0 ) = pixels[pos + 3] & 0xFF;
  172. // green
  173. IMAGE( img, x, y, 1 ) = pixels[pos + 2] & 0xFF;
  174. // red
  175. IMAGE( img, x, y, 2 ) = pixels[pos + 1] & 0xFF;
  176. }
  177. }
  178. return img;
  179. }
  180. // Grabs a frame (image) from a socket.
  181. bool CVCapture_Socket::grabFrame()
  182. {
  183. // First ensure that our addrinfo and read buffer are allocated.
  184. if (pAddrInfo == 0 || readBuf == 0)
  185. {
  186. LOGV("You haven't opened the socket capture yet!");
  187. return false;
  188. }
  189. // Establish the socket.
  190. int sockd = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, pAddrInfo->ai_protocol);
  191. if (sockd < 0 || errno != 0)
  192. {
  193. char buffer[100];
  194. sprintf(buffer, "Failed to create socket, errno = %d", errno);
  195. LOGV(buffer);
  196. ::close(sockd);
  197. return false;
  198. }
  199. // Now connect to the socket.
  200. if (connect(sockd, pAddrInfo->ai_addr, pAddrInfo->ai_addrlen) < 0 || errno != 0)
  201. {
  202. char buffer[100];
  203. sprintf(buffer, "socket connection errorno = %d", errno);
  204. LOGV(buffer);
  205. ::close(sockd);
  206. return false;
  207. }
  208. // Release the image if it hasn't been already because we are going to overwrite it.
  209. if (frame)
  210. {
  211. cvReleaseImage( &frame );
  212. frame = 0;
  213. }
  214. // Read the socket until we have filled the data with the space allocated OR run
  215. // out of data which we treat as an error.
  216. long read_count, total_read = 0;
  217. while (total_read < readBufSize)
  218. {
  219. read_count = read(sockd, &readBuf[total_read], readBufSize);
  220. if (read_count <= 0 || errno != 0)
  221. {
  222. char buffer[100];
  223. sprintf(buffer, "socket read errorno = %d", errno);
  224. LOGV(buffer);
  225. break;
  226. }
  227. total_read += read_count;
  228. }
  229. // If we read all of the data we expected, we will load the frame from the pixels.
  230. if (total_read == readBufSize)
  231. {
  232. frame = loadPixels(readBuf, width, height);
  233. }
  234. else
  235. {
  236. LOGV("full read of pixels failed");
  237. }
  238. // Close the socket and return the frame!
  239. ::close(sockd);
  240. return frame != 0;
  241. }
  242. IplImage* CVCapture_Socket::retrieveFrame()
  243. {
  244. return frame;
  245. }
  246. double CVCapture_Socket::getProperty(int id)
  247. {
  248. LOGV("unknown/unhandled property");
  249. return 0;
  250. }
  251. bool CVCapture_Socket::setProperty(int id, double value)
  252. {
  253. LOGV("unknown/unhandled property");
  254. return false;
  255. }
  256. CvCapture* cvCreateCameraCapture_Socket( const char *address, const char *port, int width, int height )
  257. {
  258. CVCapture_Socket* capture = new CVCapture_Socket;
  259. if ( capture-> open(address, port, width, height) )
  260. return capture;
  261. delete capture;
  262. return 0;
  263. }