Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

phNetSource.cpp

Go to the documentation of this file.
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
SourceForge.net Logo

Generated on Sat Jun 16 02:44:03 2007 for phission by  doxygen 1.4.4