android_hardware_qcom_camer.../cameraHal.cpp.orig
Raviprasad V Mummidi 903d325fc6 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)
2012-05-04 14:38:15 -07:00

814 lines
26 KiB
C++

/*
* 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 <CameraHardwareInterface.h>
#include <hardware/hardware.h>
#include <hardware/camera.h>
#include <binder/IMemory.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#include <linux/msm_mdp.h>
#include <gralloc_priv.h>
#include <ui/Rect.h>
#include <ui/GraphicBufferMapper.h>
#include <dlfcn.h>
#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<android::CameraHardwareInterface> openCameraHardware(int id);
android::sp<android::CameraHardwareInterface> (*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<android::CameraHardwareInterface> 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<android::IMemory>& 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<android::IMemoryHeap> 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<private_handle_t const *>(*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<android::IMemory> &dataPtr,
camera_request_memory reqClientMemory,
void *user)
{
ssize_t offset;
size_t size;
camera_memory_t *clientData = NULL;
android::sp<android::IMemoryHeap> 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<android::IMemory>& 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<android::IMemory>& 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<android::String16> 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;
}