From 903d325fc65b220902a476be260a387117f30f32 Mon Sep 17 00:00:00 2001 From: Raviprasad V Mummidi Date: Fri, 4 May 2012 14:38:15 -0700 Subject: [PATCH] Fix a whole bunch of things Support for multiple cameras. Add software decoding support Fix barcode scanners memory leak Fix 30sec video recording limit issue caused by memory leak Add support for HWA ROMs (tested only on HD2) --- Android.mk | 4 +- cameraHal.cpp | 180 +++++++++- cameraHal.cpp.orig | 813 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 977 insertions(+), 20 deletions(-) create mode 100644 cameraHal.cpp.orig diff --git a/Android.mk b/Android.mk index 5263a69..ddf51cb 100644 --- a/Android.mk +++ b/Android.mk @@ -17,8 +17,8 @@ CAMERA_LIB := camera-nexus endif TARGET_GLOBAL_LD_DIRS += -L$(LOCAL_PATH) -l${CAMERA_LIB} -LOCAL_SHARED_LIBRARIES := liblog libdl libutils libcamera_client libbinder libcutils libhardware +LOCAL_SHARED_LIBRARIES := liblog libdl libutils libcamera_client libbinder libcutils libhardware libui LOCAL_C_INCLUDES := frameworks/base/services/ frameworks/base/include -LOCAL_C_INCLUDES += hardware/libhardware/include/ hardware/libhardware/modules/gralloc/ +LOCAL_C_INCLUDES += hardware/libhardware/include/ hardware include $(BUILD_SHARED_LIBRARY) diff --git a/cameraHal.cpp b/cameraHal.cpp index 54245ea..86f731b 100644 --- a/cameraHal.cpp +++ b/cameraHal.cpp @@ -23,11 +23,21 @@ #include #include #include -#include +#include +#include +#include #define NO_ERROR 0 -//#define LOGV LOGI #define GRALLOC_USAGE_PMEM_PRIVATE_ADSP GRALLOC_USAGE_PRIVATE_0 +#define MSM_COPY_HW 1 +#define HWA 1 +#ifdef HWA +#include "qcom/display/libgralloc/gralloc_priv.h" +#else +#include "libhardware/modules/gralloc/gralloc_priv.h" +#endif + +//#define LOGV LOGI struct qcom_mdp_rect { uint32_t x; @@ -60,7 +70,9 @@ struct blitreq { }; /* Prototypes and extern functions. */ -extern "C" android::sp openCameraHardware(int id); +android::sp (*LINK_openCameraHardware)(int id); +int (*LINK_getNumberofCameras)(void); +void (*LINK_getCameraInfo)(int cameraId, struct camera_info *info); int qcamera_device_open(const hw_module_t* module, const char* name, hw_device_t** device); int CameraHAL_GetNum_Cameras(void); @@ -109,18 +121,23 @@ CameraHAL_NotifyCb(int32_t msg_type, int32_t ext1, } } -void +bool CameraHAL_CopyBuffers_Hw(int srcFd, int destFd, size_t srcOffset, size_t destOffset, int srcFormat, int destFormat, int x, int y, int w, int h) { struct blitreq blit; + bool success = true; int fb_fd = open("/dev/graphics/fb0", O_RDWR); +#ifndef MSM_COPY_HW + return false; +#endif + if (fb_fd < 0) { LOGD("CameraHAL_CopyBuffers_Hw: Error opening /dev/graphics/fb0\n"); - return; + return false; } LOGV("CameraHAL_CopyBuffers_Hw: srcFD:%d destFD:%d srcOffset:%#x" @@ -152,12 +169,48 @@ CameraHAL_CopyBuffers_Hw(int srcFd, int destFd, blit.req.src_rect.h = blit.req.dst_rect.h = h; if (ioctl(fb_fd, MSMFB_BLIT, &blit)) { - LOGE("CameraHAL_CopyBuffers_Hw: MSMFB_BLIT failed = %d %s\n", + LOGV("CameraHAL_CopyBuffers_Hw: MSMFB_BLIT failed = %d %s\n", errno, strerror(errno)); + success = false; } close(fb_fd); + return success; } +void +CameraHal_Decode_Sw(unsigned int* rgb, char* yuv420sp, int width, int height) +{ + int frameSize = width * height; + + if (!qCamera->previewEnabled()) return; + + for (int j = 0, yp = 0; j < height; j++) { + int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; + for (int i = 0; i < width; i++, yp++) { + int y = (0xff & ((int) yuv420sp[yp])) - 16; + if (y < 0) y = 0; + if ((i & 1) == 0) { + v = (0xff & yuv420sp[uvp++]) - 128; + u = (0xff & yuv420sp[uvp++]) - 128; + } + + int y1192 = 1192 * y; + int r = (y1192 + 1634 * v); + int g = (y1192 - 833 * v - 400 * u); + int b = (y1192 + 2066 * u); + + if (r < 0) r = 0; else if (r > 262143) r = 262143; + if (g < 0) g = 0; else if (g > 262143) g = 262143; + if (b < 0) b = 0; else if (b > 262143) b = 262143; + + rgb[yp] = 0xff000000 | ((b << 6) & 0xff0000) | + ((g >> 2) & 0xff00) | ((r >> 10) & 0xff); + } + } +} + + + void CameraHAL_CopyBuffers_Sw(char *dest, char *src, int size) { @@ -184,7 +237,7 @@ CameraHAL_CopyBuffers_Sw(char *dest, char *src, int size) } void -CameraHAL_HandlePreviewData(const android::sp& dataPtr, +CameraHAL_HandlePreviewData(const android::sp& dataPtr, preview_stream_ops_t *mWindow, camera_request_memory getMemory, int32_t previewWidth, int32_t previewHeight) @@ -193,7 +246,11 @@ CameraHAL_HandlePreviewData(const android::sp& dataPtr, ssize_t offset; size_t size; int32_t previewFormat = MDP_Y_CBCR_H2V2; +#ifdef HWA + int32_t destFormat = MDP_RGBX_8888; +#else int32_t destFormat = MDP_RGBA_8888; +#endif android::status_t retVal; android::sp mHeap = dataPtr->getMemory(&offset, @@ -204,11 +261,18 @@ CameraHAL_HandlePreviewData(const android::sp& dataPtr, (unsigned)offset, size, mHeap != NULL ? mHeap->base() : 0); mWindow->set_usage(mWindow, +#ifndef HWA GRALLOC_USAGE_PMEM_PRIVATE_ADSP | +#endif GRALLOC_USAGE_SW_READ_OFTEN); retVal = mWindow->set_buffers_geometry(mWindow, previewWidth, previewHeight, - HAL_PIXEL_FORMAT_RGBA_8888); +#ifdef HWA + HAL_PIXEL_FORMAT_RGBX_8888 +#else + HAL_PIXEL_FORMAT_RGBA_8888 +#endif + ); if (retVal == NO_ERROR) { int32_t stride; buffer_handle_t *bufHandle = NULL; @@ -220,10 +284,32 @@ CameraHAL_HandlePreviewData(const android::sp& dataPtr, if (retVal == NO_ERROR) { private_handle_t const *privHandle = reinterpret_cast(*bufHandle); - CameraHAL_CopyBuffers_Hw(mHeap->getHeapID(), privHandle->fd, - offset, privHandle->offset, - previewFormat, destFormat, - 0, 0, previewWidth, previewHeight); + if (!CameraHAL_CopyBuffers_Hw(mHeap->getHeapID(), privHandle->fd, + offset, privHandle->offset, + previewFormat, destFormat, + 0, 0, previewWidth, + previewHeight)) { + void *bits; + android::Rect bounds; + android::GraphicBufferMapper &mapper = + android::GraphicBufferMapper::get(); + + bounds.left = 0; + bounds.top = 0; + bounds.right = previewWidth; + bounds.bottom = previewHeight; + + mapper.lock(*bufHandle, GRALLOC_USAGE_SW_READ_OFTEN, bounds, + &bits); + LOGV("CameraHAL_HPD: w:%d h:%d bits:%p", + previewWidth, previewHeight, bits); + CameraHal_Decode_Sw((unsigned int *)bits, (char *)mHeap->base() + offset, + previewWidth, previewHeight); + + // unlock buffer before sending to display + mapper.unlock(*bufHandle); + } + mWindow->enqueue_buffer(mWindow, bufHandle); LOGV("CameraHAL_HandlePreviewData: enqueued buffer\n"); } else { @@ -252,7 +338,7 @@ CameraHAL_GenClientData(const android::sp &dataPtr, clientData = reqClientMemory(-1, size, 1, user); if (clientData != NULL) { - CameraHAL_CopyBuffers_Sw((char *)clientData->data, + CameraHAL_CopyBuffers_Sw((char *)clientData->data, (char *)(mHeap->base()) + offset, size); } else { LOGV("CameraHAL_GenClientData: ERROR allocating memory from client\n"); @@ -272,12 +358,14 @@ CameraHAL_DataCb(int32_t msg_type, const android::sp& dataPtr, CameraHAL_HandlePreviewData(dataPtr, mWindow, origCamReqMemory, previewWidth, previewHeight); } + if (origData_cb != NULL && origCamReqMemory != NULL) { camera_memory_t *clientData = CameraHAL_GenClientData(dataPtr, origCamReqMemory, user); if (clientData != NULL) { LOGV("CameraHAL_DataCb: Posting data to client\n"); origData_cb(msg_type, clientData, 0, NULL, user); + clientData->release(clientData); } } } @@ -297,6 +385,7 @@ CameraHAL_DataTSCb(nsecs_t timestamp, int32_t msg_type, systemTime()); origDataTS_cb(timestamp, msg_type, clientData, 0, user); qCamera->releaseRecordingFrame(dataPtr); + clientData->release(clientData); } else { LOGD("CameraHAL_DataTSCb: ERROR allocating memory from client\n"); } @@ -306,16 +395,48 @@ CameraHAL_DataTSCb(nsecs_t timestamp, int32_t msg_type, int CameraHAL_GetNum_Cameras(void) { + int numCameras = 1; + LOGE("CameraHAL_GetNum_Cameras:\n"); - return 1; + void *libcameraHandle = ::dlopen("libcamera.so", RTLD_NOW); + LOGD("CameraHAL_GetNum_Cameras: loading libcamera at %p", libcameraHandle); + if (!libcameraHandle) { + LOGE("FATAL ERROR: could not dlopen libcamera.so: %s", dlerror()); + } else { + if (::dlsym(libcameraHandle, "HAL_getNumberOfCameras") != NULL) { + *(void**)&LINK_getNumberofCameras = + ::dlsym(libcameraHandle, "HAL_getNumberOfCameras"); + numCameras = LINK_getNumberofCameras(); + LOGD("CameraHAL_GetNum_Cameras: numCameras:%d", numCameras); + } + dlclose(libcameraHandle); + } + return numCameras; } int CameraHAL_GetCam_Info(int camera_id, struct camera_info *info) { + bool dynamic = false; LOGV("CameraHAL_GetCam_Info:\n"); - info->facing = CAMERA_FACING_BACK; - info->orientation = 90; + void *libcameraHandle = ::dlopen("libcamera.so", RTLD_NOW); + LOGD("CameraHAL_GetNum_Cameras: loading libcamera at %p", libcameraHandle); + if (!libcameraHandle) { + LOGE("FATAL ERROR: could not dlopen libcamera.so: %s", dlerror()); + return EINVAL; + } else { + if (::dlsym(libcameraHandle, "HAL_getCameraInfo") != NULL) { + *(void**)&LINK_getCameraInfo = + ::dlsym(libcameraHandle, "HAL_getCameraInfo"); + LINK_getCameraInfo(camera_id, info); + dynamic = true; + } + dlclose(libcameraHandle); + } + if (!dynamic) { + info->facing = CAMERA_FACING_BACK; + info->orientation = 90; + } return NO_ERROR; } @@ -593,7 +714,7 @@ qcamera_send_command(struct camera_device * device, int32_t cmd, { LOGV("qcamera_send_command: cmd:%d arg0:%d arg1:%d\n", cmd, arg0, arg1); - return NO_ERROR; + return qCamera->sendCommand(cmd, arg0, arg1); } void @@ -631,17 +752,40 @@ camera_device_close(hw_device_t* device) return rc; } + int qcamera_device_open(const hw_module_t* module, const char* name, hw_device_t** device) { + void *libcameraHandle; int cameraId = atoi(name); LOGD("qcamera_device_open: name:%s device:%p cameraId:%d\n", name, device, cameraId); - qCamera = openCameraHardware(cameraId); + libcameraHandle = ::dlopen("libcamera.so", RTLD_NOW); + LOGD("loading libcamera at %p", libcameraHandle); + if (!libcameraHandle) { + LOGE("FATAL ERROR: could not dlopen libcamera.so: %s", dlerror()); + return false; + } + + if (::dlsym(libcameraHandle, "openCameraHardware") != NULL) { + *(void**)&LINK_openCameraHardware = + ::dlsym(libcameraHandle, "openCameraHardware"); + } else if (::dlsym(libcameraHandle, "HAL_openCameraHardware") != NULL) { + *(void**)&LINK_openCameraHardware = + ::dlsym(libcameraHandle, "HAL_openCameraHardware"); + } else { + LOGE("FATAL ERROR: Could not find openCameraHardware"); + dlclose(libcameraHandle); + return false; + } + + qCamera = LINK_openCameraHardware(cameraId); + ::dlclose(libcameraHandle); + camera_device_t* camera_device = NULL; camera_device_ops_t* camera_ops = NULL; diff --git a/cameraHal.cpp.orig b/cameraHal.cpp.orig new file mode 100644 index 0000000..2fcaddd --- /dev/null +++ b/cameraHal.cpp.orig @@ -0,0 +1,813 @@ +/* + * Copyright (C) 2012, Raviprasad V Mummidi. + * + * 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. + */ + +#define LOG_TAG "CameraHAL" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NO_ERROR 0 +#define GRALLOC_USAGE_PMEM_PRIVATE_ADSP GRALLOC_USAGE_PRIVATE_0 +//#define MSM_COPY_HW 1 + +//#define LOGV LOGI + +struct qcom_mdp_rect { + uint32_t x; + uint32_t y; + uint32_t w; + uint32_t h; +}; + +struct qcom_mdp_img { + uint32_t width; + int32_t height; + int32_t format; + int32_t offset; + int memory_id; /* The file descriptor */ +}; + +struct qcom_mdp_blit_req { + struct qcom_mdp_img src; + struct qcom_mdp_img dst; + struct qcom_mdp_rect src_rect; + struct qcom_mdp_rect dst_rect; + uint32_t alpha; + uint32_t transp_mask; + uint32_t flags; +}; + +struct blitreq { + unsigned int count; + struct qcom_mdp_blit_req req; +}; + +/* Prototypes and extern functions. */ +//extern "C" android::sp openCameraHardware(int id); +android::sp (*LINK_openCameraHardware)(int id); +int (*LINK_getNumberofCameras)(void); +void (*LINK_getCameraInfo)(int cameraId, struct camera_info *info); +int qcamera_device_open(const hw_module_t* module, const char* name, + hw_device_t** device); +int CameraHAL_GetNum_Cameras(void); +int CameraHAL_GetCam_Info(int camera_id, struct camera_info *info); + +/* Global variables. */ +camera_notify_callback origNotify_cb = NULL; +camera_data_callback origData_cb = NULL; +camera_data_timestamp_callback origDataTS_cb = NULL; +camera_request_memory origCamReqMemory = NULL; + +android::String8 g_str; +android::CameraParameters camSettings; +preview_stream_ops_t *mWindow = NULL; +android::sp qCamera; + +static hw_module_methods_t camera_module_methods = { + open: qcamera_device_open +}; + +camera_module_t HAL_MODULE_INFO_SYM = { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 0, + id: CAMERA_HARDWARE_MODULE_ID, + name: "Camera HAL for ICS", + author: "Raviprasad V Mummidi", + methods: &camera_module_methods, + dso: NULL, + reserved: {0}, + }, + get_number_of_cameras: CameraHAL_GetNum_Cameras, + get_camera_info: CameraHAL_GetCam_Info, +}; + +/* HAL helper functions. */ +void +CameraHAL_NotifyCb(int32_t msg_type, int32_t ext1, + int32_t ext2, void *user) +{ + LOGV("CameraHAL_NotifyCb: msg_type:%d ext1:%d ext2:%d user:%p\n", + msg_type, ext1, ext2, user); + if (origNotify_cb != NULL) { + origNotify_cb(msg_type, ext1, ext2, user); + } +} + +bool +CameraHAL_CopyBuffers_Hw(int srcFd, int destFd, + size_t srcOffset, size_t destOffset, + int srcFormat, int destFormat, + int x, int y, int w, int h) +{ + struct blitreq blit; + bool success = true; + int fb_fd = open("/dev/graphics/fb0", O_RDWR); + +#ifndef MSM_COPY_HW + return false; +#endif + + if (fb_fd < 0) { + LOGD("CameraHAL_CopyBuffers_Hw: Error opening /dev/graphics/fb0\n"); + return false; + } + + LOGV("CameraHAL_CopyBuffers_Hw: srcFD:%d destFD:%d srcOffset:%#x" + " destOffset:%#x x:%d y:%d w:%d h:%d\n", srcFd, destFd, srcOffset, + destOffset, x, y, w, h); + + memset(&blit, 0, sizeof(blit)); + blit.count = 1; + + blit.req.flags = 0; + blit.req.alpha = 0xff; + blit.req.transp_mask = 0xffffffff; + + blit.req.src.width = w; + blit.req.src.height = h; + blit.req.src.offset = srcOffset; + blit.req.src.memory_id = srcFd; + blit.req.src.format = srcFormat; + + blit.req.dst.width = w; + blit.req.dst.height = h; + blit.req.dst.offset = destOffset; + blit.req.dst.memory_id = destFd; + blit.req.dst.format = destFormat; + + blit.req.src_rect.x = blit.req.dst_rect.x = x; + blit.req.src_rect.y = blit.req.dst_rect.y = y; + blit.req.src_rect.w = blit.req.dst_rect.w = w; + blit.req.src_rect.h = blit.req.dst_rect.h = h; + + if (ioctl(fb_fd, MSMFB_BLIT, &blit)) { + LOGV("CameraHAL_CopyBuffers_Hw: MSMFB_BLIT failed = %d %s\n", + errno, strerror(errno)); + success = false; + } + close(fb_fd); + return success; +} + +void +CameraHal_Decode_Sw(unsigned int* rgb, char* yuv420sp, int width, int height) +{ + int frameSize = width * height; + + if (!qCamera->previewEnabled()) return; + + for (int j = 0, yp = 0; j < height; j++) { + int uvp = frameSize + (j >> 1) * width, u = 0, v = 0; + for (int i = 0; i < width; i++, yp++) { + int y = (0xff & ((int) yuv420sp[yp])) - 16; + if (y < 0) y = 0; + if ((i & 1) == 0) { + v = (0xff & yuv420sp[uvp++]) - 128; + u = (0xff & yuv420sp[uvp++]) - 128; + } + + int y1192 = 1192 * y; + int r = (y1192 + 1634 * v); + int g = (y1192 - 833 * v - 400 * u); + int b = (y1192 + 2066 * u); + + if (r < 0) r = 0; else if (r > 262143) r = 262143; + if (g < 0) g = 0; else if (g > 262143) g = 262143; + if (b < 0) b = 0; else if (b > 262143) b = 262143; + + rgb[yp] = 0xff000000 | ((b << 6) & 0xff0000) | + ((g >> 2) & 0xff00) | ((r >> 10) & 0xff); + } + } +} + + + +void +CameraHAL_CopyBuffers_Sw(char *dest, char *src, int size) +{ + int i; + int numWords = size / sizeof(unsigned); + unsigned *srcWords = (unsigned *)src; + unsigned *destWords = (unsigned *)dest; + + for (i = 0; i < numWords; i++) { + if ((i % 8) == 0 && (i + 8) < numWords) { + __builtin_prefetch(srcWords + 8, 0, 0); + __builtin_prefetch(destWords + 8, 1, 0); + } + *destWords++ = *srcWords++; + } + if (__builtin_expect((size - (numWords * sizeof(unsigned))) > 0, 0)) { + int numBytes = size - (numWords * sizeof(unsigned)); + char *destBytes = (char *)destWords; + char *srcBytes = (char *)srcWords; + for (i = 0; i < numBytes; i++) { + *destBytes++ = *srcBytes++; + } + } +} + +void +CameraHAL_HandlePreviewData(const android::sp& dataPtr, + preview_stream_ops_t *mWindow, + camera_request_memory getMemory, + int32_t previewWidth, int32_t previewHeight) +{ + if (mWindow != NULL && getMemory != NULL) { + ssize_t offset; + size_t size; + int32_t previewFormat = MDP_Y_CBCR_H2V2; + int32_t destFormat = MDP_RGBA_8888; + + android::status_t retVal; + android::sp mHeap = dataPtr->getMemory(&offset, + &size); + + LOGV("CameraHAL_HandlePreviewData: previewWidth:%d previewHeight:%d " + "offset:%#x size:%#x base:%p\n", previewWidth, previewHeight, + (unsigned)offset, size, mHeap != NULL ? mHeap->base() : 0); + + mWindow->set_usage(mWindow, + GRALLOC_USAGE_PMEM_PRIVATE_ADSP | + GRALLOC_USAGE_SW_READ_OFTEN); + retVal = mWindow->set_buffers_geometry(mWindow, + previewWidth, previewHeight, + HAL_PIXEL_FORMAT_RGBA_8888); + if (retVal == NO_ERROR) { + int32_t stride; + buffer_handle_t *bufHandle = NULL; + + LOGV("CameraHAL_HandlePreviewData: dequeueing buffer\n"); + retVal = mWindow->dequeue_buffer(mWindow, &bufHandle, &stride); + if (retVal == NO_ERROR) { + retVal = mWindow->lock_buffer(mWindow, bufHandle); + if (retVal == NO_ERROR) { + private_handle_t const *privHandle = + reinterpret_cast(*bufHandle); + if (!CameraHAL_CopyBuffers_Hw(mHeap->getHeapID(), privHandle->fd, + offset, privHandle->offset, + previewFormat, destFormat, + 0, 0, previewWidth, + previewHeight)) { + void *bits; + android::Rect bounds; + android::GraphicBufferMapper &mapper = + android::GraphicBufferMapper::get(); + + bounds.left = 0; + bounds.top = 0; + bounds.right = previewWidth; + bounds.bottom = previewHeight; + + mapper.lock(*bufHandle, GRALLOC_USAGE_SW_READ_OFTEN, bounds, + &bits); + LOGV("CameraHAL_HPD: w:%d h:%d bits:%p", + previewWidth, previewHeight, bits); + CameraHal_Decode_Sw((unsigned int *)bits, (char *)mHeap->base() + offset, + previewWidth, previewHeight); + + // unlock buffer before sending to display + mapper.unlock(*bufHandle); + } + + mWindow->enqueue_buffer(mWindow, bufHandle); + LOGV("CameraHAL_HandlePreviewData: enqueued buffer\n"); + } else { + LOGE("CameraHAL_HandlePreviewData: ERROR locking the buffer\n"); + mWindow->cancel_buffer(mWindow, bufHandle); + } + } else { + LOGE("CameraHAL_HandlePreviewData: ERROR dequeueing the buffer\n"); + } + } + } +} + +camera_memory_t * +CameraHAL_GenClientData(const android::sp &dataPtr, + camera_request_memory reqClientMemory, + void *user) +{ + ssize_t offset; + size_t size; + camera_memory_t *clientData = NULL; + android::sp mHeap = dataPtr->getMemory(&offset, &size); + + LOGV("CameraHAL_GenClientData: offset:%#x size:%#x base:%p\n", + (unsigned)offset, size, mHeap != NULL ? mHeap->base() : 0); + + clientData = reqClientMemory(-1, size, 1, user); + if (clientData != NULL) { + CameraHAL_CopyBuffers_Sw((char *)clientData->data, + (char *)(mHeap->base()) + offset, size); + } else { + LOGV("CameraHAL_GenClientData: ERROR allocating memory from client\n"); + } + return clientData; +} + +void +CameraHAL_DataCb(int32_t msg_type, const android::sp& dataPtr, + void *user) +{ + LOGV("CameraHAL_DataCb: msg_type:%d user:%p\n", msg_type, user); + if (msg_type == CAMERA_MSG_PREVIEW_FRAME) { + int32_t previewWidth, previewHeight; + android::CameraParameters hwParameters = qCamera->getParameters(); + hwParameters.getPreviewSize(&previewWidth, &previewHeight); + CameraHAL_HandlePreviewData(dataPtr, mWindow, origCamReqMemory, + previewWidth, previewHeight); + } + + if (origData_cb != NULL && origCamReqMemory != NULL) { + camera_memory_t *clientData = CameraHAL_GenClientData(dataPtr, + origCamReqMemory, user); + if (clientData != NULL) { + LOGV("CameraHAL_DataCb: Posting data to client\n"); + origData_cb(msg_type, clientData, 0, NULL, user); + } + } +} + +void +CameraHAL_DataTSCb(nsecs_t timestamp, int32_t msg_type, + const android::sp& dataPtr, void *user) +{ + LOGV("CameraHAL_DataTSCb: timestamp:%lld msg_type:%d user:%p\n", + timestamp /1000, msg_type, user); + + if (origDataTS_cb != NULL && origCamReqMemory != NULL) { + camera_memory_t *clientData = CameraHAL_GenClientData(dataPtr, + origCamReqMemory, user); + if (clientData != NULL) { + LOGV("CameraHAL_DataTSCb: Posting data to client timestamp:%lld\n", + systemTime()); + origDataTS_cb(timestamp, msg_type, clientData, 0, user); + qCamera->releaseRecordingFrame(dataPtr); + } else { + LOGD("CameraHAL_DataTSCb: ERROR allocating memory from client\n"); + } + } +} + +int +CameraHAL_GetNum_Cameras(void) +{ + int numCameras = 1; + + LOGE("CameraHAL_GetNum_Cameras:\n"); + void *libcameraHandle = ::dlopen("libcamera.so", RTLD_NOW); + LOGD("CameraHAL_GetNum_Cameras: loading libcamera at %p", libcameraHandle); + if (!libcameraHandle) { + LOGE("FATAL ERROR: could not dlopen libcamera.so: %s", dlerror()); + } else { + if (::dlsym(libcameraHandle, "HAL_getNumberOfCameras") != NULL) { + *(void**)&LINK_getNumberofCameras = + ::dlsym(libcameraHandle, "HAL_getNumberOfCameras"); + numCameras = LINK_getNumberofCameras(); + LOGD("CameraHAL_GetNum_Cameras: numCameras:%d", numCameras); + } + dlclose(libcameraHandle); + } + return numCameras; +} + +int +CameraHAL_GetCam_Info(int camera_id, struct camera_info *info) +{ + bool dynamic = false; + LOGV("CameraHAL_GetCam_Info:\n"); + void *libcameraHandle = ::dlopen("libcamera.so", RTLD_NOW); + LOGD("CameraHAL_GetNum_Cameras: loading libcamera at %p", libcameraHandle); + if (!libcameraHandle) { + LOGE("FATAL ERROR: could not dlopen libcamera.so: %s", dlerror()); + return EINVAL; + } else { + if (::dlsym(libcameraHandle, "HAL_getCameraInfo") != NULL) { + *(void**)&LINK_getCameraInfo = + ::dlsym(libcameraHandle, "HAL_getCameraInfo"); + LINK_getCameraInfo(camera_id, info); + dynamic = true; + } + dlclose(libcameraHandle); + } + if (!dynamic) { + info->facing = CAMERA_FACING_BACK; + info->orientation = 90; + } + return NO_ERROR; +} + +void +CameraHAL_FixupParams(android::CameraParameters &settings) +{ + const char *preview_sizes = + "1280x720,800x480,768x432,720x480,640x480,576x432,480x320,384x288,352x288,320x240,240x160,176x144"; + const char *video_sizes = + "1280x720,800x480,720x480,640x480,352x288,320x240,176x144"; + const char *preferred_size = "640x480"; + const char *preview_frame_rates = "30,27,24,15"; + const char *preferred_frame_rate = "15"; + const char *frame_rate_range = "(15,30)"; + + settings.set(android::CameraParameters::KEY_VIDEO_FRAME_FORMAT, + android::CameraParameters::PIXEL_FORMAT_YUV420SP); + + if (!settings.get(android::CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES)) { + settings.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, + preview_sizes); + } + + if (!settings.get(android::CameraParameters::KEY_SUPPORTED_VIDEO_SIZES)) { + settings.set(android::CameraParameters::KEY_SUPPORTED_VIDEO_SIZES, + video_sizes); + } + + if (!settings.get(android::CameraParameters::KEY_VIDEO_SIZE)) { + settings.set(android::CameraParameters::KEY_VIDEO_SIZE, preferred_size); + } + + if (!settings.get(android::CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO)) { + settings.set(android::CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO, + preferred_size); + } + + if (!settings.get(android::CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES)) { + settings.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES, + preview_frame_rates); + } + + if (!settings.get(android::CameraParameters::KEY_PREVIEW_FRAME_RATE)) { + settings.set(android::CameraParameters::KEY_PREVIEW_FRAME_RATE, + preferred_frame_rate); + } + + if (!settings.get(android::CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE)) { + LOGD("Setting KEY_PREVIEW_FPS_RANGE: %s\n", frame_rate_range); + settings.set(android::CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE, + frame_rate_range); + } +} + +/* Hardware Camera interface handlers. */ +int +qcamera_set_preview_window(struct camera_device * device, + struct preview_stream_ops *window) +{ + LOGV("qcamera_set_preview_window : Window :%p\n", window); + if (device == NULL) { + LOGE("qcamera_set_preview_window : Invalid device.\n"); + return -EINVAL; + } else { + LOGV("qcamera_set_preview_window : window :%p\n", window); + mWindow = window; + return 0; + } +} + +void +qcamera_set_callbacks(struct camera_device * device, + camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, void *user) +{ + LOGV("qcamera_set_callbacks: notify_cb: %p, data_cb: %p " + "data_cb_timestamp: %p, get_memory: %p, user :%p", + notify_cb, data_cb, data_cb_timestamp, get_memory, user); + + origNotify_cb = notify_cb; + origData_cb = data_cb; + origDataTS_cb = data_cb_timestamp; + origCamReqMemory = get_memory; + qCamera->setCallbacks(CameraHAL_NotifyCb, CameraHAL_DataCb, + CameraHAL_DataTSCb, user); +} + +void +qcamera_enable_msg_type(struct camera_device * device, int32_t msg_type) +{ + LOGV("qcamera_enable_msg_type: msg_type:%#x\n", msg_type); + if (msg_type == 0xfff) { + msg_type = 0x1ff; + } else { + msg_type &= ~(CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_RAW_IMAGE_NOTIFY); + } + qCamera->enableMsgType(msg_type); +} + +void +qcamera_disable_msg_type(struct camera_device * device, int32_t msg_type) +{ + LOGV("qcamera_disable_msg_type: msg_type:%#x\n", msg_type); + if (msg_type == 0xfff) { + msg_type = 0x1ff; + } + qCamera->disableMsgType(msg_type); +} + +int +qcamera_msg_type_enabled(struct camera_device * device, int32_t msg_type) +{ + LOGV("qcamera_msg_type_enabled: msg_type:%d\n", msg_type); + return qCamera->msgTypeEnabled(msg_type); +} + +int +qcamera_start_preview(struct camera_device * device) +{ + LOGV("qcamera_start_preview: Enabling CAMERA_MSG_PREVIEW_FRAME\n"); + + /* TODO: Remove hack. */ + LOGV("qcamera_start_preview: Preview enabled:%d msg enabled:%d\n", + qCamera->previewEnabled(), + qCamera->msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME)); + if (!qCamera->msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME)) { + qCamera->enableMsgType(CAMERA_MSG_PREVIEW_FRAME); + } + return qCamera->startPreview(); +} + +void +qcamera_stop_preview(struct camera_device * device) +{ + LOGV("qcamera_stop_preview: msgenabled:%d\n", + qCamera->msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME)); + + /* TODO: Remove hack. */ + if (qCamera->msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME)) { + qCamera->disableMsgType(CAMERA_MSG_PREVIEW_FRAME); + } + return qCamera->stopPreview(); +} + +int +qcamera_preview_enabled(struct camera_device * device) +{ + LOGV("qcamera_preview_enabled:\n"); + return qCamera->previewEnabled() ? 1 : 0; +} + +int +qcamera_store_meta_data_in_buffers(struct camera_device * device, int enable) +{ + LOGV("qcamera_store_meta_data_in_buffers:\n"); + return NO_ERROR; +} + +int +qcamera_start_recording(struct camera_device * device) +{ + LOGV("qcamera_start_recording\n"); + + /* TODO: Remove hack. */ + qCamera->enableMsgType(CAMERA_MSG_VIDEO_FRAME); + qCamera->startRecording(); + return NO_ERROR; +} + +void +qcamera_stop_recording(struct camera_device * device) +{ + LOGV("qcamera_stop_recording:\n"); + + /* TODO: Remove hack. */ + qCamera->disableMsgType(CAMERA_MSG_VIDEO_FRAME); + qCamera->stopRecording(); +} + +int +qcamera_recording_enabled(struct camera_device * device) +{ + LOGV("qcamera_recording_enabled:\n"); + return (int)qCamera->recordingEnabled(); +} + +void +qcamera_release_recording_frame(struct camera_device * device, + const void *opaque) +{ + /* + * We release the frame immediately in CameraHAL_DataTSCb after making a + * copy. So, this is just a NOP. + */ + LOGV("qcamera_release_recording_frame: opaque:%p\n", opaque); +} + +int +qcamera_auto_focus(struct camera_device * device) +{ + LOGV("qcamera_auto_focus:\n"); + qCamera->autoFocus(); + return NO_ERROR; +} + +int +qcamera_cancel_auto_focus(struct camera_device * device) +{ + LOGV("qcamera_cancel_auto_focus:\n"); + qCamera->cancelAutoFocus(); + return NO_ERROR; +} + +int +qcamera_take_picture(struct camera_device * device) +{ + LOGV("qcamera_take_picture:\n"); + + /* TODO: Remove hack. */ + qCamera->enableMsgType(CAMERA_MSG_SHUTTER | + CAMERA_MSG_POSTVIEW_FRAME | + CAMERA_MSG_RAW_IMAGE | + CAMERA_MSG_COMPRESSED_IMAGE); + + qCamera->takePicture(); + return NO_ERROR; +} + +int +qcamera_cancel_picture(struct camera_device * device) +{ + LOGV("camera_cancel_picture:\n"); + qCamera->cancelPicture(); + return NO_ERROR; +} + +int +qcamera_set_parameters(struct camera_device * device, const char *params) +{ + LOGV("qcamera_set_parameters: %s\n", params); + g_str = android::String8(params); + camSettings.unflatten(g_str); + qCamera->setParameters(camSettings); + return NO_ERROR; +} + +char* +qcamera_get_parameters(struct camera_device * device) +{ + char *rc = NULL; + LOGV("qcamera_get_parameters\n"); + camSettings = qCamera->getParameters(); + LOGV("qcamera_get_parameters: after calling qCamera->getParameters()\n"); + CameraHAL_FixupParams(camSettings); + g_str = camSettings.flatten(); + rc = strdup((char *)g_str.string()); + LOGV("camera_get_parameters: returning rc:%p :%s\n", + rc, (rc != NULL) ? rc : "EMPTY STRING"); + return rc; +} + +void +qcamera_put_parameters(struct camera_device *device, char *params) +{ + LOGV("qcamera_put_parameters: params:%p %s", params, params); + free(params); +} + + +int +qcamera_send_command(struct camera_device * device, int32_t cmd, + int32_t arg0, int32_t arg1) +{ + LOGV("qcamera_send_command: cmd:%d arg0:%d arg1:%d\n", + cmd, arg0, arg1); + return qCamera->sendCommand(cmd, arg0, arg1); +} + +void +qcamera_release(struct camera_device * device) +{ + LOGV("camera_release:\n"); + qCamera->release(); +} + +int +qcamera_dump(struct camera_device * device, int fd) +{ + LOGV("qcamera_dump:\n"); + android::Vector args; + return qCamera->dump(fd, args); +} + +int +camera_device_close(hw_device_t* device) +{ + int rc = -EINVAL; + LOGD("camera_device_close\n"); + camera_device_t *cameraDev = (camera_device_t *)device; + if (cameraDev) { + camera_device_ops_t *camera_ops = cameraDev->ops; + if (camera_ops) { + if (qCamera != NULL) { + qCamera.clear(); + } + free(camera_ops); + } + free(cameraDev); + rc = NO_ERROR; + } + return rc; +} + + +int +qcamera_device_open(const hw_module_t* module, const char* name, + hw_device_t** device) +{ + + void *libcameraHandle; + int cameraId = atoi(name); + + LOGD("qcamera_device_open: name:%s device:%p cameraId:%d\n", + name, device, cameraId); + + libcameraHandle = ::dlopen("libcamera.so", RTLD_NOW); + LOGD("loading libcamera at %p", libcameraHandle); + if (!libcameraHandle) { + LOGE("FATAL ERROR: could not dlopen libcamera.so: %s", dlerror()); + return false; + } + + if (::dlsym(libcameraHandle, "openCameraHardware") != NULL) { + *(void**)&LINK_openCameraHardware = + ::dlsym(libcameraHandle, "openCameraHardware"); + } else if (::dlsym(libcameraHandle, "HAL_openCameraHardware") != NULL) { + *(void**)&LINK_openCameraHardware = + ::dlsym(libcameraHandle, "HAL_openCameraHardware"); + } else { + LOGE("FATAL ERROR: Could not find openCameraHardware"); + dlclose(libcameraHandle); + return false; + } + + qCamera = LINK_openCameraHardware(cameraId); + ::dlclose(libcameraHandle); + + camera_device_t* camera_device = NULL; + camera_device_ops_t* camera_ops = NULL; + + camera_device = (camera_device_t*)malloc(sizeof(*camera_device)); + camera_ops = (camera_device_ops_t*)malloc(sizeof(*camera_ops)); + memset(camera_device, 0, sizeof(*camera_device)); + memset(camera_ops, 0, sizeof(*camera_ops)); + + camera_device->common.tag = HARDWARE_DEVICE_TAG; + camera_device->common.version = 0; + camera_device->common.module = (hw_module_t *)(module); + camera_device->common.close = camera_device_close; + camera_device->ops = camera_ops; + + camera_ops->set_preview_window = qcamera_set_preview_window; + camera_ops->set_callbacks = qcamera_set_callbacks; + camera_ops->enable_msg_type = qcamera_enable_msg_type; + camera_ops->disable_msg_type = qcamera_disable_msg_type; + camera_ops->msg_type_enabled = qcamera_msg_type_enabled; + camera_ops->start_preview = qcamera_start_preview; + camera_ops->stop_preview = qcamera_stop_preview; + camera_ops->preview_enabled = qcamera_preview_enabled; + camera_ops->store_meta_data_in_buffers = qcamera_store_meta_data_in_buffers; + camera_ops->start_recording = qcamera_start_recording; + camera_ops->stop_recording = qcamera_stop_recording; + camera_ops->recording_enabled = qcamera_recording_enabled; + camera_ops->release_recording_frame = qcamera_release_recording_frame; + camera_ops->auto_focus = qcamera_auto_focus; + camera_ops->cancel_auto_focus = qcamera_cancel_auto_focus; + camera_ops->take_picture = qcamera_take_picture; + camera_ops->cancel_picture = qcamera_cancel_picture; + + camera_ops->set_parameters = qcamera_set_parameters; + camera_ops->get_parameters = qcamera_get_parameters; + camera_ops->put_parameters = qcamera_put_parameters; + camera_ops->send_command = qcamera_send_command; + camera_ops->release = qcamera_release; + camera_ops->dump = qcamera_dump; + + *device = &camera_device->common; + return NO_ERROR; +}