summaryrefslogtreecommitdiffstats
path: root/camera/V4LCameraAdapter/V4LCameraAdapter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'camera/V4LCameraAdapter/V4LCameraAdapter.cpp')
-rw-r--r--camera/V4LCameraAdapter/V4LCameraAdapter.cpp611
1 files changed, 611 insertions, 0 deletions
diff --git a/camera/V4LCameraAdapter/V4LCameraAdapter.cpp b/camera/V4LCameraAdapter/V4LCameraAdapter.cpp
new file mode 100644
index 0000000..c365023
--- /dev/null
+++ b/camera/V4LCameraAdapter/V4LCameraAdapter.cpp
@@ -0,0 +1,611 @@
+/*
+ * 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 <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 <cutils/properties.h>
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+static int mDebugFps = 0;
+
+#define Q16_OFFSET 16
+
+#define HERE(Msg) {CAMHAL_LOGEB("--===line %d, %s===--\n", __LINE__, Msg);}
+
+namespace android {
+
+#undef LOG_TAG
+///Maintain a separate tag for V4LCameraAdapter logs to isolate issues OMX specific
+#define LOG_TAG "CameraHAL"
+
+//frames skipped before recalculating the framerate
+#define FPS_PERIOD 30
+
+Mutex gAdapterLock;
+const char *device = DEVICE;
+
+
+/*--------------------Camera Adapter Class STARTS here-----------------------------*/
+
+status_t V4LCameraAdapter::initialize(CameraProperties::Properties* caps)
+{
+ LOG_FUNCTION_NAME;
+
+ char value[PROPERTY_VALUE_MAX];
+ 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)
+ {
+ return NO_MEMORY;
+ }
+
+ if ((mCameraHandle = open(device, O_RDWR)) == -1)
+ {
+ CAMHAL_LOGEB("Error while opening handle to V4L2 Camera: %s", strerror(errno));
+ return -EINVAL;
+ }
+
+ ret = ioctl (mCameraHandle, VIDIOC_QUERYCAP, &mVideoInfo->cap);
+ if (ret < 0)
+ {
+ CAMHAL_LOGEA("Error when querying the capabilities of the V4L Camera");
+ return -EINVAL;
+ }
+
+ if ((mVideoInfo->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0)
+ {
+ CAMHAL_LOGEA("Error while adapter initialization: video capture not supported.");
+ return -EINVAL;
+ }
+
+ if (!(mVideoInfo->cap.capabilities & V4L2_CAP_STREAMING))
+ {
+ CAMHAL_LOGEA("Error while adapter initialization: Capture device does not support streaming i/o");
+ return -EINVAL;
+ }
+
+ // Initialize flags
+ mPreviewing = false;
+ mVideoInfo->isStreaming = false;
+ mRecording = false;
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return ret;
+}
+
+status_t V4LCameraAdapter::fillThisBuffer(void* frameBuf, CameraFrame::FrameType frameType)
+{
+
+ status_t ret = NO_ERROR;
+
+ if ( !mVideoInfo->isStreaming )
+ {
+ return NO_ERROR;
+ }
+
+ int i = mPreviewBufs.valueFor(( unsigned int )frameBuf);
+ if(i<0)
+ {
+ return BAD_VALUE;
+ }
+
+ mVideoInfo->buf.index = i;
+ mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
+
+ ret = ioctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
+ if (ret < 0) {
+ CAMHAL_LOGEA("Init: VIDIOC_QBUF Failed");
+ return -1;
+ }
+
+ nQueued++;
+
+ return ret;
+
+}
+
+status_t V4LCameraAdapter::setParameters(const CameraParameters &params)
+{
+ LOG_FUNCTION_NAME;
+
+ status_t ret = NO_ERROR;
+
+ int width, height;
+
+ params.getPreviewSize(&width, &height);
+
+ CAMHAL_LOGDB("Width * Height %d x %d format 0x%x", width, height, DEFAULT_PIXEL_FORMAT);
+
+ 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 = DEFAULT_PIXEL_FORMAT;
+
+ ret = ioctl(mCameraHandle, VIDIOC_S_FMT, &mVideoInfo->format);
+ if (ret < 0) {
+ CAMHAL_LOGEB("Open: VIDIOC_S_FMT Failed: %s", strerror(errno));
+ return ret;
+ }
+
+ // Udpate the current parameter set
+ mParams = params;
+
+ LOG_FUNCTION_NAME_EXIT;
+ return ret;
+}
+
+
+void V4LCameraAdapter::getParameters(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, void* bufArr, int num, size_t length, unsigned int queueable)
+{
+ status_t ret = NO_ERROR;
+
+ LOG_FUNCTION_NAME;
+
+ Mutex::Autolock lock(mLock);
+
+ switch(mode)
+ {
+ case CAMERA_PREVIEW:
+ ret = UseBuffersPreview(bufArr, num);
+ break;
+
+ //@todo Insert Image capture case here
+
+ case CAMERA_VIDEO:
+ //@warn Video capture is not fully supported yet
+ ret = UseBuffersPreview(bufArr, num);
+ break;
+
+ }
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return ret;
+}
+
+status_t V4LCameraAdapter::UseBuffersPreview(void* bufArr, int num)
+{
+ int ret = NO_ERROR;
+
+ if(NULL == bufArr)
+ {
+ return BAD_VALUE;
+ }
+
+ //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 = num;
+
+ ret = ioctl(mCameraHandle, VIDIOC_REQBUFS, &mVideoInfo->rb);
+ if (ret < 0) {
+ CAMHAL_LOGEB("VIDIOC_REQBUFS failed: %s", strerror(errno));
+ return ret;
+ }
+
+ for (int i = 0; i < num; 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 = ioctl (mCameraHandle, VIDIOC_QUERYBUF, &mVideoInfo->buf);
+ if (ret < 0) {
+ CAMHAL_LOGEB("Unable to query buffer (%s)", strerror(errno));
+ return ret;
+ }
+
+ mVideoInfo->mem[i] = mmap (0,
+ mVideoInfo->buf.length,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ mCameraHandle,
+ mVideoInfo->buf.m.offset);
+
+ if (mVideoInfo->mem[i] == MAP_FAILED) {
+ CAMHAL_LOGEB("Unable to map buffer (%s)", strerror(errno));
+ return -1;
+ }
+
+ uint32_t *ptr = (uint32_t*) bufArr;
+
+ //Associate each Camera internal buffer with the one from Overlay
+ mPreviewBufs.add((int)ptr[i], i);
+
+ }
+
+ // Update the preview buffer count
+ mPreviewBufferCount = num;
+
+ return ret;
+}
+
+status_t V4LCameraAdapter::startPreview()
+{
+ status_t ret = NO_ERROR;
+
+ Mutex::Autolock lock(mPreviewBufsLock);
+
+ if(mPreviewing)
+ {
+ return BAD_VALUE;
+ }
+
+ for (int i = 0; i < mPreviewBufferCount; i++) {
+
+ mVideoInfo->buf.index = i;
+ mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
+
+ ret = ioctl(mCameraHandle, VIDIOC_QBUF, &mVideoInfo->buf);
+ if (ret < 0) {
+ CAMHAL_LOGEA("VIDIOC_QBUF Failed");
+ return -EINVAL;
+ }
+
+ nQueued++;
+ }
+
+ enum v4l2_buf_type bufType;
+ if (!mVideoInfo->isStreaming) {
+ bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = ioctl (mCameraHandle, VIDIOC_STREAMON, &bufType);
+ if (ret < 0) {
+ CAMHAL_LOGEB("StartStreaming: Unable to start capture: %s", strerror(errno));
+ return ret;
+ }
+
+ mVideoInfo->isStreaming = true;
+ }
+
+ // Create and start preview thread for receiving buffers from V4L Camera
+ mPreviewThread = new PreviewThread(this);
+
+ CAMHAL_LOGDA("Created preview thread");
+
+
+ //Update the flag to indicate we are previewing
+ mPreviewing = true;
+
+ return ret;
+
+}
+
+status_t V4LCameraAdapter::stopPreview()
+{
+ enum v4l2_buf_type bufType;
+ int ret = NO_ERROR;
+
+ Mutex::Autolock lock(mPreviewBufsLock);
+
+ if(!mPreviewing)
+ {
+ return NO_INIT;
+ }
+
+ if (mVideoInfo->isStreaming) {
+ bufType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = ioctl (mCameraHandle, VIDIOC_STREAMOFF, &bufType);
+ if (ret < 0) {
+ CAMHAL_LOGEB("StopStreaming: Unable to stop capture: %s", strerror(errno));
+ return ret;
+ }
+
+ mVideoInfo->isStreaming = false;
+ }
+
+ mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
+
+ nQueued = 0;
+ nDequeued = 0;
+
+ /* Unmap buffers */
+ for (int i = 0; i < mPreviewBufferCount; i++)
+ if (munmap(mVideoInfo->mem[i], mVideoInfo->buf.length) < 0)
+ CAMHAL_LOGEA("Unmap failed");
+
+ mPreviewBufs.clear();
+
+ mPreviewThread->requestExitAndWait();
+ mPreviewThread.clear();
+
+ return ret;
+
+}
+
+char * V4LCameraAdapter::GetFrame(int &index)
+{
+ int ret;
+
+ mVideoInfo->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ mVideoInfo->buf.memory = V4L2_MEMORY_MMAP;
+
+ /* DQ */
+ ret = ioctl(mCameraHandle, VIDIOC_DQBUF, &mVideoInfo->buf);
+ if (ret < 0) {
+ CAMHAL_LOGEA("GetFrame: VIDIOC_DQBUF Failed");
+ return NULL;
+ }
+ nDequeued++;
+
+ index = mVideoInfo->buf.index;
+
+ 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;
+
+ // 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(size_t &length, size_t bufferCount)
+{
+ // We don't support image capture yet, safely return from here without messing up
+ return NO_ERROR;
+}
+
+static void debugShowFPS()
+{
+ static int mFrameCount = 0;
+ static int mLastFrameCount = 0;
+ static nsecs_t mLastFpsTime = 0;
+ static float mFps = 0;
+ mFrameCount++;
+ if (!(mFrameCount & 0x1F)) {
+ nsecs_t now = systemTime();
+ nsecs_t diff = now - mLastFpsTime;
+ mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
+ mLastFpsTime = now;
+ mLastFrameCount = mFrameCount;
+ ALOGD("Camera %d Frames, %f FPS", mFrameCount, mFps);
+ }
+ // XXX: mFPS has the value we want
+}
+
+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
+
+ 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;
+}
+
+/* Preview Thread */
+// ---------------------------------------------------------------------------
+
+int V4LCameraAdapter::previewThread()
+{
+ status_t ret = NO_ERROR;
+ int width, height;
+ CameraFrame frame;
+
+ if (mPreviewing)
+ {
+ int index = 0;
+ char *fp = this->GetFrame(index);
+ if(!fp)
+ {
+ return BAD_VALUE;
+ }
+
+ uint8_t* ptr = (uint8_t*) mPreviewBufs.keyAt(index);
+
+ int width, height;
+ uint16_t* dest = (uint16_t*)ptr;
+ uint16_t* src = (uint16_t*) fp;
+ mParams.getPreviewSize(&width, &height);
+ for(int i=0;i<height;i++)
+ {
+ for(int j=0;j<width;j++)
+ {
+ //*dest = *src;
+ //convert from YUYV to UYVY supported in Camera service
+ *dest = (((*src & 0xFF000000)>>24)<<16)|(((*src & 0x00FF0000)>>16)<<24) |
+ (((*src & 0xFF00)>>8)<<0)|(((*src & 0x00FF)>>0)<<8);
+ src++;
+ dest++;
+ }
+ dest += 4096/2-width;
+ }
+
+ mParams.getPreviewSize(&width, &height);
+ frame.mFrameType = CameraFrame::PREVIEW_FRAME_SYNC;
+ frame.mBuffer = ptr;
+ frame.mLength = width*height*2;
+ frame.mAlignment = width*2;
+ frame.mOffset = 0;
+ frame.mTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);;
+
+ ret = sendFrameToSubscribers(&frame);
+
+ }
+
+ return ret;
+}
+
+extern "C" CameraAdapter* CameraAdapter_Factory()
+{
+ CameraAdapter *adapter = NULL;
+ Mutex::Autolock lock(gAdapterLock);
+
+ LOG_FUNCTION_NAME;
+
+ adapter = new V4LCameraAdapter(sensor_index);
+ if ( adapter ) {
+ CAMHAL_LOGDB("New OMX Camera adapter instance created for sensor %d",sensor_index);
+ } else {
+ CAMHAL_LOGEA("Camera adapter create failed!");
+ }
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return adapter;
+}
+
+extern "C" int CameraAdapter_Capabilities(CameraProperties::Properties* properties_array,
+ const unsigned int starting_camera,
+ const unsigned int max_camera) {
+ int num_cameras_supported = 0;
+ CameraProperties::Properties* properties = NULL;
+
+ LOG_FUNCTION_NAME;
+
+ if(!properties_array)
+ {
+ return -EINVAL;
+ }
+
+ // TODO: Need to tell camera properties what other cameras we can support
+ if (starting_camera + num_cameras_supported < max_camera) {
+ num_cameras_supported++;
+ properties = properties_array + starting_camera;
+ properties->set(CameraProperties::CAMERA_NAME, "USBCamera");
+ }
+
+ LOG_FUNCTION_NAME_EXIT;
+
+ return num_cameras_supported;
+}
+
+};
+
+
+/*--------------------Camera Adapter Class ENDS here-----------------------------*/
+