summaryrefslogtreecommitdiff
path: root/tvapi/libtv/tv/CTvScreenCapture.cpp (plain)
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
25using namespace android;
26
27
28#include "CTvScreenCapture.h"
29
30#define CLEAR(x) memset (&(x), 0, sizeof (x))
31
32int 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
43int 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
73int 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
98int 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);
162IS_ERROR:
163 return iOutRet;
164}
165
166int 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
250int 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
270int 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);
301IS_ERROR:
302
303 return iOutRet;
304}
305
306int 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
322void 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
348void 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
377int 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
447int 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
465int CTvScreenCapture::VideoStop()
466{
467 StopCapturing(&m_capV4l2Cam);
468 return SUCCEED;
469}
470
471int 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
494int 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
511int CTvScreenCapture::DeinitVideoCap()
512{
513 UninitCamera(&m_capV4l2Cam);
514 CloseCamera(&m_capV4l2Cam);
515 return SUCCEED ;
516}
517
518
519CTvScreenCapture::CTvScreenCapture()
520{
521 m_capNumBuffers = 0;
522 memset(&m_capV4l2Cam, 0x00, sizeof(camera));
523 mpObserver = NULL;
524}
525CTvScreenCapture::~CTvScreenCapture()
526{
527 memset(&m_capV4l2Cam, 0x00, sizeof(camera));
528 m_pData = NULL;
529}
530
531