1 #include "videocapture.h"
2 #include <linux/v4l2-subdev.h>
3 #include <linux/v4l2-common.h>
4 #include <sys/ioctl.h>
5 #include <unistd.h>
6 #include <sys/mman.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10
11 #include <QImage>
12 #include <QDebug>
13 #include <QDate>
14 #include <unistd.h>
15 #include <stdlib.h>
16
17 #include "sunxi_camera_v2.h"
18
19 #define CLEAR(x) (memset(&(x), 0, sizeof(x)))
20 #define ALIGN(x,a) (((x) + (a-1)) & ~(a-1))
21
VideoCapture(QObject * parent,char * devname,int _width,int _height)22 VideoCapture::VideoCapture(QObject *parent, char *devname,
23 int _width,
24 int _height): QObject(parent)
25 {
26 m_stop = 0;
27 take = 0;
28 this->width = _width;
29 this->height = _height;
30 fd = 0;
31 strcpy(this->devname, devname);
32 buffers = reinterpret_cast<struct buffer *>(::calloc(BUFINFOR_NUM, sizeof(struct buffer)));
33 }
34
~VideoCapture()35 VideoCapture::~VideoCapture()
36 {
37 }
38
SetImg(QLabel * Image)39 void VideoCapture::SetImg(QLabel *Image)
40 {
41 img = Image;
42 }
43
Init()44 int VideoCapture::Init()
45 {
46 int ret=0,i=0,count=0;
47
48 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
49 struct v4l2_ext_control ctrls[4];
50 struct v4l2_ext_controls ext_ctrls;
51 struct v4l2_control control;
52 struct v4l2_input inp;
53 struct v4l2_streamparm parms;
54 struct v4l2_requestbuffers req;
55 struct v4l2_exportbuffer exp;
56 struct v4l2_capability cap;
57
58 fd = ::open(devname, O_RDWR | O_NONBLOCK, 0);
59 if (fd < 0) {
60 qDebug() << "Open " << devname << "dev fail " <<strerror(errno);
61 ::exit(1);
62 }
63 qDebug() << "devname:" << devname << "Video fd: " << fd;
64
65 CLEAR(cap);
66 ::ioctl(fd, VIDIOC_QUERYCAP, &cap);
67 if (::strstr(reinterpret_cast<const char *>(cap.driver), "vin") != NULL) {
68 csi_type = 1;
69 } else {
70 csi_type = 0;
71 }
72
73 if (csi_type) {
74 inp.index = 0;
75 if (-1 == ioctl(fd, VIDIOC_S_INPUT, &inp)) {
76 ::exit(1);
77
78 }
79
80 CLEAR(parms);
81 parms.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
82 parms.parm.capture.timeperframe.numerator = 1;
83 parms.parm.capture.timeperframe.denominator = 30;
84 parms.parm.capture.capturemode = V4L2_MODE_VIDEO;
85 /* parms.parm.capture.capturemode = V4L2_MODE_IMAGE; */
86 /*when different video have the same sensor source, 1:use sensor current win, 0:find the nearest win*/
87 parms.parm.capture.reserved[0] = 0;
88 parms.parm.capture.reserved[1] = 0; /*2:command, 1: wdr, 0: normal*/
89
90 if (-1 == ioctl(fd, VIDIOC_S_PARM, &parms)) {
91 qDebug() << "VIDIOC_S_PARM" << strerror(errno);
92 ::exit(1);
93 }
94 }
95
96
97 struct v4l2_format fmt;
98 CLEAR(fmt);
99
100 if (csi_type) {
101 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
102 fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV21;
103 fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
104 fmt.fmt.pix_mp.width = this->width;
105 fmt.fmt.pix_mp.height = this->height;
106 } else {
107 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
108 fmt.fmt.pix.width = this->width;
109 fmt.fmt.pix.height = this->height;
110 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
111 }
112 if (-1 == ioctl(fd, VIDIOC_S_FMT, &fmt)) {
113 qDebug() << "VIDIOC_S_FMT" << strerror(errno);
114 ::exit(1);
115 }
116
117 if (-1 == ioctl(fd, VIDIOC_G_FMT, &fmt)) {
118 qDebug() << "VIDIOC_G_FMT" << strerror(errno);
119 ::exit(1);
120 } else {
121 if (csi_type) {
122 nplanes = fmt.fmt.pix_mp.num_planes;
123 qDebug() << "resolution got from sensor"
124 << fmt.fmt.pix_mp.width << "*" << fmt.fmt.pix_mp.height
125 << " num_planes = " << fmt.fmt.pix_mp.num_planes;
126 }
127 }
128
129 CLEAR(req);
130 req.count = BUFINFOR_NUM;
131 if (csi_type) {
132 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
133 } else {
134 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
135 }
136 req.memory = V4L2_MEMORY_MMAP;
137 if (-1 == ioctl(fd, VIDIOC_REQBUFS, &req)) {
138 qDebug() << "VIDIOC_REQBUFS" << strerror(errno);
139 ::exit(1);
140 }
141
142 for (int n_buffers = 0; n_buffers < req.count; ++n_buffers) {
143 struct v4l2_buffer buf;
144
145 CLEAR(buf);
146 if (csi_type) {
147 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
148 buf.memory = V4L2_MEMORY_MMAP;
149 buf.index = n_buffers;
150 buf.length = nplanes;
151 buf.m.planes =
152 (struct v4l2_plane *)calloc(nplanes,
153 sizeof(struct v4l2_plane));
154 if (buf.m.planes == NULL) {
155 qDebug() << "buf.m.planes calloc" << strerror(errno);
156 ::exit(1);
157 }
158 } else {
159 buf.index = n_buffers;
160 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
161 buf.memory = V4L2_MEMORY_MMAP;
162 }
163
164 if (-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf)) {
165 qDebug() << "VIDIOC_QUERYBUF" << strerror(errno);
166 if (csi_type)
167 free(buf.m.planes);
168 ::exit(1);
169 }
170
171 if (csi_type) {
172 for (i = 0; i < nplanes; i++) {
173 buffers[n_buffers].length[i] = buf.m.planes[i].length;
174 buffers[n_buffers].start[i] =
175 mmap(NULL,/* start anywhere */
176 buf.m.planes[i].length,
177 PROT_READ | PROT_WRITE,/* required */
178 MAP_SHARED, /* recommended */
179 fd, buf.m.planes[i].m.mem_offset);
180
181 if (buffers[n_buffers].start[i] == MAP_FAILED) {
182 qDebug() << "mmap failed" << strerror(errno);
183 free(buf.m.planes);
184 ::exit(1);
185 }
186 }
187 free(buf.m.planes);
188 } else {
189 buf.index = n_buffers;
190 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
191 buf.memory = V4L2_MEMORY_MMAP;
192 ret = ::ioctl(fd, VIDIOC_QUERYBUF, &buf);
193 if(ret < 0){
194 perror("VIDIOC_REQBUFS");
195 ::exit(1);
196 }
197 buffers[buf.index].length[0] = buf.length;
198 buffers[buf.index].start[0] = ::mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
199 fd, buf.m.offset);
200 if(!(buffers[buf.index].start[0])){
201 qDebug() << "mmap " << strerror(errno);
202 ::exit(1);
203 }
204 }
205 }
206
207 for (i = 0; i < BUFINFOR_NUM; ++i) {
208 struct v4l2_buffer buf;
209 CLEAR(buf);
210
211 if (csi_type) {
212 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
213 buf.memory = V4L2_MEMORY_MMAP;
214 buf.index = i;
215 buf.length = nplanes;
216 buf.m.planes =
217 (struct v4l2_plane *)calloc(nplanes,
218 sizeof(struct v4l2_plane));
219
220 if (-1 == ioctl(fd, VIDIOC_QBUF, &buf)) {
221 qDebug() << "VIDIOC_QBUF" << strerror(errno);
222 free(buf.m.planes);
223 ::exit(1);
224 }
225 free(buf.m.planes);
226 } else {
227 buf.index = i;
228 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
229 buf.memory = V4L2_MEMORY_MMAP;
230 ret = ::ioctl(fd, VIDIOC_QBUF, &buf);
231 if(ret < 0){
232 qDebug() << "VIDIOC_QBUF" << strerror(errno);
233 ::exit(1);
234 }
235 }
236 }
237
238 if (!csi_type) {
239 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
240 }
241 if (-1 == ioctl(fd, VIDIOC_STREAMON, &type)) {
242 qDebug() << "VIDIOC_STREAMON" << strerror(errno);
243 ::exit(1);
244 }
245
246 qDebug() << "Camera Init OK";
247 return 0;
248 }
249
convert_yuv_to_rgb_pixel(int y,int u,int v)250 static int convert_yuv_to_rgb_pixel(int y, int u, int v)
251 {
252 unsigned int pixel32 = 0;
253 unsigned char *pixel = (unsigned char *)&pixel32;
254 int r, g, b;
255 r = y + (1.370705 * (v-128));
256 g = y - (0.698001 * (v-128)) - (0.337633 * (u-128));
257 b = y + (1.732446 * (u-128));
258 if(r > 255) r = 255;
259 if(g > 255) g = 255;
260 if(b > 255) b = 255;
261 if(r < 0) r = 0;
262 if(g < 0) g = 0;
263 if(b < 0) b = 0;
264 pixel[0] = r ;
265 pixel[1] = g ;
266 pixel[2] = b ;
267 return pixel32;
268 }
269
convert_yuv_to_rgb_buffer(unsigned char * yuv,unsigned char * rgb,unsigned int width,unsigned int height)270 static int convert_yuv_to_rgb_buffer(unsigned char *yuv, unsigned char *rgb, unsigned int width, unsigned int height)
271 {
272 unsigned int in, out = 0;
273 unsigned int pixel_16;
274 unsigned char pixel_24[3];
275 unsigned int pixel32;
276 int y0, u, y1, v;
277
278 for(in = 0; in < width * height * 2; in += 4)
279 {
280 pixel_16 =
281 yuv[in + 3] << 24 |
282 yuv[in + 2] << 16 |
283 yuv[in + 1] << 8 |
284 yuv[in + 0];
285 y0 = (pixel_16 & 0x000000ff);
286 u = (pixel_16 & 0x0000ff00) >> 8;
287 y1 = (pixel_16 & 0x00ff0000) >> 16;
288 v = (pixel_16 & 0xff000000) >> 24;
289 pixel32 = convert_yuv_to_rgb_pixel(y0, u, v);
290 pixel_24[0] = (pixel32 & 0x000000ff);
291 pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;
292 pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;
293 rgb[out++] = pixel_24[0];
294 rgb[out++] = pixel_24[1];
295 rgb[out++] = pixel_24[2];
296 pixel32 = convert_yuv_to_rgb_pixel(y1, u, v);
297 pixel_24[0] = (pixel32 & 0x000000ff);
298 pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;
299 pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;
300 rgb[out++] = pixel_24[0];
301 rgb[out++] = pixel_24[1];
302 rgb[out++] = pixel_24[2];
303 }
304 return 0;
305 }
306
YUV420P_to_RGB24(unsigned char * yuyv,unsigned char * rgb,int width,int height)307 void YUV420P_to_RGB24(unsigned char *yuyv, unsigned char *rgb, int width, int height)
308 {
309 const int nv_start = width * height ;
310 int index = 0, rgb_index = 0;
311 uint8_t y, u, v;
312 int r, g, b, nv_index = 0,i, j;
313
314 for(i = 0; i < height; i++){
315 for(j = 0; j < width; j ++){
316 //nv_index = (rgb_index / 2 - width / 2 * ((i + 1) / 2)) * 2;
317 nv_index = i / 2 * width + j - j % 2;
318
319 y = yuyv[rgb_index];
320 u = yuyv[nv_start + nv_index ];
321 v = yuyv[nv_start + nv_index + 1];
322
323 r = y + (140 * (v-128))/100; //r
324 g = y - (34 * (u-128))/100 - (71 * (v-128))/100; //g
325 b = y + (177 * (u-128))/100; //b
326
327 if(r > 255) r = 255;
328 if(g > 255) g = 255;
329 if(b > 255) b = 255;
330 if(r < 0) r = 0;
331 if(g < 0) g = 0;
332 if(b < 0) b = 0;
333
334 index = rgb_index % width + (height - i - 1) * width;
335 //rgb[index * 3+0] = b;
336 //rgb[index * 3+1] = g;
337 //rgb[index * 3+2] = r;
338
339 //颠倒图像
340 //rgb[height * width * 3 - i * width * 3 - 3 * j - 1] = b;
341 //rgb[height * width * 3 - i * width * 3 - 3 * j - 2] = g;
342 //rgb[height * width * 3 - i * width * 3 - 3 * j - 3] = r;
343
344 //正面图像
345 rgb[i * width * 3 + 3 * j + 0] = b;
346 rgb[i * width * 3 + 3 * j + 1] = g;
347 rgb[i * width * 3 + 3 * j + 2] = r;
348
349 rgb_index++;
350 }
351 }
352
353 return ;
354 }
355
356
LoopCapture()357 int VideoCapture::LoopCapture()
358 {
359 int ret;
360 uchar *rgb=new uchar [width * height *3];
361 char *align_buffer;
362
363 struct v4l2_buffer buf;
364
365 fd_set fds;
366 struct timeval tv;
367 int r;
368
369 FD_ZERO(&fds);
370 FD_SET(fd, &fds);
371
372 tv.tv_sec = 2; /* Timeout. */
373 tv.tv_usec = 0;
374 if (select(fd + 1, &fds, NULL, NULL, &tv) <= 0)
375 {
376 qDebug() << "timeout";
377 return -1;
378 }
379
380 CLEAR(buf);
381
382 if (csi_type)
383 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
384 else
385 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
386
387 buf.memory = V4L2_MEMORY_MMAP;
388 if (csi_type) {
389 buf.length = nplanes;
390 buf.m.planes =
391 (struct v4l2_plane *)calloc(nplanes, sizeof(struct v4l2_plane));
392 }
393 if (-1 == ioctl(fd, VIDIOC_DQBUF, &buf)) {
394 if (csi_type)
395 free(buf.m.planes);
396 qDebug() << "VIDIOC_DQBUF " << strerror(errno);
397 return -1;
398 }
399 if (csi_type) {
400 switch (nplanes) {
401 case 1:
402 // convert_yuv_to_rgb_buffer((unsigned char *)buffers[buf.index].start[0], rgb,\
403 this->width, this->height);
404 align_buffer = reinterpret_cast<char *>(::malloc(this->width * this->height * 1.5));
405
406 if (ALIGN(this->height, 16) != this->height) {
407 memcpy(align_buffer, (char *)buffers[buf.index].start[0], this->width * this->height);
408 memcpy(align_buffer + this->width * this->height,
409 ((char *)buffers[buf.index].start[0]) +
410 ALIGN(this->width, 16) * ALIGN(this->height, 16),
411 this->width * this->height / 2);
412
413 YUV420P_to_RGB24(reinterpret_cast<unsigned char *>(align_buffer),
414 rgb, this->width, this->height);
415 } else {
416
417 YUV420P_to_RGB24((unsigned char *)buffers[buf.index].start[0],
418 rgb, this->width, this->height);
419 }
420
421 free(align_buffer);
422 break;
423 }
424 } else {
425 convert_yuv_to_rgb_buffer((unsigned char *)buffers[buf.index].start[0],rgb, this->width, this->height);
426 }
427
428 if (-1 == ioctl(fd, VIDIOC_QBUF, &buf)) {
429 qDebug() << "VIDIOC_QBUF " << strerror(errno);
430 free(buf.m.planes);
431 return -1;
432 }
433
434 if(csi_type)
435 free(buf.m.planes);
436
437 QImage *mage = new QImage(rgb, width,
438 height, QImage::Format_RGB888);
439 QImage resultimg = mage->scaled(img->size());
440
441
442 QMatrix matrix;
443 matrix.rotate(180);
444 resultimg = resultimg.transformed (matrix);
445
446
447
448 img->setPixmap(QPixmap::fromImage(resultimg));
449
450 if (take == 1)
451 {
452 mage->save(tr("%1.jpg").arg("/root/IMG" + \
453 QDate::currentDate().toString("yyyyMMdd") + QTime::currentTime().toString("hhmmss")),"JPG");
454
455 take = 0;
456 }
457
458 delete mage;
459 delete [] rgb;
460
461 return 0;
462 }
463