Changeset 352 in flair-src for trunk/lib/FlairSensorActuator/src/V4LCamera.cpp
- Timestamp:
- Feb 19, 2020, 5:07:13 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/lib/FlairSensorActuator/src/V4LCamera.cpp
r351 r352 17 17 18 18 #include "V4LCamera.h" 19 #include <GroupBox.h> 20 #include <DoubleSpinBox.h> 21 #include <CheckBox.h> 22 #include <Label.h> 19 #include "V4LCamera_impl.h" 23 20 #include <Image.h> 24 21 #include <FrameworkManager.h> 25 #include <fcntl.h>26 //#include <linux/videodev2.h>27 #include <sys/ioctl.h>28 #include <unistd.h>29 #include <cstring>30 #include <sys/mman.h>31 #include <VisionFilter.h>32 22 33 23 using std::string; 34 24 using namespace flair::core; 35 using namespace flair::gui;36 25 37 26 namespace flair { … … 43 32 Camera(name, width, height, format) { 44 33 45 string deviceName="/dev/video"+std::to_string(camera_index); 46 device = open(deviceName.c_str(), O_RDWR | O_NONBLOCK); 47 if (device == -1) { 48 Thread::Err("Cannot open %s\n",deviceName.c_str()); 49 } else { 50 Printf("V4LCamera %s, opened %s\n",name.c_str(),deviceName.c_str()); 51 } 52 53 if(format == Image::Type::Format::UYVY) { 54 if(Init(width,height,V4L2_PIX_FMT_UYVY) == -1) { 55 Thread::Err("initialisation failed\n"); 56 } 57 } else if (format == Image::Type::Format::YUYV) { 58 if(Init(width,height,V4L2_PIX_FMT_YUYV) == -1) { 59 Thread::Err("initialisation failed\n"); 60 } 61 } else { 62 Thread::Err("format not supported\n"); 63 } 64 65 //todo: better handling of detection, only neeeded for omap/dm 66 //also in run, copy from v4l to cmem is not necessary if not using cmem... 67 #ifdef ARMV7A 68 useMemoryUsrPtr=true; 69 #else 70 useMemoryUsrPtr=false; 71 #endif 72 if(useMemoryUsrPtr) { 73 AllocUserBuffers(); 74 } else { 75 AllocV4LBuffers(); 76 } 77 78 for (int i=0;i < nbBuffers;i++) { 79 QueueBuffer(i); 80 } 81 82 /* enable the streaming */ 83 v4l2_buf_type type; 84 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 85 if (-1 == xioctl (device, VIDIOC_STREAMON,&type)) { 86 Thread::Err("VIDIOC_STREAMON error\n"); 87 } 88 89 // ground station 90 gain = new DoubleSpinBox(GetGroupBox()->NewRow(), "gain:", 0, 1, 0.1); 91 exposure = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "exposure:", 0,1, 0.1); 92 bright = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "bright:", 0, 1, 0.1); 93 contrast = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "contrast:", 0,1, 0.1); 94 hue = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "hue:", 0, 1, 0.1); 95 sharpness = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "sharpness:", 0, 1, 0.1); 96 sat = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "saturation:", 0, 1,0.1); 97 autogain = new CheckBox(GetGroupBox()->NewRow(), "autogain:"); 98 autoexposure = new CheckBox(GetGroupBox()->LastRowLastCol(), "autoexposure:"); 99 awb = new CheckBox(GetGroupBox()->LastRowLastCol(), "awb:"); 100 fps = new Label(GetGroupBox()->NewRow(), "fps"); 101 102 hasProblems=false; 34 pimpl_=new V4LCamera_impl(this,name,camera_index,width,height,format); 103 35 } 104 36 105 37 V4LCamera::~V4LCamera() { 106 if(useMemoryUsrPtr) {107 for (int i = 0; i < nbBuffers; i++) {108 FreeFunction((char*)buffers[i]);109 }110 } else {111 FreeFunction(imageData);112 }113 38 SafeStop(); 114 39 Join(); 115 close(device); 116 } 117 118 int V4LCamera::Init(int width, int height,unsigned long colorspace) { 119 struct v4l2_capability cap; 120 memset(&cap, 0, sizeof (v4l2_capability)); 121 122 if(-1 == xioctl(device, VIDIOC_QUERYCAP, &cap)) { 123 return -1; 124 } 125 126 if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { 127 Thread::Err("device is unable to capture video memory.\n"); 128 return -1; 129 } 130 131 struct v4l2_format form; 132 memset(&form, 0, sizeof (v4l2_format)); 133 form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 134 135 /* read the current setting */ 136 if(-1 == xioctl(device, VIDIOC_G_FMT, &form)) { 137 Thread::Err("Could not obtain specifics of capture window.\n"); 138 return -1; 139 } 140 141 /* set the values we want to change */ 142 form.fmt.pix.width = width; 143 form.fmt.pix.height = height; 144 form.fmt.win.chromakey = 0; 145 form.fmt.win.field = V4L2_FIELD_ANY; 146 form.fmt.win.clips = 0; 147 form.fmt.win.clipcount = 0; 148 form.fmt.pix.field = V4L2_FIELD_ANY; 149 form.fmt.pix.pixelformat = colorspace; 150 151 /* ask the device to change the size*/ 152 if(-1 == xioctl (device, VIDIOC_S_FMT, &form)) { 153 Thread::Err("Could not set specifics of capture window.\n"); 154 return -1; 155 } 156 157 return 0; 158 } 159 160 int V4LCamera::AllocV4LBuffers() { 161 struct v4l2_requestbuffers req; 162 memset(&req, 0, sizeof (v4l2_requestbuffers)); 163 nbBuffers=DEFAULT_V4L_BUFFERS; 164 165 try_again: 166 167 req.count = nbBuffers; 168 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 169 req.memory = V4L2_MEMORY_MMAP; 170 171 if(-1 == xioctl(device, VIDIOC_REQBUFS, &req)) { 172 if (EINVAL == errno) { 173 Thread::Err("camera does not support memory mapping\n"); 174 } else { 175 Thread::Err("VIDIOC_REQBUFS failed\n"); 176 } 177 return -1; 178 } 179 180 if(req.count < nbBuffers) { 181 if (nbBuffers == 1) { 182 Thread::Err("Insufficient buffer memory\n"); 183 return -1; 184 } else { 185 nbBuffers--; 186 Thread::Warn("Insufficient buffer memory -- decreaseing buffers to %i\n",nbBuffers); 187 goto try_again; 188 } 189 } 190 191 for(int i=0; i<req.count; i++) { 192 struct v4l2_buffer buf; 193 memset(&buf, 0, sizeof (v4l2_buffer)); 194 195 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 196 buf.memory = V4L2_MEMORY_MMAP; 197 buf.index = i; 198 199 if(-1 == xioctl(device, VIDIOC_QUERYBUF, &buf)) { 200 Thread::Err("VIDIOC_QUERYBUF error\n"); 201 return -1; 202 } 203 204 if(output->GetDataType().GetSize()!=buf.length) { 205 Thread::Err("buf size is not as exepcted %i/%i\n",buf.length,output->GetDataType().GetSize()); 206 return -1; 207 } 208 209 buffers[i]=mmap(NULL,buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,device, buf.m.offset); 210 211 if(MAP_FAILED == buffers[i]) { 212 Thread::Err("mmap error\n"); 213 return -1; 214 } 215 } 216 217 //allocate output data 218 imageData = AllocFunction(output->GetDataType().GetSize()); 219 //Printf("cmem allocated %i at %x\n",output->GetDataType().GetSize(),imageData); 220 221 return 1; 222 }; 223 224 int V4LCamera::AllocUserBuffers(void) { 225 struct v4l2_requestbuffers req; 226 memset(&req, 0, sizeof (v4l2_requestbuffers)); 227 nbBuffers=DEFAULT_V4L_BUFFERS; 228 229 req.count = nbBuffers; 230 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 231 req.memory = V4L2_MEMORY_USERPTR; 232 233 if (xioctl (device, VIDIOC_REQBUFS, &req)==-1) { 234 if (errno==EINVAL) { 235 Thread::Err("VIDIOC_REQBUFS user memory not supported\n"); 236 } else { 237 Thread::Err ("VIDIOC_REQBUFS xioctl\n"); 238 } 239 return -1; 240 } 241 242 for (int i=0; i<nbBuffers; i++) { 243 buffers[i] =AllocFunction(output->GetDataType().GetSize()); 244 } 245 246 return 1; 247 }; 248 249 int V4LCamera::GrabFrame(void) { 250 fd_set fds; 251 struct timeval tv; 252 FD_ZERO (&fds); 253 FD_SET (device, &fds); 254 255 tv.tv_sec = 0; 256 tv.tv_usec = 100000; 257 258 int r=select(device+1, &fds, NULL, NULL, &tv); 259 260 if (r==-1) { 261 char errorMsg[256]; 262 Thread::Err("select (%s)\n", strerror_r(-r, errorMsg, sizeof(errorMsg))); 263 return -1; 264 } 265 266 if (r==0) { 267 Thread::Err("select timeout\n"); 268 return -1; 269 } 270 271 struct v4l2_buffer buf; 272 memset(&buf, 0, sizeof (v4l2_buffer)); 273 buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; 274 if(useMemoryUsrPtr) { 275 buf.memory=V4L2_MEMORY_USERPTR; 276 } else { 277 buf.memory=V4L2_MEMORY_MMAP; 278 } 279 280 //get last captured buffer 281 dQueuedBuffer.index=-1; 282 for(int i=0;i<nbBuffers;i++) { 283 if (xioctl (device, VIDIOC_DQBUF, &buf)==-1) { 284 if (errno==EAGAIN) {//when no new buffer is available for reading (non blocking) 285 //Printf("%s eagain\n",Thread::ObjectName().c_str()); 286 break; 287 } else { 288 Thread::Err("VIDIOC_DQBUF xioctl\n"); 289 return -1; 290 } 291 } else { 292 //Printf("%s %i dqueued\n",Thread::ObjectName().c_str(),buf.index); 293 //Printf("%i %x %i %i\n",buf.bytesused,buf.flags,buf.field,buf.sequence); 294 if(dQueuedBuffer.index!=-1) { 295 //Printf("%s %i queued\n",Thread::ObjectName().c_str(),dQueuedBuffer.index); 296 QueueBuffer(&dQueuedBuffer); 297 } 298 dQueuedBuffer=buf; 299 } 300 } 301 //Printf("%s %i\n",Thread::ObjectName().c_str(),dQueuedBuffer.index); 302 303 return 1; 40 delete pimpl_; 304 41 } 305 42 306 43 void V4LCamera::Run(void) { 44 pimpl_->Run(); 45 /* 307 46 Time cam_time, new_time, fpsNow, fpsPrev; 308 47 int fpsCounter = 0; … … 368 107 Thread::Warn("delta t trop grand\n"); 369 108 hasProblems=true; 370 }/* 371 if(hasProblems==false) { 372 struct v4l2_format form; 373 form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 374 xioctl(device, VIDIOC_G_FMT,&form); 375 if(xioctl (device, VIDIOC_G_FMT,&form)<0) { 376 Thread::Warn("camera disconnected\n"); 377 hasProblems=true; 378 } 379 }*/ 109 } 380 110 381 111 //select buffer … … 400 130 } 401 131 } 402 } 403 404 int V4LCamera::QueueBuffer(struct v4l2_buffer *buf) { 405 if(buf->index>=0 && buf->index<nbBuffers) { 406 int ret=xioctl (device, VIDIOC_QBUF,buf); 407 if (ret==-1) { 408 Thread::Err("VIDIOC_QBUF xioctl %s\n",strerror(-ret)); 409 return -1; 410 } 411 } 412 return 0; 413 } 414 415 int V4LCamera::QueueBuffer(int index) { 416 struct v4l2_buffer buf; 417 memset(&buf, 0, sizeof (v4l2_buffer)); 418 419 buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; 420 buf.index=(unsigned long)index; 421 if(useMemoryUsrPtr) { 422 buf.memory=V4L2_MEMORY_USERPTR; 423 buf.m.userptr=(unsigned long)(buffers[index]); 424 buf.length=output->GetDataType().GetSize(); 425 } else { 426 buf.memory=V4L2_MEMORY_MMAP; 427 } 428 return QueueBuffer(&buf); 132 */ 429 133 } 430 134 431 135 bool V4LCamera::HasProblems(void) { 432 return hasProblems;136 return pimpl_->hasProblems; 433 137 } 434 138 435 139 void V4LCamera::SetAutoGain(bool value) { 436 SetProperty(V4L2_CID_AUTOGAIN,value);140 pimpl_->SetAutoGain(value); 437 141 } 438 142 … … 442 146 443 147 void V4LCamera::SetGain(float value) { 444 SetProperty(V4L2_CID_GAIN,value);148 pimpl_->SetGain(value); 445 149 } 446 150 447 151 void V4LCamera::SetExposure(float value) { 448 SetProperty(V4L2_CID_EXPOSURE,value);152 pimpl_->SetExposure(value); 449 153 } 450 154 451 155 void V4LCamera::SetBrightness(float value) { 452 SetProperty(V4L2_CID_BRIGHTNESS,value);156 pimpl_->SetBrightness(value); 453 157 } 454 158 455 159 void V4LCamera::SetSaturation(float value) { 456 SetProperty(V4L2_CID_SATURATION,value);160 pimpl_->SetSaturation(value); 457 161 } 458 162 459 163 void V4LCamera::SetHue(float value) { 460 SetProperty(V4L2_CID_HUE,value);164 pimpl_->SetHue(value); 461 165 } 462 166 463 167 void V4LCamera::SetContrast(float value) { 464 SetProperty(V4L2_CID_CONTRAST, value); 465 } 466 467 float V4LCamera::GetProperty(int property) { 468 //get min and max value 469 struct v4l2_queryctrl queryctrl; 470 queryctrl.id = property; 471 if(xioctl (device, VIDIOC_QUERYCTRL,&queryctrl)==-1) return -1; 472 int min = queryctrl.minimum; 473 int max = queryctrl.maximum; 474 475 //set value 476 struct v4l2_control control; 477 memset (&control, 0, sizeof (v4l2_control)); 478 control.id = property; 479 if(xioctl (device,VIDIOC_G_CTRL, &control)==-1) return -1; 480 481 return ((float)control.value - min + 1) / (max - min); 482 } 483 484 void V4LCamera::SetProperty(int property,float value) { 485 //get min and max value 486 struct v4l2_queryctrl queryctrl; 487 queryctrl.id = property; 488 if(xioctl (device, VIDIOC_QUERYCTRL,&queryctrl)==-1) { 489 Thread::Warn("prop %x, VIDIOC_QUERYCTRL failed\n",property); 490 } 491 int min = queryctrl.minimum; 492 int max = queryctrl.maximum; 493 494 //set value 495 struct v4l2_control control; 496 memset (&control, 0, sizeof (v4l2_control)); 497 control.id = property; 498 control.value = (int)(value * (max - min) + min); 499 if(xioctl (device,VIDIOC_S_CTRL, &control)==-1) { 500 Thread::Warn("prop %x, VIDIOC_S_CTRL failed\n",property); 501 } 502 } 503 504 int V4LCamera::xioctl( int fd, int request, void *arg) { 505 int r; 506 507 do r = ioctl (fd, request, arg); 508 while (-1 == r && EINTR == errno); 509 510 return r; 168 pimpl_->SetContrast(value); 511 169 } 512 170
Note:
See TracChangeset
for help on using the changeset viewer.