source: flair-src/trunk/lib/FlairSensorActuator/src/V4LCamera_impl.cpp @ 400

Last change on this file since 400 was 400, checked in by Sanahuja Guillaume, 6 months ago

cosmetic changes

File size: 14.1 KB
Line 
1// %flair:license{
2// This file is part of the Flair framework distributed under the
3// CECILL-C License, Version 1.0.
4// %flair:license}
5//  created:    2014/07/17
6//  filename:   V4LCamera_impl.cpp
7//
8//  author:     Guillaume Sanahuja
9//              Copyright Heudiasyc UMR UTC/CNRS 7253
10//
11//  version:    $Id: $
12//
13//  purpose:    base class for V4l camera
14//
15//
16/*********************************************************************/
17
18#include "V4LCamera_impl.h"
19#include "V4LCamera.h"
20#include <GroupBox.h>
21#include <DoubleSpinBox.h>
22#include <CheckBox.h>
23#include <Label.h>
24#include <Image.h>
25#include <FrameworkManager.h>
26#include <fcntl.h>
27#include <sys/ioctl.h>
28#include <unistd.h>
29#include <cstring>
30#include <sys/mman.h>
31#include <VisionFilter.h>
32
33using std::string;
34using namespace flair::core;
35using namespace flair::gui;
36using namespace flair::sensor;
37
38 
39V4LCamera_impl::V4LCamera_impl(V4LCamera *self,string name,uint8_t camera_index, uint16_t width, uint16_t height,
40                     Image::Type::Format format) {
41  this->self=self;
42 
43  string deviceName="/dev/video"+std::to_string(camera_index);
44  device = open(deviceName.c_str(), O_RDWR | O_NONBLOCK);
45  if (device == -1) {
46      ((Thread*)self)->Err("Cannot open %s\n",deviceName.c_str());
47  } else {
48      Printf("V4LCamera %s, opened %s\n",name.c_str(),deviceName.c_str());
49  }
50
51  if(format == Image::Type::Format::UYVY) {
52    if(Init(width,height,V4L2_PIX_FMT_UYVY) == -1) {
53     ((Thread*)self)->Err("initialisation failed\n");
54    }
55  } else if (format == Image::Type::Format::YUYV) {
56    if(Init(width,height,V4L2_PIX_FMT_YUYV) == -1) {
57     ((Thread*)self)->Err("initialisation failed\n");
58    }
59  } else {
60    ((Thread*)self)->Err("format not supported\n");
61  }
62 
63  //todo: better handling of detection, only neeeded for omap/dm
64  //also in run, copy from v4l to cmem is not necessary if not using cmem...
65#ifdef ARMV7A
66  useMemoryUsrPtr=true;
67#else
68  useMemoryUsrPtr=false;
69#endif
70  if(useMemoryUsrPtr) {
71    AllocUserBuffers();
72  } else {
73    AllocV4LBuffers();
74  }
75 
76  for (int i=0;i < nbBuffers;i++) {
77    QueueBuffer(i);
78  }
79
80  /* enable the streaming */
81  v4l2_buf_type type;
82  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
83  if (-1 == xioctl (device, VIDIOC_STREAMON,&type)) {
84    ((Thread*)self)->Err("VIDIOC_STREAMON error\n");
85  }
86 
87  // ground station
88  gain = new DoubleSpinBox(self->GetGroupBox()->NewRow(), "gain:", 0, 1, 0.1);
89  exposure = new DoubleSpinBox(self->GetGroupBox()->LastRowLastCol(), "exposure:", 0,1, 0.1);
90  bright = new DoubleSpinBox(self->GetGroupBox()->LastRowLastCol(), "bright:", 0, 1, 0.1);
91  contrast = new DoubleSpinBox(self->GetGroupBox()->LastRowLastCol(), "contrast:", 0,1, 0.1);
92  hue = new DoubleSpinBox(self->GetGroupBox()->LastRowLastCol(), "hue:", 0, 1, 0.1);
93  sharpness = new DoubleSpinBox(self->GetGroupBox()->LastRowLastCol(), "sharpness:", 0, 1, 0.1);
94  sat = new DoubleSpinBox(self->GetGroupBox()->LastRowLastCol(), "saturation:", 0, 1,0.1);
95  autogain = new CheckBox(self->GetGroupBox()->NewRow(), "autogain:");
96  autoexposure = new CheckBox(self->GetGroupBox()->LastRowLastCol(), "autoexposure:");
97  awb = new CheckBox(self->GetGroupBox()->LastRowLastCol(), "awb:");
98  fps = new Label(self->GetGroupBox()->NewRow(), "fps");
99 
100  hasProblems=false;
101}
102
103V4LCamera_impl::~V4LCamera_impl() {
104  if(useMemoryUsrPtr) {
105    for (int i = 0; i < nbBuffers; i++) {
106      FreeFunction((char*)buffers[i]);
107    }
108  } else {
109      FreeFunction(imageData);
110  }
111  close(device);
112}
113
114int V4LCamera_impl::Init(int width, int height,unsigned long colorspace) {
115  struct v4l2_capability cap;
116  memset(&cap, 0, sizeof (v4l2_capability));
117 
118  if(-1 == xioctl(device, VIDIOC_QUERYCAP, &cap)) {
119    return -1;
120  }
121     
122  if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
123    ((Thread*)self)->Err("device is unable to capture video memory.\n");
124    return -1;
125  }
126
127  struct v4l2_format form;
128  memset(&form, 0, sizeof (v4l2_format));
129  form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
130
131  /* read the current setting */
132  if(-1 == xioctl(device, VIDIOC_G_FMT, &form)) {
133   ((Thread*)self)->Err("Could not obtain specifics of capture window.\n");
134   return -1;
135  }
136
137  /* set the values we want to change */
138  form.fmt.pix.width = width; 
139  form.fmt.pix.height = height;
140  form.fmt.win.chromakey = 0;
141  form.fmt.win.field = V4L2_FIELD_ANY;
142  form.fmt.win.clips = 0;
143  form.fmt.win.clipcount = 0;
144  form.fmt.pix.field = V4L2_FIELD_ANY;
145  form.fmt.pix.pixelformat = colorspace;
146
147  /* ask the device to change the size*/
148  if(-1 == xioctl (device, VIDIOC_S_FMT, &form)) {
149    ((Thread*)self)->Err("Could not set specifics of capture window.\n");
150    return -1;
151  }
152 
153  return 0;
154}
155
156int V4LCamera_impl::AllocV4LBuffers() {
157  struct v4l2_requestbuffers req;
158  memset(&req, 0, sizeof (v4l2_requestbuffers));
159  nbBuffers=DEFAULT_V4L_BUFFERS;
160
161  try_again:
162
163  req.count = nbBuffers;
164  req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
165  req.memory = V4L2_MEMORY_MMAP;
166
167  if(-1 == xioctl(device, VIDIOC_REQBUFS, &req)) {
168    if (EINVAL == errno) {
169      ((Thread*)self)->Err("camera does not support memory mapping\n");
170    } else {
171      ((Thread*)self)->Err("VIDIOC_REQBUFS failed\n");
172    }
173    return -1;
174  }
175
176  if(req.count < nbBuffers) {
177    if (nbBuffers == 1) {
178      ((Thread*)self)->Err("Insufficient buffer memory\n");
179      return -1;
180    } else {
181      nbBuffers--;
182      ((Thread*)self)->Warn("Insufficient buffer memory -- decreaseing buffers to %i\n",nbBuffers);
183      goto try_again;
184    }
185  }
186
187  for(int i=0; i<req.count; i++) {
188    struct v4l2_buffer buf;
189    memset(&buf, 0, sizeof (v4l2_buffer));
190
191    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
192    buf.memory = V4L2_MEMORY_MMAP;
193    buf.index = i;
194
195    if(-1 == xioctl(device, VIDIOC_QUERYBUF, &buf)) {
196      ((Thread*)self)->Err("VIDIOC_QUERYBUF error\n");
197      return -1;
198    }
199
200    if(self->output->GetDataType().GetSize()!=buf.length) {
201      ((Thread*)self)->Err("buf size is not as exepcted %i/%i\n",buf.length,self->output->GetDataType().GetSize());
202      return -1;
203    }
204
205    buffers[i]=mmap(NULL,buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,device, buf.m.offset);
206
207    if(MAP_FAILED == buffers[i]) {
208      ((Thread*)self)->Err("mmap error\n");
209      return -1;
210    }
211  }
212
213  //allocate output data
214  imageData = AllocFunction(self->output->GetDataType().GetSize());
215  //Printf("cmem allocated %i at %x\n",output->GetDataType().GetSize(),imageData);
216
217  return 1;
218};
219
220int V4LCamera_impl::AllocUserBuffers(void) {
221  struct v4l2_requestbuffers req;
222  memset(&req, 0, sizeof (v4l2_requestbuffers));
223  nbBuffers=DEFAULT_V4L_BUFFERS;
224
225  req.count = nbBuffers;
226  req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
227  req.memory = V4L2_MEMORY_USERPTR;
228
229  if (xioctl (device, VIDIOC_REQBUFS, &req)==-1) {
230    if (errno==EINVAL) {
231      ((Thread*)self)->Err("VIDIOC_REQBUFS user memory not supported\n");
232    } else {
233      ((Thread*)self)->Err ("VIDIOC_REQBUFS xioctl\n");
234    }
235    return -1;
236  }
237
238  for (int i=0; i<nbBuffers; i++) {
239    buffers[i] =AllocFunction(self->output->GetDataType().GetSize());
240  }
241
242  return 1;
243};
244
245int V4LCamera_impl::GrabFrame(void) {
246  fd_set fds;
247  struct timeval tv;
248  FD_ZERO (&fds);
249  FD_SET (device, &fds);
250
251  tv.tv_sec = 0;
252  tv.tv_usec = 100000;
253
254  int r=select(device+1, &fds, NULL, NULL, &tv);
255
256  if (r==-1) {
257    char errorMsg[256];
258    ((Thread*)self)->Err("select (%s)\n", strerror_r(-r, errorMsg, sizeof(errorMsg)));
259    return -1;
260  }
261
262  if (r==0) {
263    ((Thread*)self)->Err("select timeout\n");
264    return -1;
265  }
266 
267  struct v4l2_buffer buf;
268  memset(&buf, 0, sizeof (v4l2_buffer));
269  buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
270  if(useMemoryUsrPtr) {
271    buf.memory=V4L2_MEMORY_USERPTR;
272  } else {
273    buf.memory=V4L2_MEMORY_MMAP;
274  }
275
276   //get last captured buffer
277  dQueuedBuffer.index=-1;
278  for(int i=0;i<nbBuffers;i++) {
279    if (xioctl (device, VIDIOC_DQBUF, &buf)==-1) {
280      if (errno==EAGAIN) {//when no new buffer is available for reading (non blocking)
281        //Printf("%s eagain\n",((Thread*)self)->ObjectName().c_str());
282        break;
283      } else {
284        ((Thread*)self)->Err("VIDIOC_DQBUF xioctl\n");
285        return -1;
286      }
287    } else {
288      //Printf("%s %i dqueued\n",((Thread*)self)->ObjectName().c_str(),buf.index);
289      //Printf("%i %x %i %i\n",buf.bytesused,buf.flags,buf.field,buf.sequence);
290      if(dQueuedBuffer.index!=-1) {
291        //Printf("%s %i queued\n",((Thread*)self)->ObjectName().c_str(),dQueuedBuffer.index);
292        QueueBuffer(&dQueuedBuffer);
293      }
294      dQueuedBuffer=buf;
295    }
296  }
297  //Printf("%s %i\n",((Thread*)self)->ObjectName().c_str(),dQueuedBuffer.index);
298
299  return 1;
300}
301
302void V4LCamera_impl::Run(void) {
303  Time cam_time, new_time, fpsNow, fpsPrev;
304  int fpsCounter = 0;
305
306  cam_time = GetTime();
307  fpsPrev = cam_time;
308
309  while (!self->ToBeStopped()) {
310    // fps counter
311    fpsCounter++;
312    if (fpsCounter == 100) {
313      fpsNow = GetTime();
314      fps->SetText("fps: %.1f",
315       fpsCounter / ((float)(fpsNow - fpsPrev) / 1000000000.));
316      fpsCounter = 0;
317      fpsPrev = fpsNow;
318    }
319
320    // cam properties
321    if (gain->ValueChanged() == true && autogain->Value() == false)
322      self->SetGain(gain->Value());
323    if (exposure->ValueChanged() == true && autoexposure->Value() == false)
324      self->SetExposure(exposure->Value());
325    if (bright->ValueChanged() == true)
326      self->SetBrightness(bright->Value());
327    if (sat->ValueChanged() == true)
328      self->SetSaturation(sat->Value());
329    if (contrast->ValueChanged() == true)
330      self->SetContrast(contrast->Value());
331    if (hue->ValueChanged() == true)
332      self->SetHue(hue->Value());
333    //if (sharpness->ValueChanged() == true)
334    //  cvSetCaptureProperty(capture, CV_CAP_PROP_SHARPNESS, sharpness->Value());
335    if (autogain->ValueChanged() == true) {
336      self->SetAutoGain(autogain->Value());
337      if (autogain->Value() == true) {
338        gain->setEnabled(false);
339      } else {
340        gain->setEnabled(true);
341        self->SetGain(gain->Value());
342      }
343    }
344    if (autoexposure->ValueChanged() == true) {
345      self->SetAutoExposure(autoexposure->Value());
346      if (autoexposure->Value() == true) {
347        exposure->setEnabled(false);
348      } else {
349        exposure->setEnabled(true);
350        self->SetExposure(exposure->Value());
351      }
352    }
353    //if (awb->ValueChanged() == true)
354    //  cvSetCaptureProperty(capture, CV_CAP_PROP_AWB, awb->Value());
355   
356    // cam pictures
357    if (!GrabFrame()) {
358      Printf("Could not grab a frame\n");
359    }
360       
361    //check for ps3eye deconnection in hds uav
362    new_time = GetTime();
363    if(new_time-cam_time>100*1000*1000) {
364      ((Thread*)self)->Warn("delta t trop grand\n");
365      hasProblems=true;
366    }/*
367    if(hasProblems==false) {
368      struct v4l2_format form;
369      form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
370      xioctl(device, VIDIOC_G_FMT,&form);
371      if(xioctl (device, VIDIOC_G_FMT,&form)<0) {
372        ((Thread*)self)->Warn("camera disconnected\n");
373        hasProblems=true;
374      }
375    }*/
376
377    //select buffer
378    if(useMemoryUsrPtr) {//buffers are already in CMEM
379      imageData=(char*)buffers[dQueuedBuffer.index];
380      //dequeue it latter (buffer used by ProcessUpdate)
381    } else {//copy to CMEM allocated buffer
382      memcpy(imageData,(char *)buffers[dQueuedBuffer.index],self->output->GetDataType().GetSize());
383      QueueBuffer(&dQueuedBuffer);//we can do it right now
384    }
385   
386    self->output->GetMutex();
387    self->output->buffer=imageData;
388    self->output->ReleaseMutex();
389   
390    self->output->SetDataTime(cam_time);
391    self->ProcessUpdate(self->output);
392    cam_time = new_time;
393   
394    if(useMemoryUsrPtr) {
395      QueueBuffer(&dQueuedBuffer);//now it is possible to dequeue
396    }
397  }
398}
399
400int V4LCamera_impl::QueueBuffer(struct v4l2_buffer *buf) {
401  if(buf->index>=0 && buf->index<nbBuffers) {
402    int ret=xioctl (device, VIDIOC_QBUF,buf);
403    if (ret==-1) {
404      ((Thread*)self)->Err("VIDIOC_QBUF xioctl %s\n",strerror(-ret));
405      return -1;
406    }
407  }
408  return 0;
409}
410
411int V4LCamera_impl::QueueBuffer(int index) {
412  struct v4l2_buffer buf;
413  memset(&buf, 0, sizeof (v4l2_buffer));
414 
415  buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
416  buf.index=(unsigned long)index;
417  if(useMemoryUsrPtr) {
418    buf.memory=V4L2_MEMORY_USERPTR;
419    buf.m.userptr=(unsigned long)(buffers[index]);
420    buf.length=self->output->GetDataType().GetSize();
421  } else {
422    buf.memory=V4L2_MEMORY_MMAP;
423  }
424  return QueueBuffer(&buf);
425}
426
427void V4LCamera_impl::SetAutoGain(bool value) {
428  SetProperty(V4L2_CID_AUTOGAIN, value);
429}
430
431void V4LCamera_impl::SetAutoExposure(bool value) {
432  ((Thread*)self)->Warn("not implemented\n");
433}
434
435void V4LCamera_impl::SetGain(float value) {
436  SetProperty(V4L2_CID_GAIN, value);
437}
438
439void V4LCamera_impl::SetExposure(float value) {
440  SetProperty(V4L2_CID_EXPOSURE, value);
441}
442
443void V4LCamera_impl::SetBrightness(float value) {
444  SetProperty(V4L2_CID_BRIGHTNESS, value);
445}
446
447void V4LCamera_impl::SetSaturation(float value) {
448  SetProperty(V4L2_CID_SATURATION, value);
449}
450
451void V4LCamera_impl::SetHue(float value) {
452  SetProperty(V4L2_CID_HUE, value);
453}
454
455void V4LCamera_impl::SetContrast(float value) {
456  SetProperty(V4L2_CID_CONTRAST, value);
457}
458
459float V4LCamera_impl::GetProperty(int property) {
460  //get min and max value
461  struct v4l2_queryctrl queryctrl;
462  queryctrl.id = property;
463  if(xioctl (device, VIDIOC_QUERYCTRL,&queryctrl)==-1) return -1;
464  int min = queryctrl.minimum;
465  int max = queryctrl.maximum;
466 
467  //set value
468  struct v4l2_control control;
469  memset (&control, 0, sizeof (v4l2_control));
470  control.id = property;
471  if(xioctl (device,VIDIOC_G_CTRL, &control)==-1) return -1;
472 
473  return ((float)control.value - min + 1) / (max - min);
474}
475
476void V4LCamera_impl::SetProperty(int property,float value) {
477  //get min and max value
478  struct v4l2_queryctrl queryctrl;
479  queryctrl.id = property;
480  if(xioctl (device, VIDIOC_QUERYCTRL,&queryctrl)==-1) {
481    ((Thread*)self)->Warn("prop %x, VIDIOC_QUERYCTRL failed\n",property);
482  }
483  int min = queryctrl.minimum;
484  int max = queryctrl.maximum;
485 
486  //set value
487  struct v4l2_control control;
488  memset (&control, 0, sizeof (v4l2_control));
489  control.id = property;
490  control.value = (int)(value * (max - min) + min);
491  if(xioctl (device,VIDIOC_S_CTRL, &control)==-1) {
492    ((Thread*)self)->Warn("prop %x, VIDIOC_S_CTRL failed\n",property);
493  }
494}
495
496int V4LCamera_impl::xioctl( int fd, int request, void *arg) {
497  int r;
498
499  do r = ioctl (fd, request, arg);
500  while (-1 == r && EINTR == errno);
501
502  return r;
503}
Note: See TracBrowser for help on using the repository browser.