source: flair-src/trunk/lib/FlairSensorActuator/src/V4LCamera.cpp@ 339

Last change on this file since 339 was 338, checked in by Sanahuja Guillaume, 5 years ago

remove opencv dep

File size: 11.5 KB
RevLine 
[3]1// %flair:license{
[15]2// This file is part of the Flair framework distributed under the
3// CECILL-C License, Version 1.0.
[3]4// %flair:license}
5// created: 2014/07/17
6// filename: V4LCamera.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.h"
19#include <GroupBox.h>
20#include <DoubleSpinBox.h>
21#include <CheckBox.h>
22#include <Label.h>
[338]23#include <Image.h>
[3]24#include <FrameworkManager.h>
[330]25#include <fcntl.h>
[3]26#include <linux/videodev2.h>
[330]27#include <sys/ioctl.h>
28#include <unistd.h>
29#include <cstring>
30#include <sys/mman.h>
[338]31#include <VisionFilter.h>
[330]32
33#define DEFAULT_V4L_BUFFERS 4
34
[3]35using std::string;
36using namespace flair::core;
37using namespace flair::gui;
38
[15]39namespace flair {
40namespace sensor {
[3]41
[137]42V4LCamera::V4LCamera(string name,
[15]43 uint8_t camera_index, uint16_t width, uint16_t height,
[338]44 Image::Type::Format format, uint8_t priority)
[137]45 : Thread(getFrameworkManager(), name, priority),
46 Camera(name, width, height, format) {
[330]47
[338]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 }
[330]71
[338]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 }
[330]80
[338]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 }
[330]91
[338]92 //alloc and queue bufs
93 AllocBuffers();
94 for (int bufferIndex = 0; bufferIndex < nbBuffers;++bufferIndex) {
95 QueueBuffer(bufferIndex);
[330]96 }
[338]97
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 }
[330]103
[338]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();
[330]108
[338]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");
[330]121
[338]122 hasProblems=false;
[3]123}
124
[15]125V4LCamera::~V4LCamera() {
[338]126 for (int n_buffers = 0; n_buffers < nbBuffers; n_buffers++) {
127 FreeFunction((char*)buffers[n_buffers].start);
128 }
129 SafeStop();
130 Join();
[3]131}
132
[15]133void V4LCamera::Run(void) {
134 Time cam_time, new_time, fpsNow, fpsPrev;
135 int fpsCounter = 0;
[3]136
[15]137 // init image old
[330]138 GrabFrame();
[15]139 cam_time = GetTime();
140 fpsPrev = cam_time;
141
142 while (!ToBeStopped()) {
[165]143 //check for ps3eye deconnection in hds uav
[330]144 if(hasProblems==false) {
145 struct v4l2_format form;
146 form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
147 xioctl(device, VIDIOC_G_FMT,&form);
148 if(xioctl (device, VIDIOC_G_FMT,&form)<0) {
149 Thread::Warn("camera disconnected\n");
150 hasProblems=true;
151 }
[165]152 }
153
[15]154 // fps counter
155 fpsCounter++;
[307]156 if (GetTime() > (fpsPrev + 5 * (Time)1000000000)) {
[338]157 // every 5 secondes
[15]158 fpsNow = GetTime();
159 fps->SetText("fps: %.1f",
[307]160 fpsCounter / ((float)(fpsNow - fpsPrev) / 1000000000.));
[15]161 fpsCounter = 0;
162 fpsPrev = fpsNow;
[307]163 }
164
[15]165 // cam properties
166 if (gain->ValueChanged() == true && autogain->Value() == false)
167 SetGain(gain->Value());
168 if (exposure->ValueChanged() == true && autoexposure->Value() == false)
169 SetExposure(exposure->Value());
170 if (bright->ValueChanged() == true)
171 SetBrightness(bright->Value());
172 if (sat->ValueChanged() == true)
173 SetSaturation(sat->Value());
174 if (contrast->ValueChanged() == true)
175 SetContrast(contrast->Value());
176 if (hue->ValueChanged() == true)
177 SetHue(hue->Value());
178 if (sharpness->ValueChanged() == true)
[330]179 SetProperty(V4L2_CID_SHARPNESS, sharpness->Value());
[15]180 if (autogain->ValueChanged() == true) {
181 if (autogain->Value() == true) {
182 gain->setEnabled(false);
183 } else {
184 gain->setEnabled(true);
185 SetGain(gain->Value());
186 }
187 SetAutoGain(autogain->Value());
188 }
189 if (autoexposure->ValueChanged() == true) {
190 if (autoexposure->Value() == true) {
191 exposure->setEnabled(false);
192 } else {
193 exposure->setEnabled(true);
194 SetExposure(exposure->Value());
195 }
196 SetAutoExposure(autoexposure->Value());
197 }
198 if (awb->ValueChanged() == true)
[330]199 SetProperty(V4L2_CID_AUTO_WHITE_BALANCE, awb->Value());
[3]200
[338]201 // get picture
[330]202 GrabFrame();
[15]203 new_time = GetTime();
[165]204
205 //check for ps3eye deconnection in hds uav
206 if(new_time-cam_time>100*1000*1000) {
207 Thread::Warn("delta trop grand\n");
208 hasProblems=true;
209 }
[3]210
[15]211 output->GetMutex();
[338]212 output->buffer=(char*)buffers[bufferIndex].start;
[15]213 output->ReleaseMutex();
[3]214
[15]215 output->SetDataTime(cam_time);
216 ProcessUpdate(output);
[3]217
[15]218 cam_time = new_time;
219 }
[3]220
[330]221 close(device);
[3]222}
223
[338]224int 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}
[330]242
[338]243int 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);
[330]251
[338]252 tv.tv_sec = 0;
253 tv.tv_usec = 100000;
[330]254
[338]255 int r = select (device+1, &fds, NULL, NULL, &tv);
[330]256
[338]257 if (-1 == r) {
258 char errorMsg[256];
259 Thread::Err("select (%s)\n", strerror_r(-r, errorMsg, sizeof(errorMsg)));
260 return -1;
261 }
[330]262
[338]263 if (0 == r) {
264 Thread::Err("select timeout\n");
265 return -1;
266 }
[330]267
[338]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;
[330]272
[338]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) {
[330]278 break;
[338]279 } else {
280 Thread::Err("VIDIOC_DQBUF xioctl\n");
281 return -1;
[330]282 }
[338]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 }
[330]295 }
296
297 return 1;
298}
299
300int V4LCamera::AllocBuffers(void) {
[338]301 struct v4l2_requestbuffers requestbuffers;
[330]302 memset(&requestbuffers, 0, sizeof (v4l2_requestbuffers));
303
304 unsigned int buffer_number = DEFAULT_V4L_BUFFERS;
305
306 try_again:
307
308 requestbuffers.count = buffer_number;
309 requestbuffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
[338]310 requestbuffers.memory = V4L2_MEMORY_USERPTR;//V4L2_MEMORY_MMAP;
[330]311
[338]312 if (xioctl (device, VIDIOC_REQBUFS, &requestbuffers)==-1) {
313 if (errno==EINVAL) {
314 Thread::Err("VIDIOC_REQBUFS user memory not supported\n");
[330]315 } else {
316 Thread::Err ("VIDIOC_REQBUFS xioctl\n");
317 }
318 return -1;
319 }
[338]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());
[330]325 }
326
327 return 1;
328};
329
[165]330bool V4LCamera::HasProblems(void) {
331 return hasProblems;
332}
333
[15]334void V4LCamera::SetAutoGain(bool value) {
[330]335 SetProperty(V4L2_CID_AUTOGAIN, value);
[3]336}
337
[15]338void V4LCamera::SetAutoExposure(bool value) {
[338]339 Thread::Warn("not implemented\n");
[3]340}
341
[15]342void V4LCamera::SetGain(float value) {
[330]343 SetProperty(V4L2_CID_GAIN, value);
[3]344}
345
[15]346void V4LCamera::SetExposure(float value) {
[330]347 SetProperty(V4L2_CID_EXPOSURE, value);
[3]348}
349
[15]350void V4LCamera::SetBrightness(float value) {
[330]351 SetProperty(V4L2_CID_BRIGHTNESS, value);
[3]352}
353
[15]354void V4LCamera::SetSaturation(float value) {
[330]355 SetProperty(V4L2_CID_SATURATION, value);
[3]356}
357
[15]358void V4LCamera::SetHue(float value) {
[330]359 SetProperty(V4L2_CID_HUE, value);
[3]360}
361
[15]362void V4LCamera::SetContrast(float value) {
[330]363 SetProperty(V4L2_CID_CONTRAST, value);
[3]364}
365
[330]366float V4LCamera::GetProperty(int property) {
367 //get min and max value
368 struct v4l2_queryctrl queryctrl;
369 queryctrl.id = property;
370 if(xioctl (device, VIDIOC_QUERYCTRL,&queryctrl)==-1) return -1;
371 int min = queryctrl.minimum;
372 int max = queryctrl.maximum;
373
374 //set value
375 struct v4l2_control control;
376 memset (&control, 0, sizeof (v4l2_control));
377 control.id = property;
378 if(xioctl (device,VIDIOC_G_CTRL, &control)==-1) return -1;
379
380 return ((float)control.value - min + 1) / (max - min);
381}
382
383void V4LCamera::SetProperty(int property,float value) {
384 //get min and max value
385 struct v4l2_queryctrl queryctrl;
386 queryctrl.id = property;
387 xioctl (device, VIDIOC_QUERYCTRL,&queryctrl);
388 int min = queryctrl.minimum;
389 int max = queryctrl.maximum;
390
391 //set value
392 struct v4l2_control control;
393 memset (&control, 0, sizeof (v4l2_control));
394 control.id = property;
395 control.value = (int)(value * (max - min) + min);
396 xioctl (device,VIDIOC_S_CTRL, &control);
397}
398
399int V4LCamera::xioctl( int fd, int request, void *arg) {
400 int r;
401
402 do r = ioctl (fd, request, arg);
403 while (-1 == r && EINTR == errno);
404
405 return r;
406}
407
[3]408} // end namespace sensor
409} // end namespace flair
Note: See TracBrowser for help on using the repository browser.