xref: /OK3568_Linux_fs/app/forlinx/flapp/src/plugins/allwinner/camera/camera/videocapture.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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