Now you can download a copy of these docs so you can use them offline! Download now
AxisCamera.cpp
00001 /*----------------------------------------------------------------------------*/ 00002 /* Copyright (c) FIRST 2008. All Rights Reserved. */ 00003 /* Open Source Software - may be modified and shared by FRC teams. The code */ 00004 /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ 00005 /*----------------------------------------------------------------------------*/ 00006 00007 #include "Vision/AxisCamera.h" 00008 00009 #include <string.h> 00010 #include "Synchronized.h" 00011 #include "Vision/PCVideoServer.h" 00012 #include "WPIErrors.h" 00013 00015 IMAQ_FUNC int Priv_ReadJPEGString_C(Image* _image, const unsigned char* _string, UINT32 _stringLength); 00016 00017 // Max packet without jumbo frames is 1500... add 36 because?? 00018 #define kMaxPacketSize 1536 00019 #define kImageBufferAllocationIncrement 1000 00020 00021 AxisCamera *AxisCamera::_instance = NULL; 00022 00026 AxisCamera::AxisCamera(const char *ipAddress) 00027 : AxisCameraParams(ipAddress) 00028 , m_cameraSocket(ERROR) 00029 , m_protectedImageBuffer(NULL) 00030 , m_protectedImageBufferLength(0) 00031 , m_protectedImageSize(0) 00032 , m_protectedImageSem(NULL) 00033 , m_freshImage(false) 00034 , m_imageStreamTask("cameraTask", (FUNCPTR)s_ImageStreamTaskFunction) 00035 , m_videoServer(NULL) 00036 { 00037 m_protectedImageSem = semMCreate(SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE); 00038 00039 if (!StatusIsFatal()) 00040 m_imageStreamTask.Start((int)this); 00041 } 00042 00046 AxisCamera::~AxisCamera() 00047 { 00048 delete m_videoServer; 00049 m_videoServer = NULL; 00050 00051 m_imageStreamTask.Stop(); 00052 close(m_cameraSocket); 00053 00054 SemSet_t::iterator it = m_newImageSemSet.begin(); 00055 SemSet_t::iterator end = m_newImageSemSet.end(); 00056 for (;it != end; it++) 00057 { 00058 semDelete(*it); 00059 } 00060 m_newImageSemSet.clear(); 00061 00062 semDelete(m_protectedImageSem); 00063 } 00064 00070 AxisCamera &AxisCamera::GetInstance(const char *cameraIP) 00071 { 00072 if (NULL == _instance) 00073 { 00074 _instance = new AxisCamera(cameraIP); 00075 00076 _instance->m_videoServer = new PCVideoServer(); 00077 } 00078 00079 return *_instance; 00080 } 00081 00085 void AxisCamera::DeleteInstance() 00086 { 00087 delete _instance; 00088 _instance = NULL; 00089 } 00090 00095 bool AxisCamera::IsFreshImage() 00096 { 00097 return m_freshImage; 00098 } 00099 00108 SEM_ID AxisCamera::GetNewImageSem() 00109 { 00110 SEM_ID sem = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY); 00111 m_newImageSemSet.insert(sem); 00112 return sem; 00113 } 00114 00121 int AxisCamera::GetImage(Image* imaqImage) 00122 { 00123 if (m_protectedImageBuffer == NULL) 00124 return 0; 00125 Synchronized sync(m_protectedImageSem); 00126 Priv_ReadJPEGString_C(imaqImage, 00127 (unsigned char*)m_protectedImageBuffer, m_protectedImageSize); 00128 m_freshImage = false; 00129 return 1; 00130 } 00131 00132 #if JAVA_CAMERA_LIB != 1 00133 00138 int AxisCamera::GetImage(ColorImage* image) 00139 { 00140 return GetImage(image->GetImaqImage()); 00141 } 00142 00149 HSLImage* AxisCamera::GetImage() 00150 { 00151 HSLImage *image = new HSLImage(); 00152 GetImage(image); 00153 return image; 00154 } 00155 #endif 00156 00167 int AxisCamera::CopyJPEG(char **destImage, int &destImageSize, int &destImageBufferSize) 00168 { 00169 Synchronized sync(m_protectedImageSem); 00170 if (destImage == NULL) 00171 wpi_setWPIErrorWithContext(NullParameter, "destImage must not be NULL"); 00172 00173 if (m_protectedImageBuffer == NULL || m_protectedImageSize <= 0) 00174 return 0; // if no source image 00175 00176 if (destImageBufferSize < m_protectedImageSize) // if current destination buffer too small 00177 { 00178 if (*destImage != NULL) delete [] *destImage; 00179 destImageBufferSize = m_protectedImageSize + kImageBufferAllocationIncrement; 00180 *destImage = new char[destImageBufferSize]; 00181 if (*destImage == NULL) return 0; 00182 } 00183 // copy this image into destination buffer 00184 if (*destImage == NULL) 00185 { 00186 wpi_setWPIErrorWithContext(NullParameter, "*destImage must not be NULL"); 00187 } 00188 // TODO: Is this copy realy necessary... perhaps we can simply transmit while holding the protected buffer 00189 memcpy(*destImage, m_protectedImageBuffer, m_protectedImageSize); 00190 destImageSize = m_protectedImageSize; 00191 return 1; 00192 } 00193 00198 int AxisCamera::s_ImageStreamTaskFunction(AxisCamera *thisPtr) 00199 { 00200 return thisPtr->ImageStreamTaskFunction(); 00201 } 00202 00208 int AxisCamera::ImageStreamTaskFunction() 00209 { 00210 // Loop on trying to setup the camera connection. This happens in a background 00211 // thread so it shouldn't effect the operation of user programs. 00212 while (1) 00213 { 00214 const char *requestString = "GET /mjpg/video.mjpg HTTP/1.1\n\ 00215 User-Agent: HTTPStreamClient\n\ 00216 Connection: Keep-Alive\n\ 00217 Cache-Control: no-cache\n\ 00218 Authorization: Basic RlJDOkZSQw==\n\n"; 00219 semTake(m_socketPossessionSem, WAIT_FOREVER); 00220 m_cameraSocket = CreateCameraSocket(requestString); 00221 if (m_cameraSocket == ERROR) 00222 { 00223 // Don't hammer the camera if it isn't ready. 00224 semGive(m_socketPossessionSem); 00225 taskDelay(1000); 00226 } 00227 else 00228 { 00229 ReadImagesFromCamera(); 00230 } 00231 } 00232 } 00233 00237 int AxisCamera::ReadImagesFromCamera() 00238 { 00239 char *imgBuffer = NULL; 00240 int imgBufferLength = 0; 00241 //Infinite loop, task deletion handled by taskDeleteHook 00242 // Socket cleanup handled by destructor 00243 00244 // TODO: these recv calls must be non-blocking. Otherwise if the camera 00245 // fails during a read, the code hangs and never retries when the camera comes 00246 // back up. 00247 00248 int counter = 2; 00249 while (1) 00250 { 00251 char initialReadBuffer[kMaxPacketSize] = ""; 00252 char intermediateBuffer[1]; 00253 char *trailingPtr = initialReadBuffer; 00254 int trailingCounter = 0; 00255 while (counter) 00256 { 00257 // TODO: fix me... this cannot be the most efficient way to approach this, reading one byte at a time. 00258 if(recv(m_cameraSocket, intermediateBuffer, 1, 0) == ERROR) 00259 { 00260 wpi_setErrnoErrorWithContext("Failed to read image header"); 00261 close (m_cameraSocket); 00262 return ERROR; 00263 } 00264 strncat(initialReadBuffer, intermediateBuffer, 1); 00265 // trailingCounter ensures that we start looking for the 4 byte string after 00266 // there is at least 4 bytes total. Kind of obscure. 00267 // look for 2 blank lines (\r\n) 00268 if (NULL != strstr(trailingPtr, "\r\n\r\n")) 00269 { 00270 --counter; 00271 } 00272 if (++trailingCounter >= 4) 00273 { 00274 trailingPtr++; 00275 } 00276 } 00277 counter = 1; 00278 char *contentLength = strstr(initialReadBuffer, "Content-Length: "); 00279 if (contentLength == NULL) 00280 { 00281 wpi_setWPIErrorWithContext(IncompatibleMode, "No content-length token found in packet"); 00282 close(m_cameraSocket); 00283 return ERROR; 00284 } 00285 contentLength = contentLength + 16; // skip past "content length" 00286 int readLength = atol(contentLength); // get the image byte count 00287 00288 // Make sure buffer is large enough 00289 if (imgBufferLength < readLength) 00290 { 00291 if (imgBuffer) delete[] imgBuffer; 00292 imgBufferLength = readLength + kImageBufferAllocationIncrement; 00293 imgBuffer = new char[imgBufferLength]; 00294 if (imgBuffer == NULL) 00295 { 00296 imgBufferLength = 0; 00297 continue; 00298 } 00299 } 00300 00301 // Read the image data for "Content-Length" bytes 00302 int bytesRead = 0; 00303 int remaining = readLength; 00304 while(bytesRead < readLength) 00305 { 00306 int bytesThisRecv = recv(m_cameraSocket, &imgBuffer[bytesRead], remaining, 0); 00307 bytesRead += bytesThisRecv; 00308 remaining -= bytesThisRecv; 00309 } 00310 // Update image 00311 UpdatePublicImageFromCamera(imgBuffer, readLength); 00312 if (semTake(m_paramChangedSem, NO_WAIT) == OK) 00313 { 00314 // params need to be updated: close the video stream; release the camera. 00315 close(m_cameraSocket); 00316 semGive(m_socketPossessionSem); 00317 return 0; 00318 } 00319 } 00320 } 00321 00327 void AxisCamera::UpdatePublicImageFromCamera(char *imgBuffer, int imgSize) 00328 { 00329 { 00330 Synchronized sync(m_protectedImageSem); 00331 00332 // Adjust the buffer size if current destination buffer is too small. 00333 if (m_protectedImageBufferLength < imgSize) 00334 { 00335 if (m_protectedImageBuffer != NULL) delete [] m_protectedImageBuffer; 00336 m_protectedImageBufferLength = imgSize + kImageBufferAllocationIncrement; 00337 m_protectedImageBuffer = new char[m_protectedImageBufferLength]; 00338 if (m_protectedImageBuffer == NULL) 00339 { 00340 m_protectedImageBufferLength = 0; 00341 return; 00342 } 00343 } 00344 00345 memcpy(m_protectedImageBuffer, imgBuffer, imgSize); 00346 m_protectedImageSize = imgSize; 00347 } 00348 00349 m_freshImage = true; 00350 // Notify everyone who is interested. 00351 SemSet_t::iterator it = m_newImageSemSet.begin(); 00352 SemSet_t::iterator end = m_newImageSemSet.end(); 00353 for (;it != end; it++) 00354 { 00355 semGive(*it); 00356 } 00357 } 00358 00362 void AxisCamera::RestartCameraTask() 00363 { 00364 m_imageStreamTask.Stop(); 00365 m_imageStreamTask.Start((int)this); 00366 } 00367 00368 #if JAVA_CAMERA_LIB == 1 00369 00370 // C bindings used by Java 00371 // These need to stay as is or Java has to change 00372 00373 void AxisCameraStart(const char *IPAddress) 00374 { 00375 #ifdef SVN_REV 00376 if (strlen(SVN_REV)) 00377 { 00378 printf("JavaCameraLib was compiled from SVN revision %s\n", SVN_REV); 00379 } 00380 else 00381 { 00382 printf("JavaCameraLib was compiled from a location that is not source controlled.\n"); 00383 } 00384 #else 00385 printf("JavaCameraLib was compiled without -D'SVN_REV=nnnn'\n"); 00386 #endif 00387 AxisCamera::GetInstance(IPAddress); 00388 } 00389 00390 int AxisCameraGetImage (Image* image) 00391 { 00392 return AxisCamera::GetInstance().GetImage(image); 00393 } 00394 00395 void AxisCameraWriteBrightness(int brightness) 00396 { 00397 AxisCamera::GetInstance().WriteBrightness(brightness); 00398 } 00399 00400 int AxisCameraGetBrightness() 00401 { 00402 return AxisCamera::GetInstance().GetBrightness(); 00403 } 00404 00405 void AxisCameraWriteWhiteBalance(AxisCameraParams::WhiteBalance_t whiteBalance) 00406 { 00407 AxisCamera::GetInstance().WriteWhiteBalance(whiteBalance); 00408 } 00409 00410 AxisCameraParams::WhiteBalance_t AxisCameraGetWhiteBalance() 00411 { 00412 return AxisCamera::GetInstance().GetWhiteBalance(); 00413 } 00414 00415 void AxisCameraWriteColorLevel(int colorLevel) 00416 { 00417 AxisCamera::GetInstance().WriteColorLevel(colorLevel); 00418 } 00419 00420 int AxisCameraGetColorLevel() 00421 { 00422 return AxisCamera::GetInstance().GetColorLevel(); 00423 } 00424 00425 void AxisCameraWriteExposureControl(AxisCameraParams::Exposure_t exposure) 00426 { 00427 AxisCamera::GetInstance().WriteExposureControl(exposure); 00428 } 00429 00430 AxisCameraParams::Exposure_t AxisCameraGetExposureControl() 00431 { 00432 return AxisCamera::GetInstance().GetExposureControl(); 00433 } 00434 00435 void AxisCameraWriteExposurePriority(int exposure) 00436 { 00437 AxisCamera::GetInstance().WriteExposurePriority(exposure); 00438 } 00439 00440 int AxisCameraGetExposurePriority() 00441 { 00442 return AxisCamera::GetInstance().GetExposurePriority(); 00443 } 00444 00445 void AxisCameraWriteMaxFPS(int maxFPS) 00446 { 00447 AxisCamera::GetInstance().WriteMaxFPS(maxFPS); 00448 } 00449 00450 int AxisCameraGetMaxFPS() 00451 { 00452 return AxisCamera::GetInstance().GetMaxFPS(); 00453 } 00454 00455 void AxisCameraWriteResolution(AxisCameraParams::Resolution_t resolution) 00456 { 00457 AxisCamera::GetInstance().WriteResolution(resolution); 00458 } 00459 00460 AxisCameraParams::Resolution_t AxisCameraGetResolution() 00461 { 00462 return AxisCamera::GetInstance().GetResolution(); 00463 } 00464 00465 void AxisCameraWriteCompression(int compression) 00466 { 00467 AxisCamera::GetInstance().WriteCompression(compression); 00468 } 00469 00470 int AxisCameraGetCompression() 00471 { 00472 return AxisCamera::GetInstance().GetCompression(); 00473 } 00474 00475 void AxisCameraWriteRotation(AxisCameraParams::Rotation_t rotation) 00476 { 00477 AxisCamera::GetInstance().WriteRotation(rotation); 00478 } 00479 00480 AxisCameraParams::Rotation_t AxisCameraGetRotation() 00481 { 00482 return AxisCamera::GetInstance().GetRotation(); 00483 } 00484 00485 void AxisCameraDeleteInstance() 00486 { 00487 AxisCamera::DeleteInstance(); 00488 } 00489 00490 int AxisCameraFreshImage() 00491 { 00492 return AxisCamera::GetInstance().IsFreshImage(); 00493 } 00494 00495 #endif // JAVA_CAMERA_LIB == 1 00496
Generated on Thu Jan 12 2012 22:35:17 for WPILibC++ by
1.7.1