Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * net.cpp - Camera to access images over the network 00004 * 00005 * Created: Wed Feb 01 12:24:04 2006 00006 * Copyright 2005-2008 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <fvcams/net.h> 00025 #include <fvcams/cam_exceptions.h> 00026 00027 #include <core/exception.h> 00028 #include <core/exceptions/software.h> 00029 00030 #include <fvutils/net/fuse_client.h> 00031 #include <fvutils/net/fuse_message.h> 00032 #include <fvutils/net/fuse_image_content.h> 00033 #include <fvutils/net/fuse_imagelist_content.h> 00034 #include <fvutils/system/camargp.h> 00035 #include <fvutils/compression/jpeg_decompressor.h> 00036 00037 #include <netinet/in.h> 00038 #include <cstdlib> 00039 #include <cstring> 00040 00041 using namespace fawkes; 00042 00043 namespace firevision { 00044 #if 0 /* just to make Emacs auto-indent happy */ 00045 } 00046 #endif 00047 00048 /** @class NetworkCamera <fvcams/net.h> 00049 * Network camera. 00050 * Retrieve images via network (FUSE). 00051 * @see FuseClient 00052 * @author Tim Niemueller 00053 */ 00054 00055 /** Constructor. 00056 * Allows to initiate a NetworkCamera w/o specifying an image id. This can be 00057 * done later with the set_image_id() method. 00058 * @param host host to connect to 00059 * @param port port to connect to 00060 * @param jpeg if true jpeg images will be transferred and automatically be 00061 * decompressed, otherwise raw images are transferred 00062 */ 00063 NetworkCamera::NetworkCamera(const char *host, unsigned short port, bool jpeg) 00064 { 00065 if ( host == NULL ) { 00066 throw NullPointerException("NetworkCamera: host must not be NULL"); 00067 } 00068 __image_id = 0; 00069 __host = strdup(host); 00070 __port = port; 00071 __get_jpeg = jpeg; 00072 00073 __connected = false; 00074 __opened = false; 00075 __local_version = 0; 00076 __remote_version = 0; 00077 __decompressor = NULL; 00078 __decompressed_buffer = NULL; 00079 __last_width = 0; 00080 __last_height = 0; 00081 __fuse_image = NULL; 00082 __fuse_message = NULL; 00083 __fuse_imageinfo = NULL; 00084 00085 __fusec = new FuseClient(__host, __port, this); 00086 if ( __get_jpeg ) { 00087 __decompressor = new JpegImageDecompressor(); 00088 } 00089 } 00090 00091 /** Constructor. 00092 * @param host host to connect to 00093 * @param port port to connect to 00094 * @param image_id image ID of image to retrieve 00095 * @param jpeg if true jpeg images will be transferred and automatically be 00096 * decompressed, otherwise raw images are transferred 00097 */ 00098 NetworkCamera::NetworkCamera(const char *host, unsigned short port, const char *image_id, 00099 bool jpeg) 00100 { 00101 if ( image_id == NULL ) { 00102 throw NullPointerException("NetworkCamera: image_id must not be NULL"); 00103 } 00104 if ( host == NULL ) { 00105 throw NullPointerException("NetworkCamera: host must not be NULL"); 00106 } 00107 __image_id = strdup(image_id); 00108 __host = strdup(host); 00109 __port = port; 00110 __get_jpeg = jpeg; 00111 00112 __connected = false; 00113 __opened = false; 00114 __local_version = 0; 00115 __remote_version = 0; 00116 __decompressor = NULL; 00117 __decompressed_buffer = NULL; 00118 __last_width = 0; 00119 __last_height = 0; 00120 __fuse_image = NULL; 00121 __fuse_message = NULL; 00122 __fuse_imageinfo = NULL; 00123 00124 __fusec = new FuseClient(__host, __port, this); 00125 if ( __get_jpeg ) { 00126 __decompressor = new JpegImageDecompressor(); 00127 } 00128 } 00129 00130 00131 /** Constructor. 00132 * Initialize with parameters from camera argument parser, supported values are: 00133 * - host=HOST, hostname or IP of host to connect to 00134 * - port=PORT, port number to connect to 00135 * - image=ID, image ID of image to retrieve 00136 * - jpeg=<true|false>, if true JPEGs are recieved and decompressed otherwise 00137 * raw images will be transferred (raw is the default) 00138 * @param cap camera argument parser 00139 */ 00140 NetworkCamera::NetworkCamera(const CameraArgumentParser *cap) 00141 { 00142 if ( cap->has("image") ) { 00143 __image_id = strdup(cap->get("image").c_str()); 00144 } else { 00145 throw NullPointerException("image parameter must be set"); 00146 } 00147 if ( cap->has("host") ) { 00148 __host = strdup(cap->get("host").c_str()); 00149 } else { 00150 __host = strdup("localhost"); 00151 } 00152 if ( cap->has("port") ) { 00153 int i = atoi(cap->get("port").c_str()); 00154 if ( (i < 0) || (i >= 0xFFFF) ) { 00155 throw IllegalArgumentException("Port must be in the range 0-65535"); 00156 } 00157 __port = (unsigned int)i; 00158 } else { 00159 __port = 2208; 00160 } 00161 00162 __get_jpeg = ( cap->has("jpeg") && (cap->get("jpeg") == "true")); 00163 00164 __connected = false; 00165 __opened = false; 00166 __local_version = 0; 00167 __remote_version = 0; 00168 __decompressor = NULL; 00169 __decompressed_buffer = NULL; 00170 __last_width = 0; 00171 __last_height = 0; 00172 __fuse_image = NULL; 00173 __fuse_message = NULL; 00174 __fuse_imageinfo = NULL; 00175 00176 __fusec = new FuseClient(__host, __port, this); 00177 if ( __get_jpeg ) { 00178 __decompressor = new JpegImageDecompressor(); 00179 } 00180 } 00181 00182 00183 /** Destructor. */ 00184 NetworkCamera::~NetworkCamera() 00185 { 00186 close(); 00187 delete __fusec; 00188 free(__host); 00189 free(__image_id); 00190 if ( __decompressed_buffer != NULL) free(__decompressed_buffer); 00191 delete __decompressor; 00192 } 00193 00194 00195 void 00196 NetworkCamera::open() 00197 { 00198 if ( __opened ) return; 00199 00200 __fusec->connect(); 00201 __fusec->start(); 00202 __fusec->wait_greeting(); 00203 00204 if ( __image_id) { 00205 FUSE_imagedesc_message_t *imagedesc = (FUSE_imagedesc_message_t *)calloc(1, sizeof(FUSE_imagedesc_message_t)); 00206 strncpy(imagedesc->image_id, __image_id, IMAGE_ID_MAX_LENGTH); 00207 __fusec->enqueue_and_wait(FUSE_MT_GET_IMAGE_INFO, imagedesc, sizeof(FUSE_imagedesc_message_t)); 00208 00209 if ( ! __fuse_imageinfo ) { 00210 throw Exception("Could not receive image info. Image not available?"); 00211 } 00212 } 00213 00214 __opened = true; 00215 } 00216 00217 00218 void 00219 NetworkCamera::start() 00220 { 00221 __started = true; 00222 } 00223 00224 void 00225 NetworkCamera::stop() 00226 { 00227 __started = false; 00228 } 00229 00230 00231 void 00232 NetworkCamera::print_info() 00233 { 00234 } 00235 00236 00237 void 00238 NetworkCamera::capture() 00239 { 00240 if (! __connected) { 00241 throw CaptureException("Capture failed, not connected"); 00242 } 00243 if ( __fuse_image ) { 00244 throw CaptureException("You must dispose the buffer before fetching a new image"); 00245 } 00246 if ( !__image_id ) { 00247 throw CaptureException("You must specify an image id"); 00248 } 00249 00250 FUSE_imagereq_message_t *irm = (FUSE_imagereq_message_t *)malloc(sizeof(FUSE_imagereq_message_t)); 00251 memset(irm, 0, sizeof(FUSE_imagereq_message_t)); 00252 strncpy(irm->image_id, __image_id, IMAGE_ID_MAX_LENGTH); 00253 irm->format = (__get_jpeg ? FUSE_IF_JPEG : FUSE_IF_RAW); 00254 __fusec->enqueue_and_wait(FUSE_MT_GET_IMAGE, irm, sizeof(FUSE_imagereq_message_t)); 00255 00256 if (! __connected) { 00257 throw CaptureException("Capture failed, connection died while waiting for image"); 00258 } 00259 if ( ! __fuse_image ) { 00260 throw CaptureException("Fetching the image failed, no image received"); 00261 } 00262 00263 if ( __get_jpeg ) { 00264 if ( (__fuse_image->pixel_width() != __last_width) || 00265 (__fuse_image->pixel_height() != __last_height) ) { 00266 if (__decompressed_buffer != NULL ) { 00267 free(__decompressed_buffer); 00268 } 00269 size_t buffer_size = colorspace_buffer_size(YUV422_PLANAR, __fuse_image->pixel_width(), 00270 __fuse_image->pixel_height()); 00271 __decompressed_buffer = (unsigned char *)malloc(buffer_size); 00272 __decompressor->set_decompressed_buffer(__decompressed_buffer, buffer_size); 00273 } 00274 __decompressor->set_compressed_buffer(__fuse_image->buffer(), __fuse_image->buffer_size()); 00275 __decompressor->decompress(); 00276 } 00277 } 00278 00279 00280 unsigned char * 00281 NetworkCamera::buffer() 00282 { 00283 if (__get_jpeg) { 00284 return __decompressed_buffer; 00285 } else { 00286 if ( __fuse_image ) { 00287 return __fuse_image->buffer(); 00288 } else { 00289 return NULL; 00290 } 00291 } 00292 } 00293 00294 unsigned int 00295 NetworkCamera::buffer_size() 00296 { 00297 if ( __get_jpeg ) { 00298 return colorspace_buffer_size(YUV422_PLANAR, pixel_width(), pixel_height()); 00299 } else { 00300 if (! __fuse_image) { 00301 return 0; 00302 } else { 00303 return colorspace_buffer_size((colorspace_t)__fuse_image->colorspace(), 00304 __fuse_image->pixel_width(), 00305 __fuse_image->pixel_height()); 00306 } 00307 } 00308 } 00309 00310 void 00311 NetworkCamera::close() 00312 { 00313 dispose_buffer(); 00314 if ( __started ) { 00315 stop(); 00316 } 00317 if ( __fuse_imageinfo ) { 00318 free(__fuse_imageinfo); 00319 __fuse_imageinfo = NULL; 00320 } 00321 if ( __opened ) { 00322 __fusec->disconnect(); 00323 __fusec->cancel(); 00324 __fusec->join(); 00325 __opened = false; 00326 } 00327 } 00328 00329 void 00330 NetworkCamera::dispose_buffer() 00331 { 00332 delete __fuse_image; 00333 __fuse_image = NULL; 00334 if ( __fuse_message ) { 00335 __fuse_message->unref(); 00336 __fuse_message = NULL; 00337 } 00338 } 00339 00340 unsigned int 00341 NetworkCamera::pixel_width() 00342 { 00343 if ( __fuse_imageinfo ) { 00344 return ntohl(__fuse_imageinfo->width); 00345 } else { 00346 throw NullPointerException("No valid image info received"); 00347 } 00348 } 00349 00350 unsigned int 00351 NetworkCamera::pixel_height() 00352 { 00353 if ( __fuse_imageinfo ) { 00354 return ntohl(__fuse_imageinfo->height); 00355 } else { 00356 throw NullPointerException("No valid image info received"); 00357 } 00358 } 00359 00360 fawkes::Time * 00361 NetworkCamera::capture_time() 00362 { 00363 if ( __fuse_image ) { 00364 return __fuse_image->capture_time(); 00365 } else { 00366 throw NullPointerException("No valid image exists"); 00367 } 00368 } 00369 00370 void 00371 NetworkCamera::flush() 00372 { 00373 if (! __connected) return; 00374 dispose_buffer(); 00375 } 00376 00377 00378 bool 00379 NetworkCamera::ready() 00380 { 00381 return __connected; 00382 } 00383 00384 00385 /** Select the image that is opened. 00386 * @param image_id the image id 00387 */ 00388 void 00389 NetworkCamera::set_image_id(const char *image_id) 00390 { 00391 __image_id = strdup(image_id); 00392 00393 FUSE_imagedesc_message_t *imagedesc = (FUSE_imagedesc_message_t *)calloc(1, sizeof(FUSE_imagedesc_message_t)); 00394 strncpy(imagedesc->image_id, __image_id, IMAGE_ID_MAX_LENGTH); 00395 __fusec->enqueue_and_wait(FUSE_MT_GET_IMAGE_INFO, imagedesc, sizeof(FUSE_imagedesc_message_t)); 00396 00397 if ( ! __fuse_imageinfo ) { 00398 throw Exception("Could not received image info. Image not available?"); 00399 } 00400 } 00401 00402 00403 void 00404 NetworkCamera::set_image_number(unsigned int n) 00405 { 00406 // ignored, has to go away anyway 00407 } 00408 00409 00410 colorspace_t 00411 NetworkCamera::colorspace() 00412 { 00413 if ( __get_jpeg ) { 00414 return YUV422_PLANAR; 00415 } else { 00416 if ( __fuse_imageinfo ) { 00417 return (colorspace_t)ntohs(__fuse_imageinfo->colorspace); 00418 } else { 00419 return CS_UNKNOWN; 00420 } 00421 } 00422 } 00423 00424 00425 /** List the available images. 00426 * @return a vector containing information about the available images 00427 */ 00428 std::vector<FUSE_imageinfo_t>& 00429 NetworkCamera::image_list() 00430 { 00431 __image_list.clear(); 00432 00433 if (! __connected) { 00434 throw CaptureException("Capture failed, not connected"); 00435 } 00436 00437 __fusec->enqueue_and_wait(FUSE_MT_GET_IMAGE_LIST); 00438 00439 return __image_list; 00440 } 00441 00442 00443 void 00444 NetworkCamera::fuse_invalid_server_version(uint32_t local_version, 00445 uint32_t remote_version) throw() 00446 { 00447 __local_version = local_version; 00448 __remote_version = remote_version; 00449 } 00450 00451 00452 void 00453 NetworkCamera::fuse_connection_established() throw() 00454 { 00455 __connected = true; 00456 } 00457 00458 00459 void 00460 NetworkCamera::fuse_connection_died() throw() 00461 { 00462 __connected = false; 00463 } 00464 00465 00466 void 00467 NetworkCamera::fuse_inbound_received(FuseNetworkMessage *m) throw() 00468 { 00469 switch(m->type()) { 00470 00471 case FUSE_MT_IMAGE: 00472 try { 00473 __fuse_image = m->msgc<FuseImageContent>(); 00474 if ( __fuse_image ) { 00475 __fuse_message = m; 00476 __fuse_message->ref(); 00477 } 00478 } catch (Exception &e) { 00479 __fuse_image = NULL; 00480 __fuse_message = NULL; 00481 } 00482 break; 00483 00484 00485 case FUSE_MT_IMAGE_INFO: 00486 try { 00487 __fuse_imageinfo = m->msg_copy<FUSE_imageinfo_t>(); 00488 } catch (Exception &e) { 00489 __fuse_imageinfo = NULL; 00490 } 00491 break; 00492 00493 case FUSE_MT_IMAGE_INFO_FAILED: 00494 __fuse_imageinfo = NULL; 00495 break; 00496 00497 case FUSE_MT_GET_IMAGE_FAILED: 00498 if ( __fuse_message ) { 00499 __fuse_message->unref(); 00500 } 00501 __fuse_message = NULL; 00502 __fuse_image = NULL; 00503 break; 00504 00505 case FUSE_MT_IMAGE_LIST: 00506 try { 00507 FuseImageListContent* fuse_image_list = m->msgc<FuseImageListContent>(); 00508 if (fuse_image_list ) { 00509 while ( fuse_image_list->has_next() ) { 00510 FUSE_imageinfo_t *iip = fuse_image_list->next(); 00511 FUSE_imageinfo_t ii; 00512 strncpy(ii.image_id, iip->image_id, IMAGE_ID_MAX_LENGTH); 00513 ii.colorspace = ntohs(iip->colorspace); 00514 ii.width = ntohl(iip->width); 00515 ii.height = ntohl(iip->height); 00516 ii.buffer_size = ntohl(iip->buffer_size); 00517 __image_list.push_back(ii); 00518 } 00519 } 00520 } 00521 catch (Exception &e) { 00522 } 00523 break; 00524 00525 default: 00526 break; 00527 } 00528 } 00529 00530 } // end namespace firevision