V4LCameraAdapter.cpp revision f7a4d11e9f710e2cd0592310ac1baecccb85f1d1
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 ))
46static int mDebugFps = 0;
47
48#define Q16_OFFSET 16
49
50#define HERE(Msg) {CAMHAL_LOGEB("--=== %s===--\n", Msg);}
51
52namespace Ti {
53namespace 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
64static void convertYUV422i_yuyvTouyvy(uint8_t *src, uint8_t *dest, size_t size );
65static void convertYUV422ToNV12Tiler(unsigned char *src, unsigned char *dest, int width, int height );
66static void convertYUV422ToNV12(unsigned char *src, unsigned char *dest, int width, int height );
67
68android::Mutex gV4LAdapterLock;
69char device[15];
70
71
72/*--------------------Camera Adapter Class STARTS here-----------------------------*/
73
74/*--------------------V4L wrapper functions -------------------------------*/
75status_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
86status_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
133status_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
150status_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
167status_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    }
201EXIT:
202    return ret;
203}
204
205status_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
234status_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....");
284EXIT:
285    return ret;
286}
287
288/*--------------------Camera Adapter Functions-----------------------------*/
289status_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;
336EXIT:
337    LOG_FUNCTION_NAME_EXIT;
338    return ret;
339}
340
341status_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++;
375EXIT:
376    LOG_FUNCTION_NAME_EXIT;
377    return ret;
378
379}
380
381status_t V4LCameraAdapter::setParameters(const android::CameraParameters &params)
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
417EXIT:
418    LOG_FUNCTION_NAME_EXIT;
419    return ret;
420}
421
422
423void 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
435status_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
473status_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    // Update the preview buffer count
489    mCaptureBufferCount = num;
490EXIT:
491    LOG_FUNCTION_NAME_EXIT;
492    return ret;
493
494}
495
496status_t V4LCameraAdapter::UseBuffersPreview(CameraBuffer *bufArr, int num)
497{
498    int ret = NO_ERROR;
499    LOG_FUNCTION_NAME;
500
501    if(NULL == bufArr) {
502        ret = BAD_VALUE;
503        goto EXIT;
504    }
505
506    ret = v4lInitMmap(num);
507    if (ret == NO_ERROR) {
508        for (int i = 0; i < num; i++) {
509            //Associate each Camera internal buffer with the one from Overlay
510            mPreviewBufs.add(&bufArr[i], i);
511            CAMHAL_LOGDB("Preview- buff [%d] = 0x%x ",i, mPreviewBufs.keyAt(i));
512        }
513
514        // Update the preview buffer count
515        mPreviewBufferCount = num;
516    }
517EXIT:
518    LOG_FUNCTION_NAME_EXIT;
519    return ret;
520}
521
522status_t V4LCameraAdapter::takePicture() {
523    status_t ret = NO_ERROR;
524    int width = 0;
525    int height = 0;
526    size_t yuv422i_buff_size = 0;
527    int index = 0;
528    char *fp = NULL;
529    CameraBuffer *buffer = NULL;
530    CameraFrame frame;
531
532    LOG_FUNCTION_NAME;
533
534    android::AutoMutex lock(mCaptureBufsLock);
535
536    if(mCapturing) {
537        CAMHAL_LOGEA("Already Capture in Progress...");
538        ret = BAD_VALUE;
539        goto EXIT;
540    }
541
542    mCapturing = true;
543    mPreviewing = false;
544
545    // Stop preview streaming
546    ret = v4lStopStreaming(mPreviewBufferCount);
547    if (ret < 0 ) {
548        CAMHAL_LOGEB("v4lStopStreaming Failed: %s", strerror(errno));
549        goto EXIT;
550    }
551
552    //configure for capture image size and pixel format.
553    mParams.getPictureSize(&width, &height);
554    CAMHAL_LOGDB("Image Capture Size WxH = %dx%d",width,height);
555    yuv422i_buff_size = width * height * 2;
556
557    ret = v4lSetFormat (width, height, DEFAULT_PIXEL_FORMAT);
558    if (ret < 0) {
559        CAMHAL_LOGEB("v4lSetFormat Failed: %s", strerror(errno));
560        goto EXIT;
561    }
562
563    ret = v4lInitMmap(mCaptureBufferCount);
564    if (ret < 0) {
565        CAMHAL_LOGEB("v4lInitMmap Failed: %s", strerror(errno));
566        goto EXIT;
567    }
568
569    for (int i = 0; i < mCaptureBufferCountQueueable; i++) {
570
571       mVideoInfo->buf.index = i;
572       mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
573       mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
574
575       ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
576       if (ret < 0) {
577           CAMHAL_LOGEA("VIDIOC_QBUF Failed");
578           ret = BAD_VALUE;
579           goto EXIT;
580       }
581       nQueued++;
582    }
583
584    ret = v4lStartStreaming();
585    if (ret < 0) {
586        CAMHAL_LOGEB("v4lStartStreaming Failed: %s", strerror(errno));
587        goto EXIT;
588    }
589
590    CAMHAL_LOGDA("Streaming started for Image Capture");
591
592    //get the frame and send to encode as JPG
593    fp = this->GetFrame(index);
594    if(!fp) {
595        CAMHAL_LOGEA("!!! Captured frame is NULL !!!!");
596        ret = BAD_VALUE;
597        goto EXIT;
598    }
599
600    CAMHAL_LOGDA("::Capture Frame received from V4L::");
601    buffer = mCaptureBufs.keyAt(index);
602    CAMHAL_LOGVB("## captureBuf[%d] = 0x%x, yuv422i_buff_size=%d", index, buffer->opaque, yuv422i_buff_size);
603
604    //copy the yuv422i data to the image buffer.
605    memcpy(buffer->opaque, fp, yuv422i_buff_size);
606
607#ifdef DUMP_CAPTURE_FRAME
608    //dump the YUV422 buffer in to a file
609    //a folder should have been created at /data/misc/camera/raw/
610    {
611        int fd =-1;
612        fd = open("/data/misc/camera/raw/captured_yuv422i_dump.yuv", O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777);
613        if(fd < 0) {
614            CAMHAL_LOGEB("Unable to open file: %s",  strerror(fd));
615        }
616        else {
617            write(fd, fp, yuv422i_buff_size );
618            close(fd);
619            CAMHAL_LOGDB("::Captured Frame dumped at /data/misc/camera/raw/captured_yuv422i_dump.yuv::");
620        }
621    }
622#endif
623
624    CAMHAL_LOGDA("::sending capture frame to encoder::");
625    frame.mFrameType = CameraFrame::IMAGE_FRAME;
626    frame.mBuffer = buffer;
627    frame.mLength = yuv422i_buff_size;
628    frame.mWidth = width;
629    frame.mHeight = height;
630    frame.mAlignment = width*2;
631    frame.mOffset = 0;
632    frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
633    frame.mFrameMask = (unsigned int)CameraFrame::IMAGE_FRAME;
634    frame.mQuirks |= CameraFrame::ENCODE_RAW_YUV422I_TO_JPEG;
635    frame.mQuirks |= CameraFrame::FORMAT_YUV422I_YUYV;
636
637    ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask);
638    if (ret != NO_ERROR) {
639        CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret);
640    } else {
641        ret = sendFrameToSubscribers(&frame);
642    }
643
644    // Stop streaming after image capture
645    ret = v4lStopStreaming(mCaptureBufferCount);
646    if (ret < 0 ) {
647        CAMHAL_LOGEB("v4lStopStreaming Failed: %s", strerror(errno));
648        goto EXIT;
649    }
650
651    ret = restartPreview();
652EXIT:
653    LOG_FUNCTION_NAME_EXIT;
654    return ret;
655}
656
657status_t V4LCameraAdapter::stopImageCapture()
658{
659    status_t ret = NO_ERROR;
660    LOG_FUNCTION_NAME;
661
662    //Release image buffers
663    if ( NULL != mReleaseImageBuffersCallback ) {
664        mReleaseImageBuffersCallback(mReleaseData);
665    }
666    mCaptureBufs.clear();
667
668    mCapturing = false;
669    mPreviewing = true;
670    LOG_FUNCTION_NAME_EXIT;
671    return ret;
672}
673
674status_t V4LCameraAdapter::autoFocus()
675{
676    status_t ret = NO_ERROR;
677    LOG_FUNCTION_NAME;
678
679    //autoFocus is not implemented. Just return.
680    LOG_FUNCTION_NAME_EXIT;
681    return ret;
682}
683
684status_t V4LCameraAdapter::startPreview()
685{
686    status_t ret = NO_ERROR;
687
688    LOG_FUNCTION_NAME;
689    android::AutoMutex lock(mPreviewBufsLock);
690
691    if(mPreviewing) {
692        ret = BAD_VALUE;
693        goto EXIT;
694    }
695
696    for (int i = 0; i < mPreviewBufferCountQueueable; i++) {
697
698        mVideoInfo->buf.index = i;
699        mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
700        mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
701
702        ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
703        if (ret < 0) {
704            CAMHAL_LOGEA("VIDIOC_QBUF Failed");
705            goto EXIT;
706        }
707        nQueued++;
708    }
709
710    ret = v4lStartStreaming();
711
712    // Create and start preview thread for receiving buffers from V4L Camera
713    if(!mCapturing) {
714        mPreviewThread = new PreviewThread(this);
715        CAMHAL_LOGDA("Created preview thread");
716    }
717
718    //Update the flag to indicate we are previewing
719    mPreviewing = true;
720    mCapturing = false;
721
722EXIT:
723    LOG_FUNCTION_NAME_EXIT;
724    return ret;
725}
726
727status_t V4LCameraAdapter::stopPreview()
728{
729    enum v4l2_buf_type bufType;
730    int ret = NO_ERROR;
731
732    LOG_FUNCTION_NAME;
733    android::AutoMutex lock(mStopPreviewLock);
734
735    if(!mPreviewing) {
736        return NO_INIT;
737    }
738    mPreviewing = false;
739
740    ret = v4lStopStreaming(mPreviewBufferCount);
741    if (ret < 0) {
742        CAMHAL_LOGEB("StopStreaming: FAILED: %s", strerror(errno));
743    }
744
745    nQueued = 0;
746    nDequeued = 0;
747    mFramesWithEncoder = 0;
748
749    mPreviewBufs.clear();
750
751    mPreviewThread->requestExitAndWait();
752    mPreviewThread.clear();
753
754    LOG_FUNCTION_NAME_EXIT;
755    return ret;
756}
757
758char * V4LCameraAdapter::GetFrame(int &index)
759{
760    int ret = NO_ERROR;
761    LOG_FUNCTION_NAME;
762
763    mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
764    mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
765
766    /* DQ */
767    // Some V4L drivers, notably uvc, protect each incoming call with
768    // a driver-wide mutex.  If we use poll() or blocking VIDIOC_DQBUF ioctl
769    // here then we sometimes would run into a deadlock on VIDIO_QBUF ioctl.
770    while(true) {
771      if(!mVideoInfo->isStreaming) {
772        return NULL;
773      }
774
775      ret = v4lIoctl(mCameraHandle, VIDIOC_DQBUF, &mVideoInfo->buf);
776      if((ret == 0) || (errno != EAGAIN)) {
777        break;
778      }
779    }
780
781    if (ret < 0) {
782        CAMHAL_LOGEA("GetFrame: VIDIOC_DQBUF Failed");
783        return NULL;
784    }
785    nDequeued++;
786
787    index = mVideoInfo->buf.index;
788
789    LOG_FUNCTION_NAME_EXIT;
790    return (char *)mVideoInfo->mem[mVideoInfo->buf.index];
791}
792
793//API to get the frame size required to be allocated. This size is used to override the size passed
794//by camera service when VSTAB/VNF is turned ON for example
795status_t V4LCameraAdapter::getFrameSize(size_t &width, size_t &height)
796{
797    status_t ret = NO_ERROR;
798    LOG_FUNCTION_NAME;
799
800    // Just return the current preview size, nothing more to do here.
801    mParams.getPreviewSize(( int * ) &width,
802                           ( int * ) &height);
803
804    LOG_FUNCTION_NAME_EXIT;
805
806    return ret;
807}
808
809status_t V4LCameraAdapter::getFrameDataSize(size_t &dataFrameSize, size_t bufferCount)
810{
811    // We don't support meta data, so simply return
812    return NO_ERROR;
813}
814
815status_t V4LCameraAdapter::getPictureBufferSize(CameraFrame &frame, size_t bufferCount)
816{
817    int width = 0;
818    int height = 0;
819    int bytesPerPixel = 2; // for YUV422i; default pixel format
820
821    LOG_FUNCTION_NAME;
822
823    mParams.getPictureSize( &width, &height );
824    frame.mLength = width * height * bytesPerPixel;
825    frame.mWidth = width;
826    frame.mHeight = height;
827    frame.mAlignment = width * bytesPerPixel;
828
829    CAMHAL_LOGDB("Picture size: W x H = %u x %u (size=%u bytes, alignment=%u bytes)",
830                 frame.mWidth, frame.mHeight, frame.mLength, frame.mAlignment);
831    LOG_FUNCTION_NAME_EXIT;
832    return NO_ERROR;
833}
834
835static void debugShowFPS()
836{
837    static int mFrameCount = 0;
838    static int mLastFrameCount = 0;
839    static nsecs_t mLastFpsTime = 0;
840    static float mFps = 0;
841    if(mDebugFps) {
842        mFrameCount++;
843        if (!(mFrameCount & 0x1F)) {
844            nsecs_t now = systemTime();
845            nsecs_t diff = now - mLastFpsTime;
846            mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
847            mLastFpsTime = now;
848            mLastFrameCount = mFrameCount;
849            CAMHAL_LOGD("Camera %d Frames, %f FPS", mFrameCount, mFps);
850        }
851    }
852}
853
854status_t V4LCameraAdapter::recalculateFPS()
855{
856    float currentFPS;
857
858    mFrameCount++;
859
860    if ( ( mFrameCount % FPS_PERIOD ) == 0 )
861        {
862        nsecs_t now = systemTime();
863        nsecs_t diff = now - mLastFPSTime;
864        currentFPS =  ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
865        mLastFPSTime = now;
866        mLastFrameCount = mFrameCount;
867
868        if ( 1 == mIter )
869            {
870            mFPS = currentFPS;
871            }
872        else
873            {
874            //cumulative moving average
875            mFPS = mLastFPS + (currentFPS - mLastFPS)/mIter;
876            }
877
878        mLastFPS = mFPS;
879        mIter++;
880        }
881
882    return NO_ERROR;
883}
884
885void V4LCameraAdapter::onOrientationEvent(uint32_t orientation, uint32_t tilt)
886{
887    LOG_FUNCTION_NAME;
888
889    LOG_FUNCTION_NAME_EXIT;
890}
891
892
893V4LCameraAdapter::V4LCameraAdapter(size_t sensor_index)
894{
895    LOG_FUNCTION_NAME;
896
897    // Nothing useful to do in the constructor
898    mFramesWithEncoder = 0;
899
900    LOG_FUNCTION_NAME_EXIT;
901}
902
903V4LCameraAdapter::~V4LCameraAdapter()
904{
905    LOG_FUNCTION_NAME;
906
907    // Close the camera handle and free the video info structure
908    close(mCameraHandle);
909
910    if (mVideoInfo)
911      {
912        free(mVideoInfo);
913        mVideoInfo = NULL;
914      }
915
916    LOG_FUNCTION_NAME_EXIT;
917}
918
919static void convertYUV422i_yuyvTouyvy(uint8_t *src, uint8_t *dest, size_t size ) {
920    //convert YUV422I yuyv to uyvy format.
921    uint32_t *bf = (uint32_t*)src;
922    uint32_t *dst = (uint32_t*)dest;
923
924    LOG_FUNCTION_NAME;
925
926    if (!src || !dest) {
927        return;
928    }
929
930    for(size_t i = 0; i < size; i = i+4)
931    {
932        dst[0] = ((bf[0] & 0x00FF00FF) << 8) | ((bf[0] & 0xFF00FF00) >> 8);
933        bf++;
934        dst++;
935    }
936
937    LOG_FUNCTION_NAME_EXIT;
938}
939
940static void convertYUV422ToNV12Tiler(unsigned char *src, unsigned char *dest, int width, int height ) {
941    //convert YUV422I to YUV420 NV12 format and copies directly to preview buffers (Tiler memory).
942    int stride = 4096;
943    unsigned char *bf = src;
944    unsigned char *dst_y = dest;
945    unsigned char *dst_uv = dest + ( height * stride);
946#ifdef PPM_PER_FRAME_CONVERSION
947    static int frameCount = 0;
948    static nsecs_t ppm_diff = 0;
949    nsecs_t ppm_start  = systemTime();
950#endif
951
952    LOG_FUNCTION_NAME;
953
954    if (width % 16 ) {
955        for(int i = 0; i < height; i++) {
956            for(int j = 0; j < width; j++) {
957                *dst_y = *bf;
958                dst_y++;
959                bf = bf + 2;
960            }
961            dst_y += (stride - width);
962        }
963
964        bf = src;
965        bf++;  //UV sample
966        for(int i = 0; i < height/2; i++) {
967            for(int j=0; j<width; j++) {
968                *dst_uv = *bf;
969                dst_uv++;
970                bf = bf + 2;
971            }
972            bf = bf + width*2;
973            dst_uv = dst_uv + (stride - width);
974        }
975    } else {
976        //neon conversion
977        for(int i = 0; i < height; i++) {
978            int n = width;
979            int skip = i & 0x1;       // skip uv elements for the odd rows
980            asm volatile (
981                "   pld [%[src], %[src_stride], lsl #2]                         \n\t"
982                "   cmp %[n], #16                                               \n\t"
983                "   blt 5f                                                      \n\t"
984                "0: @ 16 pixel copy                                             \n\t"
985                "   vld2.8  {q0, q1} , [%[src]]! @ q0 = yyyy.. q1 = uvuv..      \n\t"
986                "                                @ now q0 = y q1 = uv           \n\t"
987                "   vst1.32   {d0,d1}, [%[dst_y]]!                              \n\t"
988                "   cmp    %[skip], #0                                          \n\t"
989                "   bne 1f                                                      \n\t"
990                "   vst1.32  {d2,d3},[%[dst_uv]]!                               \n\t"
991                "1: @ skip odd rows for UV                                      \n\t"
992                "   sub %[n], %[n], #16                                         \n\t"
993                "   cmp %[n], #16                                               \n\t"
994                "   bge 0b                                                      \n\t"
995                "5: @ end                                                       \n\t"
996#ifdef NEEDS_ARM_ERRATA_754319_754320
997                "   vmov s0,s0  @ add noop for errata item                      \n\t"
998#endif
999                : [dst_y] "+r" (dst_y), [dst_uv] "+r" (dst_uv), [src] "+r" (src), [n] "+r" (n)
1000                : [src_stride] "r" (width), [skip] "r" (skip)
1001                : "cc", "memory", "q0", "q1", "q2", "d0", "d1", "d2", "d3"
1002            );
1003            dst_y = dst_y + (stride - width);
1004            if (skip == 0) {
1005                dst_uv = dst_uv + (stride - width);
1006            }
1007        } //end of for()
1008    }
1009
1010#ifdef PPM_PER_FRAME_CONVERSION
1011    ppm_diff += (systemTime() - ppm_start);
1012    frameCount++;
1013
1014    if (frameCount >= 30) {
1015        ppm_diff = ppm_diff / frameCount;
1016        LOGD("PPM: YUV422i to NV12 Conversion(%d x %d): %llu us ( %llu ms )", width, height,
1017                ns2us(ppm_diff), ns2ms(ppm_diff) );
1018        ppm_diff = 0;
1019        frameCount = 0;
1020    }
1021#endif
1022
1023    LOG_FUNCTION_NAME_EXIT;
1024}
1025
1026static void convertYUV422ToNV12(unsigned char *src, unsigned char *dest, int width, int height ) {
1027    //convert YUV422I to YUV420 NV12 format.
1028    unsigned char *bf = src;
1029    unsigned char *dst_y = dest;
1030    unsigned char *dst_uv = dest + (width * height);
1031
1032    LOG_FUNCTION_NAME;
1033
1034    if (width % 16 ) {
1035        for(int i = 0; i < height; i++) {
1036            for(int j = 0; j < width; j++) {
1037                *dst_y = *bf;
1038                dst_y++;
1039                bf = bf + 2;
1040            }
1041        }
1042
1043        bf = src;
1044        bf++;  //UV sample
1045        for(int i = 0; i < height/2; i++) {
1046            for(int j=0; j<width; j++) {
1047                *dst_uv = *bf;
1048                dst_uv++;
1049                bf = bf + 2;
1050            }
1051            bf = bf + width*2;
1052        }
1053    } else {
1054        //neon conversion
1055        for(int i = 0; i < height; i++) {
1056            int n = width;
1057            int skip = i & 0x1;       // skip uv elements for the odd rows
1058            asm volatile (
1059                "   pld [%[src], %[src_stride], lsl #2]                         \n\t"
1060                "   cmp %[n], #16                                               \n\t"
1061                "   blt 5f                                                      \n\t"
1062                "0: @ 16 pixel copy                                             \n\t"
1063                "   vld2.8  {q0, q1} , [%[src]]! @ q0 = yyyy.. q1 = uvuv..      \n\t"
1064                "                                @ now q0 = y q1 = uv           \n\t"
1065                "   vst1.32   {d0,d1}, [%[dst_y]]!                              \n\t"
1066                "   cmp    %[skip], #0                                          \n\t"
1067                "   bne 1f                                                      \n\t"
1068                "   vst1.32  {d2,d3},[%[dst_uv]]!                               \n\t"
1069                "1: @ skip odd rows for UV                                      \n\t"
1070                "   sub %[n], %[n], #16                                         \n\t"
1071                "   cmp %[n], #16                                               \n\t"
1072                "   bge 0b                                                      \n\t"
1073                "5: @ end                                                       \n\t"
1074#ifdef NEEDS_ARM_ERRATA_754319_754320
1075                "   vmov s0,s0  @ add noop for errata item                      \n\t"
1076#endif
1077                : [dst_y] "+r" (dst_y), [dst_uv] "+r" (dst_uv), [src] "+r" (src), [n] "+r" (n)
1078                : [src_stride] "r" (width), [skip] "r" (skip)
1079                : "cc", "memory", "q0", "q1", "q2", "d0", "d1", "d2", "d3"
1080            );
1081        }
1082    }
1083
1084    LOG_FUNCTION_NAME_EXIT;
1085}
1086
1087#ifdef SAVE_RAW_FRAMES
1088void saveFile(unsigned char* buff, int buff_size) {
1089    static int      counter = 1;
1090    int             fd = -1;
1091    char            fn[256];
1092
1093    LOG_FUNCTION_NAME;
1094    if (counter > 3) {
1095        return;
1096    }
1097    //dump nv12 buffer
1098    counter++;
1099    sprintf(fn, "/data/misc/camera/raw/nv12_dump_%03d.yuv", counter);
1100    CAMHAL_LOGEB("Dumping nv12 frame to a file : %s.", fn);
1101
1102    fd = open(fn, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777);
1103    if(fd < 0) {
1104        CAMHAL_LOGE("Unable to open file %s: %s", fn, strerror(fd));
1105        return;
1106    }
1107
1108    write(fd, buff, buff_size );
1109    close(fd);
1110
1111    LOG_FUNCTION_NAME_EXIT;
1112}
1113#endif
1114
1115/* Preview Thread */
1116// ---------------------------------------------------------------------------
1117
1118int V4LCameraAdapter::previewThread()
1119{
1120    status_t ret = NO_ERROR;
1121    int width, height;
1122    CameraFrame frame;
1123    void *y_uv[2];
1124    int index = 0;
1125    int stride = 4096;
1126    char *fp = NULL;
1127
1128    mParams.getPreviewSize(&width, &height);
1129
1130    if (mPreviewing) {
1131
1132        fp = this->GetFrame(index);
1133        if(!fp) {
1134            ret = BAD_VALUE;
1135            goto EXIT;
1136        }
1137        CameraBuffer *buffer = mPreviewBufs.keyAt(index);
1138        CameraFrame *lframe = (CameraFrame *)mFrameQueue.valueFor(buffer);
1139        if (!lframe) {
1140            ret = BAD_VALUE;
1141            goto EXIT;
1142        }
1143
1144        debugShowFPS();
1145
1146        if ( mFrameSubscribers.size() == 0 ) {
1147            ret = BAD_VALUE;
1148            goto EXIT;
1149        }
1150        y_uv[0] = (void*) lframe->mYuv[0];
1151        //y_uv[1] = (void*) lframe->mYuv[1];
1152        //y_uv[1] = (void*) (lframe->mYuv[0] + height*stride);
1153        convertYUV422ToNV12Tiler ( (unsigned char*)fp, (unsigned char*)y_uv[0], width, height);
1154        CAMHAL_LOGVB("##...index= %d.;camera buffer= 0x%x; y= 0x%x; UV= 0x%x.",index, buffer, y_uv[0], y_uv[1] );
1155
1156#ifdef SAVE_RAW_FRAMES
1157        unsigned char* nv12_buff = (unsigned char*) malloc(width*height*3/2);
1158        //Convert yuv422i to yuv420sp(NV12) & dump the frame to a file
1159        convertYUV422ToNV12 ( (unsigned char*)fp, nv12_buff, width, height);
1160        saveFile( nv12_buff, ((width*height)*3/2) );
1161        free (nv12_buff);
1162#endif
1163
1164        frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC;
1165        frame.mBuffer = buffer;
1166        frame.mLength = width*height*3/2;
1167        frame.mAlignment = stride;
1168        frame.mOffset = 0;
1169        frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
1170        frame.mFrameMask = (unsigned int)CameraFrame::PREVIEW_FRAME_SYNC;
1171
1172        if (mRecording)
1173        {
1174            frame.mFrameMask |= (unsigned int)CameraFrame::VIDEO_FRAME_SYNC;
1175            mFramesWithEncoder++;
1176        }
1177
1178        ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask);
1179        if (ret != NO_ERROR) {
1180            CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret);
1181        } else {
1182            ret = sendFrameToSubscribers(&frame);
1183        }
1184    }
1185EXIT:
1186
1187    return ret;
1188}
1189
1190//scan for video devices
1191void detectVideoDevice(char** video_device_list, int& num_device) {
1192    char dir_path[20];
1193    char* filename;
1194    char** dev_list = video_device_list;
1195    DIR *d;
1196    struct dirent *dir;
1197    int index = 0;
1198
1199    strcpy(dir_path, DEVICE_PATH);
1200    d = opendir(dir_path);
1201    if(d) {
1202        //read each entry in the /dev/ and find if there is videox entry.
1203        while ((dir = readdir(d)) != NULL) {
1204            filename = dir->d_name;
1205            if (strncmp(filename, DEVICE_NAME, 5) == 0) {
1206                strcpy(dev_list[index],DEVICE_PATH);
1207                strncat(dev_list[index],filename,sizeof(DEVICE_NAME));
1208                index++;
1209            }
1210       } //end of while()
1211       closedir(d);
1212       num_device = index;
1213
1214       for(int i=0; i<index; i++){
1215           CAMHAL_LOGDB("Video device list::dev_list[%d]= %s",i,dev_list[i]);
1216       }
1217    }
1218}
1219
1220extern "C" CameraAdapter* V4LCameraAdapter_Factory(size_t sensor_index)
1221{
1222    CameraAdapter *adapter = NULL;
1223    android::AutoMutex lock(gV4LAdapterLock);
1224
1225    LOG_FUNCTION_NAME;
1226
1227    adapter = new V4LCameraAdapter(sensor_index);
1228    if ( adapter ) {
1229        CAMHAL_LOGDB("New V4L Camera adapter instance created for sensor %d",sensor_index);
1230    } else {
1231        CAMHAL_LOGEA("V4L Camera adapter create failed for sensor index = %d!",sensor_index);
1232    }
1233
1234    LOG_FUNCTION_NAME_EXIT;
1235
1236    return adapter;
1237}
1238
1239extern "C" status_t V4LCameraAdapter_Capabilities(
1240        CameraProperties::Properties * const properties_array,
1241        const int starting_camera, const int max_camera, int & supportedCameras)
1242{
1243    status_t ret = NO_ERROR;
1244    struct v4l2_capability cap;
1245    int tempHandle = NULL;
1246    int num_cameras_supported = 0;
1247    char device_list[5][15];
1248    char* video_device_list[5];
1249    int num_v4l_devices = 0;
1250    int sensorId = 0;
1251    CameraProperties::Properties* properties = NULL;
1252
1253    LOG_FUNCTION_NAME;
1254
1255    supportedCameras = 0;
1256    memset((void*)&cap, 0, sizeof(v4l2_capability));
1257
1258    if (!properties_array) {
1259        CAMHAL_LOGEB("invalid param: properties = 0x%p", properties_array);
1260        LOG_FUNCTION_NAME_EXIT;
1261        return BAD_VALUE;
1262    }
1263
1264    for (int i = 0; i < 5; i++) {
1265        video_device_list[i] = device_list[i];
1266    }
1267    //look for the connected video devices
1268    detectVideoDevice(video_device_list, num_v4l_devices);
1269
1270    for (int i = 0; i < num_v4l_devices; i++) {
1271        if ( (starting_camera + num_cameras_supported) < max_camera) {
1272            sensorId = starting_camera + num_cameras_supported;
1273
1274            CAMHAL_LOGDB("Opening device[%d] = %s..",i, video_device_list[i]);
1275            if ((tempHandle = open(video_device_list[i], O_RDWR)) == -1) {
1276                CAMHAL_LOGEB("Error while opening handle to V4L2 Camera(%s): %s",video_device_list[i], strerror(errno));
1277                continue;
1278            }
1279
1280            ret = ioctl (tempHandle, VIDIOC_QUERYCAP, &cap);
1281            if (ret < 0) {
1282                CAMHAL_LOGEA("Error when querying the capabilities of the V4L Camera");
1283                close(tempHandle);
1284                continue;
1285            }
1286
1287            //check for video capture devices
1288            if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
1289                CAMHAL_LOGEA("Error while adapter initialization: video capture not supported.");
1290                close(tempHandle);
1291                continue;
1292            }
1293
1294            strcpy(device, video_device_list[i]);
1295            properties = properties_array + starting_camera + num_cameras_supported;
1296
1297            //fetch capabilities for this camera
1298            ret = V4LCameraAdapter::getCaps( sensorId, properties, tempHandle );
1299            if (ret < 0) {
1300                CAMHAL_LOGEA("Error while getting capabilities.");
1301                close(tempHandle);
1302                continue;
1303            }
1304
1305            num_cameras_supported++;
1306
1307        }
1308        //For now exit this loop once a valid video capture device is found.
1309        //TODO: find all V4L capture devices and it capabilities
1310        break;
1311    }//end of for() loop
1312
1313    supportedCameras = num_cameras_supported;
1314    CAMHAL_LOGDB("Number of V4L cameras detected =%d", num_cameras_supported);
1315
1316EXIT:
1317    LOG_FUNCTION_NAME_EXIT;
1318    close(tempHandle);
1319    return NO_ERROR;
1320}
1321
1322} // namespace Camera
1323} // namespace Ti
1324
1325
1326/*--------------------Camera Adapter Class ENDS here-----------------------------*/
1327
1328