00001 /* --------------------------------------------------------------------------- 00002 Phission : 00003 Realtime Vision Processing System 00004 00005 Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu) 00006 University of Massachusetts at Lowell, 00007 Laboratory for Artificial Intelligence and Robotics 00008 00009 This file is part of Phission. 00010 00011 Phission is free software; you can redistribute it and/or modify 00012 it under the terms of the GNU Lesser General Public License as published by 00013 the Free Software Foundation; either version 2 of the License, or 00014 (at your option) any later version. 00015 00016 Phission 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 Lesser General Public License for more details. 00020 00021 You should have received a copy of the GNU Lesser General Public License 00022 along with Phission; if not, write to the Free Software 00023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00024 00025 ---------------------------------------------------------------------------*/ 00026 #ifdef HAVE_CONFIG_H 00027 #include <phissionconfig.h> 00028 #endif 00029 00030 #define phNetSource_PRINT_IMAGE_SIZE() 0 00031 #define phNetSource_USE_JITTER_SYNC() 0 00032 00033 #define VERBOSE() 0 00034 00035 /* ---------------------------------------------------------------------- */ 00036 #include <phStandard.h> 00037 #include <ImageConversions.h> 00038 00039 #include <phObject.h> 00040 #include <phMutex.h> 00041 #include <phSemaphore.h> 00042 #include <phCondition.h> 00043 #include <phRWLock.h> 00044 #include <phThread.h> 00045 #include <phList.h> 00046 #include <phTimeStamp.h> 00047 #include <phTimeInterval.h> 00048 #include <phLiveObject.h> 00049 #include <phDataObject.h> 00050 #include <phImage.h> 00051 #include <phCaptureInterface.h> 00052 #include <phImageCapture.h> 00053 00054 #include <phTimeInterval.h> 00055 #include <phSocket.h> 00056 #include <phNetSource.h> 00057 00058 #include <phError.h> 00059 #include <phMemory.h> 00060 #include <phPrint.h> 00061 00062 /* ---------------------------------------------------------------------- */ 00063 /* TODO: */ 00064 struct phNetSourceInfo_t 00065 { 00066 phSocket *m_comms; 00067 char *m_host; 00068 uint32_t m_port; 00069 /* The width,height, format and title are retreived from the server. */ 00070 uint32_t m_width; 00071 uint32_t m_height; 00072 uint32_t m_format; 00073 char *m_title; 00074 00075 int m_do_resize; 00076 int m_do_convert; 00077 }; 00078 00079 /* ---------------------------------------------------------------------- */ 00080 phNetSource::phNetSource(char *path) 00081 { 00082 phFUNCTION("phNetSource::phNetSource") 00083 00084 rc = this->lock(); 00085 phPRINT_RC(rc,NULL,"this->lock()"); 00086 00087 this->setName("phNetSource"); 00088 00089 this->m_info = (struct phNetSourceInfo_t *)phCalloc(1, 00090 sizeof(struct phNetSourceInfo_t)); 00091 phPRINT_PTR(this->m_info,"phCalloc", 00092 "phCalloc failed to alloc phNetSourceInfo"); 00093 this->m_info->m_host = NULL; 00094 this->m_info->m_port = 0; 00095 this->m_info->m_comms = NULL; 00096 this->m_info->m_width = 0; 00097 this->m_info->m_height = 0; 00098 this->m_info->m_format = phImageNOFORMAT; 00099 this->m_info->m_title = NULL; 00100 this->m_info->m_do_resize = 0; 00101 this->m_info->m_do_convert = 0; 00102 00103 this->m_orig_format = phImageNOFORMAT; 00104 this->m_orig_height = 0; 00105 this->m_orig_width = 0; 00106 this->m_orig_size = 0; 00107 00108 this->m_is_open = 0; 00109 00110 this->m_type = phNetTypeTCP; 00111 this->m_temp_path = NULL; 00112 00113 this->m_connected_type = phNetTypeUNKNOWN; 00114 00115 this->m_reconnect = 1; 00116 this->m_server_wait = 1; 00117 00118 if (path != NULL) 00119 { 00120 this->setPath(path); 00121 } 00122 else 00123 { 00124 this->setPath("tcp://localhost:22345"); 00125 } 00126 00127 /* This applies the default (1) picture/image settings[w,h,format,etc.] 00128 * (2) channel settings */ 00129 this->applySettings(); 00130 00131 /* opening the device must be explicitly done */ 00132 /* capturing must be explicitly done. */ 00133 #if 0 00134 error: 00135 #endif 00136 rc = this->unlock(); 00137 phPRINT_RC(rc,NULL,"this->unlock()"); 00138 00139 return; 00140 } 00141 00142 /* ---------------------------------------------------------------------- */ 00143 phNetSource::~phNetSource () 00144 { 00145 phFUNCTION("phNetSource::~phNetSource") 00146 00147 rc = this->lock(); 00148 phPRINT_RC(rc,NULL,"this->lock()"); 00149 00150 if (this->isRunning()) 00151 { 00152 rc = this->stop(); 00153 phPRINT_RC(rc,NULL,"this->stop()"); 00154 } 00155 00156 if (this->isOpen()) 00157 { 00158 rc = this->close(); 00159 phPRINT_RC(rc,NULL,"this->close()"); 00160 } 00161 00162 phFree(this->m_info); 00163 00164 rc = this->unlock(); 00165 phPRINT_RC(rc,NULL,"this->unlock()"); 00166 } 00167 00168 /* ---------------------------------------------------------------------- */ 00169 int phNetSource::parsePath( const char *path, 00170 char **host_ptr, 00171 uint32_t *port_ptr, 00172 uint32_t *type_ptr ) 00173 { 00174 phFUNCTION("phNetSource::parsePath") 00175 00176 uint32_t i = 0; 00177 uint32_t type = phNetTypeTCP; 00178 uint32_t port = 22345; 00179 char *host = NULL; 00180 int32_t host_start = 0; 00181 uint32_t host_length = 0; 00182 uint32_t host_ptr_length = 0; 00183 uint32_t length = (uint32_t)((path != NULL) ? strlen(path) : 0); 00184 00185 /* Find the first ':' */ 00186 for (i = 0; ((i < length) && (path[i] != ':')); i++ ); 00187 00188 if (i >= length) 00189 { 00190 phCHECK_RC(-1,NULL,"Invalid path string: %s", path); 00191 } 00192 00193 if (strncmp("tcp",&(path[0]),i) == 0) 00194 { 00195 type = phNetTypeTCP; 00196 } 00197 else 00198 { 00199 type = phNetTypeUNKNOWN; 00200 } 00201 00202 /* Go past the "//" to the host */ 00203 for (i++; ((i < length) && (path[i] != '/')); i++ ); 00204 for (i++; ((i < length) && (path[i] != '/')); i++ ); 00205 00206 if (i >= length) 00207 { 00208 phCHECK_RC(-1,NULL,"Invalid path string: %s", path); 00209 } 00210 00211 /* Parse out the host */ 00212 for (i++, host_start = i, host_length = 0; 00213 ((i < length) && (path[(i > 0) ? i - 1 : 0] != ':')); 00214 i++, host_length++ ); 00215 00216 if ((i >= length) || (host_length <= 0)) 00217 { 00218 phCHECK_RC(-1,NULL,"Invalid path string: %s", path); 00219 } 00220 00221 host = (char *)phCalloc((host_length + 1),sizeof(char)); 00222 phCHECK_PTR(host,"phCalloc", 00223 "phCalloc failed to allocate host string buffer of length %d", 00224 host_length ); 00225 00226 #if defined(HAVE_SNPRINTF) 00227 snprintf(host,host_length,"%s",&(path[host_start])); 00228 #else 00229 sprintf(host,"%s",&(path[host_start])); 00230 #endif 00231 00232 /* Get the port from the end of the line */ 00233 port = atoi(&(path[i])); 00234 00235 if (host_ptr != NULL) 00236 { 00237 /* Figure out the path length */ 00238 host_ptr_length = (uint32_t)((*host_ptr) != NULL ? strlen(*host_ptr) : 0); 00239 00240 /* allocate enough space for the path */ 00241 phDALLOC((*host_ptr),host_ptr_length,(host_length+1),char); 00242 00243 #if defined(HAVE_SNPRINTF) 00244 snprintf(*host_ptr,host_length+1,"%s",host); 00245 #else 00246 sprintf(*host_ptr,"%s",host); 00247 #endif 00248 } 00249 00250 /* Assign the values through the return pointers */ 00251 if (type_ptr != NULL) 00252 *type_ptr = type; 00253 if (port_ptr != NULL) 00254 *port_ptr = port; 00255 00256 phFree(host); 00257 00258 //phPRINT("-%s:%d-\n",(*host_ptr),(*port_ptr)); 00259 00260 return phSUCCESS; 00261 error: 00262 phFree(host); 00263 00264 return phFAIL; 00265 } 00266 00267 /* ---------------------------------------------------------------------- */ 00268 /* makePath : 00269 * 00270 * This function allocates space to *path, be sure to free it */ 00271 /* ---------------------------------------------------------------------- */ 00272 int phNetSource::makePath( const char *host, 00273 uint32_t port, 00274 uint32_t type, 00275 char **path ) 00276 { 00277 phFUNCTION("phNetSource::makePath") 00278 00279 uint32_t pathLength = 0; 00280 uint32_t length = 0; 00281 uint32_t host_length = 0; 00282 uint32_t type_length = 0; 00283 char * type_string = NULL; 00284 00285 if (path == NULL) return phFAIL; 00286 00287 /* Default to the local machine */ 00288 if (host == NULL) 00289 { 00290 host = "localhost"; 00291 } 00292 host_length = (uint32_t)strlen(host); 00293 00294 /* make sure the path is valid */ 00295 port = (port != 0) ? ((port < 65535) ? port : 22345) : 22345; 00296 00297 /* Set up the type string */ 00298 switch (type) 00299 { 00300 case phNetTypeTCP: 00301 default: 00302 type_string = "tcp://"; 00303 break; 00304 } 00305 type_length = (uint32_t)strlen(type_string); 00306 00307 length = type_length + host_length + 1 + 7; 00308 00309 /* Figure out the path length */ 00310 pathLength = (uint32_t)((*path) != NULL ? strlen(*path) : 0); 00311 00312 /* allocate enough space for the path */ 00313 phDALLOC((*path),pathLength,length,char); 00314 00315 sprintf(*path,"%s%s:%u", 00316 type_string, 00317 host, 00318 port ); 00319 return phSUCCESS; 00320 error: 00321 return phFAIL; 00322 } 00323 /* ---------------------------------------------------------------------- */ 00324 int phNetSource::setHost( const char *host ) 00325 { 00326 phFUNCTION("phNetSource::setHost") 00327 int locked = 0; 00328 00329 phTHIS_LOCK(locked); 00330 00331 rc = phNetSource::makePath( host, 00332 this->m_info->m_port, 00333 this->m_type, 00334 &this->m_temp_path); 00335 phCHECK_RC(rc,NULL,"phNetSource::makePath"); 00336 00337 rc = this->setPath(this->m_temp_path); 00338 phCHECK_RC(rc,NULL,"this->setPath(%s)",this->m_temp_path); 00339 00340 phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL); 00341 } 00342 00343 /* ---------------------------------------------------------------------- */ 00344 const char *phNetSource::getHost( ) 00345 { 00346 phFUNCTION("phNetSource::getHost") 00347 int locked = 0; 00348 char *retval = NULL; 00349 00350 phTHIS_LOCK(locked); 00351 00352 retval = this->m_info->m_host; 00353 00354 phTHIS_UNLOCK_RET(locked,((const char *)retval),NULL); 00355 } 00356 00357 /* ---------------------------------------------------------------------- */ 00358 int phNetSource::setPort( uint32_t port ) 00359 { 00360 phFUNCTION("phNetSource::setPort") 00361 int locked = 0; 00362 00363 phTHIS_LOCK(locked); 00364 00365 rc = phNetSource::makePath( this->m_info->m_host, 00366 port, 00367 this->m_type, 00368 &this->m_temp_path); 00369 phCHECK_RC(rc,NULL,"phNetSource::makePath"); 00370 00371 rc = this->setPath(this->m_temp_path); 00372 phCHECK_RC(rc,NULL,"this->setPath(%s)",this->m_temp_path); 00373 00374 phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL); 00375 } 00376 00377 /* ---------------------------------------------------------------------- */ 00378 uint32_t phNetSource::getPort( ) 00379 { 00380 phFUNCTION("phNetSource::getPort") 00381 int locked = 0; 00382 uint32_t retval = 0; 00383 00384 phTHIS_LOCK(locked); 00385 00386 retval = this->m_info->m_port; 00387 00388 phTHIS_UNLOCK_RET(locked,retval,0); 00389 } 00390 00391 /* ---------------------------------------------------------------------- */ 00392 int phNetSource::setReconnect( int reconnect ) 00393 { 00394 phFUNCTION("phNetSource::setReconnect") 00395 int locked = 0; 00396 00397 phTHIS_LOCK(locked); 00398 00399 this->m_reconnect = reconnect; 00400 00401 phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL); 00402 } 00403 00404 /* ---------------------------------------------------------------------- */ 00405 int phNetSource::getReconnect( ) 00406 { 00407 phFUNCTION("phNetSource::getReconnect") 00408 int locked = 0; 00409 int retval = 0; 00410 00411 phTHIS_LOCK(locked); 00412 00413 retval = this->m_reconnect; 00414 00415 phTHIS_UNLOCK_RET(locked,retval,0); 00416 } 00417 00418 /* ---------------------------------------------------------------------- */ 00419 int phNetSource::setServerWait( int wait ) 00420 { 00421 phFUNCTION("phNetSource::setServerWait") 00422 int locked = 0; 00423 00424 phTHIS_LOCK(locked); 00425 00426 this->m_server_wait = wait; 00427 00428 phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL); 00429 } 00430 00431 /* ---------------------------------------------------------------------- */ 00432 int phNetSource::getServerWait( ) 00433 { 00434 phFUNCTION("phNetSource::getServerWait") 00435 int locked = 0; 00436 int retval = 0; 00437 00438 phTHIS_LOCK(locked); 00439 00440 retval = this->m_server_wait; 00441 00442 phTHIS_UNLOCK_RET(locked,retval,0); 00443 } 00444 00445 /* ---------------------------------------------------------------------- */ 00446 int phNetSource::setOriginalSize( ) 00447 { 00448 phFUNCTION("phNetSource::setOriginalSize") 00449 00450 rc = this->m_settings_lock.lock(); 00451 phPRINT_RC(rc,NULL,"this->m_settings_lock.lock() failed"); 00452 00453 this->m_info->m_do_resize = 0; 00454 00455 rc = this->m_settings_lock.unlock(); 00456 phPRINT_RC(rc,NULL,"this->m_settings_lock.unlock() failed"); 00457 00458 return phSUCCESS; 00459 } 00460 00461 /* ---------------------------------------------------------------------- */ 00462 int phNetSource::setOriginalFormat( ) 00463 { 00464 phFUNCTION("phNetSource::setOriginalFormat") 00465 00466 rc = this->m_settings_lock.lock(); 00467 phPRINT_RC(rc,NULL,"this->m_settings_lock.lock() failed"); 00468 00469 this->m_info->m_do_convert = 0; 00470 00471 rc = this->m_settings_lock.unlock(); 00472 phPRINT_RC(rc,NULL,"this->m_settings_lock.unlock() failed"); 00473 00474 return phSUCCESS; 00475 } 00476 00477 /* ---------------------------------------------------------------------- */ 00478 int phNetSource::setOriginal( ) 00479 { 00480 phFUNCTION("phNetSource::setOriginal") 00481 00482 rc = this->m_settings_lock.lock(); 00483 phPRINT_RC(rc,NULL,"this->m_settings_lock.lock() failed"); 00484 00485 this->m_info->m_do_convert = 0; 00486 this->m_info->m_do_resize = 0; 00487 00488 rc = this->m_settings_lock.unlock(); 00489 phPRINT_RC(rc,NULL,"this->m_settings_lock.unlock() failed"); 00490 00491 return phSUCCESS; 00492 } 00493 00494 /* ---------------------------------------------------------------------- */ 00495 int phNetSource::getOriginal( uint32_t *format, 00496 uint32_t *height, 00497 uint32_t *width, 00498 uint32_t *size ) 00499 { 00500 phFUNCTION("phNetSource::getOriginal") 00501 int locked = 0; 00502 00503 phMUTEX_LOCK(this->m_orig_lock,locked); 00504 00505 if (format != NULL) 00506 *format = this->m_orig_format; 00507 if (height != NULL) 00508 *height = this->m_orig_height; 00509 if (width != NULL) 00510 *width = this->m_orig_width; 00511 if (size != NULL) 00512 *size = this->m_orig_size; 00513 00514 phMUTEX_UNLOCK_RET(this->m_orig_lock,locked,phSUCCESS,phFAIL); 00515 } 00516 00517 /* ---------------------------------------------------------------------- */ 00518 uint32_t phNetSource::getOriginalFormat() 00519 { 00520 phFUNCTION("phNetSource::getOriginalFormat") 00521 int locked = 0; 00522 uint32_t retval = 0; 00523 00524 phMUTEX_LOCK(this->m_orig_lock,locked); 00525 00526 retval = this->m_orig_format; 00527 00528 phMUTEX_UNLOCK_RET(this->m_orig_lock,locked,retval,0); 00529 } 00530 00531 /* ---------------------------------------------------------------------- */ 00532 uint32_t phNetSource::getOriginalHeight() 00533 { 00534 phFUNCTION("phNetSource::getOriginalHeight") 00535 int locked = 0; 00536 uint32_t retval = 0; 00537 00538 phMUTEX_LOCK(this->m_orig_lock,locked); 00539 00540 retval = this->m_orig_height; 00541 00542 phMUTEX_UNLOCK_RET(this->m_orig_lock,locked,retval,0); 00543 } 00544 00545 /* ---------------------------------------------------------------------- */ 00546 uint32_t phNetSource::getOriginalWidth() 00547 { 00548 phFUNCTION("phNetSource::getOriginalWidth") 00549 int locked = 0; 00550 uint32_t retval = 0; 00551 00552 phMUTEX_LOCK(this->m_orig_lock,locked); 00553 00554 retval = this->m_orig_width; 00555 00556 phMUTEX_UNLOCK_RET(this->m_orig_lock,locked,retval,0); 00557 } 00558 00559 /* ---------------------------------------------------------------------- */ 00560 uint32_t phNetSource::getOriginalSize() 00561 { 00562 phFUNCTION("phNetSource::getOriginalSize") 00563 int locked = 0; 00564 uint32_t retval = 0; 00565 00566 phMUTEX_LOCK(this->m_orig_lock,locked); 00567 00568 retval = this->m_orig_size; 00569 00570 phMUTEX_UNLOCK_RET(this->m_orig_lock,locked,retval,0); 00571 } 00572 00573 /* ---------------------------------------------------------------------- */ 00574 const char *phNetSource::getTitle() 00575 { 00576 return (const char *)this->m_info->m_title; 00577 } 00578 00579 /* ---------------------------------------------------------------------- */ 00580 int phNetSource::resetDimensions( ) 00581 { 00582 phFUNCTION("phNetSource::resetDimensions") 00583 int locked = 0; 00584 int mlocked = 0; 00585 00586 phTHIS_LOCK(locked); 00587 phMUTEX_LOCK(this->m_orig_lock,mlocked); 00588 00589 rc = this->set( this->m_orig_width, 00590 this->m_orig_height, 00591 NULL,-1,-1,-1,-1,-1,-1, 00592 this->m_orig_format); 00593 phCHECK_RC(rc,NULL,"this->set(%d,%d,NULL,-1,-1,-1,-1,-1,-1,%s)", 00594 this->m_orig_width,this->m_orig_height, 00595 phImageFormatToString(this->m_orig_format)); 00596 00597 phMUTEX_UNLOCK(this->m_orig_lock,mlocked); 00598 phTHIS_UNLOCK(locked); 00599 00600 return phSUCCESS; 00601 error: 00602 phMUTEX_ERROR_UNLOCK(this->m_orig_lock,mlocked); 00603 phTHIS_ERROR_UNLOCK(locked); 00604 00605 return phFAIL; 00606 } 00607 00608 /* ---------------------------------------------------------------------- */ 00609 int phNetSource::onApplySettings() 00610 { 00611 phFUNCTION("phNetSource::onApplySettings") 00612 int retrc = phSUCCESS; 00613 00614 uint32_t i = 0; 00615 00616 int ch_init = 0; 00617 int ch_b = 0; 00618 int ch_hue = 0; 00619 int ch_color = 0; 00620 int ch_con = 0; 00621 int ch_white = 0; 00622 int ch_channel = 0; 00623 int ch_h = 0; 00624 int ch_w = 0; 00625 int ch_f = 0; 00626 int ch_p = 0; 00627 00628 ch_init = ph_int32_array_find(this->m_changed_array, phCHANGE_INIT,NULL); 00629 /* 00630 * this->m_changed_array contains the list of changes that are to 00631 * be applied. 00632 * 00633 * This method will call phImageCapture::onApplySettings which will empty 00634 * the array so that settings are applied only once. 00635 */ 00636 00637 #if 0 00638 /* Copy the image settings into the V4L structure */ 00639 ch_b = ph_int32_array_find(this->m_changed_array, phCHANGE_BRIGHTNESS, 00640 NULL); 00641 ch_hue = ph_int32_array_find(this->m_changed_array, phCHANGE_HUE, 00642 NULL); 00643 ch_color = ph_int32_array_find(this->m_changed_array, phCHANGE_COLOR, 00644 NULL); 00645 ch_con = ph_int32_array_find(this->m_changed_array, phCHANGE_CONTRAST, 00646 NULL); 00647 ch_white = ph_int32_array_find(this->m_changed_array, phCHANGE_WHITENESS, 00648 NULL); 00649 if (ch_init > 0) ch_b = ch_hue = ch_color = ch_con = ch_white = 1; 00650 if ((ch_b > 0) || (ch_hue > 0) || (ch_color > 0) || 00651 (ch_con > 0) || (ch_white > 0)) 00652 { 00653 } 00654 00655 /*--------------------------------------------------------------------* 00656 * From linux/Documentation/video4linux/API.html: 00657 * 00658 * "Each channel can be queries with the VIDIOCGCHAN ioctl call. 00659 * Before invoking this function the caller must set the channel 00660 * field to the channel that is being queried. On return the 00661 * struct video_channel is filled in with information about the 00662 * nature of the channel itself." 00663 *--------------------------------------------------------------------*/ 00664 ch_channel = ph_int32_array_find(this->m_changed_array,phCHANGE_CHANNEL, 00665 NULL); 00666 if ((ch_channel > 0) || (ch_init > 0)) 00667 { 00668 } 00669 /* else, the channel is < 0 or the current chn # */ 00670 #endif 00671 00672 /* settings that require the capture to not be in progress for the 00673 * phNetSource settings changes to be applied */ 00674 ch_h = ph_int32_array_find(this->m_changed_array, phCHANGE_HEIGHT, NULL); 00675 ch_w = ph_int32_array_find(this->m_changed_array, phCHANGE_WIDTH, NULL); 00676 ch_f = ph_int32_array_find(this->m_changed_array, phCHANGE_FORMAT, NULL); 00677 00678 /* We need to check the width and height settings before we force them to be 00679 * true. 00680 * 00681 * The image coming from the server can't explicitly have it's size set. 00682 * 00683 * Instead we resize the image that is received from the server using the 00684 * class's width and height settings. 00685 * 00686 * If the setSize/setHeight/setWidth method is called, then the image will 00687 * be resized from the original width and height to the new width and 00688 * height. 00689 */ 00690 if (ch_w || ch_h) 00691 { 00692 phPROGRESS("\n"); 00693 this->m_info->m_do_resize = 1; 00694 } 00695 if (ch_f) 00696 { 00697 this->m_info->m_do_convert = 1; 00698 } 00699 00700 if (ch_init > 0) ch_h = ch_w = ch_f = 1; 00701 00702 /* update internal information when the path is given */ 00703 /* Only do this when the thread isn't running and the stream isn't open */ 00704 ch_p = ph_int32_array_find(this->m_changed_array, phCHANGE_PATH, NULL); 00705 /* 00706 i = ph_int32_array_get_length(this->m_changed_array); 00707 phPROGRESS("ch_p:%d ch_init:%d running:%d open:%d length:%u\n", 00708 ch_p,ch_init,this->isRunning(),this->m_is_open,i); 00709 */ 00710 /* 00711 if ((ch_init) && (!this->isRunning())) 00712 { 00713 this->m_user_dimensions = 0; 00714 } 00715 */ 00716 00717 /* These checks prevent changing the path while the thread is active */ 00718 if (((ch_p > 0) || (ch_init > 0)) && 00719 ((!(this->isRunning())) && (!(this->m_is_open)))) 00720 { 00721 rc = phNetSource::parsePath(this->getPath(), 00722 &this->m_info->m_host, 00723 &this->m_info->m_port, 00724 &this->m_type); 00725 phPRINT_RC(rc,NULL,"phNetSource::parsePath"); 00726 retrc = 1; 00727 } 00728 00729 rc = this->phImageCapture::onApplySettings(); 00730 phCHECK_RC(rc,NULL,"this->phImageCapture::onApplySettings() failed."); 00731 00732 return retrc; 00733 error: 00734 00735 return phFAIL; 00736 } 00737 00738 /* ---------------------------------------------------------------------- */ 00739 int phNetSource::open(char *path) 00740 { 00741 phFUNCTION("phNetSource::open") 00742 00743 int locked = 0; 00744 00745 phTHIS_LOCK(locked); 00746 00747 /* device is already open, close it */ 00748 if (this->isOpen()) 00749 { 00750 rc = this->close(); 00751 phPRINT_RC(rc,NULL,"this->close()"); 00752 } 00753 00754 if (path != NULL) 00755 { 00756 rc = this->setPath( path ); 00757 phPRINT_RC(rc,NULL,"this->setPath( path:%s )",path); 00758 } 00759 00760 if (!this->isOpen()) 00761 { 00762 rc = phNetSource::parsePath(path == NULL ? this->getPath() : path, 00763 &this->m_info->m_host, 00764 &this->m_info->m_port, 00765 &this->m_type); 00766 phPRINT_RC(rc,NULL,"phNetSource::parsePath"); 00767 /* Try to apply all the settings to the V4L device */ 00768 ph_int32_array_append(this->m_changed_array,phCHANGE_INIT); 00769 this->applySettings(); 00770 00771 this->m_is_open = 1; 00772 00773 this->connect( false ); 00774 } 00775 00776 phTHIS_UNLOCK(locked); 00777 00778 return phSUCCESS; 00779 error: 00780 00781 phTHIS_ERROR_UNLOCK(locked); 00782 00783 return phFAIL; 00784 } 00785 00786 /* ---------------------------------------------------------------------- */ 00787 int phNetSource::isOpen() 00788 { 00789 return ((this->m_is_open > 0) ? 1 : 0); 00790 } 00791 00792 /* ---------------------------------------------------------------------- */ 00793 int phNetSource::isConnected() 00794 { 00795 phFUNCTION("phNetSource::isConnected") 00796 int locked = 0; 00797 int retrc = 0; 00798 00799 phTHIS_LOCK(locked); 00800 00801 if (this->m_info != NULL) 00802 { 00803 if (this->m_connected_type == phNetTypeTCP) 00804 { 00805 if (this->m_info->m_comms->isConnected()) retrc = 1; 00806 } 00807 } 00808 00809 phTHIS_UNLOCK_RET(locked,retrc,phFAIL); 00810 } 00811 00812 00813 /* ---------------------------------------------------------------------- */ 00814 int phNetSource::close() 00815 { 00816 phFUNCTION("phNetSource::close") 00817 int locked = 0; 00818 00819 phTHIS_LOCK(locked); 00820 00821 if (this->isRunning()) 00822 { 00823 rc = this->stop(); 00824 phPRINT_RC(rc,NULL,"this->stop()"); 00825 } 00826 00827 if (this->m_is_open) 00828 { 00829 rc = this->disconnect(); 00830 phCHECK_RC(rc,NULL,"this->disconnect"); 00831 00832 this->m_is_open = 0; 00833 } 00834 00835 phTHIS_UNLOCK_RET(locked,phSUCCESS,phFAIL); 00836 } 00837 00838 /* ---------------------------------------------------------------------- */ 00839 int phNetSource::connect( bool poll ) 00840 { 00841 phFUNCTION("phNetSource::connect") 00842 int locked = 0; 00843 int retrc = phSUCCESS; 00844 00845 phTHIS_LOCK(locked); 00846 00847 if (this->m_is_open && (!this->isConnected())) 00848 { 00849 if (this->m_type == phNetTypeTCP) 00850 { 00851 this->m_connected_type = phNetTypeTCP; 00852 00853 if (this->m_info->m_comms != NULL) 00854 { 00855 phDelete(this->m_info->m_comms); 00856 } 00857 this->m_info->m_comms = new phSocket(); 00858 this->m_info->m_comms->setWarningLevel(0); 00859 00860 rc = this->tcp_connect(this->m_info->m_comms, 00861 poll, 00862 this->m_info->m_host, 00863 this->m_info->m_port, 00864 &(this->m_info->m_width), 00865 &(this->m_info->m_height), 00866 &(this->m_info->m_format), 00867 &(this->m_info->m_title) 00868 ); 00869 retrc = rc; 00870 /*phCHECK_RC(rc,NULL,"this->tcp_connect()");*/ 00871 } 00872 } 00873 00874 phTHIS_UNLOCK_RET(locked,retrc,phFAIL); 00875 } 00876 00877 /* ---------------------------------------------------------------------- */ 00878 int phNetSource::getNextFrame(phImage *image, 00879 uint8_t **image_buf, 00880 uint32_t *image_size ) 00881 { 00882 phFUNCTION("phNetSource::getNextFrame") 00883 int locked = 0; 00884 00885 phTHIS_LOCK(locked); 00886 00887 if (this->m_is_open && (this->isConnected())) 00888 { 00889 if (this->m_connected_type == phNetTypeTCP) 00890 { 00891 /* Get the next buffer */ 00892 /* Get next frame */ 00893 rc = this->tcp_recv(this->m_info->m_comms, 00894 image, 00895 &this->m_info->m_width, 00896 &this->m_info->m_height, 00897 &this->m_info->m_format, 00898 image_buf, 00899 image_size); 00900 phSocket_CHECK_RC(rc,NULL,"this->tcp_recv"); 00901 } 00902 } 00903 phTHIS_UNLOCK_RET(locked,phSUCCESS,rc); 00904 } 00905 /* ---------------------------------------------------------------------- */ 00906 int phNetSource::disconnect( ) 00907 { 00908 phFUNCTION("phNetSource::disconnect") 00909 int locked = 0; 00910 int retrc = phSUCCESS; 00911 00912 phTHIS_LOCK(locked); 00913 00914 if (this->m_is_open && (this->isConnected())) 00915 { 00916 if (this->m_connected_type == phNetTypeTCP) 00917 { 00918 rc = this->tcp_disconnect( this->m_info->m_comms ); 00919 phCHECK_RC(rc,NULL,"this->tcp_disconnect()"); 00920 } 00921 00922 this->m_connected_type = phNetTypeUNKNOWN; 00923 } 00924 00925 phTHIS_UNLOCK_RET(locked,retrc,phFAIL); 00926 } 00927 00928 /* ------------------------------------------------------------------------- */ 00929 int phNetSource::tcp_connect( phSocket *comms, 00930 bool poll, 00931 char *host, 00932 uint32_t port, 00933 uint32_t *w, 00934 uint32_t *h, 00935 uint32_t *f, 00936 char **title ) 00937 { 00938 phFUNCTION("phNetSource::tcp_connect") 00939 int failrc = phFAIL; 00940 00941 char *serverTitle = NULL; 00942 00943 /* 00944 phPROGRESS("Attempting to connect to server - %s:%d\n", 00945 host,port ); 00946 */ 00947 /* connect to the server */ 00948 rc = comms->connect(host, port, poll); 00949 if (!comms->isConnected() || (rc != 0)) 00950 { 00951 failrc = rc; 00952 goto error; 00953 } 00954 /*phCHECK_RC(rc,NULL,"Failed to connect to %s\n\n", host);*/ 00955 00956 /* 00957 phPROGRESS("Connected to server (rc:%d connected:%d)- %s:%d\n", 00958 rc,comms->isConnected(),host,port ); 00959 */ 00960 rc = this->tcp_init(comms,&serverTitle,w,h,f); 00961 phCHECK_RC(rc,NULL,"tcp_init"); 00962 00963 phFree(*title); 00964 00965 (*title) = (char *)phCalloc(strlen(serverTitle) + 00966 strlen(host) + 00967 255, 00968 sizeof(char)); 00969 phCHECK_NULLPTR(title,"phCalloc","phCalloc failed to allocate title."); 00970 00971 sprintf((*title),"%s:%d - %s", 00972 host, 00973 port, 00974 serverTitle ); 00975 00976 phFree(serverTitle); 00977 00978 return phSUCCESS; 00979 error: 00980 phFree(serverTitle); 00981 return failrc; 00982 } 00983 00984 /* ------------------------------------------------------------------------- */ 00985 int phNetSource::tcp_init( phSocket *comms, 00986 char **title, 00987 uint32_t *w, 00988 uint32_t *h, 00989 uint32_t *f ) 00990 { 00991 phFUNCTION("phNetSource::tcp_init") 00992 00993 uint32_t width = 0; 00994 uint32_t height = 0; 00995 uint32_t format = phImageNOFORMAT; 00996 uint32_t titleSize = 0; 00997 uint32_t next_image = 0xaaaa; 00998 00999 rc = comms->recv_uint32(&titleSize); 01000 phSocket_CHECK_RC(rc,NULL,"Failed to receive title size\n\n"); 01001 01002 phFree(*title); 01003 01004 *title = (char *)phMalloc(titleSize+5); 01005 phCHECK_NULLPTR(*title,"phMalloc","phMalloc failed to allocate the title space."); 01006 phMemset(*title,0,titleSize+5); 01007 01008 rc = comms->recv(*title, titleSize); 01009 DEBUG_PRINT("title:%s\n",*title); 01010 phSocket_CHECK_RC(rc,NULL,"Failed to receive title size\n\n"); 01011 01012 /* receive image dimensions from server */ 01013 rc = comms->recv_uint32(&width); 01014 phSocket_CHECK_RC(rc,NULL,"Failed to receive image dimensions(width)\n\n"); 01015 01016 rc = comms->recv_uint32(&height); 01017 phSocket_CHECK_RC(rc,NULL,"Failed to receive image dimensions(height)\n\n"); 01018 01019 rc = comms->recv_uint32(&format); 01020 phSocket_CHECK_RC(rc,NULL,"Failed to receive image format \n\n"); 01021 01022 *w = width; 01023 *h = height; 01024 *f = format; 01025 01026 return phSUCCESS; 01027 01028 error: 01029 return rc; 01030 } 01031 01032 /* ------------------------------------------------------------------------- */ 01033 int phNetSource::tcp_recv( phSocket *comms, 01034 phImage *inputImage, 01035 uint32_t *w, 01036 uint32_t *h, 01037 uint32_t *f, 01038 uint8_t **data, 01039 uint32_t *data_size 01040 ) 01041 { 01042 phFUNCTION("phNetSource::tcp_recv") 01043 01044 uint32_t width = 0; 01045 uint32_t height = 0; 01046 uint32_t format = (uint32_t)phImageNOFORMAT; 01047 uint32_t size = 0; 01048 01049 phTimeStamp time_start; 01050 phTimeStamp time_stop; 01051 uint32_t host_send_time = 0; 01052 int32_t packet_id = 0xaaaa; 01053 01054 time_start.stamp(); 01055 01056 /* receive image dimensions from server */ 01057 rc = comms->recv_uint32(&width); 01058 phSocket_CHECK_RC(rc,NULL,"Failed to receive image dimensions(width)\n\n"); 01059 //phPRINT("w:%u\n",width); 01060 01061 rc = comms->recv_uint32(&height); 01062 phSocket_CHECK_RC(rc,NULL,"Failed to receive image dimensions(height)\n\n"); 01063 //phPRINT("h:%u\n",height); 01064 01065 rc = comms->recv_uint32(&format); 01066 phSocket_CHECK_RC(rc,NULL,"Failed to receive image format \n\n"); 01067 //phPRINT("f:%u\n",format); 01068 01069 rc = comms->recv_uint32(&host_send_time); 01070 phCHECK_RC(rc,NULL,"Failed to receive image host_send_time \n\n"); 01071 //phPRINT("hst:%d\n",host_send_time); 01072 01073 /* 0.) packet_id */ 01074 rc = comms->send_int32(packet_id); 01075 phSocket_CHECK_RC(rc,NULL,"Failed to send packet_id image message \n\n"); 01076 /* 1.) host_send_time: time the server started sending the data */ 01077 rc = comms->send_int32(host_send_time); 01078 phSocket_CHECK_RC(rc,NULL,"Failed to send host_send_time image message \n\n"); 01079 01080 rc = comms->recv_uint32(&size); 01081 phSocket_CHECK_RC(rc,NULL,"Failed to receive image size \n\n"); 01082 //phPRINT("s:%u\n",size); 01083 01084 /* receive a image from the server */ 01085 DEBUG_PRINT("receiving image data\n"); 01086 01087 if (size == 0) /* Try to calculate it */ 01088 { 01089 size = phIMAGE_SIZE(width,height,format); 01090 } 01091 01092 /* allocate data if it hasn't been initialized yet */ 01093 if (((*data_size) == 0) || (*data == NULL)) 01094 { 01095 (*data) = (uint8_t *)phMalloc(size); 01096 phCHECK_NULLPTR(*data,"phMalloc","phMalloc failed to allocate data."); 01097 } 01098 /* reallocate the data if the size changes */ 01099 else if (((*data_size) != size) && (*data != NULL)) 01100 { 01101 (*data) = (uint8_t *)phRealloc((*data),size); 01102 phCHECK_NULLPTR(*data,"phRealloc","phRealloc failed to allocate data."); 01103 } 01104 01105 /* Always set this */ 01106 *data_size = size; 01107 01108 /* Get the data from the server */ 01109 rc = comms->recv(*data, *data_size); 01110 phSocket_CHECK_RC(rc,NULL,"recv for image data failed."); 01111 01112 time_stop.stamp(); 01113 01114 /* Send stats back to the server */ 01115 /* 2.) */ 01116 rc = comms->send_uint32(*data_size); 01117 phSocket_CHECK_RC(rc,NULL,"Failed to send message \n\n"); 01118 /* 3.) */ 01119 rc = comms->send_uint32(time_start.getMicroseconds()); 01120 phSocket_CHECK_RC(rc,NULL,"Failed to send message\n\n"); 01121 /* 4.) */ 01122 rc = comms->send_uint32(time_stop.getMicroseconds()); 01123 phSocket_CHECK_RC(rc,NULL,"Failed to send message\n\n"); 01124 01125 #if 0 01126 phPRINT("0:%8u:%12.lf 1:%8u:%12.lf\n", 01127 time_start.getMicroseconds(), 01128 time_start.getStampValue(), 01129 time_stop.getMicroseconds(), 01130 time_stop.getStampValue()); 01131 #endif 01132 #if phNetSource_PRINT_IMAGE_SIZE() 01133 phPROGRESS("format:%s\n", 01134 phImageFormatToString(format)); 01135 phPROGRESS("recv:%lu\tactual:%lu\n", 01136 (long unsigned)*data_size, 01137 (long unsigned)phIMAGE_SIZE(width,height,format)); 01138 #endif 01139 01140 /* allocate space for the image */ 01141 inputImage->setImage(width,height,format, 01142 *data_size, 01143 *data); 01144 01145 /* keep track */ 01146 *w = width; 01147 *h = height; 01148 *f = format; 01149 01150 return phSUCCESS; 01151 error: 01152 /* might as well... */ 01153 phFree(*data); 01154 01155 *data_size = 0; 01156 01157 return rc; 01158 } 01159 01160 /* ------------------------------------------------------------------------- */ 01161 int phNetSource::tcp_disconnect( phSocket *comms ) 01162 { 01163 phFUNCTION("phNetSource::tcp_disconnect") 01164 01165 /* connect to the server */ 01166 comms->disconnect(); 01167 01168 return phSUCCESS; 01169 error: 01170 return phFAIL; 01171 } 01172 01173 /* ---------------------------------------------------------------------- */ 01174 int phNetSource::wakeup() 01175 { 01176 phFUNCTION("phNetSource::wakeup") 01177 01178 if (this->m_info != NULL) 01179 { 01180 if (this->m_info->m_comms != NULL) 01181 { 01182 this->m_info->m_comms->wakeup(); 01183 } 01184 } 01185 01186 rc = phImageCapture::wakeup(); 01187 phPRINT_RC(rc,NULL,"phImageCapture::wakeup"); 01188 01189 return phSUCCESS; 01190 } 01191 01192 /* ---------------------------------------------------------------------- */ 01193 int phNetSource::cleanup() 01194 { 01195 phFUNCTION("phNetSource::cleanup") 01196 int locked = 0; 01197 01198 phTHIS_LOOSE_LOCK(locked); 01199 01200 rc = this->close(); 01201 phPRINT_RC(rc,NULL,"this->close()"); 01202 01203 rc = this->phImageCapture::cleanup(); 01204 phPRINT_RC(rc,NULL,"this->phImageCapture::cleanup()"); 01205 01206 phTHIS_LOOSE_UNLOCK(locked); 01207 01208 return phSUCCESS; 01209 } 01210 01211 /* ---------------------------------------------------------------------- */ 01212 int phNetSource::run() 01213 { 01214 phFUNCTION("phNetSource::run") 01215 int i = 0; 01216 int foo = 0; 01217 int orig_locked = 0; 01218 01219 /* Returned value from getNextFrame and a loop count */ 01220 phImage *output_buffer = this->getImage(); 01221 01222 /* local copies of phNetSource object's member vars */ 01223 phImage *image = new phImage(); 01224 uint8_t *image_buf = NULL; 01225 uint32_t image_size = 0; 01226 int32_t local_format = 0; 01227 uint32_t local_width = 0; 01228 uint32_t local_height = 0; 01229 int local_do_resize = 0; 01230 int local_do_convert= 0; 01231 01232 int slept = 0; 01233 #if phNetSource_USE_JITTER_SYNC() 01234 int32_t sleeptime = 0; 01235 int32_t client_jitter_avg = -1; 01236 int32_t notify_jitter_avg = -1; 01237 #endif 01238 01239 /* Setup */ 01240 local_format = this->m_format; 01241 local_width = this->m_width; 01242 local_height = this->m_height; 01243 local_do_resize = this->m_info->m_do_resize; 01244 local_do_convert = this->m_info->m_do_convert; 01245 01246 /* Release the thread that spawned this one */ 01247 /* Everything has been copied and everything is ready to start */ 01248 rc = this->signal_running(); 01249 phPRINT_RC(rc,NULL,"this->signal_running"); 01250 01251 /* if we haven't connected by now and we want to wait, then wait */ 01252 while (this->m_server_wait && 01253 (!this->isConnected()) && 01254 (this->isRunning())) 01255 { 01256 rc = this->connect( false ); 01257 01258 if ((rc != -5) && (rc < 0)) this->setRunning(0); 01259 01260 if (!(foo = this->isConnected())) 01261 { 01262 phUSleep(10); 01263 //phYield(); 01264 } 01265 } 01266 01267 DEBUG_PRINT("Thread Started\n"); 01268 DEBUG_PRINT("output_buffer: %p\n",output_buffer); 01269 01270 #if phNetSource_USE_JITTER_SYNC() 01271 /* Reset all the jitter values in the object: 01272 notify, client and client avg*/ 01273 rc = output_buffer->resetJitter(); 01274 phPRINT_RC(rc,NULL,"output_buffer->resetJitter()"); 01275 01276 /* We want a moving average over 10 samples */ 01277 rc = output_buffer->setNotifyJitterAvgSamples(10); 01278 phPRINT_RC(rc,NULL,"output_buffer->setNotifyJitterAvgSamples()"); 01279 01280 /* We want a moving average over 10 samples */ 01281 rc = output_buffer->setClientJitterAvgSamples(10); 01282 phPRINT_RC(rc,NULL,"output_buffer->setClientJitterAvgSamples()"); 01283 #endif 01284 01285 while (this->isRunning() && 01286 (this->isConnected() || (this->m_reconnect))) 01287 { 01288 /* Get the current width/height/format settings to resize the 01289 * input to for output to connected objects */ 01290 rc = this->m_settings_lock.trylock(); 01291 phPRINT_RC(rc,NULL,"this->m_settings_lock.trylock();"); 01292 01293 /* only copy the settings if we have exclusize access */ 01294 if (rc == phSUCCESS) 01295 { 01296 local_do_resize = this->m_info->m_do_resize; 01297 local_do_convert = this->m_info->m_do_convert; 01298 local_width = this->m_width; 01299 local_height = this->m_height; 01300 local_format = this->m_format; 01301 01302 rc = this->m_settings_lock.unlock(); 01303 phPRINT_RC(rc,NULL,"this->m_settings_lock.unlock()"); 01304 } 01305 01306 if (!this->isConnected()) 01307 { 01308 if (this->m_reconnect) 01309 { 01310 rc = this->connect(false); 01311 01312 if (!this->isConnected()) 01313 { 01314 phUSleep(10); 01315 //phYield(); 01316 } 01317 01318 continue; 01319 } 01320 else 01321 { 01322 continue; 01323 } 01324 } 01325 01326 if (!this->isRunning()) 01327 { 01328 continue; 01329 } 01330 01331 rc = this->getNextFrame(image,&image_buf,&image_size); 01332 phPRINT_RC(rc,NULL,"this->recv()"); 01333 01334 /* If the recv failed, then disconnect; 01335 * this->m_reconnect above will try to reconnect*/ 01336 if (rc < 0) 01337 { 01338 this->disconnect(); 01339 continue; 01340 } 01341 01342 /* If there's an error, then go to the beginning 01343 * of the loop. There's a potential we can reset ourselves */ 01344 if (rc != phSUCCESS) continue; 01345 01346 /* Convert to the output format */ 01347 /* Setup the image according to desired output format */ 01348 if (local_do_resize) 01349 { 01350 rc = image->resize(local_width,local_height); 01351 phPRINT_RC(rc,NULL,"image->resize(%d,%d)", 01352 local_width,local_height); 01353 } 01354 if (local_do_convert) 01355 { 01356 rc = image->convert(local_format); 01357 phPRINT_RC(rc,NULL,"image->convert(%s)", 01358 phImageFormatToString(local_format)); 01359 } 01360 01361 /* if (output_buffer->tryWritelock() == 0) */ 01362 if (output_buffer->writeLock() == 0) 01363 { 01364 rc = output_buffer->swapImage(*image); 01365 phCHECK_RC(rc,NULL,"output_buffer->swapImage(*image)"); 01366 01367 /* Save the current frame's original settings */ 01368 phMUTEX_LOOSE_LOCK(this->m_orig_lock,orig_locked); 01369 /* \/ ORIGINAL CODE \/ */ 01370 this->m_orig_width = this->m_info->m_width; 01371 this->m_orig_height = this->m_info->m_height; 01372 this->m_orig_format = this->m_info->m_format; 01373 this->m_orig_size = image_size; 01374 phMUTEX_LOOSE_UNLOCK(this->m_orig_lock,orig_locked); 01375 01376 #if phNetSource_USE_JITTER_SYNC() 01377 client_jitter_avg = output_buffer->getClientJitterAvg(); 01378 notify_jitter_avg = output_buffer->getNotifyJitterAvg(); 01379 #endif 01380 01381 output_buffer->rwUnlock(); 01382 01383 #if phNetSource_USE_JITTER_SYNC() 01384 #if VERBOSE() 01385 /*phPROGRESS("(%p) <---\n",output_buffer);*/ 01386 phPRINT("(%s) client:%ld notify:%ld\n", 01387 function, 01388 client_jitter_avg, 01389 notify_jitter_avg); 01390 #endif 01391 /* We check to see if the client jitter is greater than the notify 01392 * jitter so we slow down the sending of images from the other side 01393 * to synch. up with how fast images are being processed on this 01394 * side */ 01395 if (notify_jitter_avg < client_jitter_avg) 01396 { 01397 sleeptime = (client_jitter_avg - notify_jitter_avg); 01398 #if VERBOSE() 01399 phPRINT("(%s)sleeptime:%ld client:%d notify:%d\n", 01400 function, 01401 sleeptime, 01402 client_jitter_avg, 01403 notify_jitter_avg); 01404 #endif 01405 slept = 1; 01406 phUSleep(sleeptime); 01407 } 01408 #endif 01409 } 01410 if (!slept) 01411 { 01412 if (1) 01413 { 01414 phUSleep(0); 01415 } 01416 else 01417 { 01418 phYield(); 01419 } 01420 } 01421 slept = 0; 01422 } 01423 01424 phDelete(image); 01425 phFree(image_buf); 01426 image_size = 0; 01427 01428 DEBUG_PRINT("Thread returning cleanly\n"); 01429 01430 return phSUCCESS; 01431 01432 error: 01433 phPROGRESS("Thread returning with error\n"); 01434 01435 phDelete(image); 01436 phFree(image_buf); 01437 image_size = 0; 01438 01439 rc = this->signal_error(); 01440 phPRINT_RC(rc,NULL,"this->signal_error"); 01441 01442 return phFAIL; 01443 } 01444
Copyright (C) 2002 - 2007 |
Philip D.S. Thoren ( pthoren@users.sourceforge.net ) University Of Massachusetts at Lowell Robotics Lab |