| /* |
| * Copyright (C) Texas Instruments - http://www.ti.com/ |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @file V4LCameraAdapter.cpp |
| * |
| * This file maps the Camera Hardware Interface to V4L2. |
| * |
| */ |
| |
| |
| #include "V4LCameraAdapter.h" |
| #include "CameraHal.h" |
| #include "TICameraParameters.h" |
| #include "DebugUtils.h" |
| #include <signal.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <sys/ioctl.h> |
| #include <sys/mman.h> |
| #include <sys/select.h> |
| #include <linux/videodev.h> |
| |
| #include <ui/GraphicBuffer.h> |
| #include <ui/GraphicBufferMapper.h> |
| |
| #include <cutils/properties.h> |
| #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) |
| static int mDebugFps = 0; |
| |
| #define Q16_OFFSET 16 |
| |
| #define HERE(Msg) {CAMHAL_LOGEB("--=== %s===--\n", Msg);} |
| |
| namespace Ti { |
| namespace Camera { |
| |
| //frames skipped before recalculating the framerate |
| #define FPS_PERIOD 30 |
| |
| //define this macro to save first few raw frames when starting the preview. |
| //#define SAVE_RAW_FRAMES 1 |
| //#define DUMP_CAPTURE_FRAME 1 |
| //#define PPM_PER_FRAME_CONVERSION 1 |
| |
| //Proto Types |
| static void convertYUV422i_yuyvTouyvy(uint8_t *src, uint8_t *dest, size_t size ); |
| static void convertYUV422ToNV12Tiler(unsigned char *src, unsigned char *dest, int width, int height ); |
| static void convertYUV422ToNV12(unsigned char *src, unsigned char *dest, int width, int height ); |
| |
| android::Mutex gV4LAdapterLock; |
| char device[15]; |
| |
| |
| /*--------------------Camera Adapter Class STARTS here-----------------------------*/ |
| |
| /*--------------------V4L wrapper functions -------------------------------*/ |
| status_t V4LCameraAdapter::v4lIoctl (int fd, int req, void* argp) { |
| status_t ret = NO_ERROR; |
| errno = 0; |
| |
| do { |
| ret = ioctl (fd, req, argp); |
| }while (-1 == ret && EINTR == errno); |
| |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::v4lInitMmap(int& count) { |
| status_t ret = NO_ERROR; |
| |
| //First allocate adapter internal buffers at V4L level for USB Cam |
| //These are the buffers from which we will copy the data into overlay buffers |
| /* Check if camera can handle NB_BUFFER buffers */ |
| mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| mVideoInfo->rb.memory = V4L2_MEMORY_MMAP; |
| mVideoInfo->rb.count = count; |
| |
| ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb); |
| if (ret < 0) { |
| CAMHAL_LOGEB("VIDIOC_REQBUFS failed: %s", strerror(errno)); |
| return ret; |
| } |
| |
| count = mVideoInfo->rb.count; |
| for (int i = 0; i < count; i++) { |
| |
| memset (&mVideoInfo->buf, 0, sizeof (struct v4l2_buffer)); |
| |
| mVideoInfo->buf.index = i; |
| mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; |
| |
| ret = v4lIoctl (mCameraHandle, VIDIOC_QUERYBUF, &mVideoInfo->buf); |
| if (ret < 0) { |
| CAMHAL_LOGEB("Unable to query buffer (%s)", strerror(errno)); |
| return ret; |
| } |
| |
| mVideoInfo->mem[i] = mmap (NULL, |
| mVideoInfo->buf.length, |
| PROT_READ | PROT_WRITE, |
| MAP_SHARED, |
| mCameraHandle, |
| mVideoInfo->buf.m.offset); |
| |
| CAMHAL_LOGVB(" mVideoInfo->mem[%d]=%p ; mVideoInfo->buf.length = %d", i, mVideoInfo->mem[i], mVideoInfo->buf.length); |
| if (mVideoInfo->mem[i] == MAP_FAILED) { |
| CAMHAL_LOGEB("Unable to map buffer [%d]. (%s)", i, strerror(errno)); |
| return -1; |
| } |
| } |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::v4lInitUsrPtr(int& count) { |
| status_t ret = NO_ERROR; |
| |
| mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| mVideoInfo->rb.memory = V4L2_MEMORY_USERPTR; |
| mVideoInfo->rb.count = count; |
| |
| ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb); |
| if (ret < 0) { |
| CAMHAL_LOGEB("VIDIOC_REQBUFS failed for USERPTR: %s", strerror(errno)); |
| return ret; |
| } |
| |
| count = mVideoInfo->rb.count; |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::v4lStartStreaming () { |
| status_t ret = NO_ERROR; |
| enum v4l2_buf_type bufType; |
| |
| if (!mVideoInfo->isStreaming) { |
| bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| |
| ret = v4lIoctl (mCameraHandle, VIDIOC_STREAMON, &bufType); |
| if (ret < 0) { |
| CAMHAL_LOGEB("StartStreaming: Unable to start capture: %s", strerror(errno)); |
| return ret; |
| } |
| mVideoInfo->isStreaming = true; |
| } |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::v4lStopStreaming (int nBufferCount) { |
| status_t ret = NO_ERROR; |
| enum v4l2_buf_type bufType; |
| |
| if (mVideoInfo->isStreaming) { |
| bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| |
| ret = v4lIoctl (mCameraHandle, VIDIOC_STREAMOFF, &bufType); |
| if (ret < 0) { |
| CAMHAL_LOGEB("StopStreaming: Unable to stop capture: %s", strerror(errno)); |
| goto EXIT; |
| } |
| mVideoInfo->isStreaming = false; |
| |
| /* Unmap buffers */ |
| mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; |
| for (int i = 0; i < nBufferCount; i++) { |
| if (munmap(mVideoInfo->mem[i], mVideoInfo->buf.length) < 0) { |
| CAMHAL_LOGEA("munmap() failed"); |
| } |
| } |
| |
| //free the memory allocated during REQBUFS, by setting the count=0 |
| mVideoInfo->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| mVideoInfo->rb.memory = V4L2_MEMORY_MMAP; |
| mVideoInfo->rb.count = 0; |
| |
| ret = v4lIoctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb); |
| if (ret < 0) { |
| CAMHAL_LOGEB("VIDIOC_REQBUFS failed: %s", strerror(errno)); |
| goto EXIT; |
| } |
| } |
| EXIT: |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::v4lSetFormat (int width, int height, uint32_t pix_format) { |
| status_t ret = NO_ERROR; |
| |
| mVideoInfo->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| ret = v4lIoctl(mCameraHandle, VIDIOC_G_FMT, &mVideoInfo->format); |
| if (ret < 0) { |
| CAMHAL_LOGEB("VIDIOC_G_FMT Failed: %s", strerror(errno)); |
| } |
| |
| mVideoInfo->width = width; |
| mVideoInfo->height = height; |
| mVideoInfo->framesizeIn = (width * height << 1); |
| mVideoInfo->formatIn = DEFAULT_PIXEL_FORMAT; |
| |
| mVideoInfo->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| mVideoInfo->format.fmt.pix.width = width; |
| mVideoInfo->format.fmt.pix.height = height; |
| mVideoInfo->format.fmt.pix.pixelformat = pix_format; |
| |
| ret = v4lIoctl(mCameraHandle, VIDIOC_S_FMT, &mVideoInfo->format); |
| if (ret < 0) { |
| CAMHAL_LOGEB("VIDIOC_S_FMT Failed: %s", strerror(errno)); |
| return ret; |
| } |
| v4lIoctl(mCameraHandle, VIDIOC_G_FMT, &mVideoInfo->format); |
| CAMHAL_LOGDB("VIDIOC_G_FMT : WxH = %dx%d", mVideoInfo->format.fmt.pix.width, mVideoInfo->format.fmt.pix.height); |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::restartPreview () |
| { |
| status_t ret = NO_ERROR; |
| int width = 0; |
| int height = 0; |
| struct v4l2_streamparm streamParams; |
| |
| //configure for preview size and pixel format. |
| mParams.getPreviewSize(&width, &height); |
| |
| ret = v4lSetFormat (width, height, DEFAULT_PIXEL_FORMAT); |
| if (ret < 0) { |
| CAMHAL_LOGEB("v4lSetFormat Failed: %s", strerror(errno)); |
| goto EXIT; |
| } |
| |
| ret = v4lInitMmap(mPreviewBufferCount); |
| if (ret < 0) { |
| CAMHAL_LOGEB("v4lInitMmap Failed: %s", strerror(errno)); |
| goto EXIT; |
| } |
| |
| //set frame rate |
| streamParams.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| streamParams.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; |
| streamParams.parm.capture.capturemode = V4L2_MODE_HIGHQUALITY; |
| streamParams.parm.capture.timeperframe.denominator = FPS_PERIOD; |
| streamParams.parm.capture.timeperframe.numerator= 1; |
| ret = v4lIoctl(mCameraHandle, VIDIOC_S_PARM, &streamParams); |
| if (ret < 0) { |
| CAMHAL_LOGEB("VIDIOC_S_PARM Failed: %s", strerror(errno)); |
| goto EXIT; |
| } |
| |
| for (int i = 0; i < mPreviewBufferCountQueueable; i++) { |
| |
| mVideoInfo->buf.index = i; |
| mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; |
| |
| ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); |
| if (ret < 0) { |
| CAMHAL_LOGEA("VIDIOC_QBUF Failed"); |
| goto EXIT; |
| } |
| nQueued++; |
| } |
| |
| ret = v4lStartStreaming(); |
| CAMHAL_LOGDA("Ready for preview...."); |
| EXIT: |
| return ret; |
| } |
| |
| /*--------------------Camera Adapter Functions-----------------------------*/ |
| status_t V4LCameraAdapter::initialize(CameraProperties::Properties* caps) |
| { |
| char value[PROPERTY_VALUE_MAX]; |
| |
| LOG_FUNCTION_NAME; |
| property_get("debug.camera.showfps", value, "0"); |
| mDebugFps = atoi(value); |
| |
| int ret = NO_ERROR; |
| |
| // Allocate memory for video info structure |
| mVideoInfo = (struct VideoInfo *) calloc (1, sizeof (struct VideoInfo)); |
| if(!mVideoInfo) { |
| ret = NO_MEMORY; |
| goto EXIT; |
| } |
| |
| if ((mCameraHandle = open(device, O_RDWR | O_NONBLOCK) ) == -1) { |
| CAMHAL_LOGEB("Error while opening handle to V4L2 Camera: %s", strerror(errno)); |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| |
| ret = v4lIoctl (mCameraHandle, VIDIOC_QUERYCAP, &mVideoInfo->cap); |
| if (ret < 0) { |
| CAMHAL_LOGEA("Error when querying the capabilities of the V4L Camera"); |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| |
| if ((mVideoInfo->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { |
| CAMHAL_LOGEA("Error while adapter initialization: video capture not supported."); |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| |
| if (!(mVideoInfo->cap.capabilities & V4L2_CAP_STREAMING)) { |
| CAMHAL_LOGEA("Error while adapter initialization: Capture device does not support streaming i/o"); |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| |
| // Initialize flags |
| mPreviewing = false; |
| mVideoInfo->isStreaming = false; |
| mRecording = false; |
| mCapturing = false; |
| EXIT: |
| LOG_FUNCTION_NAME_EXIT; |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::fillThisBuffer(CameraBuffer *frameBuf, CameraFrame::FrameType frameType) |
| { |
| status_t ret = NO_ERROR; |
| int idx = 0; |
| LOG_FUNCTION_NAME; |
| |
| if ( frameType == CameraFrame::IMAGE_FRAME) { //(1 > mCapturedFrames) |
| // Signal end of image capture |
| if ( NULL != mEndImageCaptureCallback) { |
| CAMHAL_LOGDB("===========Signal End Image Capture=========="); |
| mEndImageCaptureCallback(mEndCaptureData); |
| } |
| goto EXIT; |
| } |
| if ( !mVideoInfo->isStreaming ) { |
| goto EXIT; |
| } |
| |
| idx = mPreviewBufs.valueFor(frameBuf); |
| if(idx < 0) { |
| CAMHAL_LOGEB("Wrong index = %d",idx); |
| goto EXIT; |
| } |
| |
| mVideoInfo->buf.index = idx; |
| mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; |
| |
| ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); |
| if (ret < 0) { |
| CAMHAL_LOGEA("VIDIOC_QBUF Failed"); |
| goto EXIT; |
| } |
| nQueued++; |
| EXIT: |
| LOG_FUNCTION_NAME_EXIT; |
| return ret; |
| |
| } |
| |
| status_t V4LCameraAdapter::setParameters(const android::CameraParameters ¶ms) |
| { |
| status_t ret = NO_ERROR; |
| int width, height; |
| struct v4l2_streamparm streamParams; |
| |
| LOG_FUNCTION_NAME; |
| |
| if(!mPreviewing && !mCapturing) { |
| params.getPreviewSize(&width, &height); |
| CAMHAL_LOGDB("Width * Height %d x %d format 0x%x", width, height, DEFAULT_PIXEL_FORMAT); |
| |
| ret = v4lSetFormat( width, height, DEFAULT_PIXEL_FORMAT); |
| if (ret < 0) { |
| CAMHAL_LOGEB(" VIDIOC_S_FMT Failed: %s", strerror(errno)); |
| goto EXIT; |
| } |
| //set frame rate |
| // Now its fixed to 30 FPS |
| streamParams.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| streamParams.parm.capture.capability = V4L2_CAP_TIMEPERFRAME; |
| streamParams.parm.capture.capturemode = V4L2_MODE_HIGHQUALITY; |
| streamParams.parm.capture.timeperframe.denominator = FPS_PERIOD; |
| streamParams.parm.capture.timeperframe.numerator= 1; |
| ret = v4lIoctl(mCameraHandle, VIDIOC_S_PARM, &streamParams); |
| if (ret < 0) { |
| CAMHAL_LOGEB(" VIDIOC_S_PARM Failed: %s", strerror(errno)); |
| goto EXIT; |
| } |
| int actualFps = streamParams.parm.capture.timeperframe.denominator / streamParams.parm.capture.timeperframe.numerator; |
| CAMHAL_LOGDB("Actual FPS set is : %d.", actualFps); |
| } |
| |
| // Udpate the current parameter set |
| mParams = params; |
| |
| EXIT: |
| LOG_FUNCTION_NAME_EXIT; |
| return ret; |
| } |
| |
| |
| void V4LCameraAdapter::getParameters(android::CameraParameters& params) |
| { |
| LOG_FUNCTION_NAME; |
| |
| // Return the current parameter set |
| params = mParams; |
| |
| LOG_FUNCTION_NAME_EXIT; |
| } |
| |
| |
| ///API to give the buffers to Adapter |
| status_t V4LCameraAdapter::useBuffers(CameraMode mode, CameraBuffer *bufArr, int num, size_t length, unsigned int queueable) |
| { |
| status_t ret = NO_ERROR; |
| |
| LOG_FUNCTION_NAME; |
| |
| android::AutoMutex lock(mLock); |
| |
| switch(mode) |
| { |
| case CAMERA_PREVIEW: |
| mPreviewBufferCountQueueable = queueable; |
| ret = UseBuffersPreview(bufArr, num); |
| break; |
| |
| case CAMERA_IMAGE_CAPTURE: |
| mCaptureBufferCountQueueable = queueable; |
| ret = UseBuffersCapture(bufArr, num); |
| break; |
| |
| case CAMERA_VIDEO: |
| //@warn Video capture is not fully supported yet |
| mPreviewBufferCountQueueable = queueable; |
| ret = UseBuffersPreview(bufArr, num); |
| break; |
| |
| case CAMERA_MEASUREMENT: |
| break; |
| |
| default: |
| break; |
| } |
| |
| LOG_FUNCTION_NAME_EXIT; |
| |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::UseBuffersCapture(CameraBuffer *bufArr, int num) { |
| int ret = NO_ERROR; |
| |
| LOG_FUNCTION_NAME; |
| if(NULL == bufArr) { |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| |
| for (int i = 0; i < num; i++) { |
| //Associate each Camera internal buffer with the one from Overlay |
| mCaptureBufs.add(&bufArr[i], i); |
| CAMHAL_LOGDB("capture- buff [%d] = 0x%x ",i, mCaptureBufs.keyAt(i)); |
| } |
| |
| mCaptureBuffersAvailable.clear(); |
| for (int i = 0; i < mCaptureBufferCountQueueable; i++ ) { |
| mCaptureBuffersAvailable.add(&mCaptureBuffers[i], 0); |
| } |
| |
| // initial ref count for undeqeueued buffers is 1 since buffer provider |
| // is still holding on to it |
| for (int i = mCaptureBufferCountQueueable; i < num; i++ ) { |
| mCaptureBuffersAvailable.add(&mCaptureBuffers[i], 1); |
| } |
| |
| // Update the preview buffer count |
| mCaptureBufferCount = num; |
| EXIT: |
| LOG_FUNCTION_NAME_EXIT; |
| return ret; |
| |
| } |
| |
| status_t V4LCameraAdapter::UseBuffersPreview(CameraBuffer *bufArr, int num) |
| { |
| int ret = NO_ERROR; |
| LOG_FUNCTION_NAME; |
| |
| if(NULL == bufArr) { |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| |
| ret = v4lInitMmap(num); |
| if (ret == NO_ERROR) { |
| for (int i = 0; i < num; i++) { |
| //Associate each Camera internal buffer with the one from Overlay |
| mPreviewBufs.add(&bufArr[i], i); |
| CAMHAL_LOGDB("Preview- buff [%d] = 0x%x ",i, mPreviewBufs.keyAt(i)); |
| } |
| |
| // Update the preview buffer count |
| mPreviewBufferCount = num; |
| } |
| EXIT: |
| LOG_FUNCTION_NAME_EXIT; |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::takePicture() { |
| status_t ret = NO_ERROR; |
| int width = 0; |
| int height = 0; |
| size_t yuv422i_buff_size = 0; |
| int index = 0; |
| char *fp = NULL; |
| CameraBuffer *buffer = NULL; |
| CameraFrame frame; |
| |
| LOG_FUNCTION_NAME; |
| |
| android::AutoMutex lock(mCaptureBufsLock); |
| |
| if(mCapturing) { |
| CAMHAL_LOGEA("Already Capture in Progress..."); |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| |
| mCapturing = true; |
| mPreviewing = false; |
| |
| // Stop preview streaming |
| ret = v4lStopStreaming(mPreviewBufferCount); |
| if (ret < 0 ) { |
| CAMHAL_LOGEB("v4lStopStreaming Failed: %s", strerror(errno)); |
| goto EXIT; |
| } |
| |
| //configure for capture image size and pixel format. |
| mParams.getPictureSize(&width, &height); |
| CAMHAL_LOGDB("Image Capture Size WxH = %dx%d",width,height); |
| yuv422i_buff_size = width * height * 2; |
| |
| ret = v4lSetFormat (width, height, DEFAULT_PIXEL_FORMAT); |
| if (ret < 0) { |
| CAMHAL_LOGEB("v4lSetFormat Failed: %s", strerror(errno)); |
| goto EXIT; |
| } |
| |
| ret = v4lInitMmap(mCaptureBufferCount); |
| if (ret < 0) { |
| CAMHAL_LOGEB("v4lInitMmap Failed: %s", strerror(errno)); |
| goto EXIT; |
| } |
| |
| for (int i = 0; i < mCaptureBufferCountQueueable; i++) { |
| |
| mVideoInfo->buf.index = i; |
| mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; |
| |
| ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); |
| if (ret < 0) { |
| CAMHAL_LOGEA("VIDIOC_QBUF Failed"); |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| nQueued++; |
| } |
| |
| ret = v4lStartStreaming(); |
| if (ret < 0) { |
| CAMHAL_LOGEB("v4lStartStreaming Failed: %s", strerror(errno)); |
| goto EXIT; |
| } |
| |
| CAMHAL_LOGDA("Streaming started for Image Capture"); |
| |
| //get the frame and send to encode as JPG |
| fp = this->GetFrame(index); |
| if(!fp) { |
| CAMHAL_LOGEA("!!! Captured frame is NULL !!!!"); |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| |
| CAMHAL_LOGDA("::Capture Frame received from V4L::"); |
| buffer = mCaptureBufs.keyAt(index); |
| CAMHAL_LOGVB("## captureBuf[%d] = 0x%x, yuv422i_buff_size=%d", index, buffer->opaque, yuv422i_buff_size); |
| |
| //copy the yuv422i data to the image buffer. |
| memcpy(buffer->opaque, fp, yuv422i_buff_size); |
| |
| #ifdef DUMP_CAPTURE_FRAME |
| //dump the YUV422 buffer in to a file |
| //a folder should have been created at /data/misc/camera/raw/ |
| { |
| int fd =-1; |
| fd = open("/data/misc/camera/raw/captured_yuv422i_dump.yuv", O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777); |
| if(fd < 0) { |
| CAMHAL_LOGEB("Unable to open file: %s", strerror(fd)); |
| } |
| else { |
| write(fd, fp, yuv422i_buff_size ); |
| close(fd); |
| CAMHAL_LOGDB("::Captured Frame dumped at /data/misc/camera/raw/captured_yuv422i_dump.yuv::"); |
| } |
| } |
| #endif |
| |
| CAMHAL_LOGDA("::sending capture frame to encoder::"); |
| frame.mFrameType = CameraFrame::IMAGE_FRAME; |
| frame.mBuffer = buffer; |
| frame.mLength = yuv422i_buff_size; |
| frame.mWidth = width; |
| frame.mHeight = height; |
| frame.mAlignment = width*2; |
| frame.mOffset = 0; |
| frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); |
| frame.mFrameMask = (unsigned int)CameraFrame::IMAGE_FRAME; |
| frame.mQuirks |= CameraFrame::ENCODE_RAW_YUV422I_TO_JPEG; |
| frame.mQuirks |= CameraFrame::FORMAT_YUV422I_YUYV; |
| |
| ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask); |
| if (ret != NO_ERROR) { |
| CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret); |
| } else { |
| ret = sendFrameToSubscribers(&frame); |
| } |
| |
| // Stop streaming after image capture |
| ret = v4lStopStreaming(mCaptureBufferCount); |
| if (ret < 0 ) { |
| CAMHAL_LOGEB("v4lStopStreaming Failed: %s", strerror(errno)); |
| goto EXIT; |
| } |
| |
| ret = restartPreview(); |
| EXIT: |
| LOG_FUNCTION_NAME_EXIT; |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::stopImageCapture() |
| { |
| status_t ret = NO_ERROR; |
| LOG_FUNCTION_NAME; |
| |
| //Release image buffers |
| if ( NULL != mReleaseImageBuffersCallback ) { |
| mReleaseImageBuffersCallback(mReleaseData); |
| } |
| mCaptureBufs.clear(); |
| |
| mCapturing = false; |
| mPreviewing = true; |
| LOG_FUNCTION_NAME_EXIT; |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::autoFocus() |
| { |
| status_t ret = NO_ERROR; |
| LOG_FUNCTION_NAME; |
| |
| //autoFocus is not implemented. Just return. |
| LOG_FUNCTION_NAME_EXIT; |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::startPreview() |
| { |
| status_t ret = NO_ERROR; |
| |
| LOG_FUNCTION_NAME; |
| android::AutoMutex lock(mPreviewBufsLock); |
| |
| if(mPreviewing) { |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| |
| for (int i = 0; i < mPreviewBufferCountQueueable; i++) { |
| |
| mVideoInfo->buf.index = i; |
| mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; |
| |
| ret = v4lIoctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf); |
| if (ret < 0) { |
| CAMHAL_LOGEA("VIDIOC_QBUF Failed"); |
| goto EXIT; |
| } |
| nQueued++; |
| } |
| |
| ret = v4lStartStreaming(); |
| |
| // Create and start preview thread for receiving buffers from V4L Camera |
| if(!mCapturing) { |
| mPreviewThread = new PreviewThread(this); |
| CAMHAL_LOGDA("Created preview thread"); |
| } |
| |
| //Update the flag to indicate we are previewing |
| mPreviewing = true; |
| mCapturing = false; |
| |
| EXIT: |
| LOG_FUNCTION_NAME_EXIT; |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::stopPreview() |
| { |
| enum v4l2_buf_type bufType; |
| int ret = NO_ERROR; |
| |
| LOG_FUNCTION_NAME; |
| android::AutoMutex lock(mStopPreviewLock); |
| |
| if(!mPreviewing) { |
| return NO_INIT; |
| } |
| mPreviewing = false; |
| |
| ret = v4lStopStreaming(mPreviewBufferCount); |
| if (ret < 0) { |
| CAMHAL_LOGEB("StopStreaming: FAILED: %s", strerror(errno)); |
| } |
| |
| nQueued = 0; |
| nDequeued = 0; |
| mFramesWithEncoder = 0; |
| |
| mPreviewBufs.clear(); |
| |
| mPreviewThread->requestExitAndWait(); |
| mPreviewThread.clear(); |
| |
| LOG_FUNCTION_NAME_EXIT; |
| return ret; |
| } |
| |
| char * V4LCameraAdapter::GetFrame(int &index) |
| { |
| int ret = NO_ERROR; |
| LOG_FUNCTION_NAME; |
| |
| mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
| mVideoInfo->buf.memory = V4L2_MEMORY_MMAP; |
| |
| /* DQ */ |
| // Some V4L drivers, notably uvc, protect each incoming call with |
| // a driver-wide mutex. If we use poll() or blocking VIDIOC_DQBUF ioctl |
| // here then we sometimes would run into a deadlock on VIDIO_QBUF ioctl. |
| while(true) { |
| if(!mVideoInfo->isStreaming) { |
| return NULL; |
| } |
| |
| ret = v4lIoctl(mCameraHandle, VIDIOC_DQBUF, &mVideoInfo->buf); |
| if((ret == 0) || (errno != EAGAIN)) { |
| break; |
| } |
| } |
| |
| if (ret < 0) { |
| CAMHAL_LOGEA("GetFrame: VIDIOC_DQBUF Failed"); |
| return NULL; |
| } |
| nDequeued++; |
| |
| index = mVideoInfo->buf.index; |
| |
| LOG_FUNCTION_NAME_EXIT; |
| return (char *)mVideoInfo->mem[mVideoInfo->buf.index]; |
| } |
| |
| //API to get the frame size required to be allocated. This size is used to override the size passed |
| //by camera service when VSTAB/VNF is turned ON for example |
| status_t V4LCameraAdapter::getFrameSize(size_t &width, size_t &height) |
| { |
| status_t ret = NO_ERROR; |
| LOG_FUNCTION_NAME; |
| |
| // Just return the current preview size, nothing more to do here. |
| mParams.getPreviewSize(( int * ) &width, |
| ( int * ) &height); |
| |
| LOG_FUNCTION_NAME_EXIT; |
| |
| return ret; |
| } |
| |
| status_t V4LCameraAdapter::getFrameDataSize(size_t &dataFrameSize, size_t bufferCount) |
| { |
| // We don't support meta data, so simply return |
| return NO_ERROR; |
| } |
| |
| status_t V4LCameraAdapter::getPictureBufferSize(CameraFrame &frame, size_t bufferCount) |
| { |
| int width = 0; |
| int height = 0; |
| int bytesPerPixel = 2; // for YUV422i; default pixel format |
| |
| LOG_FUNCTION_NAME; |
| |
| mParams.getPictureSize( &width, &height ); |
| frame.mLength = width * height * bytesPerPixel; |
| frame.mWidth = width; |
| frame.mHeight = height; |
| frame.mAlignment = width * bytesPerPixel; |
| |
| CAMHAL_LOGDB("Picture size: W x H = %u x %u (size=%u bytes, alignment=%u bytes)", |
| frame.mWidth, frame.mHeight, frame.mLength, frame.mAlignment); |
| LOG_FUNCTION_NAME_EXIT; |
| return NO_ERROR; |
| } |
| |
| static void debugShowFPS() |
| { |
| static int mFrameCount = 0; |
| static int mLastFrameCount = 0; |
| static nsecs_t mLastFpsTime = 0; |
| static float mFps = 0; |
| if(mDebugFps) { |
| mFrameCount++; |
| if (!(mFrameCount & 0x1F)) { |
| nsecs_t now = systemTime(); |
| nsecs_t diff = now - mLastFpsTime; |
| mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; |
| mLastFpsTime = now; |
| mLastFrameCount = mFrameCount; |
| CAMHAL_LOGI("Camera %d Frames, %f FPS", mFrameCount, mFps); |
| } |
| } |
| } |
| |
| status_t V4LCameraAdapter::recalculateFPS() |
| { |
| float currentFPS; |
| |
| mFrameCount++; |
| |
| if ( ( mFrameCount % FPS_PERIOD ) == 0 ) |
| { |
| nsecs_t now = systemTime(); |
| nsecs_t diff = now - mLastFPSTime; |
| currentFPS = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; |
| mLastFPSTime = now; |
| mLastFrameCount = mFrameCount; |
| |
| if ( 1 == mIter ) |
| { |
| mFPS = currentFPS; |
| } |
| else |
| { |
| //cumulative moving average |
| mFPS = mLastFPS + (currentFPS - mLastFPS)/mIter; |
| } |
| |
| mLastFPS = mFPS; |
| mIter++; |
| } |
| |
| return NO_ERROR; |
| } |
| |
| void V4LCameraAdapter::onOrientationEvent(uint32_t orientation, uint32_t tilt) |
| { |
| LOG_FUNCTION_NAME; |
| |
| LOG_FUNCTION_NAME_EXIT; |
| } |
| |
| |
| V4LCameraAdapter::V4LCameraAdapter(size_t sensor_index) |
| { |
| LOG_FUNCTION_NAME; |
| |
| // Nothing useful to do in the constructor |
| mFramesWithEncoder = 0; |
| |
| LOG_FUNCTION_NAME_EXIT; |
| } |
| |
| V4LCameraAdapter::~V4LCameraAdapter() |
| { |
| LOG_FUNCTION_NAME; |
| |
| // Close the camera handle and free the video info structure |
| close(mCameraHandle); |
| |
| if (mVideoInfo) |
| { |
| free(mVideoInfo); |
| mVideoInfo = NULL; |
| } |
| |
| LOG_FUNCTION_NAME_EXIT; |
| } |
| |
| static void convertYUV422i_yuyvTouyvy(uint8_t *src, uint8_t *dest, size_t size ) { |
| //convert YUV422I yuyv to uyvy format. |
| uint32_t *bf = (uint32_t*)src; |
| uint32_t *dst = (uint32_t*)dest; |
| |
| LOG_FUNCTION_NAME; |
| |
| if (!src || !dest) { |
| return; |
| } |
| |
| for(size_t i = 0; i < size; i = i+4) |
| { |
| dst[0] = ((bf[0] & 0x00FF00FF) << 8) | ((bf[0] & 0xFF00FF00) >> 8); |
| bf++; |
| dst++; |
| } |
| |
| LOG_FUNCTION_NAME_EXIT; |
| } |
| |
| static void convertYUV422ToNV12Tiler(unsigned char *src, unsigned char *dest, int width, int height ) { |
| //convert YUV422I to YUV420 NV12 format and copies directly to preview buffers (Tiler memory). |
| int stride = 4096; |
| unsigned char *bf = src; |
| unsigned char *dst_y = dest; |
| unsigned char *dst_uv = dest + ( height * stride); |
| #ifdef PPM_PER_FRAME_CONVERSION |
| static int frameCount = 0; |
| static nsecs_t ppm_diff = 0; |
| nsecs_t ppm_start = systemTime(); |
| #endif |
| |
| LOG_FUNCTION_NAME; |
| |
| if (width % 16 ) { |
| for(int i = 0; i < height; i++) { |
| for(int j = 0; j < width; j++) { |
| *dst_y = *bf; |
| dst_y++; |
| bf = bf + 2; |
| } |
| dst_y += (stride - width); |
| } |
| |
| bf = src; |
| bf++; //UV sample |
| for(int i = 0; i < height/2; i++) { |
| for(int j=0; j<width; j++) { |
| *dst_uv = *bf; |
| dst_uv++; |
| bf = bf + 2; |
| } |
| bf = bf + width*2; |
| dst_uv = dst_uv + (stride - width); |
| } |
| } else { |
| //neon conversion |
| for(int i = 0; i < height; i++) { |
| int n = width; |
| int skip = i & 0x1; // skip uv elements for the odd rows |
| asm volatile ( |
| " pld [%[src], %[src_stride], lsl #2] \n\t" |
| " cmp %[n], #16 \n\t" |
| " blt 5f \n\t" |
| "0: @ 16 pixel copy \n\t" |
| " vld2.8 {q0, q1} , [%[src]]! @ q0 = yyyy.. q1 = uvuv.. \n\t" |
| " @ now q0 = y q1 = uv \n\t" |
| " vst1.32 {d0,d1}, [%[dst_y]]! \n\t" |
| " cmp %[skip], #0 \n\t" |
| " bne 1f \n\t" |
| " vst1.32 {d2,d3},[%[dst_uv]]! \n\t" |
| "1: @ skip odd rows for UV \n\t" |
| " sub %[n], %[n], #16 \n\t" |
| " cmp %[n], #16 \n\t" |
| " bge 0b \n\t" |
| "5: @ end \n\t" |
| #ifdef NEEDS_ARM_ERRATA_754319_754320 |
| " vmov s0,s0 @ add noop for errata item \n\t" |
| #endif |
| : [dst_y] "+r" (dst_y), [dst_uv] "+r" (dst_uv), [src] "+r" (src), [n] "+r" (n) |
| : [src_stride] "r" (width), [skip] "r" (skip) |
| : "cc", "memory", "q0", "q1", "q2", "d0", "d1", "d2", "d3" |
| ); |
| dst_y = dst_y + (stride - width); |
| if (skip == 0) { |
| dst_uv = dst_uv + (stride - width); |
| } |
| } //end of for() |
| } |
| |
| #ifdef PPM_PER_FRAME_CONVERSION |
| ppm_diff += (systemTime() - ppm_start); |
| frameCount++; |
| |
| if (frameCount >= 30) { |
| ppm_diff = ppm_diff / frameCount; |
| LOGD("PPM: YUV422i to NV12 Conversion(%d x %d): %llu us ( %llu ms )", width, height, |
| ns2us(ppm_diff), ns2ms(ppm_diff) ); |
| ppm_diff = 0; |
| frameCount = 0; |
| } |
| #endif |
| |
| LOG_FUNCTION_NAME_EXIT; |
| } |
| |
| static void convertYUV422ToNV12(unsigned char *src, unsigned char *dest, int width, int height ) { |
| //convert YUV422I to YUV420 NV12 format. |
| unsigned char *bf = src; |
| unsigned char *dst_y = dest; |
| unsigned char *dst_uv = dest + (width * height); |
| |
| LOG_FUNCTION_NAME; |
| |
| if (width % 16 ) { |
| for(int i = 0; i < height; i++) { |
| for(int j = 0; j < width; j++) { |
| *dst_y = *bf; |
| dst_y++; |
| bf = bf + 2; |
| } |
| } |
| |
| bf = src; |
| bf++; //UV sample |
| for(int i = 0; i < height/2; i++) { |
| for(int j=0; j<width; j++) { |
| *dst_uv = *bf; |
| dst_uv++; |
| bf = bf + 2; |
| } |
| bf = bf + width*2; |
| } |
| } else { |
| //neon conversion |
| for(int i = 0; i < height; i++) { |
| int n = width; |
| int skip = i & 0x1; // skip uv elements for the odd rows |
| asm volatile ( |
| " pld [%[src], %[src_stride], lsl #2] \n\t" |
| " cmp %[n], #16 \n\t" |
| " blt 5f \n\t" |
| "0: @ 16 pixel copy \n\t" |
| " vld2.8 {q0, q1} , [%[src]]! @ q0 = yyyy.. q1 = uvuv.. \n\t" |
| " @ now q0 = y q1 = uv \n\t" |
| " vst1.32 {d0,d1}, [%[dst_y]]! \n\t" |
| " cmp %[skip], #0 \n\t" |
| " bne 1f \n\t" |
| " vst1.32 {d2,d3},[%[dst_uv]]! \n\t" |
| "1: @ skip odd rows for UV \n\t" |
| " sub %[n], %[n], #16 \n\t" |
| " cmp %[n], #16 \n\t" |
| " bge 0b \n\t" |
| "5: @ end \n\t" |
| #ifdef NEEDS_ARM_ERRATA_754319_754320 |
| " vmov s0,s0 @ add noop for errata item \n\t" |
| #endif |
| : [dst_y] "+r" (dst_y), [dst_uv] "+r" (dst_uv), [src] "+r" (src), [n] "+r" (n) |
| : [src_stride] "r" (width), [skip] "r" (skip) |
| : "cc", "memory", "q0", "q1", "q2", "d0", "d1", "d2", "d3" |
| ); |
| } |
| } |
| |
| LOG_FUNCTION_NAME_EXIT; |
| } |
| |
| #ifdef SAVE_RAW_FRAMES |
| void saveFile(unsigned char* buff, int buff_size) { |
| static int counter = 1; |
| int fd = -1; |
| char fn[256]; |
| |
| LOG_FUNCTION_NAME; |
| if (counter > 3) { |
| return; |
| } |
| //dump nv12 buffer |
| counter++; |
| sprintf(fn, "/data/misc/camera/raw/nv12_dump_%03d.yuv", counter); |
| CAMHAL_LOGEB("Dumping nv12 frame to a file : %s.", fn); |
| |
| fd = open(fn, O_CREAT | O_WRONLY | O_SYNC | O_TRUNC, 0777); |
| if(fd < 0) { |
| CAMHAL_LOGE("Unable to open file %s: %s", fn, strerror(fd)); |
| return; |
| } |
| |
| write(fd, buff, buff_size ); |
| close(fd); |
| |
| LOG_FUNCTION_NAME_EXIT; |
| } |
| #endif |
| |
| /* Preview Thread */ |
| // --------------------------------------------------------------------------- |
| |
| int V4LCameraAdapter::previewThread() |
| { |
| status_t ret = NO_ERROR; |
| int width, height; |
| CameraFrame frame; |
| void *y_uv[2]; |
| int index = 0; |
| int stride = 4096; |
| char *fp = NULL; |
| |
| mParams.getPreviewSize(&width, &height); |
| |
| if (mPreviewing) { |
| |
| fp = this->GetFrame(index); |
| if(!fp) { |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| CameraBuffer *buffer = mPreviewBufs.keyAt(index); |
| CameraFrame *lframe = (CameraFrame *)mFrameQueue.valueFor(buffer); |
| if (!lframe) { |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| |
| debugShowFPS(); |
| |
| if ( mFrameSubscribers.size() == 0 ) { |
| ret = BAD_VALUE; |
| goto EXIT; |
| } |
| y_uv[0] = (void*) lframe->mYuv[0]; |
| //y_uv[1] = (void*) lframe->mYuv[1]; |
| //y_uv[1] = (void*) (lframe->mYuv[0] + height*stride); |
| convertYUV422ToNV12Tiler ( (unsigned char*)fp, (unsigned char*)y_uv[0], width, height); |
| CAMHAL_LOGVB("##...index= %d.;camera buffer= 0x%x; y= 0x%x; UV= 0x%x.",index, buffer, y_uv[0], y_uv[1] ); |
| |
| #ifdef SAVE_RAW_FRAMES |
| unsigned char* nv12_buff = (unsigned char*) malloc(width*height*3/2); |
| //Convert yuv422i to yuv420sp(NV12) & dump the frame to a file |
| convertYUV422ToNV12 ( (unsigned char*)fp, nv12_buff, width, height); |
| saveFile( nv12_buff, ((width*height)*3/2) ); |
| free (nv12_buff); |
| #endif |
| |
| frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC; |
| frame.mBuffer = buffer; |
| frame.mLength = width*height*3/2; |
| frame.mAlignment = stride; |
| frame.mOffset = 0; |
| frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); |
| frame.mFrameMask = (unsigned int)CameraFrame::PREVIEW_FRAME_SYNC; |
| |
| if (mRecording) |
| { |
| frame.mFrameMask |= (unsigned int)CameraFrame::VIDEO_FRAME_SYNC; |
| mFramesWithEncoder++; |
| } |
| |
| ret = setInitFrameRefCount(frame.mBuffer, frame.mFrameMask); |
| if (ret != NO_ERROR) { |
| CAMHAL_LOGDB("Error in setInitFrameRefCount %d", ret); |
| } else { |
| ret = sendFrameToSubscribers(&frame); |
| } |
| } |
| EXIT: |
| |
| return ret; |
| } |
| |
| //scan for video devices |
| void detectVideoDevice(char** video_device_list, int& num_device) { |
| char dir_path[20]; |
| char* filename; |
| char** dev_list = video_device_list; |
| DIR *d; |
| struct dirent *dir; |
| int index = 0; |
| |
| strcpy(dir_path, DEVICE_PATH); |
| d = opendir(dir_path); |
| if(d) { |
| //read each entry in the /dev/ and find if there is videox entry. |
| while ((dir = readdir(d)) != NULL) { |
| filename = dir->d_name; |
| if (strncmp(filename, DEVICE_NAME, 5) == 0) { |
| strcpy(dev_list[index],DEVICE_PATH); |
| strncat(dev_list[index],filename,sizeof(DEVICE_NAME)); |
| index++; |
| } |
| } //end of while() |
| closedir(d); |
| num_device = index; |
| |
| for(int i=0; i<index; i++){ |
| CAMHAL_LOGDB("Video device list::dev_list[%d]= %s",i,dev_list[i]); |
| } |
| } |
| } |
| |
| extern "C" CameraAdapter* V4LCameraAdapter_Factory(size_t sensor_index) |
| { |
| CameraAdapter *adapter = NULL; |
| android::AutoMutex lock(gV4LAdapterLock); |
| |
| LOG_FUNCTION_NAME; |
| |
| adapter = new V4LCameraAdapter(sensor_index); |
| if ( adapter ) { |
| CAMHAL_LOGDB("New V4L Camera adapter instance created for sensor %d",sensor_index); |
| } else { |
| CAMHAL_LOGEA("V4L Camera adapter create failed for sensor index = %d!",sensor_index); |
| } |
| |
| LOG_FUNCTION_NAME_EXIT; |
| |
| return adapter; |
| } |
| |
| extern "C" status_t V4LCameraAdapter_Capabilities( |
| CameraProperties::Properties * const properties_array, |
| const int starting_camera, const int max_camera, int & supportedCameras) |
| { |
| status_t ret = NO_ERROR; |
| struct v4l2_capability cap; |
| int tempHandle = NULL; |
| int num_cameras_supported = 0; |
| char device_list[5][15]; |
| char* video_device_list[5]; |
| int num_v4l_devices = 0; |
| int sensorId = 0; |
| CameraProperties::Properties* properties = NULL; |
| |
| LOG_FUNCTION_NAME; |
| |
| supportedCameras = 0; |
| memset((void*)&cap, 0, sizeof(v4l2_capability)); |
| |
| if (!properties_array) { |
| CAMHAL_LOGEB("invalid param: properties = 0x%p", properties_array); |
| LOG_FUNCTION_NAME_EXIT; |
| return BAD_VALUE; |
| } |
| |
| for (int i = 0; i < 5; i++) { |
| video_device_list[i] = device_list[i]; |
| } |
| //look for the connected video devices |
| detectVideoDevice(video_device_list, num_v4l_devices); |
| |
| for (int i = 0; i < num_v4l_devices; i++) { |
| if ( (starting_camera + num_cameras_supported) < max_camera) { |
| sensorId = starting_camera + num_cameras_supported; |
| |
| CAMHAL_LOGDB("Opening device[%d] = %s..",i, video_device_list[i]); |
| if ((tempHandle = open(video_device_list[i], O_RDWR)) == -1) { |
| CAMHAL_LOGEB("Error while opening handle to V4L2 Camera(%s): %s",video_device_list[i], strerror(errno)); |
| continue; |
| } |
| |
| ret = ioctl (tempHandle, VIDIOC_QUERYCAP, &cap); |
| if (ret < 0) { |
| CAMHAL_LOGEA("Error when querying the capabilities of the V4L Camera"); |
| close(tempHandle); |
| continue; |
| } |
| |
| //check for video capture devices |
| if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { |
| CAMHAL_LOGEA("Error while adapter initialization: video capture not supported."); |
| close(tempHandle); |
| continue; |
| } |
| |
| strcpy(device, video_device_list[i]); |
| properties = properties_array + starting_camera + num_cameras_supported; |
| |
| //fetch capabilities for this camera |
| ret = V4LCameraAdapter::getCaps( sensorId, properties, tempHandle ); |
| if (ret < 0) { |
| CAMHAL_LOGEA("Error while getting capabilities."); |
| close(tempHandle); |
| continue; |
| } |
| |
| num_cameras_supported++; |
| |
| } |
| //For now exit this loop once a valid video capture device is found. |
| //TODO: find all V4L capture devices and it capabilities |
| break; |
| }//end of for() loop |
| |
| supportedCameras = num_cameras_supported; |
| CAMHAL_LOGDB("Number of V4L cameras detected =%d", num_cameras_supported); |
| |
| EXIT: |
| LOG_FUNCTION_NAME_EXIT; |
| close(tempHandle); |
| return NO_ERROR; |
| } |
| |
| } // namespace Camera |
| } // namespace Ti |
| |
| |
| /*--------------------Camera Adapter Class ENDS here-----------------------------*/ |
| |