Changeset 348 in flair-src for trunk/lib/FlairSensorActuator/src/V4LCamera.cpp
- Timestamp:
- Feb 17, 2020, 3:44:56 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/lib/FlairSensorActuator/src/V4LCamera.cpp
r347 r348 33 33 #define DEFAULT_V4L_BUFFERS 4 34 34 35 #define CLEAR(x) memset (&(x), 0, sizeof (x))36 37 35 using std::string; 38 36 using namespace flair::core; … … 55 53 } 56 54 57 /* w/o memset some parts arent initialized - AKA: Fill it with zeros so it is clean */58 memset(&capture,0,sizeof(CvCaptureCAM_V4L));59 n_buffers = 0;60 61 62 55 if(format == Image::Type::Format::UYVY) { 63 56 if(init(width,height,V4L2_PIX_FMT_UYVY) == -1) { … … 77 70 allocBuffers(); 78 71 79 for ( capture.bufferIndex = 0;capture.bufferIndex < ((int)capture.req.count);++capture.bufferIndex) {72 for (int i=0;i < nbBuffers;i++) { 80 73 struct v4l2_buffer buf; 81 82 CLEAR (buf); 74 memset(&buf, 0, sizeof (v4l2_buffer)); 83 75 84 76 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 85 77 buf.memory = V4L2_MEMORY_MMAP; 86 buf.index = (unsigned long) capture.bufferIndex;78 buf.index = (unsigned long)i; 87 79 88 80 if (-1 == xioctl (device, VIDIOC_QBUF, &buf)) { … … 92 84 93 85 /* enable the streaming */ 94 capture.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;95 if (-1 == xioctl (device, VIDIOC_STREAMON,&capture.type)) {96 /* error enabling the stream */86 v4l2_buf_type type; 87 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 88 if (-1 == xioctl (device, VIDIOC_STREAMON,&type)) { 97 89 Thread::Err("VIDIOC_STREAMON error\n"); 98 90 } … … 115 107 116 108 V4LCamera::~V4LCamera() { 117 for (int n_buffers = 0; n_buffers < nbBuffers; n_buffers++) {118 //FreeFunction((char*)buffers[ n_buffers].start);109 for (int i = 0; i < nbBuffers; i++) { 110 //FreeFunction((char*)buffers[i].start); 119 111 } 120 112 SafeStop(); 121 113 Join(); 114 close(device); 122 115 } 123 116 124 117 int V4LCamera::init(int width, int height,unsigned long colorspace) { 125 CLEAR (capture.cap); 126 if(-1 == xioctl(device, VIDIOC_QUERYCAP, &capture.cap)) { 118 struct v4l2_capability cap; 119 memset(&cap, 0, sizeof (v4l2_capability)); 120 121 if(-1 == xioctl(device, VIDIOC_QUERYCAP, &cap)) { 127 122 return -1; 128 } else {129 CLEAR (capture.capability);130 capture.capability.type = capture.cap.capabilities;131 132 /* Query channels number */133 if (-1 == xioctl(device, VIDIOC_G_INPUT, &capture.capability.channels)) {134 return -1;135 }136 123 } 137 124 138 if ((cap ture.cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {125 if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { 139 126 Thread::Err("device is unable to capture video memory.\n"); 140 127 return -1; 141 128 } 142 129 143 /* Find Window info */ 144 CLEAR (capture.form); 145 capture.form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 146 147 if (-1 == xioctl (device, VIDIOC_G_FMT, &capture.form)) { 148 Thread::Err("Could not obtain specifics of capture window.\n"); 149 return -1; 130 struct v4l2_format form; 131 memset(&form, 0, sizeof (v4l2_format)); 132 form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 133 134 /* read the current setting */ 135 if(-1 == xioctl(device, VIDIOC_G_FMT, &form)) { 136 Thread::Err("Could not obtain specifics of capture window.\n"); 137 return -1; 138 } 139 140 /* set the values we want to change */ 141 form.fmt.pix.width = width; 142 form.fmt.pix.height = height; 143 form.fmt.win.chromakey = 0; 144 form.fmt.win.field = V4L2_FIELD_ANY; 145 form.fmt.win.clips = 0; 146 form.fmt.win.clipcount = 0; 147 form.fmt.pix.field = V4L2_FIELD_ANY; 148 form.fmt.pix.pixelformat = colorspace; 149 150 /* ask the device to change the size*/ 151 if(-1 == xioctl (device, VIDIOC_S_FMT, &form)) { 152 Thread::Err("Could not set specifics of capture window.\n"); 153 return -1; 154 } 155 156 /* Get window info again, to get the real value */ 157 if(-1 == xioctl (device, VIDIOC_G_FMT, &form)) { 158 Thread::Err("Could not obtain specifics of capture window.\n"); 159 return -1; 150 160 } 151 161 152 setVideoSize(width, height,colorspace); 153 154 unsigned int min; 155 156 /* Buggy driver paranoia. */ 157 min = capture.form.fmt.pix.width * 2; 158 if (capture.form.fmt.pix.bytesperline < min) { 159 capture.form.fmt.pix.bytesperline = min; 160 } 161 162 min = capture.form.fmt.pix.bytesperline * capture.form.fmt.pix.height; 163 if (capture.form.fmt.pix.sizeimage < min) { 164 capture.form.fmt.pix.sizeimage = min; 165 } 166 167 return 1; 168 } 169 170 int V4LCamera::setVideoSize(int width, int height,unsigned long colorspace) { 171 172 CLEAR (capture.crop); 173 capture.crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 174 capture.crop.c.left = 0; 175 capture.crop.c.top = 0; 176 capture.crop.c.height = height*24; 177 capture.crop.c.width = width*24; 178 179 /* set the crop area, but don't exit if the device don't support croping */ 180 xioctl (device, VIDIOC_S_CROP, &capture.crop); 181 182 CLEAR (capture.form); 183 capture.form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 184 185 /* read the current setting */ 186 xioctl (device, VIDIOC_G_FMT, &capture.form); 187 188 /* set the values we want to change */ 189 capture.form.fmt.pix.width = width; 190 capture.form.fmt.pix.height = height; 191 capture.form.fmt.win.chromakey = 0; 192 capture.form.fmt.win.field = V4L2_FIELD_ANY; 193 capture.form.fmt.win.clips = 0; 194 capture.form.fmt.win.clipcount = 0; 195 capture.form.fmt.pix.field = V4L2_FIELD_ANY; 196 capture.form.fmt.pix.pixelformat = colorspace; 197 198 /* ask the device to change the size*/ 199 if (-1 == xioctl (device, VIDIOC_S_FMT, &capture.form)) { 200 Thread::Err("Could not set specifics of capture window.\n"); 201 return -1; 202 } 203 204 /* Get window info again, to get the real value */ 205 if (-1 == xioctl (device, VIDIOC_G_FMT, &capture.form)) { 206 Thread::Err("Could not obtain specifics of capture window.\n"); 207 return -1; 208 } 209 return 0; 210 162 return 0; 211 163 } 212 164 213 165 /* 214 V4LCamera::V4LCamera(string name,215 uint8_t camera_index, uint16_t width, uint16_t height,216 Image::Type::Format format, uint8_t priority)217 : Thread(getFrameworkManager(), name, priority),218 Camera(name, width, height, format) {219 220 string deviceName="/dev/video"+std::to_string(camera_index);221 device = open(deviceName.c_str(), O_RDWR | O_NONBLOCK);222 if (device == -1) {223 Thread::Err("Cannot open %s\n",deviceName.c_str());224 } else {225 Printf("V4LCamera %s, opened %s\n",name.c_str(),deviceName.c_str());226 }227 228 struct v4l2_capability cap;229 memset(&cap, 0, sizeof (v4l2_capability));230 if (xioctl (device, VIDIOC_QUERYCAP, &cap)==-1) {231 Thread::Err("VIDIOC_QUERYCAP xioctl\n");232 }233 if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {234 Thread::Err("device is unable to capture video memory.\n");235 }236 237 //get v4l2_format238 struct v4l2_format form;239 form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;240 if(xioctl (device, VIDIOC_G_FMT,&form)==-1) {241 Thread::Err("VIDIOC_G_FMT xioctl\n");242 }243 244 //set width, height and format245 if (format == Image::Type::Format::UYVY) {246 form.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;247 } else if (format == Image::Type::Format::YUYV) {248 form.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;249 } else {250 Thread::Err("format not supported\n");251 }252 253 form.fmt.pix.width = width;254 form.fmt.pix.height = height;255 form.fmt.win.chromakey = 0;256 form.fmt.win.field = V4L2_FIELD_ANY;257 form.fmt.win.clips = 0;258 form.fmt.win.clipcount = 0;259 form.fmt.pix.field = V4L2_FIELD_ANY;260 if(xioctl (device, VIDIOC_S_FMT,&form)==-1) {261 Thread::Err("VIDIOC_S_FMT xioctl\n");262 }263 264 //alloc and queue bufs265 AllocBuffers();266 for (int bufferIndex = 0; bufferIndex < nbBuffers;++bufferIndex) {267 QueueBuffer(bufferIndex);268 }269 270 // enable the streaming271 v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;272 if (xioctl (device, VIDIOC_STREAMON,&type)==-1) {273 Thread::Err("VIDIOC_STREAMON xioctl\n");274 }275 276 // skip first frame. it is often bad -- this is unnotied in traditional apps,277 // but could be fatal if bad jpeg is enabled278 bufferIndex=-1;279 GrabFrame();280 281 // ground station282 gain = new DoubleSpinBox(GetGroupBox()->NewRow(), "gain:", 0, 1, 0.1);283 exposure = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "exposure:", 0,1, 0.1);284 bright = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "bright:", 0, 1, 0.1);285 contrast = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "contrast:", 0,1, 0.1);286 hue = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "hue:", 0, 1, 0.1);287 sharpness = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "sharpness:", 0, 1, 0.1);288 sat = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "saturation:", 0, 1,0.1);289 autogain = new CheckBox(GetGroupBox()->NewRow(), "autogain:");290 autoexposure = new CheckBox(GetGroupBox()->LastRowLastCol(), "autoexposure:");291 awb = new CheckBox(GetGroupBox()->LastRowLastCol(), "awb:");292 fps = new Label(GetGroupBox()->NewRow(), "fps");293 294 hasProblems=false;295 }296 297 V4LCamera::~V4LCamera() {298 for (int n_buffers = 0; n_buffers < nbBuffers; n_buffers++) {299 FreeFunction((char*)buffers[n_buffers].start);300 }301 SafeStop();302 Join();303 }304 305 166 void V4LCamera::Run(void) { 306 167 Time cam_time, new_time, fpsNow, fpsPrev; … … 395 256 */ 396 257 int V4LCamera::allocBuffers() { 397 CLEAR (capture.req); 398 399 unsigned int buffer_number = DEFAULT_V4L_BUFFERS; 400 401 try_again: 402 403 capture.req.count = buffer_number; 404 capture.req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 405 capture.req.memory = V4L2_MEMORY_MMAP; 406 407 if (-1 == xioctl (device, VIDIOC_REQBUFS, &capture.req)) { 408 if (EINVAL == errno) { 409 Thread::Warn("does not support memory mapping\n"); 410 } else { 411 perror ("VIDIOC_REQBUFS"); 412 } 413 /* free capture, and returns an error code */ 414 return -1; 415 } 416 417 if (capture.req.count < buffer_number) { 418 if (buffer_number == 1) { 419 Thread::Warn("Insufficient buffer memory\n"); 420 /* free capture, and returns an error code */ 421 return -1; 422 } else { 423 buffer_number--; 424 Thread::Warn("Insufficient buffer memory -- decreaseing buffers\n"); 425 goto try_again; 426 } 427 } 428 429 for (n_buffers = 0; n_buffers < capture.req.count; ++n_buffers) { 430 struct v4l2_buffer buf; 431 CLEAR (buf); 432 433 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 434 buf.memory = V4L2_MEMORY_MMAP; 435 buf.index = n_buffers; 436 437 if (-1 == xioctl (device, VIDIOC_QUERYBUF, &buf)) { 438 Thread::Warn ("VIDIOC_QUERYBUF error\n"); 439 /* free capture, and returns an error code */ 440 return -1; 441 } 442 443 capture.buffers[n_buffers].length = buf.length; 444 capture.buffers[n_buffers].start = 445 mmap (NULL /* start anywhere */, 446 buf.length, 447 PROT_READ | PROT_WRITE /* required */, 448 MAP_SHARED /* recommended */, 449 device, buf.m.offset); 450 451 if (MAP_FAILED == capture.buffers[n_buffers].start) { 452 Thread::Warn("mmap error\n"); 453 /* free capture, and returns an error code */ 454 return -1; 455 } 456 } 457 458 /* Set up Image data */ 459 /* 460 cvInitImageHeader( &capture.frame, 461 cvSize( capture.captureWindow.width, 462 capture.captureWindow.height ), 463 IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );*/ 464 /* Allocate space for RGBA data */ 465 capture.imageSize=capture.form.fmt.pix.width*capture.form.fmt.pix.height*2; 466 capture.imageData = AllocFunction(capture.imageSize); 467 Printf("cmem allocated %i at %x\n",capture.imageSize,capture.imageData); 468 469 return 1; 258 struct v4l2_requestbuffers req; 259 memset(&req, 0, sizeof (v4l2_requestbuffers)); 260 nbBuffers=DEFAULT_V4L_BUFFERS; 261 262 try_again: 263 264 req.count = nbBuffers; 265 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 266 req.memory = V4L2_MEMORY_MMAP; 267 268 if(-1 == xioctl(device, VIDIOC_REQBUFS, &req)) { 269 if (EINVAL == errno) { 270 Thread::Err("camera does not support memory mapping\n"); 271 } else { 272 Thread::Err("VIDIOC_REQBUFS failed\n"); 273 } 274 return -1; 275 } 276 277 if(req.count < nbBuffers) { 278 if (nbBuffers == 1) { 279 Thread::Err("Insufficient buffer memory\n"); 280 return -1; 281 } else { 282 nbBuffers--; 283 Thread::Warn("Insufficient buffer memory -- decreaseing buffers to %i\n",nbBuffers); 284 goto try_again; 285 } 286 } 287 288 for(int i=0; i<req.count; i++) { 289 struct v4l2_buffer buf; 290 memset(&buf, 0, sizeof (v4l2_buffer)); 291 292 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 293 buf.memory = V4L2_MEMORY_MMAP; 294 buf.index = i; 295 296 if(-1 == xioctl(device, VIDIOC_QUERYBUF, &buf)) { 297 Thread::Err("VIDIOC_QUERYBUF error\n"); 298 return -1; 299 } 300 301 if(output->GetDataType().GetSize()!=buf.length) { 302 Thread::Err("buf size is not as exepcted %i/%i\n",buf.length,output->GetDataType().GetSize()); 303 return -1; 304 } 305 306 buffers[i]=mmap(NULL,buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,device, buf.m.offset); 307 308 if(MAP_FAILED == buffers[i]) { 309 Thread::Err("mmap error\n"); 310 return -1; 311 } 312 } 313 314 //allocate output data 315 imageData = AllocFunction(output->GetDataType().GetSize()); 316 Printf("cmem allocated %i at %x\n",output->GetDataType().GetSize(),imageData); 317 318 return 1; 470 319 }; 471 320 321 int V4LCamera::AllocBuffers(void) { 322 struct v4l2_requestbuffers requestbuffers; 323 memset(&requestbuffers, 0, sizeof (v4l2_requestbuffers)); 324 325 unsigned int buffer_number = DEFAULT_V4L_BUFFERS; 326 327 try_again: 328 329 requestbuffers.count = buffer_number; 330 requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 331 requestbuffers.memory = V4L2_MEMORY_USERPTR; 332 333 if (xioctl (device, VIDIOC_REQBUFS, &requestbuffers)==-1) { 334 if (errno==EINVAL) { 335 Thread::Err("VIDIOC_REQBUFS user memory not supported\n"); 336 } else { 337 Thread::Err ("VIDIOC_REQBUFS xioctl\n"); 338 } 339 return -1; 340 } 341 342 nbBuffers=DEFAULT_V4L_BUFFERS; 343 for (int i=0; i<nbBuffers; i++) { 344 buffers[i] =AllocFunction(output->GetDataType().GetSize()); 345 } 346 347 return 1; 348 }; 472 349 473 350 int V4LCamera::cvGrabFrame(void) { … … 505 382 } 506 383 507 if (read_frame_v4l2 ( &capture))384 if (read_frame_v4l2 ()) 508 385 break; 509 386 } … … 512 389 } 513 390 514 int V4LCamera::read_frame_v4l2( CvCaptureCAM_V4L* capture) {391 int V4LCamera::read_frame_v4l2(void) { 515 392 struct v4l2_buffer buf; 516 517 CLEAR (buf); 393 memset(&buf, 0, sizeof (v4l2_buffer)); 518 394 519 395 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; … … 537 413 } 538 414 539 if(buf.index >= capture->req.count) {415 if(buf.index >= nbBuffers) { 540 416 Thread::Err("buf.index >= capture->req.count\n"); 541 417 } 542 543 544 capture->bufferIndex = buf.index; 545 418 419 bufferIndex = buf.index; 546 420 547 421 if (-1 == xioctl (device, VIDIOC_QBUF, &buf)) … … 611 485 612 486 // cam pictures 613 cvRetrieveRawFrame( &capture);487 cvRetrieveRawFrame(); 614 488 if (!cvGrabFrame()) { 615 489 Printf("Could not grab a frame\n"); … … 625 499 output->GetMutex(); 626 500 627 output->buffer= capture.imageData;501 output->buffer=imageData; 628 502 output->ReleaseMutex(); 629 503 … … 632 506 cam_time = new_time; 633 507 } 634 635 //cvReleaseCapture(&capture); 636 } 637 638 void V4LCamera::cvRetrieveRawFrame( CvCaptureCAM_V4L* capture) { 639 640 641 642 643 /* Now get what has already been captured as a IplImage return */ 644 645 /* First, reallocate imageData if the frame size changed */ 646 647 648 /* 649 if(((unsigned long)capture->frame.width != capture->form.fmt.pix.width) 650 || ((unsigned long)capture->frame.height != capture->form.fmt.pix.height)) { 651 if (PALETTE_YUYV == 1 || PALETTE_UYVY == 1) 652 { 653 cvFree(&capture->frame.imageData); 654 cvInitImageHeader( &capture->frame, 655 cvSize( capture->form.fmt.pix.width, 656 capture->form.fmt.pix.height ), 657 IPL_DEPTH_8U,2, IPL_ORIGIN_TL, 4 ); 658 capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize); 659 }else 660 { 661 fprintf( stderr, 662 "HIGHGUI ERROR: V4L: raw output not supported for this palette\n"); 663 } 664 665 } 666 667 */ 668 669 670 671 memcpy((char *)capture->imageData,(char *)capture->buffers[capture->bufferIndex].start,capture->imageSize); 672 673 674 675 676 } 508 } 509 510 void V4LCamera::cvRetrieveRawFrame(void) { 511 memcpy(imageData,(char *)buffers[bufferIndex],output->GetDataType().GetSize()); 512 } 513 677 514 int V4LCamera::QueueBuffer(int index) { 678 515 struct v4l2_buffer buf; … … 682 519 buf.memory = V4L2_MEMORY_USERPTR;//V4L2_MEMORY_MMAP; 683 520 buf.index = (unsigned long)index; 684 buf.m.userptr=(unsigned long)(buffers[index] .start);685 buf.length= buffers[index].length;521 buf.m.userptr=(unsigned long)(buffers[index]); 522 buf.length=output->GetDataType().GetSize(); 686 523 687 524 int ret=xioctl (device, VIDIOC_QBUF, &buf); … … 738 575 QueueBuffer(prevDQbuf); 739 576 } 740 for (int n_buffers = 0; n_buffers < nbBuffers; n_buffers++) {741 if((void*)(buf.m.userptr)==buffers[ n_buffers].start) {742 prevDQbuf= n_buffers;743 bufferIndex= n_buffers;577 for (int i=0; i<nbBuffers; i++) { 578 if((void*)(buf.m.userptr)==buffers[i]) { 579 prevDQbuf=i; 580 bufferIndex=i; 744 581 break; 745 582 } … … 750 587 return 1; 751 588 } 752 753 int V4LCamera::AllocBuffers(void) {754 struct v4l2_requestbuffers requestbuffers;755 memset(&requestbuffers, 0, sizeof (v4l2_requestbuffers));756 757 unsigned int buffer_number = DEFAULT_V4L_BUFFERS;758 759 try_again:760 761 requestbuffers.count = buffer_number;762 requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;763 requestbuffers.memory = V4L2_MEMORY_USERPTR;//V4L2_MEMORY_MMAP;764 765 if (xioctl (device, VIDIOC_REQBUFS, &requestbuffers)==-1) {766 if (errno==EINVAL) {767 Thread::Err("VIDIOC_REQBUFS user memory not supported\n");768 } else {769 Thread::Err ("VIDIOC_REQBUFS xioctl\n");770 }771 return -1;772 }773 774 nbBuffers=DEFAULT_V4L_BUFFERS;775 for (int n_buffers = 0; n_buffers < nbBuffers; n_buffers++) {776 buffers[n_buffers].length = output->GetDataType().GetSize();777 buffers[n_buffers].start =AllocFunction(output->GetDataType().GetSize());778 }779 780 return 1;781 };782 589 783 590 bool V4LCamera::HasProblems(void) {
Note:
See TracChangeset
for help on using the changeset viewer.