blob: 76eed99d160cb9ab6a17eeb3b093ac0dd5d4a919
1 | |
2 | #include <stdlib.h> |
3 | #include <fcntl.h> |
4 | #include <strings.h> |
5 | #include <sys/ioctl.h> |
6 | #include <asm/types.h> |
7 | #include <fcntl.h> |
8 | #include <unistd.h> |
9 | #include <errno.h> |
10 | #include <malloc.h> |
11 | #include <sys/stat.h> |
12 | #include <sys/types.h> |
13 | #include <time.h> |
14 | #include <sys/mman.h> |
15 | #include <stdio.h> |
16 | #include <stdlib.h> |
17 | #include <string.h> |
18 | #include <assert.h> |
19 | #include <linux/videodev2.h> |
20 | #include <dirent.h> |
21 | |
22 | #include <binder/MemoryHeapBase.h> |
23 | #include <binder/MemoryBase.h> |
24 | |
25 | using namespace android; |
26 | |
27 | |
28 | #include "CTvScreenCapture.h" |
29 | |
30 | #define CLEAR(x) memset (&(x), 0, sizeof (x)) |
31 | |
32 | int CTvScreenCapture::xioctl(int fd, int request, void *arg) |
33 | { |
34 | int r = 0; |
35 | |
36 | do { |
37 | r = ioctl(fd, request, arg); |
38 | } while (-1 == r && EINTR == errno); |
39 | |
40 | return r; |
41 | } |
42 | |
43 | int CTvScreenCapture::OpenCamera(struct camera *pCameraDev) |
44 | { |
45 | int iOutRet = 0, iRet; |
46 | struct stat st; |
47 | |
48 | do { |
49 | if (-1 == stat(pCameraDev->device_name, &st)) { |
50 | LOGD( "Cannot identify '%s'\n", pCameraDev->device_name); |
51 | iOutRet = FAILED; |
52 | break; |
53 | } |
54 | |
55 | if (!S_ISCHR(st.st_mode)) { |
56 | LOGD("%s is no device\n", pCameraDev->device_name); |
57 | iOutRet = FAILED; |
58 | break; |
59 | } |
60 | |
61 | pCameraDev->fd = open(pCameraDev->device_name, O_RDWR | O_NONBLOCK, 0); // O_NONBLOCK |
62 | if (SUCCEED > pCameraDev->fd) { |
63 | LOGD("Cannot open '%s'\n", pCameraDev->device_name); |
64 | iOutRet = FAILED; |
65 | break; |
66 | } |
67 | } while (FALSE); |
68 | |
69 | return iOutRet; |
70 | } |
71 | |
72 | |
73 | int CTvScreenCapture::InitVCap(sp<IMemory> Mem) |
74 | { |
75 | int iOutRet = FAILED; |
76 | |
77 | do { |
78 | m_pMem = Mem; |
79 | m_pData = (char *)m_pMem->pointer(); |
80 | LOGD("VVVVVVVVVVVVVVVVVVVVVVVVVVVVV %p\n", m_pData); |
81 | //default |
82 | m_capV4l2Cam.device_name = "/dev/video11"; |
83 | m_capV4l2Cam.buffers = NULL; |
84 | m_capV4l2Cam.width = 640; |
85 | m_capV4l2Cam.height = 480; |
86 | m_capV4l2Cam.display_depth = 16; //5; /* RGB24 */ |
87 | m_capV4l2Cam.frame_number = 25; //fps |
88 | iOutRet = OpenCamera(&m_capV4l2Cam) ; |
89 | if (SUCCEED != iOutRet) { |
90 | LOGD("ERROR:::Open Camera device failed\n"); |
91 | break; |
92 | } |
93 | } while (FALSE); |
94 | |
95 | return iOutRet; |
96 | } |
97 | |
98 | int CTvScreenCapture::InitMmap(struct camera *cam) |
99 | { |
100 | int iOutRet = SUCCEED, iRet; |
101 | struct v4l2_requestbuffers req; |
102 | |
103 | do { |
104 | CLEAR(req); |
105 | |
106 | req.count = 4; |
107 | req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
108 | req.memory = V4L2_MEMORY_MMAP; |
109 | |
110 | iRet = xioctl(cam->fd, VIDIOC_REQBUFS, &req); |
111 | if (FAILED == iRet) { |
112 | if (EINVAL == errno) { |
113 | LOGD("VIDIOC_REQBUFS %s does not support memory mapping\n", cam->device_name); |
114 | } |
115 | iOutRet = iRet; |
116 | break; |
117 | } |
118 | |
119 | if (req.count < 2) { |
120 | LOGD("Insufficient buffer memory on %s\n", cam->device_name); |
121 | iOutRet = FAILED; |
122 | break; |
123 | } |
124 | |
125 | cam->buffers = (struct buffer *)calloc(req.count, sizeof(*(cam->buffers))); |
126 | if (!cam->buffers) { |
127 | LOGD("Out of memory\n"); |
128 | iOutRet = FAILED; |
129 | break; |
130 | } |
131 | |
132 | for (m_capNumBuffers = 0; m_capNumBuffers < req.count; ++m_capNumBuffers) { |
133 | struct v4l2_buffer buf; |
134 | |
135 | CLEAR(buf); |
136 | |
137 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
138 | buf.memory = V4L2_MEMORY_MMAP; |
139 | buf.index = m_capNumBuffers; |
140 | |
141 | if (FAILED == xioctl(cam->fd, VIDIOC_QUERYBUF, &buf)) { |
142 | LOGD("VIDIOC_QUERYBUF ERROR\n"); |
143 | iOutRet = FAILED; |
144 | goto IS_ERROR; |
145 | } |
146 | |
147 | cam->buffers[m_capNumBuffers].length = buf.length; |
148 | cam->buffers[m_capNumBuffers].start = mmap(NULL /* start anywhere */, |
149 | buf.length, PROT_READ | PROT_WRITE /* required */, |
150 | MAP_SHARED /* recommended */, cam->fd, buf.m.offset); |
151 | |
152 | if (MAP_FAILED == cam->buffers[m_capNumBuffers].start) { |
153 | iOutRet = FAILED; |
154 | break; |
155 | } |
156 | |
157 | |
158 | } |
159 | |
160 | LOGD("END m_capNumBuffers : %d\n", m_capNumBuffers); |
161 | } while (FALSE); |
162 | IS_ERROR: |
163 | return iOutRet; |
164 | } |
165 | |
166 | int CTvScreenCapture::InitCamera(struct camera *cam) |
167 | { |
168 | int iOutRet = SUCCEED, iRet; |
169 | struct v4l2_capability *cap = &(cam->v4l2_cap); |
170 | struct v4l2_cropcap *cropcap = &(cam->v4l2_cropcap); |
171 | struct v4l2_crop *crop = &(cam->crop); |
172 | struct v4l2_format *fmt = &(cam->v4l2_fmt); |
173 | unsigned int min; |
174 | |
175 | do { |
176 | iRet = xioctl(cam->fd, VIDIOC_QUERYCAP, cap); |
177 | if (FAILED == iRet) { |
178 | if (EINVAL == errno) { |
179 | LOGD("%s is no V4L2 device\n", cam->device_name); |
180 | } |
181 | iOutRet = iRet; |
182 | break; |
183 | } |
184 | |
185 | if (!(cap->capabilities & V4L2_CAP_VIDEO_CAPTURE)) { |
186 | LOGD("%s is no video capture device\n", cam->device_name); |
187 | iOutRet = FAILED; |
188 | break; |
189 | } |
190 | |
191 | if (!(cap->capabilities & V4L2_CAP_STREAMING)) { |
192 | LOGD("%s does not support streaming i/o\n", cam->device_name); |
193 | iOutRet = FAILED; |
194 | break; |
195 | } |
196 | |
197 | LOGD("VIDOOC_QUERYCAP camera driver is [%s] card is [%s] businfo is [%s] version is [%d]\n", cap->driver, |
198 | cap->card, cap->bus_info, cap->version); |
199 | |
200 | /* Select video input, video standard and tune here. */ |
201 | |
202 | CLEAR(*cropcap); |
203 | cropcap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
204 | |
205 | crop->c.width = cam->width; |
206 | crop->c.height = cam->height; |
207 | crop->c.left = 0; |
208 | crop->c.top = 0; |
209 | crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
210 | |
211 | CLEAR(*fmt); |
212 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
213 | fmt->fmt.pix.width = cam->width; |
214 | fmt->fmt.pix.height = cam->height; |
215 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_NV21; |
216 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; |
217 | iRet = xioctl(cam->fd, VIDIOC_S_FMT, fmt); |
218 | if (FAILED == iRet) { |
219 | iOutRet = iRet; |
220 | LOGD("VIDIOC_S_FMT is ERROR\n"); |
221 | break; |
222 | } |
223 | |
224 | /* Note VIDIOC_S_FMT may change width and height. */ |
225 | /* Buggy driver paranoia. */ |
226 | min = fmt->fmt.pix.width * 2; |
227 | if (fmt->fmt.pix.bytesperline < min) { |
228 | fmt->fmt.pix.bytesperline = min; |
229 | } |
230 | |
231 | min = fmt->fmt.pix.bytesperline * fmt->fmt.pix.height; |
232 | if (fmt->fmt.pix.sizeimage < min) { |
233 | fmt->fmt.pix.sizeimage = min; |
234 | } |
235 | |
236 | iRet = InitMmap(cam); |
237 | if (FAILED == iRet) { |
238 | LOGD("INIT MMAP FAILED\n"); |
239 | iOutRet = iRet; |
240 | break; |
241 | } |
242 | |
243 | } while (FALSE); |
244 | |
245 | return iOutRet; |
246 | |
247 | } |
248 | |
249 | |
250 | int CTvScreenCapture::SetVideoParameter(int width, int height, int frame) |
251 | { |
252 | int iOutRet = SUCCEED, iRet; |
253 | |
254 | do { |
255 | m_capV4l2Cam.width = width; |
256 | m_capV4l2Cam.height = height; |
257 | m_capV4l2Cam.frame_number = frame; |
258 | |
259 | iRet = InitCamera(&m_capV4l2Cam); |
260 | if (SUCCEED != iRet) { |
261 | iOutRet = iRet; |
262 | break; |
263 | } |
264 | |
265 | } while (FALSE); |
266 | |
267 | return iOutRet ; |
268 | } |
269 | |
270 | int CTvScreenCapture::StartCapturing(struct camera *cam) |
271 | { |
272 | unsigned int i; |
273 | int iOutRet = SUCCEED, iRet; |
274 | enum v4l2_buf_type type; |
275 | |
276 | do { |
277 | for (i = 0; i < m_capNumBuffers; ++i) { |
278 | struct v4l2_buffer buf; |
279 | |
280 | //CLEAR(buf); |
281 | |
282 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
283 | buf.memory = V4L2_MEMORY_MMAP; |
284 | buf.index = i; |
285 | |
286 | iRet = xioctl(cam->fd, VIDIOC_QBUF, &buf); |
287 | if (FAILED == iRet) { |
288 | iOutRet = iRet; |
289 | goto IS_ERROR; |
290 | } |
291 | } |
292 | |
293 | |
294 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
295 | iRet = xioctl(cam->fd, VIDIOC_STREAMON, &type); |
296 | if (FAILED == iRet) { |
297 | iOutRet = iRet; |
298 | break; |
299 | } |
300 | } while (FALSE); |
301 | IS_ERROR: |
302 | |
303 | return iOutRet; |
304 | } |
305 | |
306 | int CTvScreenCapture::VideoStart() |
307 | { |
308 | int iOutRet = SUCCEED, iRet; |
309 | |
310 | do { |
311 | iRet = StartCapturing(&m_capV4l2Cam); |
312 | if (FAILED == iRet) { |
313 | iOutRet = iRet; |
314 | break; |
315 | } |
316 | |
317 | } while (FALSE); |
318 | |
319 | return iOutRet; |
320 | } |
321 | |
322 | void CTvScreenCapture::yuv_to_rgb32(unsigned char y, unsigned char u, unsigned char v, unsigned char *rgb) |
323 | { |
324 | register int r, g, b; |
325 | int rgb24; |
326 | |
327 | r = (1192 * (y - 16) + 1634 * (v - 128) ) >> 10; |
328 | g = (1192 * (y - 16) - 833 * (v - 128) - 400 * (u - 128) ) >> 10; |
329 | b = (1192 * (y - 16) + 2066 * (u - 128) ) >> 10; |
330 | |
331 | r = r > 255 ? 255 : r < 0 ? 0 : r; |
332 | g = g > 255 ? 255 : g < 0 ? 0 : g; |
333 | b = b > 255 ? 255 : b < 0 ? 0 : b; |
334 | |
335 | rgb24 = (int)((r << 16) | (g << 8) | b); |
336 | |
337 | /*ARGB*/ |
338 | *rgb = (unsigned char)r; |
339 | rgb ++; |
340 | *rgb = (unsigned char)g; |
341 | rgb++; |
342 | *rgb = (unsigned char)b; |
343 | rgb++; |
344 | *rgb = 0xff; |
345 | } |
346 | |
347 | |
348 | void CTvScreenCapture::nv21_to_rgb32(unsigned char *buf, unsigned char *rgb, int width, int height, int *len) |
349 | { |
350 | int x, y, z = 0; |
351 | int h, w; |
352 | int blocks; |
353 | unsigned char Y1, Y2, U, V; |
354 | |
355 | *len = 0; |
356 | |
357 | blocks = (width * height) * 2; |
358 | |
359 | for (h = 0, z = 0; h < height; h += 2) { |
360 | for (y = 0; y < width * 2; y += 2) { |
361 | |
362 | Y1 = buf[ h * width + y + 0]; |
363 | V = buf[ blocks / 2 + h * width / 2 + y % width + 0 ]; |
364 | Y2 = buf[ h * width + y + 1]; |
365 | U = buf[ blocks / 2 + h * width / 2 + y % width + 1 ]; |
366 | |
367 | yuv_to_rgb32(Y1, U, V, &rgb[z]); |
368 | yuv_to_rgb32(Y2, U, V, &rgb[z + 4]); |
369 | z += 8; |
370 | } |
371 | } |
372 | *len = z; |
373 | LOGD("z +++++++++++++++++++++++++++++++++ z %d\n", z); |
374 | } |
375 | |
376 | |
377 | int CTvScreenCapture::GetVideoData(int *length) |
378 | { |
379 | int iOutRet = SUCCEED, iRet; |
380 | |
381 | *length = 0; |
382 | while (true) { |
383 | fd_set fds; |
384 | struct timeval tv; |
385 | FD_ZERO(&fds); |
386 | FD_SET(m_capV4l2Cam.fd, &fds); |
387 | /* Timeout. */ |
388 | tv.tv_sec = 0; |
389 | tv.tv_usec = 30000; |
390 | iRet = select(m_capV4l2Cam.fd + 1, &fds, NULL, NULL, &tv); |
391 | if (FAILED == iRet) { |
392 | LOGD("select FAILED\n"); |
393 | if (EINTR == errno) { |
394 | LOGD("select FAILED Continue\n"); |
395 | continue; |
396 | } |
397 | |
398 | } |
399 | |
400 | if (0 == iRet) { |
401 | LOGD("select timeout\n"); |
402 | continue ; |
403 | } |
404 | |
405 | struct v4l2_buffer buf; |
406 | CLEAR(buf); |
407 | |
408 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
409 | buf.memory = V4L2_MEMORY_MMAP; |
410 | iRet = xioctl(m_capV4l2Cam.fd, VIDIOC_DQBUF, &buf); |
411 | if (FAILED == iRet) { |
412 | if (errno == EAGAIN) { |
413 | LOGD("GetVideoData EAGAIN \n"); |
414 | } |
415 | |
416 | continue; |
417 | } |
418 | |
419 | LOGD("DDDDDDDDDDAAAAAAAAAAAAAAAAAAAATTTTTTTTTTTTTTAAAAAAAAAAAAAAAAAAAAAAAAAAAAA %d %d\n", buf.length, iRet); |
420 | int tmpLen = 0; |
421 | nv21_to_rgb32((unsigned char *)m_capV4l2Cam.buffers[buf.index].start, (unsigned char *)m_pData, m_capV4l2Cam.width, m_capV4l2Cam.height, &tmpLen); |
422 | //memcpy(m_pData,m_capV4l2Cam.buffers[buf.index].start, buf.length +1); |
423 | *length = buf.length; |
424 | break; |
425 | |
426 | } |
427 | |
428 | if (*length > 0) { |
429 | mCapEvt.mFrameWide = m_capV4l2Cam.width; |
430 | mCapEvt.mFrameHeight = m_capV4l2Cam.height; |
431 | mCapEvt.mFrameNum = 1; |
432 | mCapEvt.mFrameSize = *length; |
433 | } else { |
434 | mCapEvt.mFrameWide = 0; |
435 | mCapEvt.mFrameHeight = 0; |
436 | mCapEvt.mFrameNum = 0; |
437 | mCapEvt.mFrameSize = 0; |
438 | } |
439 | |
440 | if (NULL != mpObserver) { |
441 | mpObserver->onTvEvent(mCapEvt); |
442 | } |
443 | |
444 | return iOutRet; |
445 | } |
446 | |
447 | int CTvScreenCapture::StopCapturing(struct camera *cam) |
448 | { |
449 | int iOutRet = SUCCEED, iRet; |
450 | enum v4l2_buf_type type; |
451 | |
452 | do { |
453 | type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
454 | |
455 | iRet = xioctl(cam->fd, VIDIOC_STREAMOFF, &type); |
456 | if (FAILED == iRet) { |
457 | iOutRet = iRet; |
458 | break; |
459 | } |
460 | } while (FALSE); |
461 | |
462 | return iOutRet; |
463 | } |
464 | |
465 | int CTvScreenCapture::VideoStop() |
466 | { |
467 | StopCapturing(&m_capV4l2Cam); |
468 | return SUCCEED; |
469 | } |
470 | |
471 | int CTvScreenCapture::UninitCamera(struct camera *cam) |
472 | { |
473 | unsigned int i; |
474 | |
475 | for (i = 0; i < m_capNumBuffers; ++i) { |
476 | if (cam->buffers[i].start == NULL) { |
477 | break; |
478 | } |
479 | |
480 | if (FAILED == munmap(cam->buffers[i].start, cam->buffers[i].length)) { |
481 | LOGD("ERROR::munmap cam buffer failed\n"); |
482 | break; |
483 | } |
484 | } |
485 | |
486 | if (NULL != cam->buffers) |
487 | free(cam->buffers); |
488 | |
489 | cam->buffers = NULL; |
490 | |
491 | return SUCCEED; |
492 | } |
493 | |
494 | int CTvScreenCapture::CloseCamera(struct camera *cam) |
495 | { |
496 | int iOutRet = SUCCEED, iRet; |
497 | |
498 | do { |
499 | iRet = close(cam->fd); |
500 | if (FAILED == iRet) { |
501 | iOutRet = iRet; |
502 | break; |
503 | } |
504 | |
505 | cam->fd = -1; |
506 | } while (FALSE); |
507 | |
508 | return iOutRet; |
509 | } |
510 | |
511 | int CTvScreenCapture::DeinitVideoCap() |
512 | { |
513 | UninitCamera(&m_capV4l2Cam); |
514 | CloseCamera(&m_capV4l2Cam); |
515 | return SUCCEED ; |
516 | } |
517 | |
518 | |
519 | CTvScreenCapture::CTvScreenCapture() |
520 | { |
521 | m_capNumBuffers = 0; |
522 | memset(&m_capV4l2Cam, 0x00, sizeof(camera)); |
523 | mpObserver = NULL; |
524 | } |
525 | CTvScreenCapture::~CTvScreenCapture() |
526 | { |
527 | memset(&m_capV4l2Cam, 0x00, sizeof(camera)); |
528 | m_pData = NULL; |
529 | } |
530 | |
531 |