1 /*
2 * Copyright (C) Texas Instruments - http://www.ti.com/
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /**
18 * @file V4LCameraAdapter.cpp
19 *
20 * This file maps the Camera Hardware Interface to V4L2.
21 *
22 */
23
24
25 #include "V4LCameraAdapter.h"
26 #include "CameraHal.h"
27 #include "TICameraParameters.h"
28 #include "DebugUtils.h"
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <sys/ioctl.h>
37 #include <sys/mman.h>
38 #include <sys/select.h>
39 #include <linux/videodev.h>
40
41 #include <ui/GraphicBuffer.h>
42 #include <ui/GraphicBufferMapper.h>
43
44 #include <cutils/properties.h>
45 #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
46 static int mDebugFps = 0;
47
48 #define Q16_OFFSET 16
49
50 #define HERE(Msg) {CAMHAL_LOGEB("--=== %s===--\n", Msg);}
51
52 namespace Ti {
53 namespace Camera {
54
55 //frames skipped before recalculating the framerate
56 #define FPS_PERIOD 30
57
58 //define this macro to save first few raw frames when starting the preview.
59 //#define SAVE_RAW_FRAMES 1
60 //#define DUMP_CAPTURE_FRAME 1
61 //#define PPM_PER_FRAME_CONVERSION 1
62
63 //Proto Types
64 static void convertYUV422i_yuyvTouyvy(uint8_t *src, uint8_t *dest, size_t size );
65 static void convertYUV422ToNV12Tiler(unsigned char *src, unsigned char *dest, int width, int height );
66 static void convertYUV422ToNV12(unsigned char *src, unsigned char *dest, int width, int height );
67
68 android::Mutex gV4LAdapterLock;
69 char device[15];
70
71
72 /*--------------------Camera Adapter Class STARTS here-----------------------------*/
73
74 /*--------------------V4L wrapper functions -------------------------------*/
v4lIoctl(int fd,int req,void * argp)75 status_t V4LCameraAdapter::v4lIoctl (int fd, int req, void* argp) {
76 status_t ret = NO_ERROR;
77 errno = 0;
78
79 do {
80 ret = ioctl (fd, req, argp);
81 }while (-1 == ret && EINTR == errno);
82
83 return ret;
84 }
85
v4lInitMmap(int & count)86 status_t V4LCameraAdapter::v4lInitMmap(int& count) {
87 status_t ret = NO_ERROR;
88
89 //First allocate adapter internal buffers at V4L level for USB Cam
90 //These are the buffers from which we will copy the data into overlay buffers
91 /* Check if camera can handle NB_BUFFER buffers */
92 mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
93 mVideoInfo->rb.memory = V4L2_MEMORY_MMAP;
94 mVideoInfo->rb.count = count;
95
96 ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb);
97 if (ret < 0) {
98 CAMHAL_LOGEB("VIDIOC_REQBUFS failed: %s", strerror(errno));
99 return ret;
100 }
101
102 count = mVideoInfo->rb.count;
103 for (int i = 0; i < count; i++) {
104
105 memset (&mVideoInfo->buf, 0, sizeof (struct v4l2_buffer));
106
107 mVideoInfo->buf.index = i;
108 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
109 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
110
111 ret = v4lIoctl (mCameraHandle, VIDIOC_QUERYBUF, &mVideoInfo->buf);
112 if (ret < 0) {
113 CAMHAL_LOGEB("Unable to query buffer (%s)", strerror(errno));
114 return ret;
115 }
116
117 mVideoInfo->mem[i] = mmap (NULL,
118 mVideoInfo->buf.length,
119 PROT_READ | PROT_WRITE,
120 MAP_SHARED,
121 mCameraHandle,
122 mVideoInfo->buf.m.offset);
123
124 CAMHAL_LOGVB(" mVideoInfo->mem[%d]=%p ; mVideoInfo->buf.length = %d", i, mVideoInfo->mem[i], mVideoInfo->buf.length);
125 if (mVideoInfo->mem[i] == MAP_FAILED) {
126 CAMHAL_LOGEB("Unable to map buffer [%d]. (%s)", i, strerror(errno));
127 return -1;
128 }
129 }
130 return ret;
131 }
132
v4lInitUsrPtr(int & count)133 status_t V4LCameraAdapter::v4lInitUsrPtr(int& count) {
134 status_t ret = NO_ERROR;
135
136 mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
137 mVideoInfo->rb.memory = V4L2_MEMORY_USERPTR;
138 mVideoInfo->rb.count = count;
139
140 ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb);
141 if (ret < 0) {
142 CAMHAL_LOGEB("VIDIOC_REQBUFS failed for USERPTR: %s", strerror(errno));
143 return ret;
144 }
145
146 count = mVideoInfo->rb.count;
147 return ret;
148 }
149
v4lStartStreaming()150 status_t V4LCameraAdapter::v4lStartStreaming () {
151 status_t ret = NO_ERROR;
152 enum v4l2_buf_type bufType;
153
154 if (!mVideoInfo->isStreaming) {
155 bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
156
157 ret = v4lIoctl (mCameraHandle, VIDIOC_STREAMON, &bufType);
158 if (ret < 0) {
159 CAMHAL_LOGEB("StartStreaming: Unable to start capture: %s", strerror(errno));
160 return ret;
161 }
162 mVideoInfo->isStreaming = true;
163 }
164 return ret;
165 }
166
v4lStopStreaming(int nBufferCount)167 status_t V4LCameraAdapter::v4lStopStreaming (int nBufferCount) {
168 status_t ret = NO_ERROR;
169 enum v4l2_buf_type bufType;
170
171 if (mVideoInfo->isStreaming) {
172 bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
173
174 ret = v4lIoctl (mCameraHandle, VIDIOC_STREAMOFF, &bufType);
175 if (ret < 0) {
176 CAMHAL_LOGEB("StopStreaming: Unable to stop capture: %s", strerror(errno));
177 goto EXIT;
178 }
179 mVideoInfo->isStreaming = false;
180
181 /* Unmap buffers */
182 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
183 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
184 for (int i = 0; i < nBufferCount; i++) {
185 if (munmap(mVideoInfo->mem[i], mVideoInfo->buf.length) < 0) {
186 CAMHAL_LOGEA("munmap() failed");
187 }
188 }
189
190 //free the memory allocated during REQBUFS, by setting the count=0
191 mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
192 mVideoInfo->rb.memory = V4L2_MEMORY_MMAP;
193 mVideoInfo->rb.count = 0;
194
195 ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb);
196 if (ret < 0) {
197 CAMHAL_LOGEB("VIDIOC_REQBUFS failed: %s", strerror(errno));
198 goto EXIT;
199 }
200 }
201 EXIT:
202 return ret;
203 }
204
v4lSetFormat(int width,int height,uint32_t pix_format)205 status_t V4LCameraAdapter::v4lSetFormat (int width, int height, uint32_t pix_format) {
206 status_t ret = NO_ERROR;
207
208 mVideoInfo->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
209 ret = v4lIoctl(mCameraHandle, VIDIOC_G_FMT, &mVideoInfo->format);
210 if (ret < 0) {
211 CAMHAL_LOGEB("VIDIOC_G_FMT Failed: %s", strerror(errno));
212 }
213
214 mVideoInfo->width = width;
215 mVideoInfo->height = height;
216 mVideoInfo->framesizeIn = (width * height << 1);
217 mVideoInfo->formatIn = DEFAULT_PIXEL_FORMAT;
218
219 mVideoInfo->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
220 mVideoInfo->format.fmt.pix.width = width;
221 mVideoInfo->format.fmt.pix.height = height;
222 mVideoInfo->format.fmt.pix.pixelformat = pix_format;
223
224 ret = v4lIoctl(mCameraHandle, VIDIOC_S_FMT, &mVideoInfo->format);
225 if (ret < 0) {
226 CAMHAL_LOGEB("VIDIOC_S_FMT Failed: %s", strerror(errno));
227 return ret;
228 }
229 v4lIoctl(mCameraHandle, VIDIOC_G_FMT, &mVideoInfo->format);
230 CAMHAL_LOGDB("VIDIOC_G_FMT : WxH = %dx%d", mVideoInfo->format.fmt.pix.width, mVideoInfo->format.fmt.pix.height);
231 return ret;
232 }
233
restartPreview()234 status_t V4LCameraAdapter::restartPreview ()
235 {
236 status_t ret = NO_ERROR;
237 int width = 0;
238 int height = 0;
239 struct v4l2_streamparm streamParams;
240
241 //configure for preview size and pixel format.
242 mParams.getPreviewSize(&width, &height);
243
244 ret = v4lSetFormat (width, height, DEFAULT_PIXEL_FORMAT);
245 if (ret < 0) {
246 CAMHAL_LOGEB("v4lSetFormat Failed: %s", strerror(errno));
247 goto EXIT;
248 }
249
250 ret = v4lInitMmap(mPreviewBufferCount);
251 if (ret < 0) {
252 CAMHAL_LOGEB("v4lInitMmap Failed: %s", strerror(errno));
253 goto EXIT;
254 }
255
256 //set frame rate
257 streamParams.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
258 streamParams.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
259 streamParams.parm.capture.capturemode = V4L2_MODE_HIGHQUALITY;
260 streamParams.parm.capture.timeperframe.denominator = FPS_PERIOD;
261 streamParams.parm.capture.timeperframe.numerator= 1;
262 ret = v4lIoctl(mCameraHandle, VIDIOC_S_PARM, &streamParams);
263 if (ret < 0) {
264 CAMHAL_LOGEB("VIDIOC_S_PARM Failed: %s", strerror(errno));
265 goto EXIT;
266 }
267
268 for (int i = 0; i < mPreviewBufferCountQueueable; i++) {
269
270 mVideoInfo->buf.index = i;
271 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
272 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
273
274 ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
275 if (ret < 0) {
276 CAMHAL_LOGEA("VIDIOC_QBUF Failed");
277 goto EXIT;
278 }
279 nQueued++;
280 }
281
282 ret = v4lStartStreaming();
283 CAMHAL_LOGDA("Ready for preview....");
284 EXIT:
285 return ret;
286 }
287
288 /*--------------------Camera Adapter Functions-----------------------------*/
initialize(CameraProperties::Properties * caps)289 status_t V4LCameraAdapter::initialize(CameraProperties::Properties* caps)
290 {
291 char value[PROPERTY_VALUE_MAX];
292
293 LOG_FUNCTION_NAME;
294 property_get("debug.camera.showfps", value, "0");
295 mDebugFps = atoi(value);
296
297 int ret = NO_ERROR;
298
299 // Allocate memory for video info structure
300 mVideoInfo = (struct VideoInfo *) calloc (1, sizeof (struct VideoInfo));
301 if(!mVideoInfo) {
302 ret = NO_MEMORY;
303 goto EXIT;
304 }
305
306 if ((mCameraHandle = open(device, O_RDWR | O_NONBLOCK) ) == -1) {
307 CAMHAL_LOGEB("Error while opening handle to V4L2 Camera: %s", strerror(errno));
308 ret = BAD_VALUE;
309 goto EXIT;
310 }
311
312 ret = v4lIoctl (mCameraHandle, VIDIOC_QUERYCAP, &mVideoInfo->cap);
313 if (ret < 0) {
314 CAMHAL_LOGEA("Error when querying the capabilities of the V4L Camera");
315 ret = BAD_VALUE;
316 goto EXIT;
317 }
318
319 if ((mVideoInfo->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
320 CAMHAL_LOGEA("Error while adapter initialization: video capture not supported.");
321 ret = BAD_VALUE;
322 goto EXIT;
323 }
324
325 if (!(mVideoInfo->cap.capabilities & V4L2_CAP_STREAMING)) {
326 CAMHAL_LOGEA("Error while adapter initialization: Capture device does not support streaming i/o");
327 ret = BAD_VALUE;
328 goto EXIT;
329 }
330
331 // Initialize flags
332 mPreviewing = false;
333 mVideoInfo->isStreaming = false;
334 mRecording = false;
335 mCapturing = false;
336 EXIT:
337 LOG_FUNCTION_NAME_EXIT;
338 return ret;
339 }
340
fillThisBuffer(CameraBuffer * frameBuf,CameraFrame::FrameType frameType)341 status_t V4LCameraAdapter::fillThisBuffer(CameraBuffer *frameBuf, CameraFrame::FrameType frameType)
342 {
343 status_t ret = NO_ERROR;
344 int idx = 0;
345 LOG_FUNCTION_NAME;
346
347 if ( frameType == CameraFrame::IMAGE_FRAME) { //(1 > mCapturedFrames)
348 // Signal end of image capture
349 if ( NULL != mEndImageCaptureCallback) {
350 CAMHAL_LOGDB("===========Signal End Image Capture==========");
351 mEndImageCaptureCallback(mEndCaptureData);
352 }
353 goto EXIT;
354 }
355 if ( !mVideoInfo->isStreaming ) {
356 goto EXIT;
357 }
358
359 idx = mPreviewBufs.valueFor(frameBuf);
360 if(idx < 0) {
361 CAMHAL_LOGEB("Wrong index = %d",idx);
362 goto EXIT;
363 }
364
365 mVideoInfo->buf.index = idx;
366 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
367 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
368
369 ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
370 if (ret < 0) {
371 CAMHAL_LOGEA("VIDIOC_QBUF Failed");
372 goto EXIT;
373 }
374 nQueued++;
375 EXIT:
376 LOG_FUNCTION_NAME_EXIT;
377 return ret;
378
379 }
380
setParameters(const android::CameraParameters & params)381 status_t V4LCameraAdapter::setParameters(const android::CameraParameters ¶ms)
382 {
383 status_t ret = NO_ERROR;
384 int width, height;
385 struct v4l2_streamparm streamParams;
386
387 LOG_FUNCTION_NAME;
388
389 if(!mPreviewing && !mCapturing) {
390 params.getPreviewSize(&width, &height);
391 CAMHAL_LOGDB("Width * Height %d x %d format 0x%x", width, height, DEFAULT_PIXEL_FORMAT);
392
393 ret = v4lSetFormat( width, height, DEFAULT_PIXEL_FORMAT);
394 if (ret < 0) {
395 CAMHAL_LOGEB(" VIDIOC_S_FMT Failed: %s", strerror(errno));
396 goto EXIT;
397 }
398 //set frame rate
399 // Now its fixed to 30 FPS
400 streamParams.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
401 streamParams.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
402 streamParams.parm.capture.capturemode = V4L2_MODE_HIGHQUALITY;
403 streamParams.parm.capture.timeperframe.denominator = FPS_PERIOD;
404 streamParams.parm.capture.timeperframe.numerator= 1;
405 ret = v4lIoctl(mCameraHandle, VIDIOC_S_PARM, &streamParams);
406 if (ret < 0) {
407 CAMHAL_LOGEB(" VIDIOC_S_PARM Failed: %s", strerror(errno));
408 goto EXIT;
409 }
410 int actualFps = streamParams.parm.capture.timeperframe.denominator / streamParams.parm.capture.timeperframe.numerator;
411 CAMHAL_LOGDB("Actual FPS set is : %d.", actualFps);
412 }
413
414 // Udpate the current parameter set
415 mParams = params;
416
417 EXIT:
418 LOG_FUNCTION_NAME_EXIT;
419 return ret;
420 }
421
422
getParameters(android::CameraParameters & params)423 void V4LCameraAdapter::getParameters(android::CameraParameters& params)
424 {
425 LOG_FUNCTION_NAME;
426
427 // Return the current parameter set
428 params = mParams;
429
430 LOG_FUNCTION_NAME_EXIT;
431 }
432
433
434 ///API to give the buffers to Adapter
useBuffers(CameraMode mode,CameraBuffer * bufArr,int num,size_t length,unsigned int queueable)435 status_t V4LCameraAdapter::useBuffers(CameraMode mode, CameraBuffer *bufArr, int num, size_t length, unsigned int queueable)
436 {
437 status_t ret = NO_ERROR;
438
439 LOG_FUNCTION_NAME;
440
441 android::AutoMutex lock(mLock);
442
443 switch(mode)
444 {
445 case CAMERA_PREVIEW:
446 mPreviewBufferCountQueueable = queueable;
447 ret = UseBuffersPreview(bufArr, num);
448 break;
449
450 case CAMERA_IMAGE_CAPTURE:
451 mCaptureBufferCountQueueable = queueable;
452 ret = UseBuffersCapture(bufArr, num);
453 break;
454
455 case CAMERA_VIDEO:
456 //@warn Video capture is not fully supported yet
457 mPreviewBufferCountQueueable = queueable;
458 ret = UseBuffersPreview(bufArr, num);
459 break;
460
461 case CAMERA_MEASUREMENT:
462 break;
463
464 default:
465 break;
466 }
467
468 LOG_FUNCTION_NAME_EXIT;
469
470 return ret;
471 }
472
UseBuffersCapture(CameraBuffer * bufArr,int num)473 status_t V4LCameraAdapter::UseBuffersCapture(CameraBuffer *bufArr, int num) {
474 int ret = NO_ERROR;
475
476 LOG_FUNCTION_NAME;
477 if(NULL == bufArr) {
478 ret = BAD_VALUE;
479 goto EXIT;
480 }
481
482 for (int i = 0; i < num; i++) {
483 //Associate each Camera internal buffer with the one from Overlay
484 mCaptureBufs.add(&bufArr[i], i);
485 CAMHAL_LOGDB("capture- buff [%d] = 0x%x ",i, mCaptureBufs.keyAt(i));
486 }
487
488 mCaptureBuffersAvailable.clear();
489 for (int i = 0; i < mCaptureBufferCountQueueable; i++ ) {
490 mCaptureBuffersAvailable.add(&mCaptureBuffers[i], 0);
491 }
492
493 // initial ref count for undeqeueued buffers is 1 since buffer provider
494 // is still holding on to it
495 for (int i = mCaptureBufferCountQueueable; i < num; i++ ) {
496 mCaptureBuffersAvailable.add(&mCaptureBuffers[i], 1);
497 }
498
499 // Update the preview buffer count
500 mCaptureBufferCount = num;
501 EXIT:
502 LOG_FUNCTION_NAME_EXIT;
503 return ret;
504
505 }
506
UseBuffersPreview(CameraBuffer * bufArr,int num)507 status_t V4LCameraAdapter::UseBuffersPreview(CameraBuffer *bufArr, int num)
508 {
509 int ret = NO_ERROR;
510 LOG_FUNCTION_NAME;
511
512 if(NULL == bufArr) {
513 ret = BAD_VALUE;
514 goto EXIT;
515 }
516
517 ret = v4lInitMmap(num);
518 if (ret == NO_ERROR) {
519 for (int i = 0; i < num; i++) {
520 //Associate each Camera internal buffer with the one from Overlay
521 mPreviewBufs.add(&bufArr[i], i);
522 CAMHAL_LOGDB("Preview- buff [%d] = 0x%x ",i, mPreviewBufs.keyAt(i));
523 }
524
525 // Update the preview buffer count
526 mPreviewBufferCount = num;
527 }
528 EXIT:
529 LOG_FUNCTION_NAME_EXIT;
530 return ret;
531 }
532
takePicture()533 status_t V4LCameraAdapter::takePicture() {
534 status_t ret = NO_ERROR;
535 int width = 0;
536 int height = 0;
537 size_t yuv422i_buff_size = 0;
538 int index = 0;
539 char *fp = NULL;
540 CameraBuffer *buffer = NULL;
541 CameraFrame frame;
542
543 LOG_FUNCTION_NAME;
544
545 android::AutoMutex lock(mCaptureBufsLock);
546
547 if(mCapturing) {
548 CAMHAL_LOGEA("Already Capture in Progress...");
549 ret = BAD_VALUE;
550 goto EXIT;
551 }
552
553 mCapturing = true;
554 mPreviewing = false;
555
556 // Stop preview streaming
557 ret = v4lStopStreaming(mPreviewBufferCount);
558 if (ret < 0 ) {
559 CAMHAL_LOGEB("v4lStopStreaming Failed: %s", strerror(errno));
560 goto EXIT;
561 }
562
563 //configure for capture image size and pixel format.
564 mParams.getPictureSize(&width, &height);
565 CAMHAL_LOGDB("Image Capture Size WxH = %dx%d",width,height);
566 yuv422i_buff_size = width * height * 2;
567
568 ret = v4lSetFormat (width, height, DEFAULT_PIXEL_FORMAT);
569 if (ret < 0) {
570 CAMHAL_LOGEB("v4lSetFormat Failed: %s", strerror(errno));
571 goto EXIT;
572 }
573
574 ret = v4lInitMmap(mCaptureBufferCount);
575 if (ret < 0) {
576 CAMHAL_LOGEB("v4lInitMmap Failed: %s", strerror(errno));
577 goto EXIT;
578 }
579
580 for (int i = 0; i < mCaptureBufferCountQueueable; i++) {
581
582 mVideoInfo->buf.index = i;
583 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
584 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
585
586 ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
587 if (ret < 0) {
588 CAMHAL_LOGEA("VIDIOC_QBUF Failed");
589 ret = BAD_VALUE;
590 goto EXIT;
591 }
592 nQueued++;
593 }
594
595 ret = v4lStartStreaming();
596 if (ret < 0) {
597 CAMHAL_LOGEB("v4lStartStreaming Failed: %s", strerror(errno));
598 goto EXIT;
599 }
600
601 CAMHAL_LOGDA("Streaming started for Image Capture");
602
603 //get the frame and send to encode as JPG
604 fp = this->GetFrame(index);
605 if(!fp) {
606 CAMHAL_LOGEA("!!! Captured frame is NULL !!!!");
607 ret = BAD_VALUE;
608 goto EXIT;
609 }
610
611 CAMHAL_LOGDA("::Capture Frame received from V4L::");
612 buffer = mCaptureBufs.keyAt(index);
613 CAMHAL_LOGVB("## captureBuf[%d] = 0x%x, yuv422i_buff_size=%d", index, buffer->opaque, yuv422i_buff_size);
614
615 //copy the yuv422i data to the image buffer.
616 memcpy(buffer->opaque, fp, yuv422i_buff_size);
617
618 #ifdef DUMP_CAPTURE_FRAME
619 //dump the YUV422 buffer in to a file
620 //a folder should have been created at /data/misc/camera/raw/
621 {
622 int fd =-1;
623 fd = open("/data/misc/camera/raw/captured_yuv422i_dump.yuv", O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777);
624 if(fd < 0) {
625 CAMHAL_LOGEB("Unable to open file: %s", strerror(fd));
626 }
627 else {
628 write(fd, fp, yuv422i_buff_size );
629 close(fd);
630 CAMHAL_LOGDB("::Captured Frame dumped at /data/misc/camera/raw/captured_yuv422i_dump.yuv::");
631 }
632 }
633 #endif
634
635 CAMHAL_LOGDA("::sending capture frame to encoder::");
636 frame.mFrameType = CameraFrame::IMAGE_FRAME;
637 frame.mBuffer = buffer;
638 frame.mLength = yuv422i_buff_size;
639 frame.mWidth = width;
640 frame.mHeight = height;
641 frame.mAlignment = width*2;
642 frame.mOffset = 0;
643 frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
644 frame.mFrameMask = (unsigned int)CameraFrame::IMAGE_FRAME;
645 frame.mQuirks |= CameraFrame::ENCODE_RAW_YUV422I_TO_JPEG;
646 frame.mQuirks |= CameraFrame::FORMAT_YUV422I_YUYV;
647
648 ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask);
649 if (ret != NO_ERROR) {
650 CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret);
651 } else {
652 ret = sendFrameToSubscribers(&frame);
653 }
654
655 // Stop streaming after image capture
656 ret = v4lStopStreaming(mCaptureBufferCount);
657 if (ret < 0 ) {
658 CAMHAL_LOGEB("v4lStopStreaming Failed: %s", strerror(errno));
659 goto EXIT;
660 }
661
662 ret = restartPreview();
663 EXIT:
664 LOG_FUNCTION_NAME_EXIT;
665 return ret;
666 }
667
stopImageCapture()668 status_t V4LCameraAdapter::stopImageCapture()
669 {
670 status_t ret = NO_ERROR;
671 LOG_FUNCTION_NAME;
672
673 //Release image buffers
674 if ( NULL != mReleaseImageBuffersCallback ) {
675 mReleaseImageBuffersCallback(mReleaseData);
676 }
677 mCaptureBufs.clear();
678
679 mCapturing = false;
680 mPreviewing = true;
681 LOG_FUNCTION_NAME_EXIT;
682 return ret;
683 }
684
autoFocus()685 status_t V4LCameraAdapter::autoFocus()
686 {
687 status_t ret = NO_ERROR;
688 LOG_FUNCTION_NAME;
689
690 //autoFocus is not implemented. Just return.
691 LOG_FUNCTION_NAME_EXIT;
692 return ret;
693 }
694
startPreview()695 status_t V4LCameraAdapter::startPreview()
696 {
697 status_t ret = NO_ERROR;
698
699 LOG_FUNCTION_NAME;
700 android::AutoMutex lock(mPreviewBufsLock);
701
702 if(mPreviewing) {
703 ret = BAD_VALUE;
704 goto EXIT;
705 }
706
707 for (int i = 0; i < mPreviewBufferCountQueueable; i++) {
708
709 mVideoInfo->buf.index = i;
710 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
711 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
712
713 ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
714 if (ret < 0) {
715 CAMHAL_LOGEA("VIDIOC_QBUF Failed");
716 goto EXIT;
717 }
718 nQueued++;
719 }
720
721 ret = v4lStartStreaming();
722
723 // Create and start preview thread for receiving buffers from V4L Camera
724 if(!mCapturing) {
725 mPreviewThread = new PreviewThread(this);
726 CAMHAL_LOGDA("Created preview thread");
727 }
728
729 //Update the flag to indicate we are previewing
730 mPreviewing = true;
731 mCapturing = false;
732
733 EXIT:
734 LOG_FUNCTION_NAME_EXIT;
735 return ret;
736 }
737
stopPreview()738 status_t V4LCameraAdapter::stopPreview()
739 {
740 enum v4l2_buf_type bufType;
741 int ret = NO_ERROR;
742
743 LOG_FUNCTION_NAME;
744 android::AutoMutex lock(mStopPreviewLock);
745
746 if(!mPreviewing) {
747 return NO_INIT;
748 }
749 mPreviewing = false;
750
751 ret = v4lStopStreaming(mPreviewBufferCount);
752 if (ret < 0) {
753 CAMHAL_LOGEB("StopStreaming: FAILED: %s", strerror(errno));
754 }
755
756 nQueued = 0;
757 nDequeued = 0;
758 mFramesWithEncoder = 0;
759
760 mPreviewBufs.clear();
761
762 mPreviewThread->requestExitAndWait();
763 mPreviewThread.clear();
764
765 LOG_FUNCTION_NAME_EXIT;
766 return ret;
767 }
768
GetFrame(int & index)769 char * V4LCameraAdapter::GetFrame(int &index)
770 {
771 int ret = NO_ERROR;
772 LOG_FUNCTION_NAME;
773
774 mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
775 mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
776
777 /* DQ */
778 // Some V4L drivers, notably uvc, protect each incoming call with
779 // a driver-wide mutex. If we use poll() or blocking VIDIOC_DQBUF ioctl
780 // here then we sometimes would run into a deadlock on VIDIO_QBUF ioctl.
781 while(true) {
782 if(!mVideoInfo->isStreaming) {
783 return NULL;
784 }
785
786 ret = v4lIoctl(mCameraHandle, VIDIOC_DQBUF, &mVideoInfo->buf);
787 if((ret == 0) || (errno != EAGAIN)) {
788 break;
789 }
790 }
791
792 if (ret < 0) {
793 CAMHAL_LOGEA("GetFrame: VIDIOC_DQBUF Failed");
794 return NULL;
795 }
796 nDequeued++;
797
798 index = mVideoInfo->buf.index;
799
800 LOG_FUNCTION_NAME_EXIT;
801 return (char *)mVideoInfo->mem[mVideoInfo->buf.index];
802 }
803
804 //API to get the frame size required to be allocated. This size is used to override the size passed
805 //by camera service when VSTAB/VNF is turned ON for example
getFrameSize(size_t & width,size_t & height)806 status_t V4LCameraAdapter::getFrameSize(size_t &width, size_t &height)
807 {
808 status_t ret = NO_ERROR;
809 LOG_FUNCTION_NAME;
810
811 // Just return the current preview size, nothing more to do here.
812 mParams.getPreviewSize(( int * ) &width,
813 ( int * ) &height);
814
815 LOG_FUNCTION_NAME_EXIT;
816
817 return ret;
818 }
819
getFrameDataSize(size_t & dataFrameSize,size_t bufferCount)820 status_t V4LCameraAdapter::getFrameDataSize(size_t &dataFrameSize, size_t bufferCount)
821 {
822 // We don't support meta data, so simply return
823 return NO_ERROR;
824 }
825
getPictureBufferSize(CameraFrame & frame,size_t bufferCount)826 status_t V4LCameraAdapter::getPictureBufferSize(CameraFrame &frame, size_t bufferCount)
827 {
828 int width = 0;
829 int height = 0;
830 int bytesPerPixel = 2; // for YUV422i; default pixel format
831
832 LOG_FUNCTION_NAME;
833
834 mParams.getPictureSize( &width, &height );
835 frame.mLength = width * height * bytesPerPixel;
836 frame.mWidth = width;
837 frame.mHeight = height;
838 frame.mAlignment = width * bytesPerPixel;
839
840 CAMHAL_LOGDB("Picture size: W x H = %u x %u (size=%u bytes, alignment=%u bytes)",
841 frame.mWidth, frame.mHeight, frame.mLength, frame.mAlignment);
842 LOG_FUNCTION_NAME_EXIT;
843 return NO_ERROR;
844 }
845
debugShowFPS()846 static void debugShowFPS()
847 {
848 static int mFrameCount = 0;
849 static int mLastFrameCount = 0;
850 static nsecs_t mLastFpsTime = 0;
851 static float mFps = 0;
852 if(mDebugFps) {
853 mFrameCount++;
854 if (!(mFrameCount & 0x1F)) {
855 nsecs_t now = systemTime();
856 nsecs_t diff = now - mLastFpsTime;
857 mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
858 mLastFpsTime = now;
859 mLastFrameCount = mFrameCount;
860 CAMHAL_LOGI("Camera %d Frames, %f FPS", mFrameCount, mFps);
861 }
862 }
863 }
864
recalculateFPS()865 status_t V4LCameraAdapter::recalculateFPS()
866 {
867 float currentFPS;
868
869 mFrameCount++;
870
871 if ( ( mFrameCount % FPS_PERIOD ) == 0 )
872 {
873 nsecs_t now = systemTime();
874 nsecs_t diff = now - mLastFPSTime;
875 currentFPS = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
876 mLastFPSTime = now;
877 mLastFrameCount = mFrameCount;
878
879 if ( 1 == mIter )
880 {
881 mFPS = currentFPS;
882 }
883 else
884 {
885 //cumulative moving average
886 mFPS = mLastFPS + (currentFPS - mLastFPS)/mIter;
887 }
888
889 mLastFPS = mFPS;
890 mIter++;
891 }
892
893 return NO_ERROR;
894 }
895
onOrientationEvent(uint32_t orientation,uint32_t tilt)896 void V4LCameraAdapter::onOrientationEvent(uint32_t orientation, uint32_t tilt)
897 {
898 LOG_FUNCTION_NAME;
899
900 LOG_FUNCTION_NAME_EXIT;
901 }
902
903
V4LCameraAdapter(size_t sensor_index)904 V4LCameraAdapter::V4LCameraAdapter(size_t sensor_index)
905 {
906 LOG_FUNCTION_NAME;
907
908 // Nothing useful to do in the constructor
909 mFramesWithEncoder = 0;
910
911 LOG_FUNCTION_NAME_EXIT;
912 }
913
~V4LCameraAdapter()914 V4LCameraAdapter::~V4LCameraAdapter()
915 {
916 LOG_FUNCTION_NAME;
917
918 // Close the camera handle and free the video info structure
919 close(mCameraHandle);
920
921 if (mVideoInfo)
922 {
923 free(mVideoInfo);
924 mVideoInfo = NULL;
925 }
926
927 LOG_FUNCTION_NAME_EXIT;
928 }
929
convertYUV422i_yuyvTouyvy(uint8_t * src,uint8_t * dest,size_t size)930 static void convertYUV422i_yuyvTouyvy(uint8_t *src, uint8_t *dest, size_t size ) {
931 //convert YUV422I yuyv to uyvy format.
932 uint32_t *bf = (uint32_t*)src;
933 uint32_t *dst = (uint32_t*)dest;
934
935 LOG_FUNCTION_NAME;
936
937 if (!src || !dest) {
938 return;
939 }
940
941 for(size_t i = 0; i < size; i = i+4)
942 {
943 dst[0] = ((bf[0] & 0x00FF00FF) << 8) | ((bf[0] & 0xFF00FF00) >> 8);
944 bf++;
945 dst++;
946 }
947
948 LOG_FUNCTION_NAME_EXIT;
949 }
950
convertYUV422ToNV12Tiler(unsigned char * src,unsigned char * dest,int width,int height)951 static void convertYUV422ToNV12Tiler(unsigned char *src, unsigned char *dest, int width, int height ) {
952 //convert YUV422I to YUV420 NV12 format and copies directly to preview buffers (Tiler memory).
953 int stride = 4096;
954 unsigned char *bf = src;
955 unsigned char *dst_y = dest;
956 unsigned char *dst_uv = dest + ( height * stride);
957 #ifdef PPM_PER_FRAME_CONVERSION
958 static int frameCount = 0;
959 static nsecs_t ppm_diff = 0;
960 nsecs_t ppm_start = systemTime();
961 #endif
962
963 LOG_FUNCTION_NAME;
964
965 if (width % 16 ) {
966 for(int i = 0; i < height; i++) {
967 for(int j = 0; j < width; j++) {
968 *dst_y = *bf;
969 dst_y++;
970 bf = bf + 2;
971 }
972 dst_y += (stride - width);
973 }
974
975 bf = src;
976 bf++; //UV sample
977 for(int i = 0; i < height/2; i++) {
978 for(int j=0; j<width; j++) {
979 *dst_uv = *bf;
980 dst_uv++;
981 bf = bf + 2;
982 }
983 bf = bf + width*2;
984 dst_uv = dst_uv + (stride - width);
985 }
986 } else {
987 //neon conversion
988 for(int i = 0; i < height; i++) {
989 int n = width;
990 int skip = i & 0x1; // skip uv elements for the odd rows
991 asm volatile (
992 " pld [%[src], %[src_stride], lsl #2] \n\t"
993 " cmp %[n], #16 \n\t"
994 " blt 5f \n\t"
995 "0: @ 16 pixel copy \n\t"
996 " vld2.8 {q0, q1} , [%[src]]! @ q0 = yyyy.. q1 = uvuv.. \n\t"
997 " @ now q0 = y q1 = uv \n\t"
998 " vst1.32 {d0,d1}, [%[dst_y]]! \n\t"
999 " cmp %[skip], #0 \n\t"
1000 " bne 1f \n\t"
1001 " vst1.32 {d2,d3},[%[dst_uv]]! \n\t"
1002 "1: @ skip odd rows for UV \n\t"
1003 " sub %[n], %[n], #16 \n\t"
1004 " cmp %[n], #16 \n\t"
1005 " bge 0b \n\t"
1006 "5: @ end \n\t"
1007 #ifdef NEEDS_ARM_ERRATA_754319_754320
1008 " vmov s0,s0 @ add noop for errata item \n\t"
1009 #endif
1010 : [dst_y] "+r" (dst_y), [dst_uv] "+r" (dst_uv), [src] "+r" (src), [n] "+r" (n)
1011 : [src_stride] "r" (width), [skip] "r" (skip)
1012 : "cc", "memory", "q0", "q1", "q2", "d0", "d1", "d2", "d3"
1013 );
1014 dst_y = dst_y + (stride - width);
1015 if (skip == 0) {
1016 dst_uv = dst_uv + (stride - width);
1017 }
1018 } //end of for()
1019 }
1020
1021 #ifdef PPM_PER_FRAME_CONVERSION
1022 ppm_diff += (systemTime() - ppm_start);
1023 frameCount++;
1024
1025 if (frameCount >= 30) {
1026 ppm_diff = ppm_diff / frameCount;
1027 LOGD("PPM: YUV422i to NV12 Conversion(%d x %d): %llu us ( %llu ms )", width, height,
1028 ns2us(ppm_diff), ns2ms(ppm_diff) );
1029 ppm_diff = 0;
1030 frameCount = 0;
1031 }
1032 #endif
1033
1034 LOG_FUNCTION_NAME_EXIT;
1035 }
1036
convertYUV422ToNV12(unsigned char * src,unsigned char * dest,int width,int height)1037 static void convertYUV422ToNV12(unsigned char *src, unsigned char *dest, int width, int height ) {
1038 //convert YUV422I to YUV420 NV12 format.
1039 unsigned char *bf = src;
1040 unsigned char *dst_y = dest;
1041 unsigned char *dst_uv = dest + (width * height);
1042
1043 LOG_FUNCTION_NAME;
1044
1045 if (width % 16 ) {
1046 for(int i = 0; i < height; i++) {
1047 for(int j = 0; j < width; j++) {
1048 *dst_y = *bf;
1049 dst_y++;
1050 bf = bf + 2;
1051 }
1052 }
1053
1054 bf = src;
1055 bf++; //UV sample
1056 for(int i = 0; i < height/2; i++) {
1057 for(int j=0; j<width; j++) {
1058 *dst_uv = *bf;
1059 dst_uv++;
1060 bf = bf + 2;
1061 }
1062 bf = bf + width*2;
1063 }
1064 } else {
1065 //neon conversion
1066 for(int i = 0; i < height; i++) {
1067 int n = width;
1068 int skip = i & 0x1; // skip uv elements for the odd rows
1069 asm volatile (
1070 " pld [%[src], %[src_stride], lsl #2] \n\t"
1071 " cmp %[n], #16 \n\t"
1072 " blt 5f \n\t"
1073 "0: @ 16 pixel copy \n\t"
1074 " vld2.8 {q0, q1} , [%[src]]! @ q0 = yyyy.. q1 = uvuv.. \n\t"
1075 " @ now q0 = y q1 = uv \n\t"
1076 " vst1.32 {d0,d1}, [%[dst_y]]! \n\t"
1077 " cmp %[skip], #0 \n\t"
1078 " bne 1f \n\t"
1079 " vst1.32 {d2,d3},[%[dst_uv]]! \n\t"
1080 "1: @ skip odd rows for UV \n\t"
1081 " sub %[n], %[n], #16 \n\t"
1082 " cmp %[n], #16 \n\t"
1083 " bge 0b \n\t"
1084 "5: @ end \n\t"
1085 #ifdef NEEDS_ARM_ERRATA_754319_754320
1086 " vmov s0,s0 @ add noop for errata item \n\t"
1087 #endif
1088 : [dst_y] "+r" (dst_y), [dst_uv] "+r" (dst_uv), [src] "+r" (src), [n] "+r" (n)
1089 : [src_stride] "r" (width), [skip] "r" (skip)
1090 : "cc", "memory", "q0", "q1", "q2", "d0", "d1", "d2", "d3"
1091 );
1092 }
1093 }
1094
1095 LOG_FUNCTION_NAME_EXIT;
1096 }
1097
1098 #ifdef SAVE_RAW_FRAMES
saveFile(unsigned char * buff,int buff_size)1099 void saveFile(unsigned char* buff, int buff_size) {
1100 static int counter = 1;
1101 int fd = -1;
1102 char fn[256];
1103
1104 LOG_FUNCTION_NAME;
1105 if (counter > 3) {
1106 return;
1107 }
1108 //dump nv12 buffer
1109 counter++;
1110 sprintf(fn, "/data/misc/camera/raw/nv12_dump_%03d.yuv", counter);
1111 CAMHAL_LOGEB("Dumping nv12 frame to a file : %s.", fn);
1112
1113 fd = open(fn, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777);
1114 if(fd < 0) {
1115 CAMHAL_LOGE("Unable to open file %s: %s", fn, strerror(fd));
1116 return;
1117 }
1118
1119 write(fd, buff, buff_size );
1120 close(fd);
1121
1122 LOG_FUNCTION_NAME_EXIT;
1123 }
1124 #endif
1125
1126 /* Preview Thread */
1127 // ---------------------------------------------------------------------------
1128
previewThread()1129 int V4LCameraAdapter::previewThread()
1130 {
1131 status_t ret = NO_ERROR;
1132 int width, height;
1133 CameraFrame frame;
1134 void *y_uv[2];
1135 int index = 0;
1136 int stride = 4096;
1137 char *fp = NULL;
1138
1139 mParams.getPreviewSize(&width, &height);
1140
1141 if (mPreviewing) {
1142
1143 fp = this->GetFrame(index);
1144 if(!fp) {
1145 ret = BAD_VALUE;
1146 goto EXIT;
1147 }
1148 CameraBuffer *buffer = mPreviewBufs.keyAt(index);
1149 CameraFrame *lframe = (CameraFrame *)mFrameQueue.valueFor(buffer);
1150 if (!lframe) {
1151 ret = BAD_VALUE;
1152 goto EXIT;
1153 }
1154
1155 debugShowFPS();
1156
1157 if ( mFrameSubscribers.size() == 0 ) {
1158 ret = BAD_VALUE;
1159 goto EXIT;
1160 }
1161 y_uv[0] = (void*) lframe->mYuv[0];
1162 //y_uv[1] = (void*) lframe->mYuv[1];
1163 //y_uv[1] = (void*) (lframe->mYuv[0] + height*stride);
1164 convertYUV422ToNV12Tiler ( (unsigned char*)fp, (unsigned char*)y_uv[0], width, height);
1165 CAMHAL_LOGVB("##...index= %d.;camera buffer= 0x%x; y= 0x%x; UV= 0x%x.",index, buffer, y_uv[0], y_uv[1] );
1166
1167 #ifdef SAVE_RAW_FRAMES
1168 unsigned char* nv12_buff = (unsigned char*) malloc(width*height*3/2);
1169 //Convert yuv422i to yuv420sp(NV12) & dump the frame to a file
1170 convertYUV422ToNV12 ( (unsigned char*)fp, nv12_buff, width, height);
1171 saveFile( nv12_buff, ((width*height)*3/2) );
1172 free (nv12_buff);
1173 #endif
1174
1175 frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC;
1176 frame.mBuffer = buffer;
1177 frame.mLength = width*height*3/2;
1178 frame.mAlignment = stride;
1179 frame.mOffset = 0;
1180 frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
1181 frame.mFrameMask = (unsigned int)CameraFrame::PREVIEW_FRAME_SYNC;
1182
1183 if (mRecording)
1184 {
1185 frame.mFrameMask |= (unsigned int)CameraFrame::VIDEO_FRAME_SYNC;
1186 mFramesWithEncoder++;
1187 }
1188
1189 ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask);
1190 if (ret != NO_ERROR) {
1191 CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret);
1192 } else {
1193 ret = sendFrameToSubscribers(&frame);
1194 }
1195 }
1196 EXIT:
1197
1198 return ret;
1199 }
1200
1201 //scan for video devices
detectVideoDevice(char ** video_device_list,int & num_device)1202 void detectVideoDevice(char** video_device_list, int& num_device) {
1203 char dir_path[20];
1204 char* filename;
1205 char** dev_list = video_device_list;
1206 DIR *d;
1207 struct dirent *dir;
1208 int index = 0;
1209
1210 strcpy(dir_path, DEVICE_PATH);
1211 d = opendir(dir_path);
1212 if(d) {
1213 //read each entry in the /dev/ and find if there is videox entry.
1214 while ((dir = readdir(d)) != NULL) {
1215 filename = dir->d_name;
1216 if (strncmp(filename, DEVICE_NAME, 5) == 0) {
1217 strcpy(dev_list[index],DEVICE_PATH);
1218 strncat(dev_list[index],filename,sizeof(DEVICE_NAME));
1219 index++;
1220 }
1221 } //end of while()
1222 closedir(d);
1223 num_device = index;
1224
1225 for(int i=0; i<index; i++){
1226 CAMHAL_LOGDB("Video device list::dev_list[%d]= %s",i,dev_list[i]);
1227 }
1228 }
1229 }
1230
V4LCameraAdapter_Factory(size_t sensor_index)1231 extern "C" CameraAdapter* V4LCameraAdapter_Factory(size_t sensor_index)
1232 {
1233 CameraAdapter *adapter = NULL;
1234 android::AutoMutex lock(gV4LAdapterLock);
1235
1236 LOG_FUNCTION_NAME;
1237
1238 adapter = new V4LCameraAdapter(sensor_index);
1239 if ( adapter ) {
1240 CAMHAL_LOGDB("New V4L Camera adapter instance created for sensor %d",sensor_index);
1241 } else {
1242 CAMHAL_LOGEA("V4L Camera adapter create failed for sensor index = %d!",sensor_index);
1243 }
1244
1245 LOG_FUNCTION_NAME_EXIT;
1246
1247 return adapter;
1248 }
1249
V4LCameraAdapter_Capabilities(CameraProperties::Properties * const properties_array,const int starting_camera,const int max_camera,int & supportedCameras)1250 extern "C" status_t V4LCameraAdapter_Capabilities(
1251 CameraProperties::Properties * const properties_array,
1252 const int starting_camera, const int max_camera, int & supportedCameras)
1253 {
1254 status_t ret = NO_ERROR;
1255 struct v4l2_capability cap;
1256 int tempHandle = NULL;
1257 int num_cameras_supported = 0;
1258 char device_list[5][15];
1259 char* video_device_list[5];
1260 int num_v4l_devices = 0;
1261 int sensorId = 0;
1262 CameraProperties::Properties* properties = NULL;
1263
1264 LOG_FUNCTION_NAME;
1265
1266 supportedCameras = 0;
1267 memset((void*)&cap, 0, sizeof(v4l2_capability));
1268
1269 if (!properties_array) {
1270 CAMHAL_LOGEB("invalid param: properties = 0x%p", properties_array);
1271 LOG_FUNCTION_NAME_EXIT;
1272 return BAD_VALUE;
1273 }
1274
1275 for (int i = 0; i < 5; i++) {
1276 video_device_list[i] = device_list[i];
1277 }
1278 //look for the connected video devices
1279 detectVideoDevice(video_device_list, num_v4l_devices);
1280
1281 for (int i = 0; i < num_v4l_devices; i++) {
1282 if ( (starting_camera + num_cameras_supported) < max_camera) {
1283 sensorId = starting_camera + num_cameras_supported;
1284
1285 CAMHAL_LOGDB("Opening device[%d] = %s..",i, video_device_list[i]);
1286 if ((tempHandle = open(video_device_list[i], O_RDWR)) == -1) {
1287 CAMHAL_LOGEB("Error while opening handle to V4L2 Camera(%s): %s",video_device_list[i], strerror(errno));
1288 continue;
1289 }
1290
1291 ret = ioctl (tempHandle, VIDIOC_QUERYCAP, &cap);
1292 if (ret < 0) {
1293 CAMHAL_LOGEA("Error when querying the capabilities of the V4L Camera");
1294 close(tempHandle);
1295 continue;
1296 }
1297
1298 //check for video capture devices
1299 if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
1300 CAMHAL_LOGEA("Error while adapter initialization: video capture not supported.");
1301 close(tempHandle);
1302 continue;
1303 }
1304
1305 strcpy(device, video_device_list[i]);
1306 properties = properties_array + starting_camera + num_cameras_supported;
1307
1308 //fetch capabilities for this camera
1309 ret = V4LCameraAdapter::getCaps( sensorId, properties, tempHandle );
1310 if (ret < 0) {
1311 CAMHAL_LOGEA("Error while getting capabilities.");
1312 close(tempHandle);
1313 continue;
1314 }
1315
1316 num_cameras_supported++;
1317
1318 }
1319 //For now exit this loop once a valid video capture device is found.
1320 //TODO: find all V4L capture devices and it capabilities
1321 break;
1322 }//end of for() loop
1323
1324 supportedCameras = num_cameras_supported;
1325 CAMHAL_LOGDB("Number of V4L cameras detected =%d", num_cameras_supported);
1326
1327 EXIT:
1328 LOG_FUNCTION_NAME_EXIT;
1329 close(tempHandle);
1330 return NO_ERROR;
1331 }
1332
1333 } // namespace Camera
1334 } // namespace Ti
1335
1336
1337 /*--------------------Camera Adapter Class ENDS here-----------------------------*/
1338
1339