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, 3 years 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.