/* Copyright (c) 2012-2013, The Linux Foundataion. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #define LOG_TAG "QCamera2HWI" #include <cutils/properties.h> #include <hardware/camera.h> #include <stdlib.h> #include <utils/Errors.h> #include <gralloc_priv.h> #include "QCamera2HWI.h" #include "QCameraMem.h" #define MAP_TO_DRIVER_COORDINATE(val, base, scale, offset) (val * scale / base + offset) #define CAMERA_MIN_STREAMING_BUFFERS 3 #define CAMERA_MIN_JPEG_ENCODING_BUFFERS 2 #define CAMERA_MIN_VIDEO_BUFFERS 9 namespace qcamera { cam_capability_t *gCamCapability[MM_CAMERA_MAX_NUM_SENSORS]; static pthread_mutex_t g_camlock = PTHREAD_MUTEX_INITIALIZER; camera_device_ops_t QCamera2HardwareInterface::mCameraOps = { .set_preview_window = QCamera2HardwareInterface::set_preview_window, .set_callbacks = QCamera2HardwareInterface::set_CallBacks, .enable_msg_type = QCamera2HardwareInterface::enable_msg_type, .disable_msg_type = QCamera2HardwareInterface::disable_msg_type, .msg_type_enabled = QCamera2HardwareInterface::msg_type_enabled, .start_preview = QCamera2HardwareInterface::start_preview, .stop_preview = QCamera2HardwareInterface::stop_preview, .preview_enabled = QCamera2HardwareInterface::preview_enabled, .store_meta_data_in_buffers = QCamera2HardwareInterface::store_meta_data_in_buffers, .start_recording = QCamera2HardwareInterface::start_recording, .stop_recording = QCamera2HardwareInterface::stop_recording, .recording_enabled = QCamera2HardwareInterface::recording_enabled, .release_recording_frame = QCamera2HardwareInterface::release_recording_frame, .auto_focus = QCamera2HardwareInterface::auto_focus, .cancel_auto_focus = QCamera2HardwareInterface::cancel_auto_focus, .take_picture = QCamera2HardwareInterface::take_picture, .cancel_picture = QCamera2HardwareInterface::cancel_picture, .set_parameters = QCamera2HardwareInterface::set_parameters, .get_parameters = QCamera2HardwareInterface::get_parameters, .put_parameters = QCamera2HardwareInterface::put_parameters, .send_command = QCamera2HardwareInterface::send_command, .release = QCamera2HardwareInterface::release, .dump = QCamera2HardwareInterface::dump, }; /*=========================================================================== * FUNCTION : set_preview_window * * DESCRIPTION: set preview window. * * PARAMETERS : * @device : ptr to camera device struct * @window : window ops table * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::set_preview_window(struct camera_device *device, struct preview_stream_ops *window) { int rc = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("%s: NULL camera device", __func__); return BAD_VALUE; } hw->lockAPI(); rc = hw->processAPI(QCAMERA_SM_EVT_SET_PREVIEW_WINDOW, (void *)window); if (rc == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_PREVIEW_WINDOW); rc = hw->m_apiResult.status; } hw->unlockAPI(); return rc; } /*=========================================================================== * FUNCTION : set_CallBacks * * DESCRIPTION: set callbacks for notify and data * * PARAMETERS : * @device : ptr to camera device struct * @notify_cb : notify cb * @data_cb : data cb * @data_cb_timestamp : video data cd with timestamp * @get_memory : ops table for request gralloc memory * @user : user data ptr * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::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) { QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return; } qcamera_sm_evt_setcb_payload_t payload; payload.notify_cb = notify_cb; payload.data_cb = data_cb; payload.data_cb_timestamp = data_cb_timestamp; payload.get_memory = get_memory; payload.user = user; hw->lockAPI(); int32_t rc = hw->processAPI(QCAMERA_SM_EVT_SET_CALLBACKS, (void *)&payload); if (rc == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_CALLBACKS); } hw->unlockAPI(); } /*=========================================================================== * FUNCTION : enable_msg_type * * DESCRIPTION: enable certain msg type * * PARAMETERS : * @device : ptr to camera device struct * @msg_type : msg type mask * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::enable_msg_type(struct camera_device *device, int32_t msg_type) { QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return; } hw->lockAPI(); int32_t rc = hw->processAPI(QCAMERA_SM_EVT_ENABLE_MSG_TYPE, (void *)msg_type); if (rc == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_ENABLE_MSG_TYPE); } hw->unlockAPI(); } /*=========================================================================== * FUNCTION : disable_msg_type * * DESCRIPTION: disable certain msg type * * PARAMETERS : * @device : ptr to camera device struct * @msg_type : msg type mask * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::disable_msg_type(struct camera_device *device, int32_t msg_type) { QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return; } hw->lockAPI(); int32_t rc = hw->processAPI(QCAMERA_SM_EVT_DISABLE_MSG_TYPE, (void *)msg_type); if (rc == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_DISABLE_MSG_TYPE); } hw->unlockAPI(); } /*=========================================================================== * FUNCTION : msg_type_enabled * * DESCRIPTION: if certain msg type is enabled * * PARAMETERS : * @device : ptr to camera device struct * @msg_type : msg type mask * * RETURN : 1 -- enabled * 0 -- not enabled *==========================================================================*/ int QCamera2HardwareInterface::msg_type_enabled(struct camera_device *device, int32_t msg_type) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_MSG_TYPE_ENABLED, (void *)msg_type); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_MSG_TYPE_ENABLED); ret = hw->m_apiResult.enabled; } hw->unlockAPI(); return ret; } /*=========================================================================== * FUNCTION : start_preview * * DESCRIPTION: start preview * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::start_preview(struct camera_device *device) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } ALOGD("[KPI Perf] %s: E", __func__); hw->lockAPI(); qcamera_sm_evt_enum_t evt = QCAMERA_SM_EVT_START_PREVIEW; if (hw->isNoDisplayMode()) { evt = QCAMERA_SM_EVT_START_NODISPLAY_PREVIEW; } ret = hw->processAPI(evt, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(evt); ret = hw->m_apiResult.status; } hw->unlockAPI(); ALOGD("[KPI Perf] %s: X", __func__); return ret; } /*=========================================================================== * FUNCTION : stop_preview * * DESCRIPTION: stop preview * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::stop_preview(struct camera_device *device) { QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return; } ALOGD("[KPI Perf] %s: E", __func__); hw->lockAPI(); int32_t ret = hw->processAPI(QCAMERA_SM_EVT_STOP_PREVIEW, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_STOP_PREVIEW); } hw->unlockAPI(); ALOGD("[KPI Perf] %s: X", __func__); } /*=========================================================================== * FUNCTION : preview_enabled * * DESCRIPTION: if preview is running * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : 1 -- running * 0 -- not running *==========================================================================*/ int QCamera2HardwareInterface::preview_enabled(struct camera_device *device) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_PREVIEW_ENABLED, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_PREVIEW_ENABLED); ret = hw->m_apiResult.enabled; } hw->unlockAPI(); return ret; } /*=========================================================================== * FUNCTION : store_meta_data_in_buffers * * DESCRIPTION: if need to store meta data in buffers for video frame * * PARAMETERS : * @device : ptr to camera device struct * @enable : flag if enable * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::store_meta_data_in_buffers( struct camera_device *device, int enable) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_STORE_METADATA_IN_BUFS, (void *)enable); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_STORE_METADATA_IN_BUFS); ret = hw->m_apiResult.status; } hw->unlockAPI(); return ret; } /*=========================================================================== * FUNCTION : start_recording * * DESCRIPTION: start recording * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::start_recording(struct camera_device *device) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } ALOGD("[KPI Perf] %s: E", __func__); hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_START_RECORDING, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_START_RECORDING); ret = hw->m_apiResult.status; } hw->unlockAPI(); ALOGD("[KPI Perf] %s: X", __func__); return ret; } /*=========================================================================== * FUNCTION : stop_recording * * DESCRIPTION: stop recording * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::stop_recording(struct camera_device *device) { QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return; } ALOGD("[KPI Perf] %s: E", __func__); hw->lockAPI(); int32_t ret = hw->processAPI(QCAMERA_SM_EVT_STOP_RECORDING, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_STOP_RECORDING); } hw->unlockAPI(); ALOGD("[KPI Perf] %s: X", __func__); } /*=========================================================================== * FUNCTION : recording_enabled * * DESCRIPTION: if recording is running * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : 1 -- running * 0 -- not running *==========================================================================*/ int QCamera2HardwareInterface::recording_enabled(struct camera_device *device) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_RECORDING_ENABLED, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_RECORDING_ENABLED); ret = hw->m_apiResult.enabled; } hw->unlockAPI(); return ret; } /*=========================================================================== * FUNCTION : release_recording_frame * * DESCRIPTION: return recording frame back * * PARAMETERS : * @device : ptr to camera device struct * @opaque : ptr to frame to be returned * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::release_recording_frame( struct camera_device *device, const void *opaque) { QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return; } ALOGD("%s: E", __func__); hw->lockAPI(); int32_t ret = hw->processAPI(QCAMERA_SM_EVT_RELEASE_RECORIDNG_FRAME, (void *)opaque); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_RELEASE_RECORIDNG_FRAME); } hw->unlockAPI(); ALOGD("%s: X", __func__); } /*=========================================================================== * FUNCTION : auto_focus * * DESCRIPTION: start auto focus * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::auto_focus(struct camera_device *device) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } ALOGD("[KPI Perf] %s : E", __func__); hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_START_AUTO_FOCUS, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_START_AUTO_FOCUS); ret = hw->m_apiResult.status; } hw->unlockAPI(); ALOGD("[KPI Perf] %s : X", __func__); return ret; } /*=========================================================================== * FUNCTION : cancel_auto_focus * * DESCRIPTION: cancel auto focus * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::cancel_auto_focus(struct camera_device *device) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_STOP_AUTO_FOCUS, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_STOP_AUTO_FOCUS); ret = hw->m_apiResult.status; } hw->unlockAPI(); return ret; } /*=========================================================================== * FUNCTION : take_picture * * DESCRIPTION: take picture * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::take_picture(struct camera_device *device) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } ALOGD("[KPI Perf] %s: E", __func__); hw->lockAPI(); /* Prepare snapshot in case LED needs to be flashed */ ret = hw->processAPI(QCAMERA_SM_EVT_PREPARE_SNAPSHOT, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_PREPARE_SNAPSHOT); ret = hw->m_apiResult.status; } /* Regardless what the result value for prepare_snapshot, * go ahead with capture anyway. Just like the way autofocus * is handled in capture case. */ /* capture */ ret = hw->processAPI(QCAMERA_SM_EVT_TAKE_PICTURE, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_TAKE_PICTURE); ret = hw->m_apiResult.status; } hw->unlockAPI(); ALOGD("[KPI Perf] %s: X", __func__); return ret; } /*=========================================================================== * FUNCTION : cancel_picture * * DESCRIPTION: cancel current take picture request * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::cancel_picture(struct camera_device *device) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_CANCEL_PICTURE, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_CANCEL_PICTURE); ret = hw->m_apiResult.status; } hw->unlockAPI(); return ret; } /*=========================================================================== * FUNCTION : set_parameters * * DESCRIPTION: set camera parameters * * PARAMETERS : * @device : ptr to camera device struct * @parms : string of packed parameters * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::set_parameters(struct camera_device *device, const char *parms) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS, (void *)parms); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS); ret = hw->m_apiResult.status; } hw->unlockAPI(); return ret; } /*=========================================================================== * FUNCTION : get_parameters * * DESCRIPTION: query camera parameters * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : packed parameters in a string *==========================================================================*/ char* QCamera2HardwareInterface::get_parameters(struct camera_device *device) { char *ret = NULL; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return NULL; } hw->lockAPI(); int32_t rc = hw->processAPI(QCAMERA_SM_EVT_GET_PARAMS, NULL); if (rc == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_GET_PARAMS); ret = hw->m_apiResult.params; } hw->unlockAPI(); return ret; } /*=========================================================================== * FUNCTION : put_parameters * * DESCRIPTION: return camera parameters string back to HAL * * PARAMETERS : * @device : ptr to camera device struct * @parm : ptr to parameter string to be returned * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::put_parameters(struct camera_device *device, char *parm) { QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return; } hw->lockAPI(); int32_t ret = hw->processAPI(QCAMERA_SM_EVT_PUT_PARAMS, (void *)parm); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_PUT_PARAMS); } hw->unlockAPI(); } /*=========================================================================== * FUNCTION : send_command * * DESCRIPTION: command to be executed * * PARAMETERS : * @device : ptr to camera device struct * @cmd : cmd to be executed * @arg1 : ptr to optional argument1 * @arg2 : ptr to optional argument2 * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::send_command(struct camera_device *device, int32_t cmd, int32_t arg1, int32_t arg2) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } qcamera_sm_evt_command_payload_t payload; memset(&payload, 0, sizeof(qcamera_sm_evt_command_payload_t)); payload.cmd = cmd; payload.arg1 = arg1; payload.arg2 = arg2; hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_SEND_COMMAND, (void *)&payload); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SEND_COMMAND); ret = hw->m_apiResult.status; } hw->unlockAPI(); return ret; } /*=========================================================================== * FUNCTION : release * * DESCRIPTION: release camera resource * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::release(struct camera_device *device) { QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return; } hw->lockAPI(); int32_t ret = hw->processAPI(QCAMERA_SM_EVT_RELEASE, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_RELEASE); } hw->unlockAPI(); } /*=========================================================================== * FUNCTION : dump * * DESCRIPTION: dump camera status * * PARAMETERS : * @device : ptr to camera device struct * @fd : fd for status to be dumped to * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::dump(struct camera_device *device, int fd) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_DUMP, (void *)fd); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_DUMP); ret = hw->m_apiResult.status; } hw->unlockAPI(); return ret; } /*=========================================================================== * FUNCTION : close_camera_device * * DESCRIPTION: close camera device * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::close_camera_device(hw_device_t *hw_dev) { int ret = NO_ERROR; ALOGD("[KPI Perf] %s: E",__func__); QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>( reinterpret_cast<camera_device_t *>(hw_dev)->priv); if (!hw) { ALOGE("%s: NULL camera device", __func__); return BAD_VALUE; } delete hw; ALOGD("[KPI Perf] %s: X",__func__); return ret; } /*=========================================================================== * FUNCTION : register_face_image * * DESCRIPTION: register a face image into imaging lib for face authenticatio/ * face recognition * * PARAMETERS : * @device : ptr to camera device struct * @img_ptr : ptr to image buffer * @config : ptr to config about input image, i.e., format, dimension, and etc. * * RETURN : >=0 unique ID of face registerd. * <0 failure. *==========================================================================*/ int QCamera2HardwareInterface::register_face_image(struct camera_device *device, void *img_ptr, cam_pp_offline_src_config_t *config) { int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { ALOGE("NULL camera device"); return BAD_VALUE; } qcamera_sm_evt_reg_face_payload_t payload; memset(&payload, 0, sizeof(qcamera_sm_evt_reg_face_payload_t)); payload.img_ptr = img_ptr; payload.config = config; hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_REG_FACE_IMAGE, (void *)&payload); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_REG_FACE_IMAGE); ret = hw->m_apiResult.handle; } hw->unlockAPI(); return ret; } /*=========================================================================== * FUNCTION : QCamera2HardwareInterface * * DESCRIPTION: constructor of QCamera2HardwareInterface * * PARAMETERS : * @cameraId : camera ID * * RETURN : none *==========================================================================*/ QCamera2HardwareInterface::QCamera2HardwareInterface(int cameraId) : mCameraId(cameraId), mCameraHandle(NULL), mCameraOpened(false), mPreviewWindow(NULL), mMsgEnabled(0), mStoreMetaDataInFrame(0), m_stateMachine(this), m_postprocessor(this), m_thermalAdapter(QCameraThermalAdapter::getInstance()), m_cbNotifier(this), m_bShutterSoundPlayed(false), m_currentFocusState(CAM_AF_NOT_FOCUSED), m_bStartZSLSnapshotCalled(false), m_pPowerModule(NULL), mDumpFrmCnt(0), mDumpSkipCnt(0) { mCameraDevice.common.tag = HARDWARE_DEVICE_TAG; mCameraDevice.common.version = HARDWARE_DEVICE_API_VERSION(1, 0); mCameraDevice.common.close = close_camera_device; mCameraDevice.ops = &mCameraOps; mCameraDevice.priv = this; pthread_mutex_init(&m_lock, NULL); pthread_cond_init(&m_cond, NULL); memset(&m_apiResult, 0, sizeof(qcamera_api_result_t)); pthread_mutex_init(&m_evtLock, NULL); pthread_cond_init(&m_evtCond, NULL); memset(&m_evtResult, 0, sizeof(qcamera_api_result_t)); memset(m_channels, 0, sizeof(m_channels)); #ifdef HAS_MULTIMEDIA_HINTS if (hw_get_module(POWER_HARDWARE_MODULE_ID, (const hw_module_t **)&m_pPowerModule)) { ALOGE("%s: %s module not found", __func__, POWER_HARDWARE_MODULE_ID); } #endif } /*=========================================================================== * FUNCTION : ~QCamera2HardwareInterface * * DESCRIPTION: destructor of QCamera2HardwareInterface * * PARAMETERS : none * * RETURN : none *==========================================================================*/ QCamera2HardwareInterface::~QCamera2HardwareInterface() { closeCamera(); pthread_mutex_destroy(&m_lock); pthread_cond_destroy(&m_cond); pthread_mutex_destroy(&m_evtLock); pthread_cond_destroy(&m_evtCond); } /*=========================================================================== * FUNCTION : openCamera * * DESCRIPTION: open camera * * PARAMETERS : * @hw_device : double ptr for camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::openCamera(struct hw_device_t **hw_device) { int rc = NO_ERROR; if (mCameraOpened) { *hw_device = NULL; return PERMISSION_DENIED; } rc = openCamera(); if (rc == NO_ERROR) *hw_device = &mCameraDevice.common; else *hw_device = NULL; return rc; } /*=========================================================================== * FUNCTION : openCamera * * DESCRIPTION: open camera * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::openCamera() { if (mCameraHandle) { ALOGE("Failure: Camera already opened"); return ALREADY_EXISTS; } mCameraHandle = camera_open(mCameraId); if (!mCameraHandle) { ALOGE("camera_open failed."); return UNKNOWN_ERROR; } mCameraHandle->ops->register_event_notify(mCameraHandle->camera_handle, camEvtHandle, (void *) this); int32_t rc = m_postprocessor.init(jpegEvtHandle, this); if (rc != 0) { ALOGE("Init Postprocessor failed"); return UNKNOWN_ERROR; } // update padding info from jpeg cam_padding_info_t padding_info; m_postprocessor.getJpegPaddingReq(padding_info); if (gCamCapability[mCameraId]->padding_info.width_padding < padding_info.width_padding) { gCamCapability[mCameraId]->padding_info.width_padding = padding_info.width_padding; } if (gCamCapability[mCameraId]->padding_info.height_padding < padding_info.height_padding) { gCamCapability[mCameraId]->padding_info.height_padding = padding_info.height_padding; } if (gCamCapability[mCameraId]->padding_info.plane_padding < padding_info.plane_padding) { gCamCapability[mCameraId]->padding_info.plane_padding = padding_info.plane_padding; } mParameters.init(gCamCapability[mCameraId], mCameraHandle); rc = m_thermalAdapter.init(this); if (rc != 0) { ALOGE("Init thermal adapter failed"); } mCameraOpened = true; return NO_ERROR; } /*=========================================================================== * FUNCTION : closeCamera * * DESCRIPTION: close camera * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::closeCamera() { int rc = NO_ERROR; int i; // deinit Parameters mParameters.deinit(); // stop and deinit postprocessor m_postprocessor.stop(); m_postprocessor.deinit(); m_thermalAdapter.deinit(); // delete all channels if not already deleted for (i = 0; i < QCAMERA_CH_TYPE_MAX; i++) { if (m_channels[i] != NULL) { m_channels[i]->stop(); delete m_channels[i]; m_channels[i] = NULL; } } rc = mCameraHandle->ops->close_camera(mCameraHandle->camera_handle); mCameraHandle = NULL; mCameraOpened = false; return rc; } #define DATA_PTR(MEM_OBJ,INDEX) MEM_OBJ->getPtr( INDEX ) /*=========================================================================== * FUNCTION : initCapabilities * * DESCRIPTION: initialize camera capabilities in static data struct * * PARAMETERS : * @cameraId : camera Id * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::initCapabilities(int cameraId) { int rc = NO_ERROR; mm_camera_vtbl_t *cameraHandle = NULL; QCameraHeapMemory *capabilityHeap = NULL; cameraHandle = camera_open(cameraId); if (!cameraHandle) { ALOGE("%s: camera_open failed", __func__); rc = UNKNOWN_ERROR; goto open_failed; } /* Allocate memory for capability buffer */ capabilityHeap = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE); rc = capabilityHeap->allocate(1, sizeof(cam_capability_t)); if(rc != OK) { ALOGE("%s: No memory for cappability", __func__); goto allocate_failed; } /* Map memory for capability buffer */ memset(DATA_PTR(capabilityHeap,0), 0, sizeof(cam_capability_t)); rc = cameraHandle->ops->map_buf(cameraHandle->camera_handle, CAM_MAPPING_BUF_TYPE_CAPABILITY, capabilityHeap->getFd(0), sizeof(cam_capability_t)); if(rc < 0) { ALOGE("%s: failed to map capability buffer", __func__); goto map_failed; } /* Query Capability */ rc = cameraHandle->ops->query_capability(cameraHandle->camera_handle); if(rc < 0) { ALOGE("%s: failed to query capability",__func__); goto query_failed; } gCamCapability[cameraId] = (cam_capability_t *)malloc(sizeof(cam_capability_t)); if (!gCamCapability[cameraId]) { ALOGE("%s: out of memory", __func__); goto query_failed; } memcpy(gCamCapability[cameraId], DATA_PTR(capabilityHeap,0), sizeof(cam_capability_t)); rc = NO_ERROR; query_failed: cameraHandle->ops->unmap_buf(cameraHandle->camera_handle, CAM_MAPPING_BUF_TYPE_CAPABILITY); map_failed: capabilityHeap->deallocate(); delete capabilityHeap; allocate_failed: cameraHandle->ops->close_camera(cameraHandle->camera_handle); cameraHandle = NULL; open_failed: return rc; } /*=========================================================================== * FUNCTION : getCapabilities * * DESCRIPTION: query camera capabilities * * PARAMETERS : * @cameraId : camera Id * @info : camera info struct to be filled in with camera capabilities * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::getCapabilities(int cameraId, struct camera_info *info) { int rc = NO_ERROR; pthread_mutex_lock(&g_camlock); if (NULL == gCamCapability[cameraId]) { rc = initCapabilities(cameraId); if (rc < 0) { pthread_mutex_unlock(&g_camlock); return rc; } } switch(gCamCapability[cameraId]->position) { case CAM_POSITION_BACK: info->facing = CAMERA_FACING_BACK; break; case CAM_POSITION_FRONT: info->facing = CAMERA_FACING_FRONT; break; default: ALOGE("%s:Unknown position type for camera id:%d", __func__, cameraId); rc = BAD_VALUE; break; } info->orientation = gCamCapability[cameraId]->sensor_mount_angle; pthread_mutex_unlock(&g_camlock); return rc; } /*=========================================================================== * FUNCTION : getBufNumRequired * * DESCRIPTION: return number of stream buffers needed for given stream type * * PARAMETERS : * @stream_type : type of stream * * RETURN : number of buffers needed *==========================================================================*/ uint8_t QCamera2HardwareInterface::getBufNumRequired(cam_stream_type_t stream_type) { int bufferCnt = 0; int minCaptureBuffers = mParameters.getNumOfSnapshots(); int zslQBuffers = mParameters.getZSLQueueDepth() + mParameters.getMaxUnmatchedFramesInQueue(); int minCircularBufNum = CAMERA_MIN_STREAMING_BUFFERS + CAMERA_MIN_JPEG_ENCODING_BUFFERS + mParameters.getMaxUnmatchedFramesInQueue() + mParameters.getNumOfHDRBufsIfNeeded(); // Get buffer count for the particular stream type switch (stream_type) { case CAM_STREAM_TYPE_PREVIEW: { if (mParameters.isZSLMode()) { bufferCnt = zslQBuffers + minCircularBufNum; } else { bufferCnt = CAMERA_MIN_STREAMING_BUFFERS + mParameters.getMaxUnmatchedFramesInQueue(); } } break; case CAM_STREAM_TYPE_POSTVIEW: { bufferCnt = minCaptureBuffers + mParameters.getMaxUnmatchedFramesInQueue() + mParameters.getNumOfExtraHDRBufsIfNeeded() + CAMERA_MIN_STREAMING_BUFFERS; } break; case CAM_STREAM_TYPE_SNAPSHOT: case CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT: { if (mParameters.isZSLMode()) { bufferCnt = zslQBuffers + minCircularBufNum; } else { bufferCnt = minCaptureBuffers + mParameters.getMaxUnmatchedFramesInQueue() + mParameters.getNumOfExtraHDRBufsIfNeeded() + CAMERA_MIN_STREAMING_BUFFERS; } } break; case CAM_STREAM_TYPE_RAW: if (mParameters.isZSLMode()) { bufferCnt = zslQBuffers + CAMERA_MIN_STREAMING_BUFFERS; } else { bufferCnt = minCaptureBuffers + mParameters.getMaxUnmatchedFramesInQueue() + mParameters.getNumOfExtraHDRBufsIfNeeded() + CAMERA_MIN_STREAMING_BUFFERS; } break; case CAM_STREAM_TYPE_VIDEO: { bufferCnt = CAMERA_MIN_VIDEO_BUFFERS + mParameters.getMaxUnmatchedFramesInQueue() + CAMERA_MIN_STREAMING_BUFFERS; } break; case CAM_STREAM_TYPE_METADATA: { bufferCnt = minCaptureBuffers + mParameters.getMaxUnmatchedFramesInQueue() + mParameters.getNumOfExtraHDRBufsIfNeeded() + CAMERA_MIN_STREAMING_BUFFERS; if (bufferCnt < zslQBuffers + minCircularBufNum) { bufferCnt = zslQBuffers + minCircularBufNum; } } break; case CAM_STREAM_TYPE_OFFLINE_PROC: { bufferCnt = minCaptureBuffers + mParameters.getMaxUnmatchedFramesInQueue(); if (bufferCnt < CAMERA_MIN_STREAMING_BUFFERS) { bufferCnt = CAMERA_MIN_STREAMING_BUFFERS; } } break; case CAM_STREAM_TYPE_DEFAULT: case CAM_STREAM_TYPE_MAX: default: bufferCnt = 0; break; } return bufferCnt; } /*=========================================================================== * FUNCTION : allocateStreamBuf * * DESCRIPTION: alocate stream buffers * * PARAMETERS : * @stream_type : type of stream * @size : size of buffer * @bufferCnt : [IN/OUT] minimum num of buffers to be allocated. * could be modified during allocation if more buffers needed * * RETURN : ptr to a memory obj that holds stream buffers. * NULL if failed *==========================================================================*/ QCameraMemory *QCamera2HardwareInterface::allocateStreamBuf(cam_stream_type_t stream_type, int size, uint8_t &bufferCnt) { int rc = NO_ERROR; QCameraMemory *mem = NULL; bool bCachedMem = QCAMERA_ION_USE_CACHE; // Allocate stream buffer memory object switch (stream_type) { case CAM_STREAM_TYPE_PREVIEW: { if (isNoDisplayMode()) { mem = new QCameraStreamMemory(mGetMemory, bCachedMem); } else { cam_dimension_t dim; QCameraGrallocMemory *grallocMemory = new QCameraGrallocMemory(mGetMemory); mParameters.getStreamDimension(stream_type, dim); if (grallocMemory) grallocMemory->setWindowInfo(mPreviewWindow, dim.width, dim.height, mParameters.getPreviewHalPixelFormat()); mem = grallocMemory; } } break; case CAM_STREAM_TYPE_POSTVIEW: { cam_dimension_t dim; QCameraGrallocMemory *grallocMemory = new QCameraGrallocMemory(mGetMemory); mParameters.getStreamDimension(stream_type, dim); if (grallocMemory) grallocMemory->setWindowInfo(mPreviewWindow, dim.width, dim.height, mParameters.getPreviewHalPixelFormat()); mem = grallocMemory; } break; case CAM_STREAM_TYPE_SNAPSHOT: case CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT: case CAM_STREAM_TYPE_RAW: case CAM_STREAM_TYPE_METADATA: case CAM_STREAM_TYPE_OFFLINE_PROC: mem = new QCameraStreamMemory(mGetMemory, bCachedMem); break; case CAM_STREAM_TYPE_VIDEO: { char value[PROPERTY_VALUE_MAX]; property_get("persist.camera.mem.usecache", value, "1"); if (atoi(value) == 0) { bCachedMem = QCAMERA_ION_USE_NOCACHE; } ALOGD("%s: vidoe buf using cached memory = %d", __func__, bCachedMem); mem = new QCameraVideoMemory(mGetMemory, bCachedMem); } break; case CAM_STREAM_TYPE_DEFAULT: case CAM_STREAM_TYPE_MAX: default: break; } if (!mem) { return NULL; } if (bufferCnt > 0) { rc = mem->allocate(bufferCnt, size); if (rc < 0) { delete mem; return NULL; } bufferCnt = mem->getCnt(); } return mem; } /*=========================================================================== * FUNCTION : allocateStreamInfoBuf * * DESCRIPTION: alocate stream info buffer * * PARAMETERS : * @stream_type : type of stream * * RETURN : ptr to a memory obj that holds stream info buffer. * NULL if failed *==========================================================================*/ QCameraHeapMemory *QCamera2HardwareInterface::allocateStreamInfoBuf( cam_stream_type_t stream_type) { int rc = NO_ERROR; QCameraHeapMemory *streamInfoBuf = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE); if (!streamInfoBuf) { ALOGE("allocateStreamInfoBuf: Unable to allocate streamInfo object"); return NULL; } rc = streamInfoBuf->allocate(1, sizeof(cam_stream_info_t)); if (rc < 0) { ALOGE("allocateStreamInfoBuf: Failed to allocate stream info memory"); delete streamInfoBuf; return NULL; } cam_stream_info_t *streamInfo = (cam_stream_info_t *)streamInfoBuf->getPtr(0); memset(streamInfo, 0, sizeof(cam_stream_info_t)); streamInfo->stream_type = stream_type; rc = mParameters.getStreamFormat(stream_type, streamInfo->fmt); rc = mParameters.getStreamDimension(stream_type, streamInfo->dim); streamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS; switch (stream_type) { case CAM_STREAM_TYPE_SNAPSHOT: case CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT: case CAM_STREAM_TYPE_RAW: if (mParameters.isZSLMode() && mParameters.getRecordingHintValue() != true) { streamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS; } else { streamInfo->streaming_mode = CAM_STREAMING_MODE_BURST; streamInfo->num_of_burst = mParameters.getNumOfSnapshots(); } break; case CAM_STREAM_TYPE_POSTVIEW: streamInfo->streaming_mode = CAM_STREAMING_MODE_BURST; streamInfo->num_of_burst = mParameters.getNumOfSnapshots(); break; default: break; } //set flip mode based on Stream type; int flipMode = mParameters.getFlipMode(stream_type); if (flipMode > 0) { streamInfo->pp_config.feature_mask |= CAM_QCOM_FEATURE_FLIP; streamInfo->pp_config.flip = flipMode; } return streamInfoBuf; } /*=========================================================================== * FUNCTION : setPreviewWindow * * DESCRIPTION: set preview window impl * * PARAMETERS : * @window : ptr to window ops table struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::setPreviewWindow( struct preview_stream_ops *window) { mPreviewWindow = window; return NO_ERROR; } /*=========================================================================== * FUNCTION : setCallBacks * * DESCRIPTION: set callbacks impl * * PARAMETERS : * @notify_cb : notify cb * @data_cb : data cb * @data_cb_timestamp : data cb with time stamp * @get_memory : request memory ops table * @user : user data ptr * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::setCallBacks(camera_notify_callback notify_cb, camera_data_callback data_cb, camera_data_timestamp_callback data_cb_timestamp, camera_request_memory get_memory, void *user) { mNotifyCb = notify_cb; mDataCb = data_cb; mDataCbTimestamp = data_cb_timestamp; mGetMemory = get_memory; mCallbackCookie = user; m_cbNotifier.setCallbacks(notify_cb, data_cb, data_cb_timestamp, user); return NO_ERROR; } /*=========================================================================== * FUNCTION : enableMsgType * * DESCRIPTION: enable msg type impl * * PARAMETERS : * @msg_type : msg type mask to be enabled * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::enableMsgType(int32_t msg_type) { mMsgEnabled |= msg_type; return NO_ERROR; } /*=========================================================================== * FUNCTION : disableMsgType * * DESCRIPTION: disable msg type impl * * PARAMETERS : * @msg_type : msg type mask to be disabled * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::disableMsgType(int32_t msg_type) { mMsgEnabled &= ~msg_type; return NO_ERROR; } /*=========================================================================== * FUNCTION : msgTypeEnabled * * DESCRIPTION: impl to determine if certain msg_type is enabled * * PARAMETERS : * @msg_type : msg type mask * * RETURN : 0 -- not enabled * none 0 -- enabled *==========================================================================*/ int QCamera2HardwareInterface::msgTypeEnabled(int32_t msg_type) { return (mMsgEnabled & msg_type); } /*=========================================================================== * FUNCTION : msgTypeEnabledWithLock * * DESCRIPTION: impl to determine if certain msg_type is enabled with lock * * PARAMETERS : * @msg_type : msg type mask * * RETURN : 0 -- not enabled * none 0 -- enabled *==========================================================================*/ int QCamera2HardwareInterface::msgTypeEnabledWithLock(int32_t msg_type) { int enabled = 0; lockAPI(); enabled = mMsgEnabled & msg_type; unlockAPI(); return enabled; } /*=========================================================================== * FUNCTION : startPreview * * DESCRIPTION: start preview impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::startPreview() { int32_t rc = NO_ERROR; ALOGD("%s: E", __func__); // start preview stream if (mParameters.isZSLMode() && mParameters.getRecordingHintValue() !=true) { rc = startChannel(QCAMERA_CH_TYPE_ZSL); } else { rc = startChannel(QCAMERA_CH_TYPE_PREVIEW); } ALOGD("%s: X", __func__); return rc; } /*=========================================================================== * FUNCTION : stopPreview * * DESCRIPTION: stop preview impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::stopPreview() { ALOGD("%s: E", __func__); // stop preview stream if (mParameters.isZSLMode() && mParameters.getRecordingHintValue() !=true) { stopChannel(QCAMERA_CH_TYPE_ZSL); } else { stopChannel(QCAMERA_CH_TYPE_PREVIEW); } // delete all channels from preparePreview unpreparePreview(); ALOGD("%s: X", __func__); return NO_ERROR; } /*=========================================================================== * FUNCTION : storeMetaDataInBuffers * * DESCRIPTION: enable store meta data in buffers for video frames impl * * PARAMETERS : * @enable : flag if need enable * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::storeMetaDataInBuffers(int enable) { mStoreMetaDataInFrame = enable; return NO_ERROR; } /*=========================================================================== * FUNCTION : startRecording * * DESCRIPTION: start recording impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::startRecording() { int32_t rc = NO_ERROR; ALOGD("%s: E", __func__); if (mParameters.getRecordingHintValue() == false) { ALOGE("%s: start recording when hint is false, stop preview first", __func__); stopChannel(QCAMERA_CH_TYPE_PREVIEW); delChannel(QCAMERA_CH_TYPE_PREVIEW); // Set recording hint to TRUE mParameters.updateRecordingHintValue(TRUE); rc = preparePreview(); if (rc == NO_ERROR) { rc = startChannel(QCAMERA_CH_TYPE_PREVIEW); } } if (rc == NO_ERROR) { rc = startChannel(QCAMERA_CH_TYPE_VIDEO); } #ifdef HAS_MULTIMEDIA_HINTS if (rc == NO_ERROR) { if (m_pPowerModule) { if (m_pPowerModule->powerHint) { m_pPowerModule->powerHint(m_pPowerModule, POWER_HINT_VIDEO_ENCODE, (void *)"state=1"); } } } #endif ALOGD("%s: X", __func__); return rc; } /*=========================================================================== * FUNCTION : stopRecording * * DESCRIPTION: stop recording impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::stopRecording() { int rc = stopChannel(QCAMERA_CH_TYPE_VIDEO); ALOGD("%s: E", __func__); #ifdef HAS_MULTIMEDIA_HINTS if (m_pPowerModule) { if (m_pPowerModule->powerHint) { m_pPowerModule->powerHint(m_pPowerModule, POWER_HINT_VIDEO_ENCODE, (void *)"state=0"); } } #endif ALOGD("%s: X", __func__); return rc; } /*=========================================================================== * FUNCTION : releaseRecordingFrame * * DESCRIPTION: return video frame impl * * PARAMETERS : * @opaque : ptr to video frame to be returned * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::releaseRecordingFrame(const void * opaque) { int32_t rc = UNKNOWN_ERROR; QCameraVideoChannel *pChannel = (QCameraVideoChannel *)m_channels[QCAMERA_CH_TYPE_VIDEO]; ALOGD("%s: opaque data = %p", __func__,opaque); if(pChannel != NULL) { rc = pChannel->releaseFrame(opaque, mStoreMetaDataInFrame > 0); } return rc; } /*=========================================================================== * FUNCTION : autoFocus * * DESCRIPTION: start auto focus impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::autoFocus() { int rc = NO_ERROR; cam_focus_mode_type focusMode = mParameters.getFocusMode(); switch (focusMode) { case CAM_FOCUS_MODE_AUTO: case CAM_FOCUS_MODE_MACRO: { rc = mCameraHandle->ops->do_auto_focus(mCameraHandle->camera_handle); if (rc == NO_ERROR) { mParameters.setAFRunning(true); } } break; case CAM_FOCUS_MODE_CONTINOUS_VIDEO: // According to Google API definition, the focus callback will immediately // return with a boolean that indicates whether the focus is sharp or not. // The focus position is locked after autoFocus call. // in this sense, the effect is the same as cancel_auto_focus { rc = mParameters.setLockCAF(true); // send evt notify that foucs is done sendEvtNotify(CAMERA_MSG_FOCUS, (m_currentFocusState == CAM_AF_FOCUSED)? true : false, 0); } break; case CAM_FOCUS_MODE_CONTINOUS_PICTURE: // According to Google API definition, if the autofocus is in the middle // of scanning, the focus callback will return when it completes. If the // autofocus is not scanning, focus callback will immediately return with // a boolean that indicates whether the focus is sharp or not. The apps // can then decide if they want to take a picture immediately or to change // the focus mode to auto, and run a full autofocus cycle. The focus position // is locked after autoFocus call. if (m_currentFocusState != CAM_AF_SCANNING) { // lock focus rc = mParameters.setLockCAF(true); // send evt notify that foucs is done sendEvtNotify(CAMERA_MSG_FOCUS, (m_currentFocusState == CAM_AF_FOCUSED)? true : false, 0); } else { // set flag that lock CAF is needed once focus state becomes focsued/not focused mParameters.setLockCAFNeeded(true); rc = NO_ERROR; } break; case CAM_FOCUS_MODE_INFINITY: case CAM_FOCUS_MODE_FIXED: case CAM_FOCUS_MODE_EDOF: default: ALOGE("%s: No ops in focusMode (%d)", __func__, focusMode); rc = BAD_VALUE; break; } return rc; } /*=========================================================================== * FUNCTION : cancelAutoFocus * * DESCRIPTION: cancel auto focus impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::cancelAutoFocus() { int rc = NO_ERROR; cam_focus_mode_type focusMode = mParameters.getFocusMode(); switch (focusMode) { case CAM_FOCUS_MODE_AUTO: case CAM_FOCUS_MODE_MACRO: if (mParameters.isAFRunning()) { rc = mCameraHandle->ops->cancel_auto_focus(mCameraHandle->camera_handle); if (rc == NO_ERROR) { mParameters.setAFRunning(false); } } break; case CAM_FOCUS_MODE_CONTINOUS_VIDEO: case CAM_FOCUS_MODE_CONTINOUS_PICTURE: if (mParameters.isCAFLocked()) { // resume CAF by unlock CAF rc = mParameters.setLockCAF(false);; mParameters.setLockCAFNeeded(false); } break; case CAM_FOCUS_MODE_INFINITY: case CAM_FOCUS_MODE_FIXED: case CAM_FOCUS_MODE_EDOF: default: ALOGI("%s: No ops in focusMode (%d)", __func__, focusMode); break; } return rc; } /*=========================================================================== * FUNCTION : takePicture * * DESCRIPTION: take picture impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::takePicture() { int rc = NO_ERROR; uint8_t numSnapshots = mParameters.getNumOfSnapshots(); ALOGD("%s: E", __func__); if (mParameters.isZSLMode()) { QCameraPicChannel *pZSLChannel = (QCameraPicChannel *)m_channels[QCAMERA_CH_TYPE_ZSL]; if (NULL != pZSLChannel) { // start postprocessor m_postprocessor.start(pZSLChannel); rc = pZSLChannel->takePicture(numSnapshots); if (rc != NO_ERROR) { ALOGE("%s: cannot take ZSL picture", __func__); m_postprocessor.stop(); return rc; } } else { ALOGE("%s: ZSL channel is NULL", __func__); return UNKNOWN_ERROR; } } else { // normal capture case // need to stop preview channel stopChannel(QCAMERA_CH_TYPE_PREVIEW); delChannel(QCAMERA_CH_TYPE_PREVIEW); // start snapshot if (mParameters.isJpegPictureFormat() || mParameters.isNV16PictureFormat() ) { rc = addCaptureChannel(); if (rc == NO_ERROR) { // start postprocessor m_postprocessor.start(m_channels[QCAMERA_CH_TYPE_CAPTURE]); // start catpure channel rc = startChannel(QCAMERA_CH_TYPE_CAPTURE); if (rc != NO_ERROR) { ALOGE("%s: cannot start capture channel", __func__); m_postprocessor.stop(); delChannel(QCAMERA_CH_TYPE_CAPTURE); return rc; } } else { ALOGE("%s: cannot add capture channel", __func__); return rc; } } else { rc = addRawChannel(); if (rc == NO_ERROR) { // start postprocessor m_postprocessor.start(m_channels[QCAMERA_CH_TYPE_RAW]); rc = startChannel(QCAMERA_CH_TYPE_RAW); if (rc != NO_ERROR) { ALOGE("%s: cannot start raw channel", __func__); m_postprocessor.stop(); delChannel(QCAMERA_CH_TYPE_RAW); return rc; } } else { ALOGE("%s: cannot add raw channel", __func__); return rc; } } } ALOGD("%s: X", __func__); return rc; } /*=========================================================================== * FUNCTION : cancelPicture * * DESCRIPTION: cancel picture impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::cancelPicture() { //stop post processor m_postprocessor.stop(); if (mParameters.isZSLMode()) { QCameraPicChannel *pZSLChannel = (QCameraPicChannel *)m_channels[QCAMERA_CH_TYPE_ZSL]; if (NULL != pZSLChannel) { if (m_bStartZSLSnapshotCalled) { mCameraHandle->ops->stop_zsl_snapshot( mCameraHandle->camera_handle); m_bStartZSLSnapshotCalled = false; } pZSLChannel->cancelPicture(); } } else { // normal capture case if (mParameters.isJpegPictureFormat() || mParameters.isNV16PictureFormat() ) { stopChannel(QCAMERA_CH_TYPE_CAPTURE); delChannel(QCAMERA_CH_TYPE_CAPTURE); } else { stopChannel(QCAMERA_CH_TYPE_RAW); delChannel(QCAMERA_CH_TYPE_RAW); } } return NO_ERROR; } /*=========================================================================== * FUNCTION : takeLiveSnapshot * * DESCRIPTION: take live snapshot during recording * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::takeLiveSnapshot() { int rc = NO_ERROR; // start post processor rc = m_postprocessor.start(m_channels[QCAMERA_CH_TYPE_SNAPSHOT]); // start snapshot channel if (rc == NO_ERROR) { rc = startChannel(QCAMERA_CH_TYPE_SNAPSHOT); } return rc; } /*=========================================================================== * FUNCTION : cancelLiveSnapshot * * DESCRIPTION: cancel current live snapshot request * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::cancelLiveSnapshot() { int rc = NO_ERROR; //stop post processor m_postprocessor.stop(); // stop snapshot channel rc = stopChannel(QCAMERA_CH_TYPE_SNAPSHOT); return rc; } /*=========================================================================== * FUNCTION : getParameters * * DESCRIPTION: get parameters impl * * PARAMETERS : none * * RETURN : a string containing parameter pairs *==========================================================================*/ char* QCamera2HardwareInterface::getParameters() { char* strParams = NULL; String8 str; str = mParameters.flatten( ); strParams = (char *)malloc(sizeof(char)*(str.length()+1)); if(strParams != NULL){ memset(strParams, 0, sizeof(char)*(str.length()+1)); strncpy(strParams, str.string(), str.length()); strParams[str.length()] = 0; } return strParams; } /*=========================================================================== * FUNCTION : putParameters * * DESCRIPTION: put parameters string impl * * PARAMETERS : * @parms : parameters string to be released * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::putParameters(char *parms) { free(parms); return NO_ERROR; } /*=========================================================================== * FUNCTION : sendCommand * * DESCRIPTION: send command impl * * PARAMETERS : * @command : command to be executed * @arg1 : optional argument 1 * @arg2 : optional argument 2 * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::sendCommand(int32_t command, int32_t /*arg1*/, int32_t /*arg2*/) { int rc = NO_ERROR; switch (command) { case CAMERA_CMD_START_FACE_DETECTION: case CAMERA_CMD_STOP_FACE_DETECTION: rc = setFaceDetection(command == CAMERA_CMD_START_FACE_DETECTION? true : false); break; default: rc = NO_ERROR; break; } return rc; } /*=========================================================================== * FUNCTION : registerFaceImage * * DESCRIPTION: register face image impl * * PARAMETERS : * @img_ptr : ptr to image buffer * @config : ptr to config struct about input image info * @faceID : [OUT] face ID to uniquely identifiy the registered face image * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::registerFaceImage(void *img_ptr, cam_pp_offline_src_config_t *config, int32_t &faceID) { int rc = NO_ERROR; faceID = -1; if (img_ptr == NULL || config == NULL) { ALOGE("%s: img_ptr or config is NULL", __func__); return BAD_VALUE; } // allocate ion memory for source image QCameraHeapMemory *imgBuf = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE); if (imgBuf == NULL) { ALOGE("%s: Unable to new heap memory obj for image buf", __func__); return NO_MEMORY; } rc = imgBuf->allocate(1, config->input_buf_planes.plane_info.frame_len); if (rc < 0) { ALOGE("%s: Unable to allocate heap memory for image buf", __func__); delete imgBuf; return NO_MEMORY; } void *pBufPtr = imgBuf->getPtr(0); if (pBufPtr == NULL) { ALOGE("%s: image buf is NULL", __func__); imgBuf->deallocate(); delete imgBuf; return NO_MEMORY; } memcpy(pBufPtr, img_ptr, config->input_buf_planes.plane_info.frame_len); cam_pp_feature_config_t pp_feature; memset(&pp_feature, 0, sizeof(cam_pp_feature_config_t)); pp_feature.feature_mask = CAM_QCOM_FEATURE_REGISTER_FACE; QCameraReprocessChannel *pChannel = addOfflineReprocChannel(*config, pp_feature, NULL, NULL); if (pChannel == NULL) { ALOGE("%s: fail to add offline reprocess channel", __func__); imgBuf->deallocate(); delete imgBuf; return UNKNOWN_ERROR; } rc = pChannel->start(); if (rc != NO_ERROR) { ALOGE("%s: Cannot start reprocess channel", __func__); imgBuf->deallocate(); delete imgBuf; delete pChannel; return rc; } rc = pChannel->doReprocess(imgBuf->getFd(0), imgBuf->getSize(0), faceID); // done with register face image, free imgbuf and delete reprocess channel imgBuf->deallocate(); delete imgBuf; imgBuf = NULL; pChannel->stop(); delete pChannel; pChannel = NULL; return rc; } /*=========================================================================== * FUNCTION : release * * DESCRIPTION: release camera resource impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::release() { // stop and delete all channels for (int i = 0; i <QCAMERA_CH_TYPE_MAX ; i++) { if (m_channels[i] != NULL) { stopChannel((qcamera_ch_type_enum_t)i); delChannel((qcamera_ch_type_enum_t)i); } } return NO_ERROR; } /*=========================================================================== * FUNCTION : dump * * DESCRIPTION: camera status dump impl * * PARAMETERS : * @fd : fd for the buffer to be dumped with camera status * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::dump(int /*fd*/) { ALOGE("%s: not supported yet", __func__); return INVALID_OPERATION; } /*=========================================================================== * FUNCTION : processAPI * * DESCRIPTION: process API calls from upper layer * * PARAMETERS : * @api : API to be processed * @api_payload : ptr to API payload if any * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::processAPI(qcamera_sm_evt_enum_t api, void *api_payload) { return m_stateMachine.procAPI(api, api_payload); } /*=========================================================================== * FUNCTION : processEvt * * DESCRIPTION: process Evt from backend via mm-camera-interface * * PARAMETERS : * @evt : event type to be processed * @evt_payload : ptr to event payload if any * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::processEvt(qcamera_sm_evt_enum_t evt, void *evt_payload) { return m_stateMachine.procEvt(evt, evt_payload); } /*=========================================================================== * FUNCTION : processSyncEvt * * DESCRIPTION: process synchronous Evt from backend * * PARAMETERS : * @evt : event type to be processed * @evt_payload : ptr to event payload if any * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::processSyncEvt(qcamera_sm_evt_enum_t evt, void *evt_payload) { int rc = NO_ERROR; pthread_mutex_lock(&m_evtLock); rc = processEvt(evt, evt_payload); if (rc == NO_ERROR) { memset(&m_evtResult, 0, sizeof(qcamera_api_result_t)); while (m_evtResult.request_api != evt) { pthread_cond_wait(&m_evtCond, &m_evtLock); } rc = m_evtResult.status; } pthread_mutex_unlock(&m_evtLock); return rc; } /*=========================================================================== * FUNCTION : evtHandle * * DESCRIPTION: Function registerd to mm-camera-interface to handle backend events * * PARAMETERS : * @camera_handle : event type to be processed * @evt : ptr to event * @user_data : user data ptr * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::camEvtHandle(uint32_t /*camera_handle*/, mm_camera_event_t *evt, void *user_data) { QCamera2HardwareInterface *obj = (QCamera2HardwareInterface *)user_data; if (obj && evt) { mm_camera_event_t *payload = (mm_camera_event_t *)malloc(sizeof(mm_camera_event_t)); if (NULL != payload) { *payload = *evt; obj->processEvt(QCAMERA_SM_EVT_EVT_NOTIFY, payload); } } else { ALOGE("%s: NULL user_data", __func__); } } /*=========================================================================== * FUNCTION : jpegEvtHandle * * DESCRIPTION: Function registerd to mm-jpeg-interface to handle jpeg events * * PARAMETERS : * @status : status of jpeg job * @client_hdl: jpeg client handle * @jobId : jpeg job Id * @p_ouput : ptr to jpeg output result struct * @userdata : user data ptr * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::jpegEvtHandle(jpeg_job_status_t status, uint32_t /*client_hdl*/, uint32_t jobId, mm_jpeg_output_t *p_output, void *userdata) { QCamera2HardwareInterface *obj = (QCamera2HardwareInterface *)userdata; if (obj) { qcamera_jpeg_evt_payload_t *payload = (qcamera_jpeg_evt_payload_t *)malloc(sizeof(qcamera_jpeg_evt_payload_t)); if (NULL != payload) { memset(payload, 0, sizeof(qcamera_jpeg_evt_payload_t)); payload->status = status; payload->jobId = jobId; if (p_output != NULL) { payload->out_data = *p_output; } obj->processEvt(QCAMERA_SM_EVT_JPEG_EVT_NOTIFY, payload); } } else { ALOGE("%s: NULL user_data", __func__); } } /*=========================================================================== * FUNCTION : thermalEvtHandle * * DESCRIPTION: routine to handle thermal event notification * * PARAMETERS : * @level : thermal level * @userdata : userdata passed in during registration * @data : opaque data from thermal client * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::thermalEvtHandle( qcamera_thermal_level_enum_t level, void *userdata, void *data) { // Make sure thermal events are logged ALOGI("%s: level = %d, userdata = %p, data = %p", __func__, level, userdata, data); //We don't need to lockAPI, waitAPI here. QCAMERA_SM_EVT_THERMAL_NOTIFY // becomes an aync call. This also means we can only pass payload // by value, not by address. return processAPI(QCAMERA_SM_EVT_THERMAL_NOTIFY, (void *)level); } /*=========================================================================== * FUNCTION : sendEvtNotify * * DESCRIPTION: send event notify to notify thread * * PARAMETERS : * @msg_type: msg type to be sent * @ext1 : optional extension1 * @ext2 : optional extension2 * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::sendEvtNotify(int32_t msg_type, int32_t ext1, int32_t ext2) { qcamera_callback_argm_t cbArg; memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); cbArg.cb_type = QCAMERA_NOTIFY_CALLBACK; cbArg.msg_type = msg_type; cbArg.ext1 = ext1; cbArg.ext2 = ext2; return m_cbNotifier.notifyCallback(cbArg); } /*=========================================================================== * FUNCTION : processAutoFocusEvent * * DESCRIPTION: process auto focus event * * PARAMETERS : * @focus_data: struct containing auto focus result info * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::processAutoFocusEvent(cam_auto_focus_data_t &focus_data) { int32_t ret = NO_ERROR; m_currentFocusState = focus_data.focus_state; cam_focus_mode_type focusMode = mParameters.getFocusMode(); switch (focusMode) { case CAM_FOCUS_MODE_AUTO: case CAM_FOCUS_MODE_MACRO: if (mParameters.isAFRunning()) { if (focus_data.focus_state == CAM_AF_SCANNING) { // in the middle of focusing, just ignore it break; } // update focus distance mParameters.updateFocusDistances(&focus_data.focus_dist); ret = sendEvtNotify(CAMERA_MSG_FOCUS, (focus_data.focus_state == CAM_AF_FOCUSED)? true : false, 0); mParameters.setAFRunning(false); } else { ret = UNKNOWN_ERROR; ALOGE("%s: autoFocusEvent when no auto_focus running", __func__); } break; case CAM_FOCUS_MODE_CONTINOUS_VIDEO: case CAM_FOCUS_MODE_CONTINOUS_PICTURE: if (focus_data.focus_state == CAM_AF_FOCUSED || focus_data.focus_state == CAM_AF_NOT_FOCUSED) { // update focus distance mParameters.updateFocusDistances(&focus_data.focus_dist); if (mParameters.isLockCAFNeeded()) { mParameters.setLockCAFNeeded(false); ret = mParameters.setLockCAF(true); } ret = sendEvtNotify(CAMERA_MSG_FOCUS, (focus_data.focus_state == CAM_AF_FOCUSED)? true : false, 0); } ret = sendEvtNotify(CAMERA_MSG_FOCUS_MOVE, (focus_data.focus_state == CAM_AF_SCANNING)? true : false, 0); break; case CAM_FOCUS_MODE_INFINITY: case CAM_FOCUS_MODE_FIXED: case CAM_FOCUS_MODE_EDOF: default: ALOGD("%s: no ops for autofocus event in focusmode %d", __func__, focusMode); break; } return ret; } /*=========================================================================== * FUNCTION : processZoomEvent * * DESCRIPTION: process zoom event * * PARAMETERS : * @crop_info : crop info as a result of zoom operation * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::processZoomEvent(cam_crop_data_t &crop_info) { int32_t ret = NO_ERROR; for (int i = 0; i < QCAMERA_CH_TYPE_MAX; i++) { if (m_channels[i] != NULL) { ret = m_channels[i]->processZoomDone(mPreviewWindow, crop_info); } } return ret; } /*=========================================================================== * FUNCTION : processPrepSnapshotDone * * DESCRIPTION: process prep snapshot done event * * PARAMETERS : * @prep_snapshot_state : state of prepare snapshot done. In other words, * i.e. whether need future frames for capture. * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::processPrepSnapshotDoneEvent( cam_prep_snapshot_state_t prep_snapshot_state) { int32_t ret = NO_ERROR; if (m_channels[QCAMERA_CH_TYPE_ZSL] && prep_snapshot_state == NEED_FUTURE_FRAME) { ret = mCameraHandle->ops->start_zsl_snapshot( mCameraHandle->camera_handle); if (ret < 0) { ALOGE("%s: start_led_zsl_capture failed %d", __func__, ret); return ret; } m_bStartZSLSnapshotCalled = true; } return ret; } /*=========================================================================== * FUNCTION : processJpegNotify * * DESCRIPTION: process jpeg event * * PARAMETERS : * @jpeg_evt: ptr to jpeg event payload * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::processJpegNotify(qcamera_jpeg_evt_payload_t *jpeg_evt) { return m_postprocessor.processJpegEvt(jpeg_evt); } /*=========================================================================== * FUNCTION : lockAPI * * DESCRIPTION: lock to process API * * PARAMETERS : none * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::lockAPI() { pthread_mutex_lock(&m_lock); } /*=========================================================================== * FUNCTION : waitAPIResult * * DESCRIPTION: wait for API result coming back. This is a blocking call, it will * return only cerntain API event type arrives * * PARAMETERS : * @api_evt : API event type * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::waitAPIResult(qcamera_sm_evt_enum_t api_evt) { ALOGV("%s: wait for API result of evt (%d)", __func__, api_evt); memset(&m_apiResult, 0, sizeof(qcamera_api_result_t)); while (m_apiResult.request_api != api_evt) { pthread_cond_wait(&m_cond, &m_lock); } ALOGV("%s: return (%d) from API result wait for evt (%d)", __func__, m_apiResult.status, api_evt); } /*=========================================================================== * FUNCTION : unlockAPI * * DESCRIPTION: API processing is done, unlock * * PARAMETERS : none * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::unlockAPI() { pthread_mutex_unlock(&m_lock); } /*=========================================================================== * FUNCTION : signalAPIResult * * DESCRIPTION: signal condition viarable that cerntain API event type arrives * * PARAMETERS : * @result : API result * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::signalAPIResult(qcamera_api_result_t *result) { pthread_mutex_lock(&m_lock); m_apiResult = *result; pthread_cond_signal(&m_cond); pthread_mutex_unlock(&m_lock); } /*=========================================================================== * FUNCTION : signalEvtResult * * DESCRIPTION: signal condition variable that certain event was processed * * PARAMETERS : * @result : Event result * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::signalEvtResult(qcamera_api_result_t *result) { pthread_mutex_lock(&m_evtLock); m_evtResult = *result; pthread_cond_signal(&m_evtCond); pthread_mutex_unlock(&m_evtLock); } /*=========================================================================== * FUNCTION : addStreamToChannel * * DESCRIPTION: add a stream into a channel * * PARAMETERS : * @pChannel : ptr to channel obj * @streamType : type of stream to be added * @streamCB : callback of stream * @userData : user data ptr to callback * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::addStreamToChannel(QCameraChannel *pChannel, cam_stream_type_t streamType, stream_cb_routine streamCB, void *userData) { int32_t rc = NO_ERROR; QCameraHeapMemory *pStreamInfo = allocateStreamInfoBuf(streamType); if (pStreamInfo == NULL) { ALOGE("%s: no mem for stream info buf", __func__); return NO_MEMORY; } uint8_t minStreamBufNum = getBufNumRequired(streamType); rc = pChannel->addStream(*this, pStreamInfo, minStreamBufNum, &gCamCapability[mCameraId]->padding_info, streamCB, userData); if (rc != NO_ERROR) { ALOGE("%s: add stream type (%d) failed, ret = %d", __func__, streamType, rc); pStreamInfo->deallocate(); delete pStreamInfo; return rc; } return rc; } /*=========================================================================== * FUNCTION : addPreviewChannel * * DESCRIPTION: add a preview channel that contains a preview stream * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::addPreviewChannel() { int32_t rc = NO_ERROR; QCameraChannel *pChannel = NULL; if (m_channels[QCAMERA_CH_TYPE_PREVIEW] != NULL) { // if we had preview channel before, delete it first delete m_channels[QCAMERA_CH_TYPE_PREVIEW]; m_channels[QCAMERA_CH_TYPE_PREVIEW] = NULL; } pChannel = new QCameraChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { ALOGE("%s: no mem for preview channel", __func__); return NO_MEMORY; } // preview only channel, don't need bundle attr and cb rc = pChannel->init(NULL, NULL, NULL); if (rc != NO_ERROR) { ALOGE("%s: init preview channel failed, ret = %d", __func__, rc); delete pChannel; return rc; } // meta data stream always coexists with preview if applicable rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_METADATA, metadata_stream_cb_routine, this); if (rc != NO_ERROR) { ALOGE("%s: add metadata stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } if (isNoDisplayMode()) { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_PREVIEW, nodisplay_preview_stream_cb_routine, this); } else { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_PREVIEW, preview_stream_cb_routine, this); } if (rc != NO_ERROR) { ALOGE("%s: add preview stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } m_channels[QCAMERA_CH_TYPE_PREVIEW] = pChannel; return rc; } /*=========================================================================== * FUNCTION : addVideoChannel * * DESCRIPTION: add a video channel that contains a video stream * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::addVideoChannel() { int32_t rc = NO_ERROR; QCameraVideoChannel *pChannel = NULL; if (m_channels[QCAMERA_CH_TYPE_VIDEO] != NULL) { // if we had video channel before, delete it first delete m_channels[QCAMERA_CH_TYPE_VIDEO]; m_channels[QCAMERA_CH_TYPE_VIDEO] = NULL; } pChannel = new QCameraVideoChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { ALOGE("%s: no mem for video channel", __func__); return NO_MEMORY; } // preview only channel, don't need bundle attr and cb rc = pChannel->init(NULL, NULL, NULL); if (rc != 0) { ALOGE("%s: init video channel failed, ret = %d", __func__, rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_VIDEO, video_stream_cb_routine, this); if (rc != NO_ERROR) { ALOGE("%s: add video stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } m_channels[QCAMERA_CH_TYPE_VIDEO] = pChannel; return rc; } /*=========================================================================== * FUNCTION : addSnapshotChannel * * DESCRIPTION: add a snapshot channel that contains a snapshot stream * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code * NOTE : Add this channel for live snapshot usecase. Regular capture will * use addCaptureChannel. *==========================================================================*/ int32_t QCamera2HardwareInterface::addSnapshotChannel() { int32_t rc = NO_ERROR; QCameraChannel *pChannel = NULL; if (m_channels[QCAMERA_CH_TYPE_SNAPSHOT] != NULL) { // if we had ZSL channel before, delete it first delete m_channels[QCAMERA_CH_TYPE_SNAPSHOT]; m_channels[QCAMERA_CH_TYPE_SNAPSHOT] = NULL; } pChannel = new QCameraChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { ALOGE("%s: no mem for snapshot channel", __func__); return NO_MEMORY; } rc = pChannel->init(NULL, NULL, NULL); if (rc != NO_ERROR) { ALOGE("%s: init snapshot channel failed, ret = %d", __func__, rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT, snapshot_stream_cb_routine, this); if (rc != NO_ERROR) { ALOGE("%s: add snapshot stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } m_channels[QCAMERA_CH_TYPE_SNAPSHOT] = pChannel; return rc; } /*=========================================================================== * FUNCTION : addRawChannel * * DESCRIPTION: add a raw channel that contains a raw image stream * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::addRawChannel() { int32_t rc = NO_ERROR; QCameraChannel *pChannel = NULL; if (m_channels[QCAMERA_CH_TYPE_RAW] != NULL) { // if we had raw channel before, delete it first delete m_channels[QCAMERA_CH_TYPE_RAW]; m_channels[QCAMERA_CH_TYPE_RAW] = NULL; } pChannel = new QCameraChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { ALOGE("%s: no mem for raw channel", __func__); return NO_MEMORY; } rc = pChannel->init(NULL, NULL, NULL); if (rc != NO_ERROR) { ALOGE("%s: init raw channel failed, ret = %d", __func__, rc); delete pChannel; return rc; } // meta data stream always coexists with snapshot in regular RAW capture case rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_METADATA, metadata_stream_cb_routine, this); if (rc != NO_ERROR) { ALOGE("%s: add metadata stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_RAW, raw_stream_cb_routine, this); if (rc != NO_ERROR) { ALOGE("%s: add snapshot stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } m_channels[QCAMERA_CH_TYPE_RAW] = pChannel; return rc; } /*=========================================================================== * FUNCTION : addZSLChannel * * DESCRIPTION: add a ZSL channel that contains a preview stream and * a snapshot stream * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::addZSLChannel() { int32_t rc = NO_ERROR; QCameraPicChannel *pChannel = NULL; if (m_channels[QCAMERA_CH_TYPE_ZSL] != NULL) { // if we had ZSL channel before, delete it first delete m_channels[QCAMERA_CH_TYPE_ZSL]; m_channels[QCAMERA_CH_TYPE_ZSL] = NULL; } pChannel = new QCameraPicChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { ALOGE("%s: no mem for ZSL channel", __func__); return NO_MEMORY; } // ZSL channel, init with bundle attr and cb mm_camera_channel_attr_t attr; memset(&attr, 0, sizeof(mm_camera_channel_attr_t)); attr.notify_mode = MM_CAMERA_SUPER_BUF_NOTIFY_BURST; attr.look_back = mParameters.getZSLBackLookCount(); attr.post_frame_skip = mParameters.getZSLBurstInterval(); attr.water_mark = mParameters.getZSLQueueDepth(); attr.max_unmatched_frames = mParameters.getMaxUnmatchedFramesInQueue(); rc = pChannel->init(&attr, zsl_channel_cb, this); if (rc != 0) { ALOGE("%s: init ZSL channel failed, ret = %d", __func__, rc); delete pChannel; return rc; } // meta data stream always coexists with preview if applicable rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_METADATA, metadata_stream_cb_routine, this); if (rc != NO_ERROR) { ALOGE("%s: add metadata stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } if (isNoDisplayMode()) { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_PREVIEW, nodisplay_preview_stream_cb_routine, this); } else { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_PREVIEW, preview_stream_cb_routine, this); } if (rc != NO_ERROR) { ALOGE("%s: add preview stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_SNAPSHOT, NULL, this); if (rc != NO_ERROR) { ALOGE("%s: add snapshot stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } m_channels[QCAMERA_CH_TYPE_ZSL] = pChannel; return rc; } /*=========================================================================== * FUNCTION : addCaptureChannel * * DESCRIPTION: add a capture channel that contains a snapshot stream * and a postview stream * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code * NOTE : Add this channel for regular capture usecase. * For Live snapshot usecase, use addSnapshotChannel. *==========================================================================*/ int32_t QCamera2HardwareInterface::addCaptureChannel() { int32_t rc = NO_ERROR; QCameraChannel *pChannel = NULL; if (m_channels[QCAMERA_CH_TYPE_CAPTURE] != NULL) { delete m_channels[QCAMERA_CH_TYPE_CAPTURE]; m_channels[QCAMERA_CH_TYPE_CAPTURE] = NULL; } pChannel = new QCameraChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { ALOGE("%s: no mem for capture channel", __func__); return NO_MEMORY; } // Capture channel, only need snapshot and postview streams start together mm_camera_channel_attr_t attr; memset(&attr, 0, sizeof(mm_camera_channel_attr_t)); attr.notify_mode = MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS; attr.max_unmatched_frames = mParameters.getMaxUnmatchedFramesInQueue(); rc = pChannel->init(&attr, capture_channel_cb_routine, this); if (rc != NO_ERROR) { ALOGE("%s: init capture channel failed, ret = %d", __func__, rc); delete pChannel; return rc; } // meta data stream always coexists with snapshot in regular capture case rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_METADATA, metadata_stream_cb_routine, this); if (rc != NO_ERROR) { ALOGE("%s: add metadata stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_POSTVIEW, postview_stream_cb_routine, this); if (rc != NO_ERROR) { ALOGE("%s: add postview stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_NON_ZSL_SNAPSHOT, NULL, this); if (rc != NO_ERROR) { ALOGE("%s: add snapshot stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } m_channels[QCAMERA_CH_TYPE_CAPTURE] = pChannel; return rc; } /*=========================================================================== * FUNCTION : addMetaDataChannel * * DESCRIPTION: add a meta data channel that contains a metadata stream * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::addMetaDataChannel() { int32_t rc = NO_ERROR; QCameraChannel *pChannel = NULL; if (m_channels[QCAMERA_CH_TYPE_METADATA] != NULL) { delete m_channels[QCAMERA_CH_TYPE_METADATA]; m_channels[QCAMERA_CH_TYPE_METADATA] = NULL; } pChannel = new QCameraChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { ALOGE("%s: no mem for metadata channel", __func__); return NO_MEMORY; } rc = pChannel->init(NULL, NULL, NULL); if (rc != NO_ERROR) { ALOGE("%s: init metadata channel failed, ret = %d", __func__, rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_METADATA, metadata_stream_cb_routine, this); if (rc != NO_ERROR) { ALOGE("%s: add metadata stream failed, ret = %d", __func__, rc); delete pChannel; return rc; } m_channels[QCAMERA_CH_TYPE_METADATA] = pChannel; return rc; } /*=========================================================================== * FUNCTION : addOnlineReprocChannel * * DESCRIPTION: add a online reprocess channel that will do reprocess on frames * coming from input channel * * PARAMETERS : * @pInputChannel : ptr to input channel whose frames will be post-processed * * RETURN : Ptr to the newly created channel obj. NULL if failed. *==========================================================================*/ QCameraReprocessChannel *QCamera2HardwareInterface::addOnlineReprocChannel( QCameraChannel *pInputChannel) { int32_t rc = NO_ERROR; QCameraReprocessChannel *pChannel = NULL; if (pInputChannel == NULL) { ALOGE("%s: input channel obj is NULL", __func__); return NULL; } pChannel = new QCameraReprocessChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { ALOGE("%s: no mem for reprocess channel", __func__); return NULL; } // Capture channel, only need snapshot and postview streams start together mm_camera_channel_attr_t attr; memset(&attr, 0, sizeof(mm_camera_channel_attr_t)); attr.notify_mode = MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS; attr.max_unmatched_frames = mParameters.getMaxUnmatchedFramesInQueue(); rc = pChannel->init(&attr, postproc_channel_cb_routine, this); if (rc != NO_ERROR) { ALOGE("%s: init reprocess channel failed, ret = %d", __func__, rc); delete pChannel; return NULL; } // pp feature config cam_pp_feature_config_t pp_config; memset(&pp_config, 0, sizeof(cam_pp_feature_config_t)); if (gCamCapability[mCameraId]->min_required_pp_mask & CAM_QCOM_FEATURE_SHARPNESS) { pp_config.feature_mask |= CAM_QCOM_FEATURE_SHARPNESS; pp_config.sharpness = mParameters.getInt(QCameraParameters::KEY_QC_SHARPNESS); } if (mParameters.isWNREnabled()) { pp_config.feature_mask |= CAM_QCOM_FEATURE_DENOISE2D; pp_config.denoise2d.denoise_enable = 1; pp_config.denoise2d.process_plates = mParameters.getWaveletDenoiseProcessPlate(); } if (isCACEnabled()) { pp_config.feature_mask |= CAM_QCOM_FEATURE_CAC; } if (needRotationReprocess()) { pp_config.feature_mask |= CAM_QCOM_FEATURE_ROTATION; int rotation = mParameters.getJpegRotation(); if (rotation == 0) { pp_config.rotation = ROTATE_0; } else if (rotation == 90) { pp_config.rotation = ROTATE_90; } else if (rotation == 180) { pp_config.rotation = ROTATE_180; } else if (rotation == 270) { pp_config.rotation = ROTATE_270; } } uint8_t minStreamBufNum = mParameters.getNumOfSnapshots(); rc = pChannel->addReprocStreamsFromSource(*this, pp_config, pInputChannel, minStreamBufNum, &gCamCapability[mCameraId]->padding_info); if (rc != NO_ERROR) { delete pChannel; return NULL; } return pChannel; } /*=========================================================================== * FUNCTION : addOfflineReprocChannel * * DESCRIPTION: add a offline reprocess channel contains one reproc stream, * that will do reprocess on frames coming from external images * * PARAMETERS : * @img_config : offline reporcess image info * @pp_feature : pp feature config * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ QCameraReprocessChannel *QCamera2HardwareInterface::addOfflineReprocChannel( cam_pp_offline_src_config_t &img_config, cam_pp_feature_config_t &pp_feature, stream_cb_routine stream_cb, void *userdata) { int32_t rc = NO_ERROR; QCameraReprocessChannel *pChannel = NULL; pChannel = new QCameraReprocessChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { ALOGE("%s: no mem for reprocess channel", __func__); return NULL; } rc = pChannel->init(NULL, NULL, NULL); if (rc != NO_ERROR) { ALOGE("%s: init reprocess channel failed, ret = %d", __func__, rc); delete pChannel; return NULL; } QCameraHeapMemory *pStreamInfo = allocateStreamInfoBuf(CAM_STREAM_TYPE_OFFLINE_PROC); if (pStreamInfo == NULL) { ALOGE("%s: no mem for stream info buf", __func__); delete pChannel; return NULL; } cam_stream_info_t *streamInfoBuf = (cam_stream_info_t *)pStreamInfo->getPtr(0); memset(streamInfoBuf, 0, sizeof(cam_stream_info_t)); streamInfoBuf->stream_type = CAM_STREAM_TYPE_OFFLINE_PROC; streamInfoBuf->fmt = img_config.input_fmt; streamInfoBuf->dim = img_config.input_dim; streamInfoBuf->buf_planes = img_config.input_buf_planes; streamInfoBuf->streaming_mode = CAM_STREAMING_MODE_BURST; streamInfoBuf->num_of_burst = img_config.num_of_bufs; streamInfoBuf->reprocess_config.pp_type = CAM_OFFLINE_REPROCESS_TYPE; streamInfoBuf->reprocess_config.offline = img_config; streamInfoBuf->reprocess_config.pp_feature_config = pp_feature; rc = pChannel->addStream(*this, pStreamInfo, img_config.num_of_bufs, &gCamCapability[mCameraId]->padding_info, stream_cb, userdata); if (rc != NO_ERROR) { ALOGE("%s: add reprocess stream failed, ret = %d", __func__, rc); pStreamInfo->deallocate(); delete pStreamInfo; delete pChannel; return NULL; } return pChannel; } /*=========================================================================== * FUNCTION : addChannel * * DESCRIPTION: add a channel by its type * * PARAMETERS : * @ch_type : channel type * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::addChannel(qcamera_ch_type_enum_t ch_type) { int32_t rc = UNKNOWN_ERROR; switch (ch_type) { case QCAMERA_CH_TYPE_ZSL: rc = addZSLChannel(); break; case QCAMERA_CH_TYPE_CAPTURE: rc = addCaptureChannel(); break; case QCAMERA_CH_TYPE_PREVIEW: rc = addPreviewChannel(); break; case QCAMERA_CH_TYPE_VIDEO: rc = addVideoChannel(); break; case QCAMERA_CH_TYPE_SNAPSHOT: rc = addSnapshotChannel(); break; case QCAMERA_CH_TYPE_RAW: rc = addRawChannel(); break; case QCAMERA_CH_TYPE_METADATA: rc = addMetaDataChannel(); break; default: break; } return rc; } /*=========================================================================== * FUNCTION : delChannel * * DESCRIPTION: delete a channel by its type * * PARAMETERS : * @ch_type : channel type * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::delChannel(qcamera_ch_type_enum_t ch_type) { if (m_channels[ch_type] != NULL) { delete m_channels[ch_type]; m_channels[ch_type] = NULL; } return NO_ERROR; } /*=========================================================================== * FUNCTION : startChannel * * DESCRIPTION: start a channel by its type * * PARAMETERS : * @ch_type : channel type * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::startChannel(qcamera_ch_type_enum_t ch_type) { int32_t rc = UNKNOWN_ERROR; if (m_channels[ch_type] != NULL) { rc = m_channels[ch_type]->start(); } return rc; } /*=========================================================================== * FUNCTION : stopChannel * * DESCRIPTION: stop a channel by its type * * PARAMETERS : * @ch_type : channel type * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::stopChannel(qcamera_ch_type_enum_t ch_type) { int32_t rc = UNKNOWN_ERROR; if (m_channels[ch_type] != NULL) { rc = m_channels[ch_type]->stop(); } return rc; } /*=========================================================================== * FUNCTION : preparePreview * * DESCRIPTION: add channels needed for preview * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::preparePreview() { int32_t rc = NO_ERROR; if (mParameters.isZSLMode() && mParameters.getRecordingHintValue() !=true) { rc = addChannel(QCAMERA_CH_TYPE_ZSL); if (rc != NO_ERROR) { return rc; } } else { bool recordingHint = mParameters.getRecordingHintValue(); if(recordingHint) { rc = addChannel(QCAMERA_CH_TYPE_SNAPSHOT); if (rc != NO_ERROR) { return rc; } rc = addChannel(QCAMERA_CH_TYPE_VIDEO); if (rc != NO_ERROR) { delChannel(QCAMERA_CH_TYPE_SNAPSHOT); return rc; } } rc = addChannel(QCAMERA_CH_TYPE_PREVIEW); if (rc != NO_ERROR) { if (recordingHint) { delChannel(QCAMERA_CH_TYPE_SNAPSHOT); delChannel(QCAMERA_CH_TYPE_VIDEO); } return rc; } } return rc; } /*=========================================================================== * FUNCTION : unpreparePreview * * DESCRIPTION: delete channels for preview * * PARAMETERS : none * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::unpreparePreview() { if (mParameters.isZSLMode() && mParameters.getRecordingHintValue() !=true) { delChannel(QCAMERA_CH_TYPE_ZSL); } else { delChannel(QCAMERA_CH_TYPE_PREVIEW); if(mParameters.getRecordingHintValue() == true) { delChannel(QCAMERA_CH_TYPE_VIDEO); delChannel(QCAMERA_CH_TYPE_SNAPSHOT); } } } /*=========================================================================== * FUNCTION : playShutter * * DESCRIPTION: send request to play shutter sound * * PARAMETERS : none * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::playShutter(){ if (mNotifyCb == NULL || msgTypeEnabledWithLock(CAMERA_MSG_SHUTTER) == 0){ ALOGV("%s: shutter msg not enabled or NULL cb", __func__); return; } qcamera_callback_argm_t cbArg; memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); cbArg.cb_type = QCAMERA_NOTIFY_CALLBACK; cbArg.msg_type = CAMERA_MSG_SHUTTER; cbArg.ext1 = 0; if(!m_bShutterSoundPlayed){ cbArg.ext2 = true; m_cbNotifier.notifyCallback(cbArg); } cbArg.ext2 = false; m_cbNotifier.notifyCallback(cbArg); m_bShutterSoundPlayed = false; } /*=========================================================================== * FUNCTION : getChannelByHandle * * DESCRIPTION: return a channel by its handle * * PARAMETERS : * @channelHandle : channel handle * * RETURN : a channel obj if found, NULL if not found *==========================================================================*/ QCameraChannel *QCamera2HardwareInterface::getChannelByHandle(uint32_t channelHandle) { for(int i = 0; i < QCAMERA_CH_TYPE_MAX; i++) { if (m_channels[i] != NULL && m_channels[i]->getMyHandle() == channelHandle) { return m_channels[i]; } } return NULL; } /*=========================================================================== * FUNCTION : processFaceDetectionReuslt * * DESCRIPTION: process face detection reuslt * * PARAMETERS : * @fd_data : ptr to face detection result struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::processFaceDetectionResult(cam_face_detection_data_t *fd_data) { if (!mParameters.isFaceDetectionEnabled()) { ALOGD("%s: FaceDetection not enabled, no ops here", __func__); return NO_ERROR; } if ((NULL == mDataCb) || (msgTypeEnabledWithLock(CAMERA_MSG_PREVIEW_METADATA) == 0)) { ALOGD("%s: prevew metadata msgtype not enabled, no ops here", __func__); return NO_ERROR; } cam_dimension_t display_dim; mParameters.getStreamDimension(CAM_STREAM_TYPE_PREVIEW, display_dim); if (display_dim.width <= 0 || display_dim.height <= 0) { ALOGE("%s: Invalid preview width or height (%d x %d)", __func__, display_dim.width, display_dim.height); return UNKNOWN_ERROR; } // process face detection result size_t faceResultSize = sizeof(camera_frame_metadata_t); faceResultSize += sizeof(camera_face_t) * MAX_ROI; camera_memory_t *faceResultBuffer = mGetMemory(-1, faceResultSize, 1, mCallbackCookie); if ( NULL == faceResultBuffer ) { ALOGE("%s: Not enough memory for face result data", __func__); return NO_MEMORY; } unsigned char *faceData = ( unsigned char * ) faceResultBuffer->data; memset(faceData, 0, faceResultSize); camera_frame_metadata_t *roiData = (camera_frame_metadata_t * ) faceData; camera_face_t *faces = (camera_face_t *) ( faceData + sizeof(camera_frame_metadata_t) ); roiData->number_of_faces = fd_data->num_faces_detected; roiData->faces = faces; if (roiData->number_of_faces > 0) { for (int i = 0; i < roiData->number_of_faces; i++) { faces[i].id = fd_data->faces[i].face_id; faces[i].score = fd_data->faces[i].score; // left faces[i].rect[0] = MAP_TO_DRIVER_COORDINATE(fd_data->faces[i].face_boundary.left, display_dim.width, 2000, -1000); // top faces[i].rect[1] = MAP_TO_DRIVER_COORDINATE(fd_data->faces[i].face_boundary.top, display_dim.height, 2000, -1000); // right faces[i].rect[2] = faces[i].rect[0] + MAP_TO_DRIVER_COORDINATE(fd_data->faces[i].face_boundary.width, display_dim.width, 2000, 0); // bottom faces[i].rect[3] = faces[i].rect[1] + MAP_TO_DRIVER_COORDINATE(fd_data->faces[i].face_boundary.height, display_dim.height, 2000, 0); // Center of left eye faces[i].left_eye[0] = MAP_TO_DRIVER_COORDINATE(fd_data->faces[i].left_eye_center.x, display_dim.width, 2000, -1000); faces[i].left_eye[1] = MAP_TO_DRIVER_COORDINATE(fd_data->faces[i].left_eye_center.y, display_dim.height, 2000, -1000); // Center of right eye faces[i].right_eye[0] = MAP_TO_DRIVER_COORDINATE(fd_data->faces[i].right_eye_center.x, display_dim.width, 2000, -1000); faces[i].right_eye[1] = MAP_TO_DRIVER_COORDINATE(fd_data->faces[i].right_eye_center.y, display_dim.height, 2000, -1000); // Center of mouth faces[i].mouth[0] = MAP_TO_DRIVER_COORDINATE(fd_data->faces[i].mouth_center.x, display_dim.width, 2000, -1000); faces[i].mouth[1] = MAP_TO_DRIVER_COORDINATE(fd_data->faces[i].mouth_center.y, display_dim.height, 2000, -1000); #if 0 faces[i].smile_degree = fd_data->faces[i].smile_degree; faces[i].smile_score = fd_data->faces[i].smile_confidence; faces[i].blink_detected = fd_data->faces[i].blink_detected; faces[i].face_recognised = fd_data->faces[i].face_recognised; faces[i].gaze_angle = fd_data->faces[i].gaze_angle; // upscale by 2 to recover from demaen downscaling faces[i].updown_dir = fd_data->faces[i].updown_dir * 2; faces[i].leftright_dir = fd_data->faces[i].leftright_dir * 2; faces[i].roll_dir = fd_data->faces[i].roll_dir * 2; faces[i].leye_blink = fd_data->faces[i].left_blink; faces[i].reye_blink = fd_data->faces[i].right_blink; faces[i].left_right_gaze = fd_data->faces[i].left_right_gaze; faces[i].top_bottom_gaze = fd_data->faces[i].top_bottom_gaze; #endif } } qcamera_callback_argm_t cbArg; memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); cbArg.cb_type = QCAMERA_DATA_CALLBACK; cbArg.msg_type = CAMERA_MSG_PREVIEW_METADATA; cbArg.data = faceResultBuffer; cbArg.metadata = roiData; cbArg.user_data = faceResultBuffer; cbArg.cookie = this; cbArg.release_cb = releaseCameraMemory; m_cbNotifier.notifyCallback(cbArg); return NO_ERROR; } /*=========================================================================== * FUNCTION : releaseCameraMemory * * DESCRIPTION: releases camera memory objects * * PARAMETERS : * @data : buffer to be released * @cookie : context data * * RETURN : None *==========================================================================*/ void QCamera2HardwareInterface::releaseCameraMemory(void *data, void */*cookie*/) { camera_memory_t *mem = ( camera_memory_t * ) data; if ( NULL != mem ) { mem->release(mem); } } /*=========================================================================== * FUNCTION : returnStreamBuffer * * DESCRIPTION: returns back a stream buffer * * PARAMETERS : * @data : buffer to be released * @cookie : context data * * RETURN : None *==========================================================================*/ void QCamera2HardwareInterface::returnStreamBuffer(void *data, void *cookie) { QCameraStream *stream = ( QCameraStream * ) cookie; int idx = ( int ) data; if ( ( NULL != stream )) { stream->bufDone(idx); } } /*=========================================================================== * FUNCTION : processHistogramStats * * DESCRIPTION: process histogram stats * * PARAMETERS : * @hist_data : ptr to histogram stats struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::processHistogramStats(cam_hist_stats_t &/*stats_data*/) { if (!mParameters.isHistogramEnabled()) { ALOGD("%s: Histogram not enabled, no ops here", __func__); return NO_ERROR; } camera_memory_t *histBuffer = mGetMemory(-1, sizeof(cam_histogram_data_t), 1, mCallbackCookie); if ( NULL == histBuffer ) { ALOGE("%s: Not enough memory for histogram data", __func__); return NO_MEMORY; } cam_histogram_data_t *pHistData = (cam_histogram_data_t *)histBuffer->data; if (pHistData == NULL) { ALOGE("%s: memory data ptr is NULL", __func__); return UNKNOWN_ERROR; } return NO_ERROR; } /*=========================================================================== * FUNCTION : updateThermalLevel * * DESCRIPTION: update thermal level depending on thermal events * * PARAMETERS : * @level : thermal level * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::updateThermalLevel( qcamera_thermal_level_enum_t level) { int ret = NO_ERROR; cam_fps_range_t adjustedRange; int minFPS, maxFPS; qcamera_thermal_mode thermalMode = mParameters.getThermalMode(); enum msm_vfe_frame_skip_pattern skipPattern; mParameters.getPreviewFpsRange(&minFPS, &maxFPS); switch(level) { case QCAMERA_THERMAL_NO_ADJUSTMENT: { adjustedRange.min_fps = minFPS / 1000.0f; adjustedRange.max_fps = maxFPS / 1000.0f; skipPattern = NO_SKIP; } break; case QCAMERA_THERMAL_SLIGHT_ADJUSTMENT: { adjustedRange.min_fps = (minFPS / 2) / 1000.0f; adjustedRange.max_fps = (maxFPS / 2) / 1000.0f; if ( adjustedRange.min_fps < 1 ) { adjustedRange.min_fps = 1; } if ( adjustedRange.max_fps < 1 ) { adjustedRange.max_fps = 1; } skipPattern = EVERY_2FRAME; } break; case QCAMERA_THERMAL_BIG_ADJUSTMENT: { adjustedRange.min_fps = (minFPS / 4) / 1000.0f; adjustedRange.max_fps = (maxFPS / 4) / 1000.0f; if ( adjustedRange.min_fps < 1 ) { adjustedRange.min_fps = 1; } if ( adjustedRange.max_fps < 1 ) { adjustedRange.max_fps = 1; } skipPattern = EVERY_4FRAME; } break; case QCAMERA_THERMAL_SHUTDOWN: { // Stop Preview? // Set lowest min FPS for now adjustedRange.min_fps = minFPS/1000.0f; adjustedRange.max_fps = minFPS/1000.0f; for ( int i = 0 ; i < gCamCapability[mCameraId]->fps_ranges_tbl_cnt ; i++ ) { if ( gCamCapability[mCameraId]->fps_ranges_tbl[i].min_fps < adjustedRange.min_fps ) { adjustedRange.min_fps = gCamCapability[mCameraId]->fps_ranges_tbl[i].min_fps; adjustedRange.max_fps = adjustedRange.min_fps; } } skipPattern = MAX_SKIP; } break; default: { ALOGE("%s: Invalid thermal level %d", __func__, level); return BAD_VALUE; } break; } ALOGI("%s: Thermal level %d, FPS range [%3.2f,%3.2f], frameskip %d", __func__, level, adjustedRange.min_fps, adjustedRange.max_fps, skipPattern); if (thermalMode == QCAMERA_THERMAL_ADJUST_FPS) ret = mParameters.adjustPreviewFpsRange(&adjustedRange); else if (thermalMode == QCAMERA_THERMAL_ADJUST_FRAMESKIP) ret = mParameters.setFrameSkip(skipPattern); else ALOGE("%s: Incorrect thermal mode %d", __func__, thermalMode); return ret; } /*=========================================================================== * FUNCTION : updateParameters * * DESCRIPTION: update parameters * * PARAMETERS : * @parms : input parameters string * @needRestart : output, flag to indicate if preview restart is needed * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::updateParameters(const char *parms, bool &needRestart) { String8 str = String8(parms); QCameraParameters param(str); return mParameters.updateParameters(param, needRestart); } /*=========================================================================== * FUNCTION : commitParameterChanges * * DESCRIPTION: commit parameter changes to the backend to take effect * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code * NOTE : This function must be called after updateParameters. * Otherwise, no change will be passed to backend to take effect. *==========================================================================*/ int QCamera2HardwareInterface::commitParameterChanges() { int rc = mParameters.commitParameters(); if (rc == NO_ERROR) { // update number of snapshot based on committed parameters setting rc = mParameters.setNumOfSnapshot(); } return rc; } /*=========================================================================== * FUNCTION : needDebugFps * * DESCRIPTION: if fps log info need to be printed out * * PARAMETERS : none * * RETURN : true: need print out fps log * false: no need to print out fps log *==========================================================================*/ bool QCamera2HardwareInterface::needDebugFps() { return mParameters.isFpsDebugEnabled(); } /*=========================================================================== * FUNCTION : isCACEnabled * * DESCRIPTION: if CAC is enabled * * PARAMETERS : none * * RETURN : true: needed * false: no need *==========================================================================*/ bool QCamera2HardwareInterface::isCACEnabled() { char prop[PROPERTY_VALUE_MAX]; memset(prop, 0, sizeof(prop)); property_get("persist.camera.feature.cac", prop, "0"); int enableCAC = atoi(prop); return enableCAC == 1; } /*=========================================================================== * FUNCTION : needReprocess * * DESCRIPTION: if reprocess is needed * * PARAMETERS : none * * RETURN : true: needed * false: no need *==========================================================================*/ bool QCamera2HardwareInterface::needReprocess() { if (!mParameters.isJpegPictureFormat()) { // RAW image, no need to reprocess return false; } if (((gCamCapability[mCameraId]->min_required_pp_mask > 0) || mParameters.isWNREnabled() || isCACEnabled())) { // TODO: add for ZSL HDR later ALOGD("%s: need do reprocess for ZSL WNR or min PP reprocess", __func__); return true; } return needRotationReprocess(); } /*=========================================================================== * FUNCTION : needRotationReprocess * * DESCRIPTION: if rotation needs to be done by reprocess in pp * * PARAMETERS : none * * RETURN : true: needed * false: no need *==========================================================================*/ bool QCamera2HardwareInterface::needRotationReprocess() { if (!mParameters.isJpegPictureFormat()) { // RAW image, no need to reprocess return false; } if ((gCamCapability[mCameraId]->qcom_supported_feature_mask & CAM_QCOM_FEATURE_ROTATION) > 0 && mParameters.getJpegRotation() > 0) { // current rotation is not zero, and pp has the capability to process rotation ALOGD("%s: need do reprocess for rotation", __func__); return true; } return false; } /*=========================================================================== * FUNCTION : getThumbnailSize * * DESCRIPTION: get user set thumbnail size * * PARAMETERS : * @dim : output of thumbnail dimension * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::getThumbnailSize(cam_dimension_t &dim) { mParameters.getThumbnailSize(&dim.width, &dim.height); } /*=========================================================================== * FUNCTION : getJpegQuality * * DESCRIPTION: get user set jpeg quality * * PARAMETERS : none * * RETURN : jpeg quality setting *==========================================================================*/ int QCamera2HardwareInterface::getJpegQuality() { return mParameters.getJpegQuality(); } /*=========================================================================== * FUNCTION : getJpegRotation * * DESCRIPTION: get rotation information to be passed into jpeg encoding * * PARAMETERS : none * * RETURN : rotation information *==========================================================================*/ int QCamera2HardwareInterface::getJpegRotation() { return mParameters.getJpegRotation(); } /*=========================================================================== * FUNCTION : getExifData * * DESCRIPTION: get exif data to be passed into jpeg encoding * * PARAMETERS : none * * RETURN : exif data from user setting and GPS *==========================================================================*/ QCameraExif *QCamera2HardwareInterface::getExifData() { QCameraExif *exif = new QCameraExif(); if (exif == NULL) { ALOGE("%s: No memory for QCameraExif", __func__); return NULL; } int32_t rc = NO_ERROR; uint32_t count = 0; // add exif entries char dateTime[20]; memset(dateTime, 0, sizeof(dateTime)); count = 20; rc = mParameters.getExifDateTime(dateTime, count); if(rc == NO_ERROR) { exif->addEntry(EXIFTAGID_EXIF_DATE_TIME_ORIGINAL, EXIF_ASCII, count, (void *)dateTime); } else { ALOGE("%s: getExifDateTime failed", __func__); } rat_t focalLength; rc = mParameters.getExifFocalLength(&focalLength); if (rc == NO_ERROR) { exif->addEntry(EXIFTAGID_FOCAL_LENGTH, EXIF_RATIONAL, 1, (void *)&(focalLength)); } else { ALOGE("%s: getExifFocalLength failed", __func__); } uint16_t isoSpeed = mParameters.getExifIsoSpeed(); exif->addEntry(EXIFTAGID_ISO_SPEED_RATING, EXIF_SHORT, 1, (void *)&(isoSpeed)); char gpsProcessingMethod[EXIF_ASCII_PREFIX_SIZE + GPS_PROCESSING_METHOD_SIZE]; count = 0; rc = mParameters.getExifGpsProcessingMethod(gpsProcessingMethod, count); if(rc == NO_ERROR) { exif->addEntry(EXIFTAGID_GPS_PROCESSINGMETHOD, EXIF_ASCII, count, (void *)gpsProcessingMethod); } else { ALOGE("%s: getExifGpsProcessingMethod failed", __func__); } rat_t latitude[3]; char latRef[2]; rc = mParameters.getExifLatitude(latitude, latRef); if(rc == NO_ERROR) { exif->addEntry(EXIFTAGID_GPS_LATITUDE, EXIF_RATIONAL, 3, (void *)latitude); exif->addEntry(EXIFTAGID_GPS_LATITUDE_REF, EXIF_ASCII, 2, (void *)latRef); } else { ALOGE("%s: getExifLatitude failed", __func__); } rat_t longitude[3]; char lonRef[2]; rc = mParameters.getExifLongitude(longitude, lonRef); if(rc == NO_ERROR) { exif->addEntry(EXIFTAGID_GPS_LONGITUDE, EXIF_RATIONAL, 3, (void *)longitude); exif->addEntry(EXIFTAGID_GPS_LONGITUDE_REF, EXIF_ASCII, 2, (void *)lonRef); } else { ALOGE("%s: getExifLongitude failed", __func__); } rat_t altitude; char altRef; rc = mParameters.getExifAltitude(&altitude, &altRef); if(rc == NO_ERROR) { exif->addEntry(EXIFTAGID_GPS_ALTITUDE, EXIF_RATIONAL, 1, (void *)&(altitude)); exif->addEntry(EXIFTAGID_GPS_ALTITUDE_REF, EXIF_BYTE, 1, (void *)&altRef); } else { ALOGE("%s: getExifAltitude failed", __func__); } char gpsDateStamp[20]; rat_t gpsTimeStamp[3]; rc = mParameters.getExifGpsDateTimeStamp(gpsDateStamp, 20, gpsTimeStamp); if(rc == NO_ERROR) { exif->addEntry(EXIFTAGID_GPS_DATESTAMP, EXIF_ASCII, strlen(gpsDateStamp) + 1, (void *)gpsDateStamp); exif->addEntry(EXIFTAGID_GPS_TIMESTAMP, EXIF_RATIONAL, 3, (void *)gpsTimeStamp); } else { ALOGE("%s: getExifGpsDataTimeStamp failed", __func__); } char value[PROPERTY_VALUE_MAX]; if (property_get("ro.product.manufacturer", value, "QCOM-AA") > 0) { exif->addEntry(EXIFTAGID_MAKE, EXIF_ASCII, strlen(value) + 1, (void *)value); } else { ALOGE("%s: getExifMaker failed", __func__); } if (property_get("ro.product.model", value, "QCAM-AA") > 0) { exif->addEntry(EXIFTAGID_MODEL, EXIF_ASCII, strlen(value) + 1, (void *)value); } else { ALOGE("%s: getExifModel failed", __func__); } return exif; } /*=========================================================================== * FUNCTION : setHistogram * * DESCRIPTION: set if histogram should be enabled * * PARAMETERS : * @histogram_en : bool flag if histogram should be enabled * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::setHistogram(bool histogram_en) { return mParameters.setHistogram(histogram_en); } /*=========================================================================== * FUNCTION : setFaceDetection * * DESCRIPTION: set if face detection should be enabled * * PARAMETERS : * @enabled : bool flag if face detection should be enabled * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::setFaceDetection(bool enabled) { return mParameters.setFaceDetection(enabled); } /*=========================================================================== * FUNCTION : prepareHardwareForSnapshot * * DESCRIPTION: prepare hardware for snapshot, such as LED * * PARAMETERS : * @afNeeded: flag indicating if Auto Focus needs to be done during preparation * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::prepareHardwareForSnapshot(int32_t afNeeded) { ALOGD("[KPI Perf] %s: Prepare hardware such as LED",__func__); return mCameraHandle->ops->prepare_snapshot(mCameraHandle->camera_handle, afNeeded); } }; // namespace qcamera