Changeset 338 in flair-src for trunk/lib/FlairSensorActuator/src/V4LCamera.cpp
- Timestamp:
- Oct 17, 2019, 2:49:35 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to
/branches/sanscv merged eligible
-
Property svn:mergeinfo
set to
-
trunk/lib/FlairSensorActuator/src/V4LCamera.cpp
r330 r338 21 21 #include <CheckBox.h> 22 22 #include <Label.h> 23 #include < cvimage.h>23 #include <Image.h> 24 24 #include <FrameworkManager.h> 25 25 #include <fcntl.h> 26 26 #include <linux/videodev2.h> 27 28 27 #include <sys/ioctl.h> 29 28 #include <unistd.h> 30 29 #include <cstring> 31 30 #include <sys/mman.h> 32 31 #include <VisionFilter.h> 33 32 34 33 #define DEFAULT_V4L_BUFFERS 4 … … 43 42 V4LCamera::V4LCamera(string name, 44 43 uint8_t camera_index, uint16_t width, uint16_t height, 45 cvimage::Type::Format format, uint8_t priority)44 Image::Type::Format format, uint8_t priority) 46 45 : Thread(getFrameworkManager(), name, priority), 47 46 Camera(name, width, height, format) { 48 47 49 string deviceName="/dev/video"+std::to_string(camera_index); 50 device = open(deviceName.c_str(), O_RDWR | O_NONBLOCK); 51 if (device == -1) { 52 Thread::Err("Cannot open %s\n"); 53 } 48 string deviceName="/dev/video"+std::to_string(camera_index); 49 device = open(deviceName.c_str(), O_RDWR | O_NONBLOCK); 50 if (device == -1) { 51 Thread::Err("Cannot open %s\n",deviceName.c_str()); 52 } else { 53 Printf("V4LCamera %s, opened %s\n",name.c_str(),deviceName.c_str()); 54 } 55 56 struct v4l2_capability cap; 57 memset(&cap, 0, sizeof (v4l2_capability)); 58 if (xioctl (device, VIDIOC_QUERYCAP, &cap)==-1) { 59 Thread::Err("VIDIOC_QUERYCAP xioctl\n"); 60 } 61 if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { 62 Thread::Err("device is unable to capture video memory.\n"); 63 } 64 65 //get v4l2_format 66 struct v4l2_format form; 67 form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 68 if(xioctl (device, VIDIOC_G_FMT,&form)==-1) { 69 Thread::Err("VIDIOC_G_FMT xioctl\n"); 70 } 71 72 //set width, height and format 73 if (format == Image::Type::Format::UYVY) { 74 form.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; 75 } else if (format == Image::Type::Format::YUYV) { 76 form.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 77 } else { 78 Thread::Err("format not supported\n"); 79 } 80 81 form.fmt.pix.width = width; 82 form.fmt.pix.height = height; 83 form.fmt.win.chromakey = 0; 84 form.fmt.win.field = V4L2_FIELD_ANY; 85 form.fmt.win.clips = 0; 86 form.fmt.win.clipcount = 0; 87 form.fmt.pix.field = V4L2_FIELD_ANY; 88 if(xioctl (device, VIDIOC_S_FMT,&form)==-1) { 89 Thread::Err("VIDIOC_S_FMT xioctl\n"); 90 } 91 92 //alloc and queue bufs 93 AllocBuffers(); 94 for (int bufferIndex = 0; bufferIndex < nbBuffers;++bufferIndex) { 95 QueueBuffer(bufferIndex); 96 } 54 97 55 //get v4l2_format 56 struct v4l2_format form; 57 form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 58 xioctl (device, VIDIOC_G_FMT,&form); 59 60 //set width, height and format 61 if (format == cvimage::Type::Format::UYVY) { 62 form.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; 63 } else if (format == cvimage::Type::Format::YUYV) { 64 form.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 65 } else { 66 Thread::Err("format not supported\n"); 67 } 68 69 form.fmt.pix.width = width; 70 form.fmt.pix.height = height; 71 form.fmt.win.chromakey = 0; 72 form.fmt.win.field = V4L2_FIELD_ANY; 73 form.fmt.win.clips = 0; 74 form.fmt.win.clipcount = 0; 75 form.fmt.pix.field = V4L2_FIELD_ANY; 76 xioctl (device, VIDIOC_S_FMT, &form); 77 78 /* This is just a technicality, but all buffers must be filled up before any 79 staggered SYNC is applied. SO, filler up. (see V4L HowTo) */ 80 81 AllocBuffers(); 82 83 for (int bufferIndex = 0; bufferIndex < ((int)requestbuffers.count);++bufferIndex) { 84 struct v4l2_buffer buf; 85 86 memset(&buf, 0, sizeof (v4l2_buffer)); 87 88 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 89 buf.memory = V4L2_MEMORY_MMAP; 90 buf.index = (unsigned long)bufferIndex; 91 92 if (-1 == xioctl (device, VIDIOC_QBUF, &buf)) { 93 Thread::Err("VIDIOC_QBUF xioctl\n"); 94 break; 95 } 96 } 97 98 // enable the streaming 99 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 100 if (-1 == xioctl (device, VIDIOC_STREAMON,&type)) { 101 Thread::Err("VIDIOC_STREAMON xioctl\n"); 102 } 103 104 105 // skip first frame. it is often bad -- this is unnotied in traditional apps, 106 // but could be fatal if bad jpeg is enabled 107 GrabFrame(); 108 109 110 111 // station sol 112 gain = new DoubleSpinBox(GetGroupBox()->NewRow(), "gain:", 0, 1, 0.1); 113 exposure = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "exposure:", 0, 114 1, 0.1); 115 bright = 116 new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "bright:", 0, 1, 0.1); 117 contrast = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "contrast:", 0, 118 1, 0.1); 119 hue = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "hue:", 0, 1, 0.1); 120 sharpness = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "sharpness:", 121 0, 1, 0.1); 122 sat = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "saturation:", 0, 1, 123 0.1); 124 autogain = new CheckBox(GetGroupBox()->NewRow(), "autogain:"); 125 autoexposure = new CheckBox(GetGroupBox()->LastRowLastCol(), "autoexposure:"); 126 awb = new CheckBox(GetGroupBox()->LastRowLastCol(), "awb:"); 127 fps = new Label(GetGroupBox()->NewRow(), "fps"); 128 129 hasProblems=false; 98 // enable the streaming 99 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 100 if (xioctl (device, VIDIOC_STREAMON,&type)==-1) { 101 Thread::Err("VIDIOC_STREAMON xioctl\n"); 102 } 103 104 // skip first frame. it is often bad -- this is unnotied in traditional apps, 105 // but could be fatal if bad jpeg is enabled 106 bufferIndex=-1; 107 GrabFrame(); 108 109 // ground station 110 gain = new DoubleSpinBox(GetGroupBox()->NewRow(), "gain:", 0, 1, 0.1); 111 exposure = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "exposure:", 0,1, 0.1); 112 bright = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "bright:", 0, 1, 0.1); 113 contrast = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "contrast:", 0,1, 0.1); 114 hue = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "hue:", 0, 1, 0.1); 115 sharpness = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "sharpness:", 0, 1, 0.1); 116 sat = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "saturation:", 0, 1,0.1); 117 autogain = new CheckBox(GetGroupBox()->NewRow(), "autogain:"); 118 autoexposure = new CheckBox(GetGroupBox()->LastRowLastCol(), "autoexposure:"); 119 awb = new CheckBox(GetGroupBox()->LastRowLastCol(), "awb:"); 120 fps = new Label(GetGroupBox()->NewRow(), "fps"); 121 122 hasProblems=false; 130 123 } 131 124 132 125 V4LCamera::~V4LCamera() { 133 SafeStop(); 134 Join(); 126 for (int n_buffers = 0; n_buffers < nbBuffers; n_buffers++) { 127 FreeFunction((char*)buffers[n_buffers].start); 128 } 129 SafeStop(); 130 Join(); 135 131 } 136 132 137 133 void V4LCamera::Run(void) { 138 134 Time cam_time, new_time, fpsNow, fpsPrev; 139 char* buffer; // raw image140 135 int fpsCounter = 0; 141 136 … … 160 155 fpsCounter++; 161 156 if (GetTime() > (fpsPrev + 5 * (Time)1000000000)) { 162 // toute les5 secondes157 // every 5 secondes 163 158 fpsNow = GetTime(); 164 159 fps->SetText("fps: %.1f", … … 204 199 SetProperty(V4L2_CID_AUTO_WHITE_BALANCE, awb->Value()); 205 200 206 // cam pictures 207 buffer = RetrieveRawFrame(); 201 // get picture 208 202 GrabFrame(); 209 203 new_time = GetTime(); … … 216 210 217 211 output->GetMutex(); 218 output->buffer = buffer;212 output->buffer=(char*)buffers[bufferIndex].start; 219 213 output->ReleaseMutex(); 220 214 … … 228 222 } 229 223 230 void V4LCamera::GrabFrame(void) { 231 unsigned int count; 232 233 count = 1; 234 235 while (count-- > 0) { 236 for (;;) { 237 fd_set fds; 238 struct timeval tv; 239 int r; 240 241 FD_ZERO (&fds); 242 FD_SET (device, &fds); 243 244 /* Timeout. */ 245 tv.tv_sec = 2; 246 tv.tv_usec = 0; 247 248 r = select (device+1, &fds, NULL, NULL, &tv); 249 250 if (-1 == r) { 251 if (EINTR == errno) continue; 252 Thread::Err("select\n"); 224 int V4LCamera::QueueBuffer(int index) { 225 struct v4l2_buffer buf; 226 if(index>=0 && index<nbBuffers) { 227 memset(&buf, 0, sizeof (v4l2_buffer)); 228 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 229 buf.memory = V4L2_MEMORY_USERPTR;//V4L2_MEMORY_MMAP; 230 buf.index = (unsigned long)index; 231 buf.m.userptr=(unsigned long)(buffers[index].start); 232 buf.length=buffers[index].length; 233 234 int ret=xioctl (device, VIDIOC_QBUF, &buf); 235 if (ret==-1) { 236 Thread::Err("VIDIOC_QBUF xioctl %s\n",strerror(-ret)); 237 return -1; 238 } 239 } 240 return 0; 241 } 242 243 int V4LCamera::GrabFrame(void) { 244 //queue previous buffer 245 if(QueueBuffer(bufferIndex)<0) return -1; 246 247 fd_set fds; 248 struct timeval tv; 249 FD_ZERO (&fds); 250 FD_SET (device, &fds); 251 252 tv.tv_sec = 0; 253 tv.tv_usec = 100000; 254 255 int r = select (device+1, &fds, NULL, NULL, &tv); 256 257 if (-1 == r) { 258 char errorMsg[256]; 259 Thread::Err("select (%s)\n", strerror_r(-r, errorMsg, sizeof(errorMsg))); 260 return -1; 261 } 262 263 if (0 == r) { 264 Thread::Err("select timeout\n"); 265 return -1; 266 } 267 268 struct v4l2_buffer buf; 269 memset(&buf, 0, sizeof (v4l2_buffer)); 270 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 271 buf.memory = V4L2_MEMORY_USERPTR;//V4L2_MEMORY_MMAP; 272 273 //get last captured image 274 int prevDQbuf=-1; 275 for(int i=0;i<4;i++) { 276 if (xioctl (device, VIDIOC_DQBUF, &buf)==-1) { 277 if (errno==EAGAIN) { 278 break; 279 } else { 280 Thread::Err("VIDIOC_DQBUF xioctl\n"); 281 return -1; 253 282 } 254 255 if (0 == r) { 256 Thread::Err("select timeout\n"); 257 /* end the infinite loop */ 258 break; 259 } 260 261 if (read_frame_v4l2 ()) break; 262 } 263 } 264 } 265 266 int V4LCamera::read_frame_v4l2(void) { 267 struct v4l2_buffer buf; 268 memset(&buf, 0, sizeof (v4l2_buffer)); 269 270 271 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 272 buf.memory = V4L2_MEMORY_MMAP; 273 274 if (-1 == xioctl (device, VIDIOC_DQBUF, &buf)) { 275 switch (errno) { 276 case EAGAIN: 277 return 0; 278 279 case EIO: 280 /* Could ignore EIO, see spec. */ 281 282 /* fall through */ 283 284 default: 285 /* display the error and stop processing */ 286 Thread::Err("VIDIOC_DQBUF xioctl\n"); 287 return 1; 288 } 289 } 290 291 if(buf.index >= requestbuffers.count) { 292 Thread::Err("buf.index >= requestbuffers.count\n"); 293 } 283 } else { 284 if(prevDQbuf!=-1) { 285 QueueBuffer(prevDQbuf); 286 } 287 for (int n_buffers = 0; n_buffers < nbBuffers; n_buffers++) { 288 if((void*)(buf.m.userptr)==buffers[n_buffers].start) { 289 prevDQbuf=n_buffers; 290 bufferIndex=n_buffers; 291 break; 292 } 293 } 294 } 295 } 294 296 295 #ifdef USE_TEMP_BUFFER296 memcpy(capture->buffers[MAX_V4L_BUFFERS].start,297 capture->buffers[buf.index].start,298 capture->buffers[MAX_V4L_BUFFERS].length );299 capture->bufferIndex = MAX_V4L_BUFFERS;300 //printf("got data in buff %d, len=%d, flags=0x%X, seq=%d, used=%d)\n",301 // buf.index, buf.length, buf.flags, buf.sequence, buf.bytesused);302 #else303 bufferIndex = buf.index;304 #endif305 306 if (-1 == xioctl (device, VIDIOC_QBUF, &buf)) {307 Thread::Err ("VIDIOC_QBUF xioctl\n");308 }309 310 297 return 1; 311 298 } 312 299 313 300 int V4LCamera::AllocBuffers(void) { 301 struct v4l2_requestbuffers requestbuffers; 314 302 memset(&requestbuffers, 0, sizeof (v4l2_requestbuffers)); 315 303 … … 320 308 requestbuffers.count = buffer_number; 321 309 requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 322 requestbuffers.memory = V4L2_MEMORY_ MMAP;323 324 if ( -1 == xioctl (device, VIDIOC_REQBUFS, &requestbuffers)) {325 if ( EINVAL == errno) {326 Thread::Err(" not support memory mapping not supportted\n");310 requestbuffers.memory = V4L2_MEMORY_USERPTR;//V4L2_MEMORY_MMAP; 311 312 if (xioctl (device, VIDIOC_REQBUFS, &requestbuffers)==-1) { 313 if (errno==EINVAL) { 314 Thread::Err("VIDIOC_REQBUFS user memory not supported\n"); 327 315 } else { 328 316 Thread::Err ("VIDIOC_REQBUFS xioctl\n"); … … 330 318 return -1; 331 319 } 332 333 if (requestbuffers.count < buffer_number) { 334 if (buffer_number == 1) { 335 Thread::Err("Insufficient buffer memory\n"); 336 return -1; 337 } else { 338 buffer_number--; 339 Thread::Warn ("Insufficient buffer memory, decreasing buffers\n"); 340 goto try_again; 341 } 320 321 nbBuffers=DEFAULT_V4L_BUFFERS; 322 for (int n_buffers = 0; n_buffers < nbBuffers; n_buffers++) { 323 buffers[n_buffers].length = output->GetDataType().GetSize(); 324 buffers[n_buffers].start =AllocFunction(output->GetDataType().GetSize()); 342 325 } 343 326 344 for (int n_buffers = 0; n_buffers < requestbuffers.count; ++n_buffers) {345 struct v4l2_buffer buf;346 347 memset(&buf, 0, sizeof (v4l2_buffer));348 349 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;350 buf.memory = V4L2_MEMORY_MMAP;351 buf.index = n_buffers;352 353 if (-1 == xioctl (device, VIDIOC_QUERYBUF, &buf)) {354 Thread::Err("VIDIOC_QUERYBUF xioctl\n");355 return -1;356 }357 358 buffers[n_buffers].length = buf.length;359 buffers[n_buffers].start =360 mmap (NULL /* start anywhere */,361 buf.length,362 PROT_READ | PROT_WRITE /* required */,363 MAP_SHARED /* recommended */,364 device, buf.m.offset);365 366 if (MAP_FAILED == buffers[n_buffers].start) {367 Thread::Err("mmap\n");368 return -1;369 }370 }371 372 //todo: verifier cette alloc, pas de double buffeinrg?373 //peut on initialiser l'image dans le constrcteur de la camera?374 375 output->buffer=output->allocFunction(output->dataType.GetSize());376 327 return 1; 377 328 }; 378 329 379 char *V4LCamera::RetrieveRawFrame(void) {380 381 /* [FD] this really belongs here */382 if (ioctl(device, VIDIOCSYNC, &mmaps[bufferIndex].frame) == -1) {383 Thread::Err("Could not SYNC to video stream. %s\n", strerror(errno));384 }385 386 /* Now get what has already been captured as a IplImage return */387 if (output->dataType.GetFormat() == cvimage::Type::Format::YUYV || output->dataType.GetFormat() == cvimage::Type::Format::UYVY) {388 #ifdef USE_TEMP_BUFFER389 capture->frame.imageData=(char*)capture->buffers[capture->bufferIndex].start;390 #else391 Printf("frame is not allocated\n");392 memcpy((char *)frame,(char *)buffers[bufferIndex].start,output->GetDataType().GetSize());393 #endif394 } else {395 Thread::Err("palette %d not supported for raw output\n",output->dataType.GetFormat());396 }397 398 return(frame);399 }400 401 330 bool V4LCamera::HasProblems(void) { 402 331 return hasProblems; … … 408 337 409 338 void V4LCamera::SetAutoExposure(bool value) { 410 Thread::Warn("not implemented in opencv\n");339 Thread::Warn("not implemented\n"); 411 340 } 412 341
Note:
See TracChangeset
for help on using the changeset viewer.