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