android_hardware_qcom_camer.../cameraHal.cpp
2012-02-08 16:17:30 -08:00

687 lines
22 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>
#define NO_ERROR 0
//#define LOGV LOGI
#define GRALLOC_USAGE_PMEM_PRIVATE_ADSP GRALLOC_USAGE_PRIVATE_0
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);
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);
}
}
void
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;
int fb_fd = open("/dev/graphics/fb0", O_RDWR);
if (fb_fd < 0) {
LOGD("CameraHAL_CopyBuffers_Hw: Error opening /dev/graphics/fb0\n");
return;
}
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)) {
LOGE("CameraHAL_CopyBuffers_Hw: MSMFB_BLIT failed = %d %s\n",
errno, strerror(errno));
}
close(fb_fd);
}
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);
CameraHAL_CopyBuffers_Hw(mHeap->getHeapID(), privHandle->fd,
offset, privHandle->offset,
previewFormat, destFormat,
0, 0, previewWidth, previewHeight);
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)
{
LOGE("CameraHAL_GetNum_Cameras:\n");
return 1;
}
int
CameraHAL_GetCam_Info(int camera_id, struct camera_info *info)
{
LOGV("CameraHAL_GetCam_Info:\n");
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 NO_ERROR;
}
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)
{
int cameraId = atoi(name);
LOGD("qcamera_device_open: name:%s device:%p cameraId:%d\n",
name, device, cameraId);
qCamera = openCameraHardware(cameraId);
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;
}