/* Copyright (c) 2012-2016, The Linux Foundation. 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" // To remove #include <cutils/properties.h> // System definitions #include <utils/Errors.h> #include <dlfcn.h> #include <stdio.h> #include <stdlib.h> #include "gralloc_priv.h" #include "native_handle.h" // Camera definitions #include "android/QCamera2External.h" #include "QCamera2HWI.h" #include "QCameraBufferMaps.h" #include "QCameraFlash.h" #include "QCameraTrace.h" extern "C" { #include "mm_camera_dbg.h" } #define MAP_TO_DRIVER_COORDINATE(val, base, scale, offset) \ ((int32_t)val * (int32_t)scale / (int32_t)base + (int32_t)offset) #define CAMERA_MIN_STREAMING_BUFFERS 3 #define EXTRA_ZSL_PREVIEW_STREAM_BUF 2 #define CAMERA_MIN_JPEG_ENCODING_BUFFERS 2 #define CAMERA_MIN_VIDEO_BUFFERS 9 #define CAMERA_MIN_CALLBACK_BUFFERS 5 #define CAMERA_LONGSHOT_STAGES 4 #define CAMERA_MIN_CAMERA_BATCH_BUFFERS 6 #define CAMERA_ISP_PING_PONG_BUFFERS 2 #define MIN_UNDEQUEUED_BUFFERS 1 // This is required if preview window is not set #define HDR_CONFIDENCE_THRESHOLD 0.4 #define CAMERA_OPEN_PERF_TIME_OUT 500 // 500 milliseconds // Very long wait, just to be sure we don't deadlock #define CAMERA_DEFERRED_THREAD_TIMEOUT 5000000000 // 5 seconds #define CAMERA_DEFERRED_MAP_BUF_TIMEOUT 2000000000 // 2 seconds #define CAMERA_MIN_METADATA_BUFFERS 10 // Need at least 10 for ZSL snapshot #define CAMERA_INITIAL_MAPPABLE_PREVIEW_BUFFERS 5 #define CAMERA_MAX_PARAM_APPLY_DELAY 3 namespace qcamera { extern cam_capability_t *gCamCapability[MM_CAMERA_MAX_NUM_SENSORS]; extern pthread_mutex_t gCamLock; volatile uint32_t gCamHalLogLevel = 1; extern uint8_t gNumCameraSessions; uint32_t QCamera2HardwareInterface::sNextJobId = 1; 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) { ATRACE_CALL(); int rc = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d window = %p", hw->getCameraId(), window); hw->lockAPI(); qcamera_api_result_t apiResult; rc = hw->processAPI(QCAMERA_SM_EVT_SET_PREVIEW_WINDOW, (void *)window); if (rc == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_PREVIEW_WINDOW, &apiResult); rc = apiResult.status; } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); 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) { ATRACE_CALL(); QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return; } LOGD("E camera id %d", hw->getCameraId()); 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(); qcamera_api_result_t apiResult; int32_t rc = hw->processAPI(QCAMERA_SM_EVT_SET_CALLBACKS, (void *)&payload); if (rc == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_CALLBACKS, &apiResult); } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); } /*=========================================================================== * 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) { ATRACE_CALL(); QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; 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, &apiResult); } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); } /*=========================================================================== * 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) { ATRACE_CALL(); QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; 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, &apiResult); } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); } /*=========================================================================== * 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) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_MSG_TYPE_ENABLED, (void *)&msg_type); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_MSG_TYPE_ENABLED, &apiResult); ret = apiResult.enabled; } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); return ret; } /*=========================================================================== * FUNCTION : prepare_preview * * DESCRIPTION: prepare preview * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::prepare_preview(struct camera_device *device) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGH("[KPI Perf]: E PROFILE_PREPARE_PREVIEW camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; qcamera_sm_evt_enum_t evt = QCAMERA_SM_EVT_PREPARE_PREVIEW; ret = hw->processAPI(evt, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(evt, &apiResult); ret = apiResult.status; } hw->unlockAPI(); LOGH("[KPI Perf]: X"); 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) { KPI_ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGI("[KPI Perf]: E PROFILE_START_PREVIEW camera id %d", hw->getCameraId()); // Release the timed perf lock acquired in openCamera hw->m_perfLock.lock_rel_timed(); hw->m_perfLock.lock_acq(); hw->lockAPI(); qcamera_api_result_t apiResult; 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, &apiResult); ret = apiResult.status; } hw->unlockAPI(); hw->m_bPreviewStarted = true; LOGI("[KPI Perf]: X ret = %d", ret); 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) { KPI_ATRACE_CALL(); QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return; } LOGI("[KPI Perf]: E PROFILE_STOP_PREVIEW camera id %d", hw->getCameraId()); // Disable power Hint for preview hw->m_perfLock.powerHint(POWER_HINT_VIDEO_ENCODE, false); hw->m_perfLock.lock_acq(); hw->lockAPI(); qcamera_api_result_t apiResult; int32_t ret = hw->processAPI(QCAMERA_SM_EVT_STOP_PREVIEW, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_STOP_PREVIEW, &apiResult); } hw->unlockAPI(); LOGI("[KPI Perf]: X ret = %d", ret); } /*=========================================================================== * 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) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_PREVIEW_ENABLED, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_PREVIEW_ENABLED, &apiResult); ret = apiResult.enabled; } //if preview enabled, can enable preview callback send if(apiResult.enabled) { hw->m_stateMachine.setPreviewCallbackNeeded(true); } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); 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) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; 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, &apiResult); ret = apiResult.status; } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); return ret; } /*=========================================================================== * FUNCTION : restart_start_preview * * DESCRIPTION: start preview as part of the restart preview * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::restart_start_preview(struct camera_device *device) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGI("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; if (hw->getRelatedCamSyncInfo()->sync_control == CAM_SYNC_RELATED_SENSORS_ON) { ret = hw->processAPI(QCAMERA_SM_EVT_RESTART_START_PREVIEW, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_RESTART_START_PREVIEW, &apiResult); ret = apiResult.status; } } else { LOGE("This function is not supposed to be called in single-camera mode"); ret = INVALID_OPERATION; } // Preview restart done, update the mPreviewRestartNeeded flag to false. hw->mPreviewRestartNeeded = false; hw->unlockAPI(); LOGI("X camera id %d", hw->getCameraId()); return ret; } /*=========================================================================== * FUNCTION : restart_stop_preview * * DESCRIPTION: stop preview as part of the restart preview * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::restart_stop_preview(struct camera_device *device) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGI("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; if (hw->getRelatedCamSyncInfo()->sync_control == CAM_SYNC_RELATED_SENSORS_ON) { ret = hw->processAPI(QCAMERA_SM_EVT_RESTART_STOP_PREVIEW, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_RESTART_STOP_PREVIEW, &apiResult); ret = apiResult.status; } } else { LOGE("This function is not supposed to be called in single-camera mode"); ret = INVALID_OPERATION; } hw->unlockAPI(); LOGI("X camera id %d", hw->getCameraId()); return ret; } /*=========================================================================== * FUNCTION : pre_start_recording * * DESCRIPTION: prepare for the start recording * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::pre_start_recording(struct camera_device *device) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGH("[KPI Perf]: E PROFILE_PRE_START_RECORDING camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_PRE_START_RECORDING, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_PRE_START_RECORDING, &apiResult); ret = apiResult.status; } hw->unlockAPI(); LOGH("[KPI Perf]: X"); 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) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGI("[KPI Perf]: E PROFILE_START_RECORDING camera id %d", hw->getCameraId()); // Give HWI control to call pre_start_recording in single camera mode. // In dual-cam mode, this control belongs to muxer. if (hw->getRelatedCamSyncInfo()->sync_control != CAM_SYNC_RELATED_SENSORS_ON) { ret = pre_start_recording(device); if (ret != NO_ERROR) { LOGE("pre_start_recording failed with ret = %d", ret); return ret; } } hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_START_RECORDING, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_START_RECORDING, &apiResult); ret = apiResult.status; } hw->unlockAPI(); hw->m_bRecordStarted = true; LOGI("[KPI Perf]: X ret = %d", ret); 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) { ATRACE_CALL(); QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return; } LOGI("[KPI Perf]: E PROFILE_STOP_RECORDING camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; int32_t ret = hw->processAPI(QCAMERA_SM_EVT_STOP_RECORDING, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_STOP_RECORDING, &apiResult); } hw->unlockAPI(); LOGI("[KPI Perf]: X ret = %d", ret); } /*=========================================================================== * 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) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_RECORDING_ENABLED, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_RECORDING_ENABLED, &apiResult); ret = apiResult.enabled; } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); 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) { ATRACE_CALL(); int32_t ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return; } if (!opaque) { LOGE("Error!! Frame info is NULL"); return; } LOGD("E camera id %d", hw->getCameraId()); //Close and delete duplicated native handle and FD's. if (hw->mVideoMem != NULL) { ret = hw->mVideoMem->closeNativeHandle(opaque, hw->mStoreMetaDataInFrame > 0); if (ret != NO_ERROR) { LOGE("Invalid video metadata"); return; } } else { LOGW("Possible FD leak. Release recording called after stop"); } hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_RELEASE_RECORIDNG_FRAME, (void *)opaque); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_RELEASE_RECORIDNG_FRAME, &apiResult); } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); } /*=========================================================================== * 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) { KPI_ATRACE_INT("Camera:AutoFocus", 1); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGH("[KPI Perf] : E PROFILE_AUTO_FOCUS camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_START_AUTO_FOCUS, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_START_AUTO_FOCUS, &apiResult); ret = apiResult.status; } hw->unlockAPI(); LOGH("[KPI Perf] : X ret = %d", ret); 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) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGH("[KPI Perf] : E PROFILE_CANCEL_AUTO_FOCUS camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_STOP_AUTO_FOCUS, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_STOP_AUTO_FOCUS, &apiResult); ret = apiResult.status; } hw->unlockAPI(); LOGH("[KPI Perf] : X ret = %d", ret); return ret; } /*=========================================================================== * FUNCTION : pre_take_picture * * DESCRIPTION: pre take picture, restart preview if necessary. * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::pre_take_picture(struct camera_device *device) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGH("[KPI Perf]: E PROFILE_PRE_TAKE_PICTURE camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_PRE_TAKE_PICTURE, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_PRE_TAKE_PICTURE, &apiResult); ret = apiResult.status; } hw->unlockAPI(); LOGH("[KPI Perf]: X"); 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) { KPI_ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGI("[KPI Perf]: E PROFILE_TAKE_PICTURE camera id %d", hw->getCameraId()); if (!hw->mLongshotEnabled) { hw->m_perfLock.lock_acq(); } qcamera_api_result_t apiResult; /** Added support for Retro-active Frames: * takePicture() is called before preparing Snapshot to indicate the * mm-camera-channel to pick up legacy frames even * before LED estimation is triggered. */ LOGH("isLiveSnap %d, isZSL %d, isHDR %d longshot = %d", hw->isLiveSnapshot(), hw->isZSLMode(), hw->isHDRMode(), hw->isLongshotEnabled()); // Check for Retro-active Frames if ((hw->mParameters.getNumOfRetroSnapshots() > 0) && !hw->isLiveSnapshot() && hw->isZSLMode() && !hw->isHDRMode() && !hw->isLongshotEnabled()) { // Set Retro Picture Mode hw->setRetroPicture(1); hw->m_bLedAfAecLock = 0; LOGL("Retro Enabled"); // Give HWI control to call pre_take_picture in single camera mode. // In dual-cam mode, this control belongs to muxer. if (hw->getRelatedCamSyncInfo()->sync_control != CAM_SYNC_RELATED_SENSORS_ON) { ret = pre_take_picture(device); if (ret != NO_ERROR) { LOGE("pre_take_picture failed with ret = %d",ret); return ret; } } /* Call take Picture for total number of snapshots required. This includes the number of retro frames and normal frames */ hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_TAKE_PICTURE, NULL); if (ret == NO_ERROR) { // Wait for retro frames, before calling prepare snapshot LOGD("Wait for Retro frames to be done"); hw->waitAPIResult(QCAMERA_SM_EVT_TAKE_PICTURE, &apiResult); ret = apiResult.status; } /* Unlock API since it is acquired in prepare snapshot seperately */ hw->unlockAPI(); /* Prepare snapshot in case LED needs to be flashed */ LOGD("Start Prepare Snapshot"); ret = hw->prepare_snapshot(device); } else { hw->setRetroPicture(0); // Check if prepare snapshot is done if (!hw->mPrepSnapRun) { // Ignore the status from prepare_snapshot hw->prepare_snapshot(device); } // Give HWI control to call pre_take_picture in single camera mode. // In dual-cam mode, this control belongs to muxer. if (hw->getRelatedCamSyncInfo()->sync_control != CAM_SYNC_RELATED_SENSORS_ON) { ret = pre_take_picture(device); if (ret != NO_ERROR) { LOGE("pre_take_picture failed with ret = %d",ret); return ret; } } // Regardless what the result value for prepare_snapshot, // go ahead with capture anyway. Just like the way autofocus // is handled in capture case /* capture */ LOGL("Capturing normal frames"); hw->lockAPI(); ret = hw->processAPI(QCAMERA_SM_EVT_TAKE_PICTURE, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_TAKE_PICTURE, &apiResult); ret = apiResult.status; } hw->unlockAPI(); if (!hw->isLongshotEnabled()){ // For longshot mode, we prepare snapshot only once hw->mPrepSnapRun = false; } } LOGI("[KPI Perf]: X ret = %d", ret); 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) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGI("[KPI Perf]: E PROFILE_CANCEL_PICTURE camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_CANCEL_PICTURE, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_CANCEL_PICTURE, &apiResult); ret = apiResult.status; } hw->unlockAPI(); LOGI("[KPI Perf]: X camera id %d ret = %d", hw->getCameraId(), ret); 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) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS, (void *)parms); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS, &apiResult); ret = apiResult.status; } // Give HWI control to restart (if necessary) after set params // in single camera mode. In dual-cam mode, this control belongs to muxer. if (hw->getRelatedCamSyncInfo()->sync_control != CAM_SYNC_RELATED_SENSORS_ON) { if ((ret == NO_ERROR) && hw->getNeedRestart()) { LOGD("stopping after param change"); ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS_STOP, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS_STOP, &apiResult); ret = apiResult.status; } } if (ret == NO_ERROR) { LOGD("committing param change"); ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS_COMMIT, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS_COMMIT, &apiResult); ret = apiResult.status; } } if ((ret == NO_ERROR) && hw->getNeedRestart()) { LOGD("restarting after param change"); ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS_RESTART, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS_RESTART, &apiResult); ret = apiResult.status; } } } hw->unlockAPI(); LOGD("X camera id %d ret %d", hw->getCameraId(), ret); return ret; } /*=========================================================================== * FUNCTION : stop_after_set_params * * DESCRIPTION: stop after a set param call, if necessary * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::stop_after_set_params(struct camera_device *device) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; if (hw->getRelatedCamSyncInfo()->sync_control == CAM_SYNC_RELATED_SENSORS_ON) { ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS_STOP, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS_STOP, &apiResult); ret = apiResult.status; } } else { LOGE("is not supposed to be called in single-camera mode"); ret = INVALID_OPERATION; } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); return ret; } /*=========================================================================== * FUNCTION : commit_params * * DESCRIPTION: commit after a set param call * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::commit_params(struct camera_device *device) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; if (hw->getRelatedCamSyncInfo()->sync_control == CAM_SYNC_RELATED_SENSORS_ON) { ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS_COMMIT, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS_COMMIT, &apiResult); ret = apiResult.status; } } else { LOGE("is not supposed to be called in single-camera mode"); ret = INVALID_OPERATION; } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); return ret; } /*=========================================================================== * FUNCTION : restart_after_set_params * * DESCRIPTION: restart after a set param call, if necessary * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::restart_after_set_params(struct camera_device *device) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; if (hw->getRelatedCamSyncInfo()->sync_control == CAM_SYNC_RELATED_SENSORS_ON) { ret = hw->processAPI(QCAMERA_SM_EVT_SET_PARAMS_RESTART, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SET_PARAMS_RESTART, &apiResult); ret = apiResult.status; } } else { LOGE("is not supposed to be called in single-camera mode"); ret = INVALID_OPERATION; } hw->unlockAPI(); LOGD("X camera id %d", hw->getCameraId()); 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) { ATRACE_CALL(); char *ret = NULL; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return NULL; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; int32_t rc = hw->processAPI(QCAMERA_SM_EVT_GET_PARAMS, NULL); if (rc == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_GET_PARAMS, &apiResult); ret = apiResult.params; } hw->unlockAPI(); LOGD("E camera id %d", hw->getCameraId()); 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) { ATRACE_CALL(); QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; int32_t ret = hw->processAPI(QCAMERA_SM_EVT_PUT_PARAMS, (void *)parm); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_PUT_PARAMS, &apiResult); } hw->unlockAPI(); LOGD("E camera id %d", hw->getCameraId()); } /*=========================================================================== * 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) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d", hw->getCameraId()); 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(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_SEND_COMMAND, (void *)&payload); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SEND_COMMAND, &apiResult); ret = apiResult.status; } hw->unlockAPI(); LOGD("E camera id %d", hw->getCameraId()); return ret; } /*=========================================================================== * FUNCTION : send_command_restart * * DESCRIPTION: restart if necessary after a send_command * * 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_restart(struct camera_device *device, int32_t cmd, int32_t arg1, int32_t arg2) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("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(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_SEND_COMMAND_RESTART, (void *)&payload); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_SEND_COMMAND_RESTART, &apiResult); ret = apiResult.status; } hw->unlockAPI(); LOGD("E camera id %d", hw->getCameraId()); return ret; } /*=========================================================================== * FUNCTION : release * * DESCRIPTION: release camera resource * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::release(struct camera_device *device) { ATRACE_CALL(); QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; int32_t ret = hw->processAPI(QCAMERA_SM_EVT_RELEASE, NULL); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_RELEASE, &apiResult); } hw->unlockAPI(); LOGD("E camera id %d", hw->getCameraId()); } /*=========================================================================== * 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; //Log level property is read when "adb shell dumpsys media.camera" is //called so that the log level can be controlled without restarting //media server getLogLevel(); QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_DUMP, (void *)&fd); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_DUMP, &apiResult); ret = apiResult.status; } hw->unlockAPI(); LOGD("E camera id %d", hw->getCameraId()); 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) { KPI_ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>( reinterpret_cast<camera_device_t *>(hw_dev)->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGI("[KPI Perf]: E camera id %d", hw->getCameraId()); delete hw; LOGI("[KPI Perf]: X"); 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) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } LOGD("E camera id %d", hw->getCameraId()); 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(); qcamera_api_result_t apiResult; ret = hw->processAPI(QCAMERA_SM_EVT_REG_FACE_IMAGE, (void *)&payload); if (ret == NO_ERROR) { hw->waitAPIResult(QCAMERA_SM_EVT_REG_FACE_IMAGE, &apiResult); ret = apiResult.handle; } hw->unlockAPI(); LOGD("E camera id %d", hw->getCameraId()); return ret; } /*=========================================================================== * FUNCTION : prepare_snapshot * * DESCRIPTION: prepares hardware for snapshot * * PARAMETERS : * @device : ptr to camera device struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::prepare_snapshot(struct camera_device *device) { ATRACE_CALL(); int ret = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(device->priv); if (!hw) { LOGE("NULL camera device"); return BAD_VALUE; } if (hw->isLongshotEnabled() && hw->mPrepSnapRun == true) { // For longshot mode, we prepare snapshot only once LOGH("prepare snapshot only once "); return NO_ERROR; } LOGH("[KPI Perf]: E PROFILE_PREPARE_SNAPSHOT camera id %d", hw->getCameraId()); hw->lockAPI(); qcamera_api_result_t apiResult; /* Prepare snapshot in case LED needs to be flashed */ if (hw->mFlashNeeded || hw->mParameters.isChromaFlashEnabled()) { /* 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, &apiResult); ret = apiResult.status; } hw->mPrepSnapRun = true; } hw->unlockAPI(); LOGH("[KPI Perf]: X, ret: %d", ret); return ret; } /*=========================================================================== * FUNCTION : QCamera2HardwareInterface * * DESCRIPTION: constructor of QCamera2HardwareInterface * * PARAMETERS : * @cameraId : camera ID * * RETURN : none *==========================================================================*/ QCamera2HardwareInterface::QCamera2HardwareInterface(uint32_t cameraId) : mCameraId(cameraId), mCameraHandle(NULL), mCameraOpened(false), m_bRelCamCalibValid(false), mPreviewWindow(NULL), mMsgEnabled(0), mStoreMetaDataInFrame(0), mJpegCb(NULL), mCallbackCookie(NULL), mJpegCallbackCookie(NULL), m_bMpoEnabled(TRUE), m_stateMachine(this), m_smThreadActive(true), m_postprocessor(this), m_thermalAdapter(QCameraThermalAdapter::getInstance()), m_cbNotifier(this), m_bPreviewStarted(false), m_bRecordStarted(false), m_currentFocusState(CAM_AF_STATE_INACTIVE), mDumpFrmCnt(0U), mDumpSkipCnt(0U), mThermalLevel(QCAMERA_THERMAL_NO_ADJUSTMENT), mActiveAF(false), m_HDRSceneEnabled(false), mLongshotEnabled(false), mLiveSnapshotThread(0), mIntPicThread(0), mFlashNeeded(false), mDeviceRotation(0U), mCaptureRotation(0U), mJpegExifRotation(0U), mUseJpegExifRotation(false), mIs3ALocked(false), mPrepSnapRun(false), mZoomLevel(0), mPreviewRestartNeeded(false), mVFrameCount(0), mVLastFrameCount(0), mVLastFpsTime(0), mVFps(0), mPFrameCount(0), mPLastFrameCount(0), mPLastFpsTime(0), mPFps(0), mInstantAecFrameCount(0), m_bIntJpegEvtPending(false), m_bIntRawEvtPending(false), mReprocJob(0), mJpegJob(0), mMetadataAllocJob(0), mInitPProcJob(0), mParamAllocJob(0), mParamInitJob(0), mOutputCount(0), mInputCount(0), mAdvancedCaptureConfigured(false), mHDRBracketingEnabled(false), mNumPreviewFaces(-1), mJpegClientHandle(0), mJpegHandleOwner(false), mMetadataMem(NULL), mVideoMem(NULL), mCACDoneReceived(false), m_bNeedRestart(false) { #ifdef TARGET_TS_MAKEUP memset(&mFaceRect, -1, sizeof(mFaceRect)); #endif getLogLevel(); ATRACE_CALL(); 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); m_apiResultList = NULL; pthread_mutex_init(&m_evtLock, NULL); pthread_cond_init(&m_evtCond, NULL); memset(&m_evtResult, 0, sizeof(qcamera_api_result_t)); pthread_mutex_init(&m_int_lock, NULL); pthread_cond_init(&m_int_cond, NULL); memset(m_channels, 0, sizeof(m_channels)); memset(&mExifParams, 0, sizeof(mm_jpeg_exif_params_t)); memset(m_BackendFileName, 0, QCAMERA_MAX_FILEPATH_LENGTH); memset(mDefOngoingJobs, 0, sizeof(mDefOngoingJobs)); memset(&mJpegMetadata, 0, sizeof(mJpegMetadata)); memset(&mJpegHandle, 0, sizeof(mJpegHandle)); memset(&mJpegMpoHandle, 0, sizeof(mJpegMpoHandle)); mDeferredWorkThread.launch(deferredWorkRoutine, this); mDeferredWorkThread.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, FALSE, FALSE); m_perfLock.lock_init(); pthread_mutex_init(&mGrallocLock, NULL); mEnqueuedBuffers = 0; mFrameSkipStart = 0; mFrameSkipEnd = 0; mLastPreviewFrameID = 0; //Load and read GPU library. lib_surface_utils = NULL; LINK_get_surface_pixel_alignment = NULL; mSurfaceStridePadding = CAM_PAD_TO_32; lib_surface_utils = dlopen("libadreno_utils.so", RTLD_NOW); if (lib_surface_utils) { *(void **)&LINK_get_surface_pixel_alignment = dlsym(lib_surface_utils, "get_gpu_pixel_alignment"); if (LINK_get_surface_pixel_alignment) { mSurfaceStridePadding = LINK_get_surface_pixel_alignment(); } dlclose(lib_surface_utils); } } /*=========================================================================== * FUNCTION : ~QCamera2HardwareInterface * * DESCRIPTION: destructor of QCamera2HardwareInterface * * PARAMETERS : none * * RETURN : none *==========================================================================*/ QCamera2HardwareInterface::~QCamera2HardwareInterface() { LOGH("E"); mDeferredWorkThread.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, TRUE); mDeferredWorkThread.exit(); if (mMetadataMem != NULL) { delete mMetadataMem; mMetadataMem = NULL; } m_perfLock.lock_acq(); lockAPI(); m_smThreadActive = false; unlockAPI(); m_stateMachine.releaseThread(); closeCamera(); m_perfLock.lock_rel(); m_perfLock.lock_deinit(); pthread_mutex_destroy(&m_lock); pthread_cond_destroy(&m_cond); pthread_mutex_destroy(&m_evtLock); pthread_cond_destroy(&m_evtCond); pthread_mutex_destroy(&m_int_lock); pthread_cond_destroy(&m_int_cond); pthread_mutex_destroy(&mGrallocLock); LOGH("X"); } /*=========================================================================== * FUNCTION : deferPPInit * * DESCRIPTION: Queue postproc init task to deferred thread * * PARAMETERS : none * * RETURN : uint32_t job id of pproc init job * 0 -- failure *==========================================================================*/ uint32_t QCamera2HardwareInterface::deferPPInit() { // init pproc DeferWorkArgs args; DeferPProcInitArgs pprocInitArgs; memset(&args, 0, sizeof(DeferWorkArgs)); memset(&pprocInitArgs, 0, sizeof(DeferPProcInitArgs)); pprocInitArgs.jpeg_cb = jpegEvtHandle; pprocInitArgs.user_data = this; args.pprocInitArgs = pprocInitArgs; return queueDeferredWork(CMD_DEF_PPROC_INIT, args); } /*=========================================================================== * 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) { KPI_ATRACE_CALL(); int rc = NO_ERROR; if (mCameraOpened) { *hw_device = NULL; LOGE("Permission Denied"); return PERMISSION_DENIED; } LOGI("[KPI Perf]: E PROFILE_OPEN_CAMERA camera id %d", mCameraId); m_perfLock.lock_acq_timed(CAMERA_OPEN_PERF_TIME_OUT); rc = openCamera(); if (rc == NO_ERROR){ *hw_device = &mCameraDevice.common; if (m_thermalAdapter.init(this) != 0) { LOGW("Init thermal adapter failed"); } } else *hw_device = NULL; LOGI("[KPI Perf]: X PROFILE_OPEN_CAMERA camera id %d, rc: %d", mCameraId, rc); 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() { int32_t rc = NO_ERROR; char value[PROPERTY_VALUE_MAX]; if (mCameraHandle) { LOGE("Failure: Camera already opened"); return ALREADY_EXISTS; } rc = QCameraFlash::getInstance().reserveFlashForCamera(mCameraId); if (rc < 0) { LOGE("Failed to reserve flash for camera id: %d", mCameraId); return UNKNOWN_ERROR; } // alloc param buffer DeferWorkArgs args; memset(&args, 0, sizeof(args)); mParamAllocJob = queueDeferredWork(CMD_DEF_PARAM_ALLOC, args); if (mParamAllocJob == 0) { LOGE("Failed queueing PARAM_ALLOC job"); return -ENOMEM; } if (gCamCapability[mCameraId] != NULL) { // allocate metadata buffers DeferWorkArgs args; DeferMetadataAllocArgs metadataAllocArgs; memset(&args, 0, sizeof(args)); memset(&metadataAllocArgs, 0, sizeof(metadataAllocArgs)); uint32_t padding = gCamCapability[mCameraId]->padding_info.plane_padding; metadataAllocArgs.size = PAD_TO_SIZE(sizeof(metadata_buffer_t), padding); metadataAllocArgs.bufferCnt = CAMERA_MIN_METADATA_BUFFERS; args.metadataAllocArgs = metadataAllocArgs; mMetadataAllocJob = queueDeferredWork(CMD_DEF_METADATA_ALLOC, args); if (mMetadataAllocJob == 0) { LOGE("Failed to allocate metadata buffer"); rc = -ENOMEM; goto error_exit1; } rc = camera_open((uint8_t)mCameraId, &mCameraHandle); if (rc) { LOGE("camera_open failed. rc = %d, mCameraHandle = %p", rc, mCameraHandle); goto error_exit2; } mCameraHandle->ops->register_event_notify(mCameraHandle->camera_handle, camEvtHandle, (void *) this); } else { LOGH("Capabilities not inited, initializing now."); rc = camera_open((uint8_t)mCameraId, &mCameraHandle); if (rc) { LOGE("camera_open failed. rc = %d, mCameraHandle = %p", rc, mCameraHandle); goto error_exit2; } if(NO_ERROR != initCapabilities(mCameraId,mCameraHandle)) { LOGE("initCapabilities failed."); rc = UNKNOWN_ERROR; goto error_exit3; } mCameraHandle->ops->register_event_notify(mCameraHandle->camera_handle, camEvtHandle, (void *) this); } // Init params in the background // 1. It's safe to queue init job, even if alloc job is not yet complete. // It will be queued to the same thread, so the alloc is guaranteed to // finish first. // 2. However, it is not safe to begin param init until after camera is // open. That is why we wait until after camera open completes to schedule // this task. memset(&args, 0, sizeof(args)); mParamInitJob = queueDeferredWork(CMD_DEF_PARAM_INIT, args); if (mParamInitJob == 0) { LOGE("Failed queuing PARAM_INIT job"); rc = -ENOMEM; goto error_exit3; } mCameraOpened = true; //Notify display HAL that a camera session is active. //But avoid calling the same during bootup because camera service might open/close //cameras at boot time during its initialization and display service will also internally //wait for camera service to initialize first while calling this display API, resulting in a //deadlock situation. Since boot time camera open/close calls are made only to fetch //capabilities, no need of this display bw optimization. //Use "service.bootanim.exit" property to know boot status. property_get("service.bootanim.exit", value, "0"); if (atoi(value) == 1) { pthread_mutex_lock(&gCamLock); if (gNumCameraSessions++ == 0) { setCameraLaunchStatus(true); } pthread_mutex_unlock(&gCamLock); } return NO_ERROR; error_exit3: if(mJpegClientHandle) { deinitJpegHandle(); } mCameraHandle->ops->close_camera(mCameraHandle->camera_handle); mCameraHandle = NULL; error_exit2: waitDeferredWork(mMetadataAllocJob); error_exit1: waitDeferredWork(mParamAllocJob); return rc; } /*=========================================================================== * FUNCTION : bundleRelatedCameras * * DESCRIPTION: bundle cameras to enable syncing of cameras * * PARAMETERS : * @sync :indicates whether syncing is On or Off * @sessionid :session id for other camera session * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::bundleRelatedCameras(bool syncOn, uint32_t sessionid) { LOGD("bundleRelatedCameras sync %d with sessionid %d", syncOn, sessionid); int32_t rc = mParameters.bundleRelatedCameras(syncOn, sessionid); if (rc != NO_ERROR) { LOGE("bundleRelatedCameras failed %d", rc); return rc; } return rc; } /*=========================================================================== * FUNCTION : getCameraSessionId * * DESCRIPTION: gets the backend session Id of this HWI instance * * PARAMETERS : * @sessionid : pointer to the output session id * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::getCameraSessionId(uint32_t* session_id) { int32_t rc = NO_ERROR; if(session_id != NULL) { rc = mCameraHandle->ops->get_session_id(mCameraHandle->camera_handle, session_id); LOGD("Getting Camera Session Id %d", *session_id); } else { LOGE("Session Id is Null"); return UNKNOWN_ERROR; } return rc; } /*=========================================================================== * FUNCTION : isFrameSyncEnabled * * DESCRIPTION: returns whether frame sync is enabled * * PARAMETERS : none * * RETURN : bool indicating whether frame sync is enabled *==========================================================================*/ bool QCamera2HardwareInterface::isFrameSyncEnabled(void) { return mParameters.isFrameSyncEnabled(); } /*=========================================================================== * FUNCTION : setFrameSyncEnabled * * DESCRIPTION: sets whether frame sync is enabled * * PARAMETERS : * @enable : flag whether to enable or disable frame sync * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::setFrameSyncEnabled(bool enable) { return mParameters.setFrameSyncEnabled(enable); } /*=========================================================================== * FUNCTION : getRelatedCamSyncInfo * * DESCRIPTION:returns the related cam sync info for this HWI instance * * PARAMETERS :none * * RETURN : const pointer to cam_sync_related_sensors_event_info_t *==========================================================================*/ const cam_sync_related_sensors_event_info_t* QCamera2HardwareInterface::getRelatedCamSyncInfo(void) { return mParameters.getRelatedCamSyncInfo(); } /*=========================================================================== * FUNCTION : setRelatedCamSyncInfo * * DESCRIPTION:sets the related cam sync info for this HWI instance * * PARAMETERS : * @info : ptr to related cam info parameters * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::setRelatedCamSyncInfo( cam_sync_related_sensors_event_info_t* info) { if(info) { return mParameters.setRelatedCamSyncInfo(info); } else { return BAD_TYPE; } } /*=========================================================================== * FUNCTION : getMpoComposition * * DESCRIPTION:function to retrieve whether Mpo composition should be enabled * or not * * PARAMETERS :none * * RETURN : bool indicates whether mpo composition is enabled or not *==========================================================================*/ bool QCamera2HardwareInterface::getMpoComposition(void) { LOGH("MpoComposition:%d ", m_bMpoEnabled); return m_bMpoEnabled; } /*=========================================================================== * FUNCTION : setMpoComposition * * DESCRIPTION:set if Mpo composition should be enabled for this HWI instance * * PARAMETERS : * @enable : indicates whether Mpo composition enabled or not * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::setMpoComposition(bool enable) { // By default set Mpo composition to disable m_bMpoEnabled = false; // Enable Mpo composition only if // 1) frame sync is ON between two cameras and // 2) any advanced features are not enabled (AOST features) and // 3) not in recording mode (for liveshot case) // 4) flash is not needed if ((getRelatedCamSyncInfo()->sync_control == CAM_SYNC_RELATED_SENSORS_ON) && !mParameters.isAdvCamFeaturesEnabled() && !mParameters.getRecordingHintValue() && !mFlashNeeded && !isLongshotEnabled()) { m_bMpoEnabled = enable; LOGH("MpoComposition:%d ", m_bMpoEnabled); return NO_ERROR; } else { return BAD_TYPE; } } /*=========================================================================== * FUNCTION : getRecordingHintValue * * DESCRIPTION:function to retrieve recording hint value * * PARAMETERS :none * * RETURN : bool indicates whether recording hint is enabled or not *==========================================================================*/ bool QCamera2HardwareInterface::getRecordingHintValue(void) { return mParameters.getRecordingHintValue(); } /*=========================================================================== * FUNCTION : setRecordingHintValue * * DESCRIPTION:set recording hint value * * PARAMETERS : * @enable : video hint value * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::setRecordingHintValue(int32_t value) { return mParameters.updateRecordingHintValue(value); } /*=========================================================================== * 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; char value[PROPERTY_VALUE_MAX]; LOGI("E"); if (!mCameraOpened) { return NO_ERROR; } LOGI("[KPI Perf]: E PROFILE_CLOSE_CAMERA camera id %d", mCameraId); // set open flag to false mCameraOpened = false; // Reset Stream config info mParameters.setStreamConfigure(false, false, true); // deinit Parameters mParameters.deinit(); // exit notifier m_cbNotifier.exit(); // stop and deinit postprocessor waitDeferredWork(mReprocJob); // Close the JPEG session waitDeferredWork(mJpegJob); m_postprocessor.stop(); deinitJpegHandle(); m_postprocessor.deinit(); mInitPProcJob = 0; // reset job id, so pproc can be reinited later 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; } } //free all pending api results here if(m_apiResultList != NULL) { api_result_list *apiResultList = m_apiResultList; api_result_list *apiResultListNext; while (apiResultList != NULL) { apiResultListNext = apiResultList->next; free(apiResultList); apiResultList = apiResultListNext; } } rc = mCameraHandle->ops->close_camera(mCameraHandle->camera_handle); mCameraHandle = NULL; //Notify display HAL that there is no active camera session //but avoid calling the same during bootup. Refer to openCamera //for more details. property_get("service.bootanim.exit", value, "0"); if (atoi(value) == 1) { pthread_mutex_lock(&gCamLock); if (--gNumCameraSessions == 0) { setCameraLaunchStatus(false); } pthread_mutex_unlock(&gCamLock); } if (mExifParams.debug_params) { free(mExifParams.debug_params); mExifParams.debug_params = NULL; } if (QCameraFlash::getInstance().releaseFlashFromCamera(mCameraId) != 0) { LOGD("Failed to release flash for camera id: %d", mCameraId); } LOGI("[KPI Perf]: X PROFILE_CLOSE_CAMERA camera id %d, rc: %d", mCameraId, rc); 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(uint32_t cameraId, mm_camera_vtbl_t *cameraHandle) { ATRACE_CALL(); int rc = NO_ERROR; QCameraHeapMemory *capabilityHeap = NULL; /* Allocate memory for capability buffer */ capabilityHeap = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE); rc = capabilityHeap->allocate(1, sizeof(cam_capability_t), NON_SECURE); if(rc != OK) { LOGE("No memory for cappability"); goto allocate_failed; } /* Map memory for capability buffer */ memset(DATA_PTR(capabilityHeap,0), 0, sizeof(cam_capability_t)); cam_buf_map_type_list bufMapList; rc = QCameraBufferMaps::makeSingletonBufMapList( CAM_MAPPING_BUF_TYPE_CAPABILITY, 0 /*stream id*/, 0 /*buffer index*/, -1 /*plane index*/, 0 /*cookie*/, capabilityHeap->getFd(0), sizeof(cam_capability_t), bufMapList, capabilityHeap->getPtr(0)); if (rc == NO_ERROR) { rc = cameraHandle->ops->map_bufs(cameraHandle->camera_handle, &bufMapList); } if(rc < 0) { LOGE("failed to map capability buffer"); goto map_failed; } /* Query Capability */ rc = cameraHandle->ops->query_capability(cameraHandle->camera_handle); if(rc < 0) { LOGE("failed to query capability"); goto query_failed; } gCamCapability[cameraId] = (cam_capability_t *)malloc(sizeof(cam_capability_t)); if (!gCamCapability[cameraId]) { LOGE("out of memory"); goto query_failed; } memcpy(gCamCapability[cameraId], DATA_PTR(capabilityHeap,0), sizeof(cam_capability_t)); int index; for (index = 0; index < CAM_ANALYSIS_INFO_MAX; index++) { cam_analysis_info_t *p_analysis_info = &gCamCapability[cameraId]->analysis_info[index]; p_analysis_info->analysis_padding_info.offset_info.offset_x = 0; p_analysis_info->analysis_padding_info.offset_info.offset_y = 0; } 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: return rc; } /*=========================================================================== * FUNCTION : getCapabilities * * DESCRIPTION: query camera capabilities * * PARAMETERS : * @cameraId : camera Id * @info : camera info struct to be filled in with camera capabilities * * RETURN : int type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::getCapabilities(uint32_t cameraId, struct camera_info *info, cam_sync_type_t *p_cam_type) { ATRACE_CALL(); int rc = NO_ERROR; struct camera_info *p_info = NULL; pthread_mutex_lock(&gCamLock); p_info = get_cam_info(cameraId, p_cam_type); p_info->device_version = CAMERA_DEVICE_API_VERSION_1_0; p_info->static_camera_characteristics = NULL; memcpy(info, p_info, sizeof (struct camera_info)); pthread_mutex_unlock(&gCamLock); return rc; } /*=========================================================================== * FUNCTION : getCamHalCapabilities * * DESCRIPTION: get the HAL capabilities structure * * PARAMETERS : * @cameraId : camera Id * * RETURN : capability structure of respective camera * *==========================================================================*/ cam_capability_t* QCamera2HardwareInterface::getCamHalCapabilities() { return gCamCapability[mCameraId]; } /*=========================================================================== * 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(); char value[PROPERTY_VALUE_MAX]; bool raw_yuv = false; int persist_cnt = 0; int zslQBuffers = mParameters.getZSLQueueDepth(); int minCircularBufNum = mParameters.getMaxUnmatchedFramesInQueue() + CAMERA_MIN_JPEG_ENCODING_BUFFERS; int maxStreamBuf = minCaptureBuffers + mParameters.getMaxUnmatchedFramesInQueue() + mParameters.getNumOfExtraHDRInBufsIfNeeded() - mParameters.getNumOfExtraHDROutBufsIfNeeded() + mParameters.getNumOfExtraBuffersForImageProc() + EXTRA_ZSL_PREVIEW_STREAM_BUF; int minUndequeCount = 0; if (!isNoDisplayMode()) { if(mPreviewWindow != NULL) { if (mPreviewWindow->get_min_undequeued_buffer_count(mPreviewWindow,&minUndequeCount) != 0) { LOGW("get_min_undequeued_buffer_count failed"); //TODO: hardcoded because MIN_UNDEQUEUED_BUFFERS not defined //minUndequeCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS; minUndequeCount = MIN_UNDEQUEUED_BUFFERS; } } else { //preview window might not be set at this point. So, query directly //from BufferQueue implementation of gralloc buffers. //minUndequeCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS; //hardcoded because MIN_UNDEQUEUED_BUFFERS not defined. REVISIT minUndequeCount = MIN_UNDEQUEUED_BUFFERS; } if (minUndequeCount != MIN_UNDEQUEUED_BUFFERS) { // minUndequeCount from valid preview window != hardcoded MIN_UNDEQUEUED_BUFFERS // and so change the MACRO as per minUndequeCount LOGW("WARNING : minUndequeCount(%d) != hardcoded value(%d)", minUndequeCount, MIN_UNDEQUEUED_BUFFERS); } } LOGD("minCaptureBuffers = %d zslQBuffers = %d minCircularBufNum = %d" "maxStreamBuf = %d minUndequeCount = %d", minCaptureBuffers, zslQBuffers, minCircularBufNum, maxStreamBuf, minUndequeCount); // Get buffer count for the particular stream type switch (stream_type) { case CAM_STREAM_TYPE_PREVIEW: { if (mParameters.isZSLMode()) { // We need to add two extra streming buffers to add // flexibility in forming matched super buf in ZSL queue. // with number being 'zslQBuffers + minCircularBufNum' // we see preview buffers sometimes get dropped at CPP // and super buf is not forming in ZSL Q for long time. bufferCnt = zslQBuffers + minCircularBufNum + mParameters.getNumOfExtraBuffersForImageProc() + mParameters.getNumOfExtraBuffersForPreview() + mParameters.getNumOfExtraHDRInBufsIfNeeded(); } else { bufferCnt = CAMERA_MIN_STREAMING_BUFFERS + mParameters.getMaxUnmatchedFramesInQueue() + mParameters.getNumOfExtraBuffersForPreview(); } // ISP allocates native preview buffers and so reducing same from HAL allocation if (bufferCnt > CAMERA_ISP_PING_PONG_BUFFERS ) bufferCnt -= CAMERA_ISP_PING_PONG_BUFFERS; if (mParameters.getRecordingHintValue() == true) bufferCnt += EXTRA_ZSL_PREVIEW_STREAM_BUF; // Add the display minUndequeCount count on top of camera requirement bufferCnt += minUndequeCount; property_get("persist.camera.preview_yuv", value, "0"); persist_cnt = atoi(value); if ((persist_cnt < CAM_MAX_NUM_BUFS_PER_STREAM) && (bufferCnt < persist_cnt)) { bufferCnt = persist_cnt; } } break; case CAM_STREAM_TYPE_POSTVIEW: { bufferCnt = minCaptureBuffers + mParameters.getMaxUnmatchedFramesInQueue() + mParameters.getNumOfExtraHDRInBufsIfNeeded() - mParameters.getNumOfExtraHDROutBufsIfNeeded() + mParameters.getNumOfExtraBuffersForImageProc(); if (bufferCnt > maxStreamBuf) { bufferCnt = maxStreamBuf; } bufferCnt += minUndequeCount; } break; case CAM_STREAM_TYPE_SNAPSHOT: { if (mParameters.isZSLMode() || mLongshotEnabled) { if ((minCaptureBuffers == 1 || mParameters.isUbiRefocus()) && !mLongshotEnabled) { // Single ZSL snapshot case bufferCnt = zslQBuffers + CAMERA_MIN_STREAMING_BUFFERS + mParameters.getNumOfExtraBuffersForImageProc(); } else { // ZSL Burst or Longshot case bufferCnt = zslQBuffers + minCircularBufNum + mParameters.getNumOfExtraBuffersForImageProc(); } if (getSensorType() == CAM_SENSOR_YUV && bufferCnt > CAMERA_ISP_PING_PONG_BUFFERS) { //ISP allocates native buffers in YUV case bufferCnt -= CAMERA_ISP_PING_PONG_BUFFERS; } } else { bufferCnt = minCaptureBuffers + mParameters.getNumOfExtraHDRInBufsIfNeeded() - mParameters.getNumOfExtraHDROutBufsIfNeeded() + mParameters.getNumOfExtraBuffersForImageProc(); if (bufferCnt > maxStreamBuf) { bufferCnt = maxStreamBuf; } } } break; case CAM_STREAM_TYPE_RAW: property_get("persist.camera.raw_yuv", value, "0"); raw_yuv = atoi(value) > 0 ? true : false; if (isRdiMode() || raw_yuv) { bufferCnt = zslQBuffers + minCircularBufNum; } else if (mParameters.isZSLMode()) { bufferCnt = zslQBuffers + minCircularBufNum; if (getSensorType() == CAM_SENSOR_YUV && bufferCnt > CAMERA_ISP_PING_PONG_BUFFERS) { //ISP allocates native buffers in YUV case bufferCnt -= CAMERA_ISP_PING_PONG_BUFFERS; } } else { bufferCnt = minCaptureBuffers + mParameters.getNumOfExtraHDRInBufsIfNeeded() - mParameters.getNumOfExtraHDROutBufsIfNeeded() + mParameters.getNumOfExtraBuffersForImageProc(); if (bufferCnt > maxStreamBuf) { bufferCnt = maxStreamBuf; } } property_get("persist.camera.preview_raw", value, "0"); persist_cnt = atoi(value); if ((persist_cnt < CAM_MAX_NUM_BUFS_PER_STREAM) && (bufferCnt < persist_cnt)) { bufferCnt = persist_cnt; } property_get("persist.camera.video_raw", value, "0"); persist_cnt = atoi(value); if ((persist_cnt < CAM_MAX_NUM_BUFS_PER_STREAM) && (bufferCnt < persist_cnt)) { bufferCnt = persist_cnt; } break; case CAM_STREAM_TYPE_VIDEO: { if (mParameters.getBufBatchCount()) { //Video Buffer in case of HFR or camera batching.. bufferCnt = CAMERA_MIN_CAMERA_BATCH_BUFFERS; } else if (mParameters.getVideoBatchSize()) { //Video Buffer count only for HAL to HAL batching. bufferCnt = (CAMERA_MIN_VIDEO_BATCH_BUFFERS * mParameters.getVideoBatchSize()); if (bufferCnt < CAMERA_MIN_VIDEO_BUFFERS) { bufferCnt = CAMERA_MIN_VIDEO_BUFFERS; } } else { // No batching enabled. bufferCnt = CAMERA_MIN_VIDEO_BUFFERS; } bufferCnt += mParameters.getNumOfExtraBuffersForVideo(); //if its 4K encoding usecase, then add extra buffer cam_dimension_t dim; mParameters.getStreamDimension(CAM_STREAM_TYPE_VIDEO, dim); if (is4k2kResolution(&dim)) { //get additional buffer count property_get("vidc.enc.dcvs.extra-buff-count", value, "0"); bufferCnt += atoi(value); } } break; case CAM_STREAM_TYPE_METADATA: { if (mParameters.isZSLMode()) { // MetaData buffers should be >= (Preview buffers-minUndequeCount) bufferCnt = zslQBuffers + minCircularBufNum + mParameters.getNumOfExtraHDRInBufsIfNeeded() - mParameters.getNumOfExtraHDROutBufsIfNeeded() + mParameters.getNumOfExtraBuffersForImageProc() + EXTRA_ZSL_PREVIEW_STREAM_BUF; } else { bufferCnt = minCaptureBuffers + mParameters.getNumOfExtraHDRInBufsIfNeeded() - mParameters.getNumOfExtraHDROutBufsIfNeeded() + mParameters.getMaxUnmatchedFramesInQueue() + CAMERA_MIN_STREAMING_BUFFERS + mParameters.getNumOfExtraBuffersForImageProc(); if (bufferCnt > zslQBuffers + minCircularBufNum) { bufferCnt = zslQBuffers + minCircularBufNum; } } if (CAMERA_MIN_METADATA_BUFFERS > bufferCnt) { bufferCnt = CAMERA_MIN_METADATA_BUFFERS; } } break; case CAM_STREAM_TYPE_OFFLINE_PROC: { bufferCnt = minCaptureBuffers; // One of the ubifocus buffers is miscellaneous buffer if (mParameters.isUbiRefocus()) { bufferCnt -= 1; } if (mLongshotEnabled) { bufferCnt = mParameters.getLongshotStages(); } } break; case CAM_STREAM_TYPE_CALLBACK: bufferCnt = CAMERA_MIN_CALLBACK_BUFFERS; break; case CAM_STREAM_TYPE_ANALYSIS: case CAM_STREAM_TYPE_DEFAULT: case CAM_STREAM_TYPE_MAX: default: bufferCnt = 0; break; } LOGH("Buffer count = %d for stream type = %d", bufferCnt, stream_type); if (CAM_MAX_NUM_BUFS_PER_STREAM < bufferCnt) { LOGW("Buffer count %d for stream type %d exceeds limit %d", bufferCnt, stream_type, CAM_MAX_NUM_BUFS_PER_STREAM); return CAM_MAX_NUM_BUFS_PER_STREAM; } return (uint8_t)bufferCnt; } /*=========================================================================== * FUNCTION : allocateStreamBuf * * DESCRIPTION: alocate stream buffers * * PARAMETERS : * @stream_type : type of stream * @size : size of buffer * @stride : stride of buffer * @scanline : scanline 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, size_t size, int stride, int scanline, uint8_t &bufferCnt) { int rc = NO_ERROR; QCameraMemory *mem = NULL; bool bCachedMem = QCAMERA_ION_USE_CACHE; bool bPoolMem = false; char value[PROPERTY_VALUE_MAX]; property_get("persist.camera.mem.usepool", value, "1"); if (atoi(value) == 1) { bPoolMem = true; } // Allocate stream buffer memory object switch (stream_type) { case CAM_STREAM_TYPE_PREVIEW: { if (isNoDisplayMode()) { mem = new QCameraStreamMemory(mGetMemory, bCachedMem, (bPoolMem) ? &m_memoryPool : NULL, stream_type); } else { cam_dimension_t dim; int minFPS, maxFPS; QCameraGrallocMemory *grallocMemory = new QCameraGrallocMemory(mGetMemory); mParameters.getStreamDimension(stream_type, dim); /* we are interested only in maxfps here */ mParameters.getPreviewFpsRange(&minFPS, &maxFPS); int usage = 0; if(mParameters.isUBWCEnabled()) { cam_format_t fmt; mParameters.getStreamFormat(CAM_STREAM_TYPE_PREVIEW,fmt); if (fmt == CAM_FORMAT_YUV_420_NV12_UBWC) { usage = GRALLOC_USAGE_PRIVATE_ALLOC_UBWC ; } } if (grallocMemory) { grallocMemory->setMappable( CAMERA_INITIAL_MAPPABLE_PREVIEW_BUFFERS); grallocMemory->setWindowInfo(mPreviewWindow, dim.width,dim.height, stride, scanline, mParameters.getPreviewHalPixelFormat(), maxFPS, usage); pthread_mutex_lock(&mGrallocLock); if (bufferCnt > CAMERA_INITIAL_MAPPABLE_PREVIEW_BUFFERS) { mEnqueuedBuffers = (bufferCnt - CAMERA_INITIAL_MAPPABLE_PREVIEW_BUFFERS); } else { mEnqueuedBuffers = 0; } pthread_mutex_unlock(&mGrallocLock); } mem = grallocMemory; } } break; case CAM_STREAM_TYPE_POSTVIEW: { if (isNoDisplayMode() || isPreviewRestartEnabled()) { mem = new QCameraStreamMemory(mGetMemory, bCachedMem); } else { cam_dimension_t dim; int minFPS, maxFPS; QCameraGrallocMemory *grallocMemory = new QCameraGrallocMemory(mGetMemory); mParameters.getStreamDimension(stream_type, dim); /* we are interested only in maxfps here */ mParameters.getPreviewFpsRange(&minFPS, &maxFPS); if (grallocMemory) { grallocMemory->setWindowInfo(mPreviewWindow, dim.width, dim.height, stride, scanline, mParameters.getPreviewHalPixelFormat(), maxFPS); } mem = grallocMemory; } } break; case CAM_STREAM_TYPE_ANALYSIS: case CAM_STREAM_TYPE_SNAPSHOT: case CAM_STREAM_TYPE_RAW: case CAM_STREAM_TYPE_OFFLINE_PROC: mem = new QCameraStreamMemory(mGetMemory, bCachedMem, (bPoolMem) ? &m_memoryPool : NULL, stream_type); break; case CAM_STREAM_TYPE_METADATA: { if (mMetadataMem == NULL) { mem = new QCameraMetadataStreamMemory(QCAMERA_ION_USE_CACHE); } else { mem = mMetadataMem; mMetadataMem = NULL; int32_t numAdditionalBuffers = bufferCnt - mem->getCnt(); if (numAdditionalBuffers > 0) { rc = mem->allocateMore(numAdditionalBuffers, size); if (rc != NO_ERROR) { LOGE("Failed to allocate additional buffers, " "but attempting to proceed."); } } bufferCnt = mem->getCnt(); // The memory is already allocated and initialized, so // simply return here. return mem; } } break; case CAM_STREAM_TYPE_VIDEO: { //Use uncached allocation by default if (mParameters.isVideoBuffersCached() || mParameters.isSeeMoreEnabled() || mParameters.isHighQualityNoiseReductionMode()) { bCachedMem = QCAMERA_ION_USE_CACHE; } else { bCachedMem = QCAMERA_ION_USE_NOCACHE; } QCameraVideoMemory *videoMemory = NULL; if (mParameters.getVideoBatchSize()) { videoMemory = new QCameraVideoMemory( mGetMemory, FALSE, QCAMERA_MEM_TYPE_BATCH); if (videoMemory == NULL) { LOGE("Out of memory for video batching obj"); return NULL; } /* * numFDs = BATCH size * numInts = 5 // OFFSET, SIZE, USAGE, TIMESTAMP, FORMAT */ rc = videoMemory->allocateMeta( CAMERA_MIN_VIDEO_BATCH_BUFFERS, mParameters.getVideoBatchSize(), VIDEO_METADATA_NUM_INTS); if (rc < 0) { delete videoMemory; return NULL; } } else { videoMemory = new QCameraVideoMemory(mGetMemory, bCachedMem); if (videoMemory == NULL) { LOGE("Out of memory for video obj"); return NULL; } } int usage = 0; cam_format_t fmt; mParameters.getStreamFormat(CAM_STREAM_TYPE_VIDEO,fmt); if (mParameters.isUBWCEnabled() && (fmt == CAM_FORMAT_YUV_420_NV12_UBWC)) { usage = private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; } videoMemory->setVideoInfo(usage, fmt); mem = videoMemory; mVideoMem = videoMemory; } break; case CAM_STREAM_TYPE_CALLBACK: mem = new QCameraStreamMemory(mGetMemory, bCachedMem, (bPoolMem) ? &m_memoryPool : NULL, stream_type); break; case CAM_STREAM_TYPE_DEFAULT: case CAM_STREAM_TYPE_MAX: default: break; } if (!mem) { return NULL; } if (bufferCnt > 0) { if (mParameters.isSecureMode() && (stream_type == CAM_STREAM_TYPE_RAW) && (mParameters.isRdiMode())) { LOGD("Allocating %d secure buffers of size %d ", bufferCnt, size); rc = mem->allocate(bufferCnt, size, SECURE); } else { rc = mem->allocate(bufferCnt, size, NON_SECURE); } if (rc < 0) { delete mem; return NULL; } bufferCnt = mem->getCnt(); } LOGH("rc = %d type = %d count = %d size = %d cache = %d, pool = %d", rc, stream_type, bufferCnt, size, bCachedMem, bPoolMem); return mem; } /*=========================================================================== * FUNCTION : allocateMoreStreamBuf * * DESCRIPTION: alocate more stream buffers from the memory object * * PARAMETERS : * @mem_obj : memory object ptr * @size : size of buffer * @bufferCnt : [IN/OUT] additional number of buffers to be allocated. * output will be the number of total buffers * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::allocateMoreStreamBuf( QCameraMemory *mem_obj, size_t size, uint8_t &bufferCnt) { int rc = NO_ERROR; if (bufferCnt > 0) { rc = mem_obj->allocateMore(bufferCnt, size); bufferCnt = mem_obj->getCnt(); } return rc; } /*=========================================================================== * FUNCTION : allocateMiscBuf * * DESCRIPTION: alocate miscellaneous buffer * * PARAMETERS : * @streamInfo : stream info * * RETURN : ptr to a memory obj that holds stream info buffer. * NULL if failed *==========================================================================*/ QCameraHeapMemory *QCamera2HardwareInterface::allocateMiscBuf( cam_stream_info_t *streamInfo) { int rc = NO_ERROR; uint8_t bufNum = 0; size_t bufSize = 0; QCameraHeapMemory *miscBuf = NULL; cam_feature_mask_t feature_mask = streamInfo->reprocess_config.pp_feature_config.feature_mask; switch (streamInfo->stream_type) { case CAM_STREAM_TYPE_OFFLINE_PROC: if (CAM_QCOM_FEATURE_TRUEPORTRAIT & feature_mask) { bufNum = 1; bufSize = mParameters.getTPMaxMetaSize(); } else if (CAM_QCOM_FEATURE_REFOCUS & feature_mask) { bufNum = 1; bufSize = mParameters.getRefocusMaxMetaSize(); } break; default: break; } if (bufNum && bufSize) { miscBuf = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE); if (!miscBuf) { LOGE("Unable to allocate miscBuf object"); return NULL; } rc = miscBuf->allocate(bufNum, bufSize, NON_SECURE); if (rc < 0) { LOGE("Failed to allocate misc buffer memory"); delete miscBuf; return NULL; } } return miscBuf; } /*=========================================================================== * 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; char value[PROPERTY_VALUE_MAX]; bool raw_yuv = false; QCameraHeapMemory *streamInfoBuf = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE); if (!streamInfoBuf) { LOGE("allocateStreamInfoBuf: Unable to allocate streamInfo object"); return NULL; } rc = streamInfoBuf->allocate(1, sizeof(cam_stream_info_t), NON_SECURE); if (rc < 0) { LOGE("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); rc = mParameters.getStreamRotation(stream_type, streamInfo->pp_config, streamInfo->dim); streamInfo->num_bufs = getBufNumRequired(stream_type); streamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS; streamInfo->is_secure = NON_SECURE; switch (stream_type) { case CAM_STREAM_TYPE_SNAPSHOT: if ((mParameters.isZSLMode() && mParameters.getRecordingHintValue() != true) || mLongshotEnabled) { streamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS; } else { streamInfo->streaming_mode = CAM_STREAMING_MODE_BURST; streamInfo->num_of_burst = (uint8_t) (mParameters.getNumOfSnapshots() + mParameters.getNumOfExtraHDRInBufsIfNeeded() - mParameters.getNumOfExtraHDROutBufsIfNeeded() + mParameters.getNumOfExtraBuffersForImageProc()); } break; case CAM_STREAM_TYPE_RAW: property_get("persist.camera.raw_yuv", value, "0"); raw_yuv = atoi(value) > 0 ? true : false; if ((mParameters.isZSLMode()) || (isRdiMode()) || (raw_yuv)) { streamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS; } else { streamInfo->streaming_mode = CAM_STREAMING_MODE_BURST; streamInfo->num_of_burst = mParameters.getNumOfSnapshots(); } if (mParameters.isSecureMode() && mParameters.isRdiMode()) { streamInfo->is_secure = SECURE; } else { streamInfo->is_secure = NON_SECURE; } break; case CAM_STREAM_TYPE_POSTVIEW: if (mLongshotEnabled) { streamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS; } else { streamInfo->streaming_mode = CAM_STREAMING_MODE_BURST; streamInfo->num_of_burst = (uint8_t)(mParameters.getNumOfSnapshots() + mParameters.getNumOfExtraHDRInBufsIfNeeded() - mParameters.getNumOfExtraHDROutBufsIfNeeded() + mParameters.getNumOfExtraBuffersForImageProc()); } break; case CAM_STREAM_TYPE_VIDEO: streamInfo->dis_enable = mParameters.isDISEnabled(); if (mParameters.getBufBatchCount()) { //Update stream info structure with batch mode info streamInfo->streaming_mode = CAM_STREAMING_MODE_BATCH; streamInfo->user_buf_info.frame_buf_cnt = mParameters.getBufBatchCount(); streamInfo->user_buf_info.size = (uint32_t)(sizeof(struct msm_camera_user_buf_cont_t)); cam_fps_range_t pFpsRange; mParameters.getHfrFps(pFpsRange); streamInfo->user_buf_info.frameInterval = (long)((1000/pFpsRange.video_max_fps) * 1000); LOGH("Video Batch Count = %d, interval = %ld", streamInfo->user_buf_info.frame_buf_cnt, streamInfo->user_buf_info.frameInterval); } case CAM_STREAM_TYPE_PREVIEW: if (mParameters.getRecordingHintValue()) { if(mParameters.isDISEnabled()) { streamInfo->is_type = mParameters.getISType(); } else { streamInfo->is_type = IS_TYPE_NONE; } } if (mParameters.isSecureMode()) { streamInfo->is_secure = SECURE; } break; case CAM_STREAM_TYPE_ANALYSIS: streamInfo->noFrameExpected = 1; break; default: break; } // Update feature mask mParameters.updatePpFeatureMask(stream_type); // Get feature mask mParameters.getStreamPpMask(stream_type, streamInfo->pp_config.feature_mask); // Update pp config if (streamInfo->pp_config.feature_mask & CAM_QCOM_FEATURE_FLIP) { int flipMode = mParameters.getFlipMode(stream_type); if (flipMode > 0) { streamInfo->pp_config.flip = (uint32_t)flipMode; } } if (streamInfo->pp_config.feature_mask & CAM_QCOM_FEATURE_SHARPNESS) { streamInfo->pp_config.sharpness = mParameters.getSharpness(); } if (streamInfo->pp_config.feature_mask & CAM_QCOM_FEATURE_EFFECT) { streamInfo->pp_config.effect = mParameters.getEffectValue(); } if (streamInfo->pp_config.feature_mask & CAM_QCOM_FEATURE_DENOISE2D) { streamInfo->pp_config.denoise2d.denoise_enable = 1; streamInfo->pp_config.denoise2d.process_plates = mParameters.getDenoiseProcessPlate(CAM_INTF_PARM_WAVELET_DENOISE); } if (!((needReprocess()) && (CAM_STREAM_TYPE_SNAPSHOT == stream_type || CAM_STREAM_TYPE_RAW == stream_type))) { if (gCamCapability[mCameraId]->qcom_supported_feature_mask & CAM_QCOM_FEATURE_CROP) streamInfo->pp_config.feature_mask |= CAM_QCOM_FEATURE_CROP; if (gCamCapability[mCameraId]->qcom_supported_feature_mask & CAM_QCOM_FEATURE_SCALE) streamInfo->pp_config.feature_mask |= CAM_QCOM_FEATURE_SCALE; } LOGH("type %d, fmt %d, dim %dx%d, num_bufs %d mask = 0x%x\n", stream_type, streamInfo->fmt, streamInfo->dim.width, streamInfo->dim.height, streamInfo->num_bufs, streamInfo->pp_config.feature_mask); return streamInfoBuf; } /*=========================================================================== * FUNCTION : allocateStreamUserBuf * * DESCRIPTION: allocate user ptr for stream buffers * * PARAMETERS : * @streamInfo : stream info structure * * RETURN : ptr to a memory obj that holds stream info buffer. * NULL if failed *==========================================================================*/ QCameraMemory *QCamera2HardwareInterface::allocateStreamUserBuf( cam_stream_info_t *streamInfo) { int rc = NO_ERROR; QCameraMemory *mem = NULL; int size = 0; if (streamInfo->streaming_mode != CAM_STREAMING_MODE_BATCH) { LOGE("Stream is not in BATCH mode. Invalid Stream"); return NULL; } // Allocate stream user buffer memory object switch (streamInfo->stream_type) { case CAM_STREAM_TYPE_VIDEO: { QCameraVideoMemory *video_mem = new QCameraVideoMemory( mGetMemory, FALSE, QCAMERA_MEM_TYPE_BATCH); if (video_mem == NULL) { LOGE("Out of memory for video obj"); return NULL; } /* * numFDs = BATCH size * numInts = 5 // OFFSET, SIZE, USAGE, TIMESTAMP, FORMAT */ rc = video_mem->allocateMeta(streamInfo->num_bufs, mParameters.getBufBatchCount(), VIDEO_METADATA_NUM_INTS); if (rc < 0) { LOGE("allocateMeta failed"); delete video_mem; return NULL; } int usage = 0; cam_format_t fmt; mParameters.getStreamFormat(CAM_STREAM_TYPE_VIDEO, fmt); if(mParameters.isUBWCEnabled() && (fmt == CAM_FORMAT_YUV_420_NV12_UBWC)) { usage = private_handle_t::PRIV_FLAGS_UBWC_ALIGNED; } video_mem->setVideoInfo(usage, fmt); mem = static_cast<QCameraMemory *>(video_mem); mVideoMem = video_mem; } break; case CAM_STREAM_TYPE_PREVIEW: case CAM_STREAM_TYPE_POSTVIEW: case CAM_STREAM_TYPE_ANALYSIS: case CAM_STREAM_TYPE_SNAPSHOT: case CAM_STREAM_TYPE_RAW: case CAM_STREAM_TYPE_METADATA: case CAM_STREAM_TYPE_OFFLINE_PROC: case CAM_STREAM_TYPE_CALLBACK: LOGE("Stream type Not supported.for BATCH processing"); break; case CAM_STREAM_TYPE_DEFAULT: case CAM_STREAM_TYPE_MAX: default: break; } if (!mem) { LOGE("Failed to allocate mem"); return NULL; } /*Size of this buffer will be number of batch buffer */ size = PAD_TO_SIZE((streamInfo->num_bufs * streamInfo->user_buf_info.size), CAM_PAD_TO_4K); LOGH("Allocating BATCH Buffer count = %d", streamInfo->num_bufs); if (size > 0) { // Allocating one buffer for all batch buffers rc = mem->allocate(1, size, NON_SECURE); if (rc < 0) { delete mem; return NULL; } } return mem; } /*=========================================================================== * FUNCTION : waitForDeferredAlloc * * DESCRIPTION: Wait for deferred allocation, if applicable * (applicable only for metadata buffers so far) * * PARAMETERS : * @stream_type : type of stream to (possibly) wait for * * RETURN : None *==========================================================================*/ void QCamera2HardwareInterface::waitForDeferredAlloc(cam_stream_type_t stream_type) { if (stream_type == CAM_STREAM_TYPE_METADATA) { waitDeferredWork(mMetadataAllocJob); } } /*=========================================================================== * 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 : setJpegCallBacks * * DESCRIPTION: set JPEG callbacks impl * * PARAMETERS : * @jpegCb : Jpeg callback method * @callbackCookie : callback cookie * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ void QCamera2HardwareInterface::setJpegCallBacks(jpeg_data_callback jpegCb, void *callbackCookie) { LOGH("camera id %d", getCameraId()); mJpegCb = jpegCb; mJpegCallbackCookie = callbackCookie; m_cbNotifier.setJpegCallBacks(mJpegCb, mJpegCallbackCookie); } /*=========================================================================== * 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) { int32_t rc = NO_ERROR; if (mParameters.isUBWCEnabled()) { /*Need Special CALLBACK stream incase application requesting for Preview callback in UBWC case*/ if (!(msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME)) && (msg_type & CAMERA_MSG_PREVIEW_FRAME)) { // Start callback channel only when preview/zsl channel is active QCameraChannel* previewCh = NULL; if (isZSLMode() && (getRecordingHintValue() != true)) { previewCh = m_channels[QCAMERA_CH_TYPE_ZSL]; } else { previewCh = m_channels[QCAMERA_CH_TYPE_PREVIEW]; } QCameraChannel* callbackCh = m_channels[QCAMERA_CH_TYPE_CALLBACK]; if ((callbackCh != NULL) && (previewCh != NULL) && previewCh->isActive()) { rc = startChannel(QCAMERA_CH_TYPE_CALLBACK); if (rc != NO_ERROR) { LOGE("START Callback Channel failed"); } } } } mMsgEnabled |= msg_type; LOGH("(0x%x) : mMsgEnabled = 0x%x rc = %d", msg_type , mMsgEnabled, rc); return rc; } /*=========================================================================== * 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) { int32_t rc = NO_ERROR; if (mParameters.isUBWCEnabled()) { /*STOP CALLBACK STREAM*/ if ((msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME)) && (msg_type & CAMERA_MSG_PREVIEW_FRAME)) { // Stop callback channel only if it is active if ((m_channels[QCAMERA_CH_TYPE_CALLBACK] != NULL) && (m_channels[QCAMERA_CH_TYPE_CALLBACK]->isActive())) { rc = stopChannel(QCAMERA_CH_TYPE_CALLBACK); if (rc != NO_ERROR) { LOGE("STOP Callback Channel failed"); } } } } mMsgEnabled &= ~msg_type; LOGH("(0x%x) : mMsgEnabled = 0x%x rc = %d", msg_type , mMsgEnabled, rc); return rc; } /*=========================================================================== * 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() { KPI_ATRACE_CALL(); int32_t rc = NO_ERROR; LOGI("E ZSL = %d Recording Hint = %d", mParameters.isZSLMode(), mParameters.getRecordingHintValue()); m_perfLock.lock_acq(); updateThermalLevel((void *)&mThermalLevel); setDisplayFrameSkip(); // start preview stream if (mParameters.isZSLMode() && mParameters.getRecordingHintValue() != true) { rc = startChannel(QCAMERA_CH_TYPE_ZSL); } else { rc = startChannel(QCAMERA_CH_TYPE_PREVIEW); } if (rc != NO_ERROR) { LOGE("failed to start channels"); m_perfLock.lock_rel(); return rc; } if ((msgTypeEnabled(CAMERA_MSG_PREVIEW_FRAME)) && (m_channels[QCAMERA_CH_TYPE_CALLBACK] != NULL)) { rc = startChannel(QCAMERA_CH_TYPE_CALLBACK); if (rc != NO_ERROR) { LOGE("failed to start callback stream"); stopChannel(QCAMERA_CH_TYPE_ZSL); stopChannel(QCAMERA_CH_TYPE_PREVIEW); m_perfLock.lock_rel(); return rc; } } updatePostPreviewParameters(); m_stateMachine.setPreviewCallbackNeeded(true); // if job id is non-zero, that means the postproc init job is already // pending or complete if (mInitPProcJob == 0) { mInitPProcJob = deferPPInit(); if (mInitPProcJob == 0) { LOGE("Unable to initialize postprocessor, mCameraHandle = %p", mCameraHandle); rc = -ENOMEM; m_perfLock.lock_rel(); return rc; } } m_perfLock.lock_rel(); if (rc == NO_ERROR) { if (!mParameters.isSeeMoreEnabled()) { // Set power Hint for preview m_perfLock.powerHint(POWER_HINT_VIDEO_ENCODE, true); } } LOGI("X rc = %d", rc); return rc; } int32_t QCamera2HardwareInterface::updatePostPreviewParameters() { // Enable OIS only in Camera mode and 4k2k camcoder mode int32_t rc = NO_ERROR; rc = mParameters.updateOisValue(1); return NO_ERROR; } /*=========================================================================== * FUNCTION : stopPreview * * DESCRIPTION: stop preview impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::stopPreview() { KPI_ATRACE_CALL(); LOGI("E"); mNumPreviewFaces = -1; mActiveAF = false; // Disable power Hint for preview m_perfLock.powerHint(POWER_HINT_VIDEO_ENCODE, false); m_perfLock.lock_acq(); // stop preview stream stopChannel(QCAMERA_CH_TYPE_CALLBACK); stopChannel(QCAMERA_CH_TYPE_ZSL); stopChannel(QCAMERA_CH_TYPE_PREVIEW); stopChannel(QCAMERA_CH_TYPE_RAW); m_cbNotifier.flushPreviewNotifications(); //add for ts makeup #ifdef TARGET_TS_MAKEUP ts_makeup_finish(); #endif // delete all channels from preparePreview unpreparePreview(); m_perfLock.lock_rel(); LOGI("X"); 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 : preStartRecording * * DESCRIPTION: Prepare start recording impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::preStartRecording() { int32_t rc = NO_ERROR; LOGH("E"); if (mParameters.getRecordingHintValue() == false) { // Give HWI control to restart preview only in single camera mode. // In dual-cam mode, this control belongs to muxer. if (getRelatedCamSyncInfo()->sync_control != CAM_SYNC_RELATED_SENSORS_ON) { LOGH("start recording when hint is false, stop preview first"); stopPreview(); // Set recording hint to TRUE mParameters.updateRecordingHintValue(TRUE); rc = preparePreview(); if (rc == NO_ERROR) { rc = startPreview(); } } else { // For dual cam mode, update the flag mPreviewRestartNeeded to true // Restart control will be handled by muxer. mPreviewRestartNeeded = true; } } LOGH("X rc = %d", rc); return rc; } /*=========================================================================== * 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; LOGI("E"); mVideoMem = NULL; //link meta stream with video channel if low power mode. if (isLowPowerMode()) { // Find and try to link a metadata stream from preview channel QCameraChannel *pMetaChannel = NULL; QCameraStream *pMetaStream = NULL; QCameraChannel *pVideoChannel = m_channels[QCAMERA_CH_TYPE_VIDEO]; if (m_channels[QCAMERA_CH_TYPE_PREVIEW] != NULL) { pMetaChannel = m_channels[QCAMERA_CH_TYPE_PREVIEW]; uint32_t streamNum = pMetaChannel->getNumOfStreams(); QCameraStream *pStream = NULL; for (uint32_t i = 0 ; i < streamNum ; i++ ) { pStream = pMetaChannel->getStreamByIndex(i); if ((NULL != pStream) && (CAM_STREAM_TYPE_METADATA == pStream->getMyType())) { pMetaStream = pStream; break; } } } if ((NULL != pMetaChannel) && (NULL != pMetaStream)) { rc = pVideoChannel->linkStream(pMetaChannel, pMetaStream); if (NO_ERROR != rc) { LOGW("Metadata stream link failed %d", rc); } } } if (rc == NO_ERROR) { rc = startChannel(QCAMERA_CH_TYPE_VIDEO); } if (mParameters.isTNRSnapshotEnabled() && !isLowPowerMode()) { QCameraChannel *pChannel = m_channels[QCAMERA_CH_TYPE_SNAPSHOT]; if (!mParameters.is4k2kVideoResolution()) { // Find and try to link a metadata stream from preview channel QCameraChannel *pMetaChannel = NULL; QCameraStream *pMetaStream = NULL; if (m_channels[QCAMERA_CH_TYPE_PREVIEW] != NULL) { pMetaChannel = m_channels[QCAMERA_CH_TYPE_PREVIEW]; uint32_t streamNum = pMetaChannel->getNumOfStreams(); QCameraStream *pStream = NULL; for (uint32_t i = 0 ; i < streamNum ; i++ ) { pStream = pMetaChannel->getStreamByIndex(i); if ((NULL != pStream) && (CAM_STREAM_TYPE_METADATA == pStream->getMyType())) { pMetaStream = pStream; break; } } } if ((NULL != pMetaChannel) && (NULL != pMetaStream)) { rc = pChannel->linkStream(pMetaChannel, pMetaStream); if (NO_ERROR != rc) { LOGW("Metadata stream link failed %d", rc); } } } LOGH("START snapshot Channel for TNR processing"); rc = pChannel->start(); } if (rc == NO_ERROR) { if (!mParameters.isSeeMoreEnabled()) { // Set power Hint for video encoding m_perfLock.powerHint(POWER_HINT_VIDEO_ENCODE, true); } } LOGI("X rc = %d", rc); 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() { LOGI("E"); // stop snapshot channel if (mParameters.isTNRSnapshotEnabled()) { LOGH("STOP snapshot Channel for TNR processing"); stopChannel(QCAMERA_CH_TYPE_SNAPSHOT); } int rc = stopChannel(QCAMERA_CH_TYPE_VIDEO); m_cbNotifier.flushVideoNotifications(); // Disable power hint for video encoding m_perfLock.powerHint(POWER_HINT_VIDEO_ENCODE, false); mVideoMem = NULL; LOGI("X rc = %d", rc); 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]; LOGD("opaque data = %p",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(); LOGH("E"); switch (focusMode) { case CAM_FOCUS_MODE_AUTO: case CAM_FOCUS_MODE_MACRO: case CAM_FOCUS_MODE_CONTINOUS_VIDEO: case CAM_FOCUS_MODE_CONTINOUS_PICTURE: mActiveAF = true; LOGI("Send AUTO FOCUS event. focusMode=%d, m_currentFocusState=%d", focusMode, m_currentFocusState); rc = mCameraHandle->ops->do_auto_focus(mCameraHandle->camera_handle); break; case CAM_FOCUS_MODE_INFINITY: case CAM_FOCUS_MODE_FIXED: case CAM_FOCUS_MODE_EDOF: default: LOGI("No ops in focusMode (%d)", focusMode); rc = sendEvtNotify(CAMERA_MSG_FOCUS, true, 0); break; } if (NO_ERROR != rc) { mActiveAF = false; } LOGH("X rc = %d", rc); 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: case CAM_FOCUS_MODE_CONTINOUS_VIDEO: case CAM_FOCUS_MODE_CONTINOUS_PICTURE: mActiveAF = false; rc = mCameraHandle->ops->cancel_auto_focus(mCameraHandle->camera_handle); break; case CAM_FOCUS_MODE_INFINITY: case CAM_FOCUS_MODE_FIXED: case CAM_FOCUS_MODE_EDOF: default: LOGD("No ops in focusMode (%d)", focusMode); break; } return rc; } /*=========================================================================== * FUNCTION : processUFDumps * * DESCRIPTION: process UF jpeg dumps for refocus support * * PARAMETERS : * @evt : payload of jpeg event, including information about jpeg encoding * status, jpeg size and so on. * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code * * NOTE : none *==========================================================================*/ bool QCamera2HardwareInterface::processUFDumps(qcamera_jpeg_evt_payload_t *evt) { bool ret = true; if (mParameters.isUbiRefocus()) { int index = (int)getOutputImageCount(); bool allFocusImage = (index == ((int)mParameters.getRefocusOutputCount() - 1)); char name[FILENAME_MAX]; camera_memory_t *jpeg_mem = NULL; omx_jpeg_ouput_buf_t *jpeg_out = NULL; size_t dataLen; uint8_t *dataPtr; if (NO_ERROR != waitDeferredWork(mInitPProcJob)) { LOGE("Init PProc Deferred work failed"); return false; } if (!m_postprocessor.getJpegMemOpt()) { dataLen = evt->out_data.buf_filled_len; dataPtr = evt->out_data.buf_vaddr; } else { jpeg_out = (omx_jpeg_ouput_buf_t*) evt->out_data.buf_vaddr; if (!jpeg_out) { LOGE("Null pointer detected"); return false; } jpeg_mem = (camera_memory_t *)jpeg_out->mem_hdl; if (!jpeg_mem) { LOGE("Null pointer detected"); return false; } dataPtr = (uint8_t *)jpeg_mem->data; dataLen = jpeg_mem->size; } if (allFocusImage) { snprintf(name, sizeof(name), "AllFocusImage"); index = -1; } else { snprintf(name, sizeof(name), "%d", 0); } CAM_DUMP_TO_FILE(QCAMERA_DUMP_FRM_LOCATION"ubifocus", name, index, "jpg", dataPtr, dataLen); LOGD("Dump the image %d %d allFocusImage %d", getOutputImageCount(), index, allFocusImage); setOutputImageCount(getOutputImageCount() + 1); if (!allFocusImage) { ret = false; } } return ret; } /*=========================================================================== * FUNCTION : unconfigureAdvancedCapture * * DESCRIPTION: unconfigure Advanced Capture. * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::unconfigureAdvancedCapture() { int32_t rc = NO_ERROR; if (mAdvancedCaptureConfigured) { mAdvancedCaptureConfigured = false; if(mIs3ALocked) { mParameters.set3ALock(false); mIs3ALocked = false; } if (mParameters.isHDREnabled() || mParameters.isAEBracketEnabled()) { rc = mParameters.setToneMapMode(true, true); if (rc != NO_ERROR) { LOGW("Failed to enable tone map during HDR/AEBracketing"); } mHDRBracketingEnabled = false; rc = mParameters.stopAEBracket(); } else if ((mParameters.isChromaFlashEnabled()) || (mFlashNeeded && !mLongshotEnabled) || (mParameters.getLowLightLevel() != CAM_LOW_LIGHT_OFF) || (mParameters.getManualCaptureMode() >= CAM_MANUAL_CAPTURE_TYPE_2)) { rc = mParameters.resetFrameCapture(TRUE); } else if (mParameters.isUbiFocusEnabled() || mParameters.isUbiRefocus()) { rc = configureAFBracketing(false); } else if (mParameters.isOptiZoomEnabled()) { rc = mParameters.setAndCommitZoom(mZoomLevel); setDisplaySkip(FALSE, CAMERA_MAX_PARAM_APPLY_DELAY); } else if (mParameters.isStillMoreEnabled()) { cam_still_more_t stillmore_config = mParameters.getStillMoreSettings(); stillmore_config.burst_count = 0; mParameters.setStillMoreSettings(stillmore_config); /* If SeeMore is running, it will handle re-enabling tone map */ if (!mParameters.isSeeMoreEnabled() && !mParameters.isLTMForSeeMoreEnabled()) { rc = mParameters.setToneMapMode(true, true); if (rc != NO_ERROR) { LOGW("Failed to enable tone map during StillMore"); } } /* Re-enable Tintless */ mParameters.setTintless(true); } else { LOGW("No Advanced Capture feature enabled!!"); rc = BAD_VALUE; } } return rc; } /*=========================================================================== * FUNCTION : configureAdvancedCapture * * DESCRIPTION: configure Advanced Capture. * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::configureAdvancedCapture() { LOGH("E"); int32_t rc = NO_ERROR; rc = mParameters.checkFeatureConcurrency(); if (rc != NO_ERROR) { LOGE("Cannot support Advanced capture modes"); return rc; } setOutputImageCount(0); mInputCount = 0; mAdvancedCaptureConfigured = true; /* Display should be disabled for advanced modes */ bool bSkipDisplay = true; if (getRelatedCamSyncInfo()->mode == CAM_MODE_SECONDARY) { // no Advance capture settings for Aux camera LOGH("X Secondary Camera, no need to process!! "); return rc; } /* Do not stop display if in stillmore livesnapshot */ if (mParameters.isStillMoreEnabled() && mParameters.isSeeMoreEnabled()) { bSkipDisplay = false; } if (mParameters.isUbiFocusEnabled() || mParameters.isUbiRefocus()) { rc = configureAFBracketing(); } else if (mParameters.isOptiZoomEnabled()) { rc = configureOptiZoom(); } else if(mParameters.isHDREnabled()) { rc = configureHDRBracketing(); if (mHDRBracketingEnabled) { rc = mParameters.setToneMapMode(false, true); if (rc != NO_ERROR) { LOGW("Failed to disable tone map during HDR"); } } } else if (mParameters.isAEBracketEnabled()) { rc = mParameters.setToneMapMode(false, true); if (rc != NO_ERROR) { LOGW("Failed to disable tone map during AEBracketing"); } rc = configureAEBracketing(); } else if (mParameters.isStillMoreEnabled()) { rc = configureStillMore(); } else if ((mParameters.isChromaFlashEnabled()) || (mParameters.getLowLightLevel() != CAM_LOW_LIGHT_OFF) || (mParameters.getManualCaptureMode() >= CAM_MANUAL_CAPTURE_TYPE_2)) { rc = mParameters.configFrameCapture(TRUE); } else if (mFlashNeeded && !mLongshotEnabled) { rc = mParameters.configFrameCapture(TRUE); bSkipDisplay = false; } else { LOGH("Advanced Capture feature not enabled!! "); mAdvancedCaptureConfigured = false; bSkipDisplay = false; } LOGH("Stop preview temporarily for advanced captures"); setDisplaySkip(bSkipDisplay); LOGH("X rc = %d", rc); return rc; } /*=========================================================================== * FUNCTION : configureAFBracketing * * DESCRIPTION: configure AF Bracketing. * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::configureAFBracketing(bool enable) { LOGH("E"); int32_t rc = NO_ERROR; cam_af_bracketing_t *af_bracketing_need; if (mParameters.isUbiRefocus()) { af_bracketing_need = &gCamCapability[mCameraId]->refocus_af_bracketing_need; } else { af_bracketing_need = &gCamCapability[mCameraId]->ubifocus_af_bracketing_need; } //Enable AF Bracketing. cam_af_bracketing_t afBracket; memset(&afBracket, 0, sizeof(cam_af_bracketing_t)); afBracket.enable = enable; afBracket.burst_count = af_bracketing_need->burst_count; for(int8_t i = 0; i < MAX_AF_BRACKETING_VALUES; i++) { afBracket.focus_steps[i] = af_bracketing_need->focus_steps[i]; LOGH("focus_step[%d] = %d", i, afBracket.focus_steps[i]); } //Send cmd to backend to set AF Bracketing for Ubi Focus. rc = mParameters.commitAFBracket(afBracket); if ( NO_ERROR != rc ) { LOGE("cannot configure AF bracketing"); return rc; } if (enable) { mParameters.set3ALock(true); mIs3ALocked = true; } LOGH("X rc = %d", rc); return rc; } /*=========================================================================== * FUNCTION : configureHDRBracketing * * DESCRIPTION: configure HDR Bracketing. * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::configureHDRBracketing() { LOGH("E"); int32_t rc = NO_ERROR; cam_hdr_bracketing_info_t& hdrBracketingSetting = gCamCapability[mCameraId]->hdr_bracketing_setting; // 'values' should be in "idx1,idx2,idx3,..." format uint32_t hdrFrameCount = hdrBracketingSetting.num_frames; LOGH("HDR values %d, %d frame count: %u", (int8_t) hdrBracketingSetting.exp_val.values[0], (int8_t) hdrBracketingSetting.exp_val.values[1], hdrFrameCount); // Enable AE Bracketing for HDR cam_exp_bracketing_t aeBracket; memset(&aeBracket, 0, sizeof(cam_exp_bracketing_t)); aeBracket.mode = hdrBracketingSetting.exp_val.mode; if (aeBracket.mode == CAM_EXP_BRACKETING_ON) { mHDRBracketingEnabled = true; } String8 tmp; for (uint32_t i = 0; i < hdrFrameCount; i++) { tmp.appendFormat("%d", (int8_t) hdrBracketingSetting.exp_val.values[i]); tmp.append(","); } if (mParameters.isHDR1xFrameEnabled() && mParameters.isHDR1xExtraBufferNeeded()) { tmp.appendFormat("%d", 0); tmp.append(","); } if( !tmp.isEmpty() && ( MAX_EXP_BRACKETING_LENGTH > tmp.length() ) ) { //Trim last comma memset(aeBracket.values, '\0', MAX_EXP_BRACKETING_LENGTH); memcpy(aeBracket.values, tmp.string(), tmp.length() - 1); } LOGH("HDR config values %s", aeBracket.values); rc = mParameters.setHDRAEBracket(aeBracket); if ( NO_ERROR != rc ) { LOGE("cannot configure HDR bracketing"); return rc; } LOGH("X rc = %d", rc); return rc; } /*=========================================================================== * FUNCTION : configureAEBracketing * * DESCRIPTION: configure AE Bracketing. * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::configureAEBracketing() { LOGH("E"); int32_t rc = NO_ERROR; rc = mParameters.setAEBracketing(); if ( NO_ERROR != rc ) { LOGE("cannot configure AE bracketing"); return rc; } LOGH("X rc = %d", rc); return rc; } /*=========================================================================== * FUNCTION : configureOptiZoom * * DESCRIPTION: configure Opti Zoom. * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::configureOptiZoom() { int32_t rc = NO_ERROR; //store current zoom level. mZoomLevel = mParameters.getParmZoomLevel(); //set zoom level to 1x; mParameters.setAndCommitZoom(0); mParameters.set3ALock(true); mIs3ALocked = true; return rc; } /*=========================================================================== * FUNCTION : configureStillMore * * DESCRIPTION: configure StillMore. * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::configureStillMore() { int32_t rc = NO_ERROR; uint8_t burst_cnt = 0; cam_still_more_t stillmore_config; cam_still_more_t stillmore_cap; /* Disable Tone Map. If seemore is enabled, it will handle disabling it. */ if (!mParameters.isSeeMoreEnabled() && !mParameters.isLTMForSeeMoreEnabled()) { rc = mParameters.setToneMapMode(false, true); if (rc != NO_ERROR) { LOGW("Failed to disable tone map during StillMore"); } } /* Lock 3A */ mParameters.set3ALock(true); mIs3ALocked = true; /* Disable Tintless */ mParameters.setTintless(false); /* Initialize burst count from capability */ stillmore_cap = mParameters.getStillMoreCapability(); burst_cnt = stillmore_cap.max_burst_count; /* Reconfigure burst count from dynamic scene data */ cam_dyn_img_data_t dynamic_img_data = mParameters.getDynamicImgData(); if (dynamic_img_data.input_count >= stillmore_cap.min_burst_count && dynamic_img_data.input_count <= stillmore_cap.max_burst_count) { burst_cnt = dynamic_img_data.input_count; } /* Reconfigure burst count in the case of liveshot */ if (mParameters.isSeeMoreEnabled()) { burst_cnt = 1; } /* Reconfigure burst count from user input */ char prop[PROPERTY_VALUE_MAX]; property_get("persist.camera.imglib.stillmore", prop, "0"); uint8_t burst_setprop = (uint32_t)atoi(prop); if (burst_setprop != 0) { if ((burst_setprop < stillmore_cap.min_burst_count) || (burst_setprop > stillmore_cap.max_burst_count)) { burst_cnt = stillmore_cap.max_burst_count; } else { burst_cnt = burst_setprop; } } memset(&stillmore_config, 0, sizeof(cam_still_more_t)); stillmore_config.burst_count = burst_cnt; mParameters.setStillMoreSettings(stillmore_config); LOGH("Stillmore burst %d", burst_cnt); return rc; } /*=========================================================================== * FUNCTION : stopAdvancedCapture * * DESCRIPTION: stops advanced capture based on capture type * * PARAMETERS : * @pChannel : channel. * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::stopAdvancedCapture( QCameraPicChannel *pChannel) { LOGH("stop bracketig"); int32_t rc = NO_ERROR; if(mParameters.isUbiFocusEnabled() || mParameters.isUbiRefocus()) { rc = pChannel->stopAdvancedCapture(MM_CAMERA_AF_BRACKETING); } else if (mParameters.isChromaFlashEnabled() || (mFlashNeeded && !mLongshotEnabled) || (mParameters.getLowLightLevel() != CAM_LOW_LIGHT_OFF) || (mParameters.getManualCaptureMode() >= CAM_MANUAL_CAPTURE_TYPE_2)) { rc = pChannel->stopAdvancedCapture(MM_CAMERA_FRAME_CAPTURE); } else if(mParameters.isHDREnabled() || mParameters.isAEBracketEnabled()) { rc = pChannel->stopAdvancedCapture(MM_CAMERA_AE_BRACKETING); } else if (mParameters.isOptiZoomEnabled()) { rc = pChannel->stopAdvancedCapture(MM_CAMERA_ZOOM_1X); } else if (mParameters.isStillMoreEnabled()) { LOGH("stopAdvancedCapture not needed for StillMore"); } else { LOGH("No Advanced Capture feature enabled!"); rc = BAD_VALUE; } return rc; } /*=========================================================================== * FUNCTION : startAdvancedCapture * * DESCRIPTION: starts advanced capture based on capture type * * PARAMETERS : * @pChannel : channel. * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::startAdvancedCapture( QCameraPicChannel *pChannel) { LOGH("Start bracketing"); int32_t rc = NO_ERROR; if(mParameters.isUbiFocusEnabled() || mParameters.isUbiRefocus()) { rc = pChannel->startAdvancedCapture(MM_CAMERA_AF_BRACKETING); } else if (mParameters.isOptiZoomEnabled()) { rc = pChannel->startAdvancedCapture(MM_CAMERA_ZOOM_1X); } else if (mParameters.isStillMoreEnabled()) { LOGH("startAdvancedCapture not needed for StillMore"); } else if (mParameters.isHDREnabled() || mParameters.isAEBracketEnabled()) { rc = pChannel->startAdvancedCapture(MM_CAMERA_AE_BRACKETING); } else if (mParameters.isChromaFlashEnabled() || (mFlashNeeded && !mLongshotEnabled) || (mParameters.getLowLightLevel() != CAM_LOW_LIGHT_OFF) || (mParameters.getManualCaptureMode() >= CAM_MANUAL_CAPTURE_TYPE_2)) { cam_capture_frame_config_t config = mParameters.getCaptureFrameConfig(); rc = pChannel->startAdvancedCapture(MM_CAMERA_FRAME_CAPTURE, &config); } else { LOGE("No Advanced Capture feature enabled!"); rc = BAD_VALUE; } return rc; } /*=========================================================================== * FUNCTION : preTakePicture * * DESCRIPTION: Prepare take picture impl, Restarts preview if necessary * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::preTakePicture() { int32_t rc = NO_ERROR; LOGH("E"); if (mParameters.getRecordingHintValue() == true) { // Give HWI control to restart preview only in single camera mode. // In dual-cam mode, this control belongs to muxer. if (getRelatedCamSyncInfo()->sync_control != CAM_SYNC_RELATED_SENSORS_ON) { LOGH("restart preview if rec hint is true and preview is running"); stopPreview(); mParameters.updateRecordingHintValue(FALSE); // start preview again rc = preparePreview(); if (rc == NO_ERROR) { rc = startPreview(); if (rc != NO_ERROR) { unpreparePreview(); } } } else { // For dual cam mode, update the flag mPreviewRestartNeeded to true // Restart control will be handled by muxer. mPreviewRestartNeeded = true; } } LOGH("X rc = %d", rc); 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; // Get total number for snapshots (retro + regular) uint8_t numSnapshots = mParameters.getNumOfSnapshots(); // Get number of retro-active snapshots uint8_t numRetroSnapshots = mParameters.getNumOfRetroSnapshots(); LOGH("E"); //Set rotation value from user settings as Jpeg rotation //to configure back-end modules. mParameters.setJpegRotation(mParameters.getRotation()); // Check if retro-active snapshots are not enabled if (!isRetroPicture() || !mParameters.isZSLMode()) { numRetroSnapshots = 0; LOGH("Reset retro snaphot count to zero"); } //Do special configure for advanced capture modes. rc = configureAdvancedCapture(); if (rc != NO_ERROR) { LOGE("Unsupported capture call"); return rc; } if (mAdvancedCaptureConfigured) { numSnapshots = mParameters.getBurstCountForAdvancedCapture(); } LOGI("snap count = %d zsl = %d advanced = %d", numSnapshots, mParameters.isZSLMode(), mAdvancedCaptureConfigured); if (mParameters.isZSLMode()) { QCameraChannel *pChannel = m_channels[QCAMERA_CH_TYPE_ZSL]; QCameraPicChannel *pPicChannel = (QCameraPicChannel *)pChannel; if (NULL != pPicChannel) { if (mParameters.getofflineRAW()) { startRAWChannel(pPicChannel); pPicChannel = (QCameraPicChannel *)m_channels[QCAMERA_CH_TYPE_RAW]; if (pPicChannel == NULL) { LOGE("RAW Channel is NULL in Manual capture mode"); stopRAWChannel(); return UNKNOWN_ERROR; } } rc = configureOnlineRotation(*pPicChannel); if (rc != NO_ERROR) { LOGE("online rotation failed"); return rc; } // start postprocessor DeferWorkArgs args; memset(&args, 0, sizeof(DeferWorkArgs)); args.pprocArgs = pPicChannel; // No need to wait for mInitPProcJob here, because it was // queued in startPreview, and will definitely be processed before // mReprocJob can begin. mReprocJob = queueDeferredWork(CMD_DEF_PPROC_START, args); if (mReprocJob == 0) { LOGE("Failure: Unable to start pproc"); return -ENOMEM; } // Check if all preview buffers are mapped before creating // a jpeg session as preview stream buffers are queried during the same uint8_t numStreams = pChannel->getNumOfStreams(); QCameraStream *pStream = NULL; QCameraStream *pPreviewStream = NULL; for (uint8_t i = 0 ; i < numStreams ; i++ ) { pStream = pChannel->getStreamByIndex(i); if (!pStream) continue; if (CAM_STREAM_TYPE_PREVIEW == pStream->getMyType()) { pPreviewStream = pStream; break; } } if (pPreviewStream != NULL) { Mutex::Autolock l(mMapLock); QCameraMemory *pMemory = pStream->getStreamBufs(); if (!pMemory) { LOGE("Error!! pMemory is NULL"); return -ENOMEM; } uint8_t waitCnt = 2; while (!pMemory->checkIfAllBuffersMapped() && (waitCnt > 0)) { LOGL(" Waiting for preview buffers to be mapped"); mMapCond.waitRelative( mMapLock, CAMERA_DEFERRED_MAP_BUF_TIMEOUT); LOGL("Wait completed!!"); waitCnt--; } // If all buffers are not mapped after retries, assert assert(pMemory->checkIfAllBuffersMapped()); } else { assert(pPreviewStream); } // Create JPEG session mJpegJob = queueDeferredWork(CMD_DEF_CREATE_JPEG_SESSION, args); if (mJpegJob == 0) { LOGE("Failed to queue CREATE_JPEG_SESSION"); if (NO_ERROR != waitDeferredWork(mReprocJob)) { LOGE("Reprocess Deferred work was failed"); } m_postprocessor.stop(); return -ENOMEM; } if (mAdvancedCaptureConfigured) { rc = startAdvancedCapture(pPicChannel); if (rc != NO_ERROR) { LOGE("cannot start zsl advanced capture"); return rc; } } if (mLongshotEnabled && mPrepSnapRun) { mCameraHandle->ops->start_zsl_snapshot( mCameraHandle->camera_handle, pPicChannel->getMyHandle()); } // If frame sync is ON and it is a SECONDARY camera, // we do not need to send the take picture command to interface // It will be handled along with PRIMARY camera takePicture request mm_camera_req_buf_t buf; memset(&buf, 0x0, sizeof(buf)); if ((!mParameters.isAdvCamFeaturesEnabled() && !mFlashNeeded && !isLongshotEnabled() && isFrameSyncEnabled()) && (getRelatedCamSyncInfo()->sync_control == CAM_SYNC_RELATED_SENSORS_ON)) { if (getRelatedCamSyncInfo()->mode == CAM_MODE_PRIMARY) { buf.type = MM_CAMERA_REQ_FRAME_SYNC_BUF; buf.num_buf_requested = numSnapshots; rc = pPicChannel->takePicture(&buf); if (rc != NO_ERROR) { LOGE("FS_DBG cannot take ZSL picture, stop pproc"); if (NO_ERROR != waitDeferredWork(mReprocJob)) { LOGE("Reprocess Deferred work failed"); return UNKNOWN_ERROR; } if (NO_ERROR != waitDeferredWork(mJpegJob)) { LOGE("Jpeg Deferred work failed"); return UNKNOWN_ERROR; } m_postprocessor.stop(); return rc; } LOGI("PRIMARY camera: send frame sync takePicture!!"); } } else { buf.type = MM_CAMERA_REQ_SUPER_BUF; buf.num_buf_requested = numSnapshots; buf.num_retro_buf_requested = numRetroSnapshots; rc = pPicChannel->takePicture(&buf); if (rc != NO_ERROR) { LOGE("cannot take ZSL picture, stop pproc"); if (NO_ERROR != waitDeferredWork(mReprocJob)) { LOGE("Reprocess Deferred work failed"); return UNKNOWN_ERROR; } if (NO_ERROR != waitDeferredWork(mJpegJob)) { LOGE("Jpeg Deferred work failed"); return UNKNOWN_ERROR; } m_postprocessor.stop(); return rc; } } } else { LOGE("ZSL channel is NULL"); return UNKNOWN_ERROR; } } else { // start snapshot if (mParameters.isJpegPictureFormat() || mParameters.isNV16PictureFormat() || mParameters.isNV21PictureFormat()) { //STOP Preview for Non ZSL use case stopPreview(); //Config CAPTURE channels rc = declareSnapshotStreams(); if (NO_ERROR != rc) { return rc; } rc = addCaptureChannel(); if ((rc == NO_ERROR) && (NULL != m_channels[QCAMERA_CH_TYPE_CAPTURE])) { if (!mParameters.getofflineRAW()) { rc = configureOnlineRotation( *m_channels[QCAMERA_CH_TYPE_CAPTURE]); if (rc != NO_ERROR) { LOGE("online rotation failed"); delChannel(QCAMERA_CH_TYPE_CAPTURE); return rc; } } DeferWorkArgs args; memset(&args, 0, sizeof(DeferWorkArgs)); args.pprocArgs = m_channels[QCAMERA_CH_TYPE_CAPTURE]; // No need to wait for mInitPProcJob here, because it was // queued in startPreview, and will definitely be processed before // mReprocJob can begin. mReprocJob = queueDeferredWork(CMD_DEF_PPROC_START, args); if (mReprocJob == 0) { LOGE("Failure: Unable to start pproc"); return -ENOMEM; } // Create JPEG session mJpegJob = queueDeferredWork(CMD_DEF_CREATE_JPEG_SESSION, args); if (mJpegJob == 0) { LOGE("Failed to queue CREATE_JPEG_SESSION"); if (NO_ERROR != waitDeferredWork(mReprocJob)) { LOGE("Reprocess Deferred work was failed"); } m_postprocessor.stop(); return -ENOMEM; } // start catpure channel rc = m_channels[QCAMERA_CH_TYPE_CAPTURE]->start(); if (rc != NO_ERROR) { LOGE("cannot start capture channel"); if (NO_ERROR != waitDeferredWork(mReprocJob)) { LOGE("Reprocess Deferred work failed"); return UNKNOWN_ERROR; } if (NO_ERROR != waitDeferredWork(mJpegJob)) { LOGE("Jpeg Deferred work failed"); return UNKNOWN_ERROR; } delChannel(QCAMERA_CH_TYPE_CAPTURE); return rc; } QCameraPicChannel *pCapChannel = (QCameraPicChannel *)m_channels[QCAMERA_CH_TYPE_CAPTURE]; if (NULL != pCapChannel) { if (mParameters.isUbiFocusEnabled() || mParameters.isUbiRefocus() || mParameters.isChromaFlashEnabled()) { rc = startAdvancedCapture(pCapChannel); if (rc != NO_ERROR) { LOGE("cannot start advanced capture"); return rc; } } } if ( mLongshotEnabled ) { rc = longShot(); if (NO_ERROR != rc) { if (NO_ERROR != waitDeferredWork(mReprocJob)) { LOGE("Reprocess Deferred work failed"); return UNKNOWN_ERROR; } if (NO_ERROR != waitDeferredWork(mJpegJob)) { LOGE("Jpeg Deferred work failed"); return UNKNOWN_ERROR; } delChannel(QCAMERA_CH_TYPE_CAPTURE); return rc; } } } else { LOGE("cannot add capture channel"); delChannel(QCAMERA_CH_TYPE_CAPTURE); return rc; } } else { // Stop Preview before taking NZSL snapshot stopPreview(); rc = mParameters.updateRAW(gCamCapability[mCameraId]->raw_dim[0]); if (NO_ERROR != rc) { LOGE("Raw dimension update failed %d", rc); return rc; } rc = declareSnapshotStreams(); if (NO_ERROR != rc) { LOGE("RAW stream info configuration failed %d", rc); return rc; } rc = addChannel(QCAMERA_CH_TYPE_RAW); if (rc == NO_ERROR) { // start postprocessor if (NO_ERROR != waitDeferredWork(mInitPProcJob)) { LOGE("Reprocess Deferred work failed"); return UNKNOWN_ERROR; } rc = m_postprocessor.start(m_channels[QCAMERA_CH_TYPE_RAW]); if (rc != NO_ERROR) { LOGE("cannot start postprocessor"); delChannel(QCAMERA_CH_TYPE_RAW); return rc; } rc = startChannel(QCAMERA_CH_TYPE_RAW); if (rc != NO_ERROR) { LOGE("cannot start raw channel"); m_postprocessor.stop(); delChannel(QCAMERA_CH_TYPE_RAW); return rc; } } else { LOGE("cannot add raw channel"); return rc; } } } //When take picture, stop sending preview callbacks to APP m_stateMachine.setPreviewCallbackNeeded(false); LOGI("X rc = %d", rc); return rc; } /*=========================================================================== * FUNCTION : configureOnlineRotation * * DESCRIPTION: Configure backend with expected rotation for snapshot stream * * PARAMETERS : * @ch : Channel containing a snapshot stream * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::configureOnlineRotation(QCameraChannel &ch) { int rc = NO_ERROR; uint32_t streamId = 0; QCameraStream *pStream = NULL; for (uint8_t i = 0; i < ch.getNumOfStreams(); i++) { QCameraStream *stream = ch.getStreamByIndex(i); if ((NULL != stream) && ((CAM_STREAM_TYPE_SNAPSHOT == stream->getMyType()) || (CAM_STREAM_TYPE_RAW == stream->getMyType()))) { pStream = stream; break; } } if (NULL == pStream) { LOGE("No snapshot stream found!"); return BAD_VALUE; } streamId = pStream->getMyServerID(); // Update online rotation configuration rc = mParameters.addOnlineRotation(mParameters.getJpegRotation(), streamId, mParameters.getDeviceRotation()); if (rc != NO_ERROR) { LOGE("addOnlineRotation failed %d", rc); return rc; } return rc; } /*=========================================================================== * FUNCTION : declareSnapshotStreams * * DESCRIPTION: Configure backend with expected snapshot streams * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::declareSnapshotStreams() { int rc = NO_ERROR; // Update stream info configuration rc = mParameters.setStreamConfigure(true, mLongshotEnabled, false); if (rc != NO_ERROR) { LOGE("setStreamConfigure failed %d", rc); return rc; } return rc; } /*=========================================================================== * FUNCTION : longShot * * DESCRIPTION: Queue one more ZSL frame * in the longshot pipe. * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::longShot() { int32_t rc = NO_ERROR; uint8_t numSnapshots = mParameters.getNumOfSnapshots(); QCameraPicChannel *pChannel = NULL; if (mParameters.isZSLMode()) { pChannel = (QCameraPicChannel *)m_channels[QCAMERA_CH_TYPE_ZSL]; } else { pChannel = (QCameraPicChannel *)m_channels[QCAMERA_CH_TYPE_CAPTURE]; } if (NULL != pChannel) { mm_camera_req_buf_t buf; memset(&buf, 0x0, sizeof(buf)); buf.type = MM_CAMERA_REQ_SUPER_BUF; buf.num_buf_requested = numSnapshots; rc = pChannel->takePicture(&buf); } else { LOGE("Capture channel not initialized!"); rc = NO_INIT; goto end; } end: return rc; } /*=========================================================================== * FUNCTION : stopCaptureChannel * * DESCRIPTION: Stops capture channel * * PARAMETERS : * @destroy : Set to true to stop and delete camera channel. * Set to false to only stop capture channel. * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::stopCaptureChannel(bool destroy) { int rc = NO_ERROR; if (mParameters.isJpegPictureFormat() || mParameters.isNV16PictureFormat() || mParameters.isNV21PictureFormat()) { rc = stopChannel(QCAMERA_CH_TYPE_CAPTURE); if (destroy && (NO_ERROR == rc)) { // Destroy camera channel but dont release context waitDeferredWork(mJpegJob); rc = delChannel(QCAMERA_CH_TYPE_CAPTURE, false); } } 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() { waitDeferredWork(mReprocJob); waitDeferredWork(mJpegJob); //stop post processor m_postprocessor.stop(); unconfigureAdvancedCapture(); LOGH("Enable display frames again"); setDisplaySkip(FALSE); if (!mLongshotEnabled) { m_perfLock.lock_rel(); } if (mParameters.isZSLMode()) { QCameraPicChannel *pPicChannel = NULL; if (mParameters.getofflineRAW()) { pPicChannel = (QCameraPicChannel *)m_channels[QCAMERA_CH_TYPE_RAW]; } else { pPicChannel = (QCameraPicChannel *)m_channels[QCAMERA_CH_TYPE_ZSL]; } if (NULL != pPicChannel) { pPicChannel->cancelPicture(); stopRAWChannel(); stopAdvancedCapture(pPicChannel); } } else { // normal capture case if (mParameters.isJpegPictureFormat() || mParameters.isNV16PictureFormat() || mParameters.isNV21PictureFormat()) { 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 : captureDone * * DESCRIPTION: Function called when the capture is completed before encoding * * PARAMETERS : none * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::captureDone() { qcamera_sm_internal_evt_payload_t *payload = (qcamera_sm_internal_evt_payload_t *) malloc(sizeof(qcamera_sm_internal_evt_payload_t)); if (NULL != payload) { memset(payload, 0, sizeof(qcamera_sm_internal_evt_payload_t)); payload->evt_type = QCAMERA_INTERNAL_EVT_ZSL_CAPTURE_DONE; int32_t rc = processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload); if (rc != NO_ERROR) { LOGE("processEvt ZSL capture done failed"); free(payload); payload = NULL; } } else { LOGE("No memory for ZSL capture done event"); } } /*=========================================================================== * FUNCTION : Live_Snapshot_thread * * DESCRIPTION: Seperate thread for taking live snapshot during recording * * PARAMETERS : @data - pointer to QCamera2HardwareInterface class object * * RETURN : none *==========================================================================*/ void* Live_Snapshot_thread (void* data) { QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(data); if (!hw) { LOGE("take_picture_thread: NULL camera device"); return (void *)BAD_VALUE; } if (hw->bLiveSnapshot) { hw->takeLiveSnapshot_internal(); } else { hw->cancelLiveSnapshot_internal(); } return (void* )NULL; } /*=========================================================================== * FUNCTION : Int_Pic_thread * * DESCRIPTION: Seperate thread for taking snapshot triggered by camera backend * * PARAMETERS : @data - pointer to QCamera2HardwareInterface class object * * RETURN : none *==========================================================================*/ void* Int_Pic_thread (void* data) { int rc = NO_ERROR; QCamera2HardwareInterface *hw = reinterpret_cast<QCamera2HardwareInterface *>(data); if (!hw) { LOGE("take_picture_thread: NULL camera device"); return (void *)BAD_VALUE; } bool JpegMemOpt = false; char raw_format[PROPERTY_VALUE_MAX]; memset(raw_format, 0, sizeof(raw_format)); rc = hw->takeBackendPic_internal(&JpegMemOpt, &raw_format[0]); if (rc == NO_ERROR) { hw->checkIntPicPending(JpegMemOpt, &raw_format[0]); } else { //Snapshot attempt not successful, we need to do cleanup here hw->clearIntPendingEvents(); } return (void* )NULL; } /*=========================================================================== * 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; if (mLiveSnapshotThread != 0) { pthread_join(mLiveSnapshotThread,NULL); mLiveSnapshotThread = 0; } bLiveSnapshot = true; rc= pthread_create(&mLiveSnapshotThread, NULL, Live_Snapshot_thread, (void *) this); if (!rc) { pthread_setname_np(mLiveSnapshotThread, "CAM_liveSnap"); } return rc; } /*=========================================================================== * FUNCTION : takePictureInternal * * DESCRIPTION: take snapshot triggered by backend * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::takePictureInternal() { int rc = NO_ERROR; rc= pthread_create(&mIntPicThread, NULL, Int_Pic_thread, (void *) this); if (!rc) { pthread_setname_np(mIntPicThread, "CAM_IntPic"); } return rc; } /*=========================================================================== * FUNCTION : checkIntPicPending * * DESCRIPTION: timed wait for jpeg completion event, and send * back completion event to backend * * PARAMETERS : none * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::checkIntPicPending(bool JpegMemOpt, char *raw_format) { bool bSendToBackend = true; cam_int_evt_params_t params; int rc = NO_ERROR; struct timespec ts; struct timeval tp; gettimeofday(&tp, NULL); ts.tv_sec = tp.tv_sec + 5; ts.tv_nsec = tp.tv_usec * 1000; if (true == m_bIntJpegEvtPending || (true == m_bIntRawEvtPending)) { //Waiting in HAL for snapshot taken notification pthread_mutex_lock(&m_int_lock); rc = pthread_cond_timedwait(&m_int_cond, &m_int_lock, &ts); if (ETIMEDOUT == rc || 0x0 == m_BackendFileName[0]) { //Hit a timeout, or some spurious activity bSendToBackend = false; } if (true == m_bIntJpegEvtPending) { params.event_type = 0; mParameters.getStreamFormat(CAM_STREAM_TYPE_SNAPSHOT, params.picture_format); } else if (true == m_bIntRawEvtPending) { params.event_type = 1; mParameters.getStreamFormat(CAM_STREAM_TYPE_RAW, params.picture_format); } pthread_mutex_unlock(&m_int_lock); if (true == m_bIntJpegEvtPending) { //Attempting to restart preview after taking JPEG snapshot lockAPI(); rc = processAPI(QCAMERA_SM_EVT_SNAPSHOT_DONE, NULL); unlockAPI(); m_postprocessor.setJpegMemOpt(JpegMemOpt); } else if (true == m_bIntRawEvtPending) { //Attempting to restart preview after taking RAW snapshot stopChannel(QCAMERA_CH_TYPE_RAW); delChannel(QCAMERA_CH_TYPE_RAW); //restoring the old raw format property_set("persist.camera.raw.format", raw_format); } if (true == bSendToBackend) { //send event back to server with the file path params.dim = m_postprocessor.m_dst_dim; memcpy(¶ms.path[0], &m_BackendFileName[0], QCAMERA_MAX_FILEPATH_LENGTH); memset(&m_BackendFileName[0], 0x0, QCAMERA_MAX_FILEPATH_LENGTH); params.size = mBackendFileSize; rc = mParameters.setIntEvent(params); } clearIntPendingEvents(); } return; } /*=========================================================================== * FUNCTION : takeBackendPic_internal * * DESCRIPTION: take snapshot triggered by backend * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::takeBackendPic_internal(bool *JpegMemOpt, char *raw_format) { int rc = NO_ERROR; qcamera_api_result_t apiResult; lockAPI(); //Set rotation value from user settings as Jpeg rotation //to configure back-end modules. mParameters.setJpegRotation(mParameters.getRotation()); setRetroPicture(0); /* Prepare snapshot in case LED needs to be flashed */ if (mFlashNeeded == 1 || mParameters.isChromaFlashEnabled()) { // Start Preparing for normal Frames LOGH("Start Prepare Snapshot"); /* Prepare snapshot in case LED needs to be flashed */ rc = processAPI(QCAMERA_SM_EVT_PREPARE_SNAPSHOT, NULL); if (rc == NO_ERROR) { waitAPIResult(QCAMERA_SM_EVT_PREPARE_SNAPSHOT, &apiResult); rc = apiResult.status; } LOGH("Prep Snapshot done rc = %d", rc); mPrepSnapRun = true; } unlockAPI(); if (true == m_bIntJpegEvtPending) { //Attempting to take JPEG snapshot if (NO_ERROR != waitDeferredWork(mInitPProcJob)) { LOGE("Init PProc Deferred work failed"); return UNKNOWN_ERROR; } *JpegMemOpt = m_postprocessor.getJpegMemOpt(); m_postprocessor.setJpegMemOpt(false); /* capture */ lockAPI(); LOGH("Capturing internal snapshot"); rc = processAPI(QCAMERA_SM_EVT_TAKE_PICTURE, NULL); if (rc == NO_ERROR) { waitAPIResult(QCAMERA_SM_EVT_TAKE_PICTURE, &apiResult); rc = apiResult.status; } unlockAPI(); } else if (true == m_bIntRawEvtPending) { //Attempting to take RAW snapshot (void)JpegMemOpt; stopPreview(); //getting the existing raw format type property_get("persist.camera.raw.format", raw_format, "17"); //setting it to a default know value for this task property_set("persist.camera.raw.format", "18"); rc = addChannel(QCAMERA_CH_TYPE_RAW); if (rc == NO_ERROR) { // start postprocessor if (NO_ERROR != waitDeferredWork(mInitPProcJob)) { LOGE("Init PProc Deferred work failed"); return UNKNOWN_ERROR; } rc = m_postprocessor.start(m_channels[QCAMERA_CH_TYPE_RAW]); if (rc != NO_ERROR) { LOGE("cannot start postprocessor"); delChannel(QCAMERA_CH_TYPE_RAW); return rc; } rc = startChannel(QCAMERA_CH_TYPE_RAW); if (rc != NO_ERROR) { LOGE("cannot start raw channel"); m_postprocessor.stop(); delChannel(QCAMERA_CH_TYPE_RAW); return rc; } } else { LOGE("cannot add raw channel"); return rc; } } return rc; } /*=========================================================================== * FUNCTION : clearIntPendingEvents * * DESCRIPTION: clear internal pending events pertaining to backend * snapshot requests * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ void QCamera2HardwareInterface::clearIntPendingEvents() { int rc = NO_ERROR; if (true == m_bIntRawEvtPending) { preparePreview(); startPreview(); } if (true == m_bIntJpegEvtPending) { if (false == mParameters.isZSLMode()) { lockAPI(); rc = processAPI(QCAMERA_SM_EVT_START_PREVIEW, NULL); unlockAPI(); } } pthread_mutex_lock(&m_int_lock); if (true == m_bIntJpegEvtPending) { m_bIntJpegEvtPending = false; } else if (true == m_bIntRawEvtPending) { m_bIntRawEvtPending = false; } pthread_mutex_unlock(&m_int_lock); return; } /*=========================================================================== * FUNCTION : takeLiveSnapshot_internal * * DESCRIPTION: take live snapshot during recording * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::takeLiveSnapshot_internal() { int rc = NO_ERROR; QCameraChannel *pChannel = NULL; //Set rotation value from user settings as Jpeg rotation //to configure back-end modules. mParameters.setJpegRotation(mParameters.getRotation()); // Configure advanced capture rc = configureAdvancedCapture(); if (rc != NO_ERROR) { LOGE("Unsupported capture call"); goto end; } if (isLowPowerMode()) { pChannel = m_channels[QCAMERA_CH_TYPE_VIDEO]; } else { pChannel = m_channels[QCAMERA_CH_TYPE_SNAPSHOT]; } if (NULL == pChannel) { LOGE("Snapshot/Video channel not initialized"); rc = NO_INIT; goto end; } DeferWorkArgs args; memset(&args, 0, sizeof(DeferWorkArgs)); args.pprocArgs = pChannel; // No need to wait for mInitPProcJob here, because it was // queued in startPreview, and will definitely be processed before // mReprocJob can begin. mReprocJob = queueDeferredWork(CMD_DEF_PPROC_START, args); if (mReprocJob == 0) { LOGE("Failed to queue CMD_DEF_PPROC_START"); rc = -ENOMEM; goto end; } // Create JPEG session mJpegJob = queueDeferredWork(CMD_DEF_CREATE_JPEG_SESSION, args); if (mJpegJob == 0) { LOGE("Failed to queue CREATE_JPEG_SESSION"); if (NO_ERROR != waitDeferredWork(mReprocJob)) { LOGE("Reprocess Deferred work was failed"); } m_postprocessor.stop(); rc = -ENOMEM; goto end; } if (isLowPowerMode()) { mm_camera_req_buf_t buf; memset(&buf, 0x0, sizeof(buf)); buf.type = MM_CAMERA_REQ_SUPER_BUF; buf.num_buf_requested = 1; rc = ((QCameraVideoChannel*)pChannel)->takePicture(&buf); goto end; } //Disable reprocess for 4K liveshot case if (!mParameters.is4k2kVideoResolution()) { rc = configureOnlineRotation(*m_channels[QCAMERA_CH_TYPE_SNAPSHOT]); if (rc != NO_ERROR) { LOGE("online rotation failed"); if (NO_ERROR != waitDeferredWork(mReprocJob)) { LOGE("Reprocess Deferred work was failed"); } if (NO_ERROR != waitDeferredWork(mJpegJob)) { LOGE("Jpeg Deferred work was failed"); } m_postprocessor.stop(); return rc; } } if ((NULL != pChannel) && (mParameters.isTNRSnapshotEnabled())) { QCameraStream *pStream = NULL; for (uint32_t i = 0 ; i < pChannel->getNumOfStreams(); i++ ) { pStream = pChannel->getStreamByIndex(i); if ((NULL != pStream) && (CAM_STREAM_TYPE_SNAPSHOT == pStream->getMyType())) { break; } } if (pStream != NULL) { LOGD("REQUEST_FRAMES event for TNR snapshot"); cam_stream_parm_buffer_t param; memset(¶m, 0, sizeof(cam_stream_parm_buffer_t)); param.type = CAM_STREAM_PARAM_TYPE_REQUEST_FRAMES; param.frameRequest.enableStream = 1; rc = pStream->setParameter(param); if (rc != NO_ERROR) { LOGE("Stream Event REQUEST_FRAMES failed"); } goto end; } } // start snapshot channel if ((rc == NO_ERROR) && (NULL != pChannel)) { // Do not link metadata stream for 4K2k resolution // as CPP processing would be done on snapshot stream and not // reprocess stream if (!mParameters.is4k2kVideoResolution()) { // Find and try to link a metadata stream from preview channel QCameraChannel *pMetaChannel = NULL; QCameraStream *pMetaStream = NULL; QCameraStream *pPreviewStream = NULL; if (m_channels[QCAMERA_CH_TYPE_PREVIEW] != NULL) { pMetaChannel = m_channels[QCAMERA_CH_TYPE_PREVIEW]; uint32_t streamNum = pMetaChannel->getNumOfStreams(); QCameraStream *pStream = NULL; for (uint32_t i = 0 ; i < streamNum ; i++ ) { pStream = pMetaChannel->getStreamByIndex(i); if (NULL != pStream) { if (CAM_STREAM_TYPE_METADATA == pStream->getMyType()) { pMetaStream = pStream; } else if (CAM_STREAM_TYPE_PREVIEW == pStream->getMyType()) { pPreviewStream = pStream; } } } } if ((NULL != pMetaChannel) && (NULL != pMetaStream)) { rc = pChannel->linkStream(pMetaChannel, pMetaStream); if (NO_ERROR != rc) { LOGE("Metadata stream link failed %d", rc); } } if ((NULL != pMetaChannel) && (NULL != pPreviewStream)) { rc = pChannel->linkStream(pMetaChannel, pPreviewStream); if (NO_ERROR != rc) { LOGE("Preview stream link failed %d", rc); } } } rc = pChannel->start(); } end: if (rc != NO_ERROR) { rc = processAPI(QCAMERA_SM_EVT_CANCEL_PICTURE, NULL); rc = sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); } 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; if (mLiveSnapshotThread != 0) { pthread_join(mLiveSnapshotThread,NULL); mLiveSnapshotThread = 0; } bLiveSnapshot = false; rc= pthread_create(&mLiveSnapshotThread, NULL, Live_Snapshot_thread, (void *) this); if (!rc) { pthread_setname_np(mLiveSnapshotThread, "CAM_cancel_liveSnap"); } return rc; } /*=========================================================================== * FUNCTION : cancelLiveSnapshot_internal * * DESCRIPTION: cancel live snapshot during recording * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::cancelLiveSnapshot_internal() { int rc = NO_ERROR; unconfigureAdvancedCapture(); LOGH("Enable display frames again"); setDisplaySkip(FALSE); if (!mLongshotEnabled) { m_perfLock.lock_rel(); } //stop post processor m_postprocessor.stop(); // stop snapshot channel if (!mParameters.isTNRSnapshotEnabled()) { rc = stopChannel(QCAMERA_CH_TYPE_SNAPSHOT); } else { QCameraChannel *pChannel = m_channels[QCAMERA_CH_TYPE_SNAPSHOT]; if (NULL != pChannel) { QCameraStream *pStream = NULL; for (uint32_t i = 0 ; i < pChannel->getNumOfStreams(); i++ ) { pStream = pChannel->getStreamByIndex(i); if ((NULL != pStream) && (CAM_STREAM_TYPE_SNAPSHOT == pStream->getMyType())) { break; } } if (pStream != NULL) { LOGD("REQUEST_FRAMES event for TNR snapshot"); cam_stream_parm_buffer_t param; memset(¶m, 0, sizeof(cam_stream_parm_buffer_t)); param.type = CAM_STREAM_PARAM_TYPE_REQUEST_FRAMES; param.frameRequest.enableStream = 0; rc = pStream->setParameter(param); if (rc != NO_ERROR) { LOGE("Stream Event REQUEST_FRAMES failed"); } } } } return rc; } /*=========================================================================== * 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, __unused int32_t &arg1, __unused int32_t &arg2) { int rc = NO_ERROR; switch (command) { #ifndef VANILLA_HAL case CAMERA_CMD_LONGSHOT_ON: m_perfLock.lock_acq(); arg1 = arg2 = 0; // Longshot can only be enabled when image capture // is not active. if ( !m_stateMachine.isCaptureRunning() ) { LOGI("Longshot Enabled"); mLongshotEnabled = true; rc = mParameters.setLongshotEnable(mLongshotEnabled); // Due to recent buffer count optimizations // ZSL might run with considerably less buffers // when not in longshot mode. Preview needs to // restart in this case. if (isZSLMode() && m_stateMachine.isPreviewRunning()) { QCameraChannel *pChannel = NULL; QCameraStream *pSnapStream = NULL; pChannel = m_channels[QCAMERA_CH_TYPE_ZSL]; if (NULL != pChannel) { QCameraStream *pStream = NULL; for (uint32_t i = 0; i < pChannel->getNumOfStreams(); i++) { pStream = pChannel->getStreamByIndex(i); if (pStream != NULL) { if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT)) { pSnapStream = pStream; break; } } } if (NULL != pSnapStream) { uint8_t required = 0; required = getBufNumRequired(CAM_STREAM_TYPE_SNAPSHOT); if (pSnapStream->getBufferCount() < required) { // We restart here, to reset the FPS and no // of buffers as per the requirement of longshot usecase. arg1 = QCAMERA_SM_EVT_RESTART_PERVIEW; if (getRelatedCamSyncInfo()->sync_control == CAM_SYNC_RELATED_SENSORS_ON) { arg2 = QCAMERA_SM_EVT_DELAYED_RESTART; } } } } } // mPrepSnapRun = false; mCACDoneReceived = FALSE; } else { rc = NO_INIT; } break; case CAMERA_CMD_LONGSHOT_OFF: m_perfLock.lock_rel(); if ( mLongshotEnabled && m_stateMachine.isCaptureRunning() ) { cancelPicture(); processEvt(QCAMERA_SM_EVT_SNAPSHOT_DONE, NULL); QCameraChannel *pZSLChannel = m_channels[QCAMERA_CH_TYPE_ZSL]; if (isZSLMode() && (NULL != pZSLChannel) && mPrepSnapRun) { mCameraHandle->ops->stop_zsl_snapshot( mCameraHandle->camera_handle, pZSLChannel->getMyHandle()); } } mPrepSnapRun = false; LOGI("Longshot Disabled"); mLongshotEnabled = false; rc = mParameters.setLongshotEnable(mLongshotEnabled); mCACDoneReceived = FALSE; break; case CAMERA_CMD_HISTOGRAM_ON: case CAMERA_CMD_HISTOGRAM_OFF: rc = setHistogram(command == CAMERA_CMD_HISTOGRAM_ON? true : false); LOGH("Histogram -> %s", mParameters.isHistogramEnabled() ? "Enabled" : "Disabled"); break; #endif case CAMERA_CMD_START_FACE_DETECTION: case CAMERA_CMD_STOP_FACE_DETECTION: mParameters.setFaceDetectionOption(command == CAMERA_CMD_START_FACE_DETECTION? true : false); rc = setFaceDetection(command == CAMERA_CMD_START_FACE_DETECTION? true : false); LOGH("FaceDetection -> %s", mParameters.isFaceDetectionEnabled() ? "Enabled" : "Disabled"); break; #ifndef VANILLA_HAL case CAMERA_CMD_HISTOGRAM_SEND_DATA: #endif 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) { LOGE("img_ptr or config is NULL"); return BAD_VALUE; } // allocate ion memory for source image QCameraHeapMemory *imgBuf = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE); if (imgBuf == NULL) { LOGE("Unable to new heap memory obj for image buf"); return NO_MEMORY; } rc = imgBuf->allocate(1, config->input_buf_planes.plane_info.frame_len, NON_SECURE); if (rc < 0) { LOGE("Unable to allocate heap memory for image buf"); delete imgBuf; return NO_MEMORY; } void *pBufPtr = imgBuf->getPtr(0); if (pBufPtr == NULL) { LOGE("image buf is NULL"); 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) { LOGE("fail to add offline reprocess channel"); imgBuf->deallocate(); delete imgBuf; return UNKNOWN_ERROR; } rc = pChannel->start(); if (rc != NO_ERROR) { LOGE("Cannot start reprocess channel"); imgBuf->deallocate(); delete imgBuf; delete pChannel; return rc; } ssize_t bufSize = imgBuf->getSize(0); if (BAD_INDEX != bufSize) { rc = pChannel->doReprocess(imgBuf->getFd(0), imgBuf->getPtr(0), (size_t)bufSize, faceID); } else { LOGE("Failed to retrieve buffer size (bad index)"); return UNKNOWN_ERROR; } // 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) { dprintf(fd, "\n Camera HAL information Begin \n"); dprintf(fd, "Camera ID: %d \n", mCameraId); dprintf(fd, "StoreMetaDataInFrame: %d \n", mStoreMetaDataInFrame); dprintf(fd, "\n Configuration: %s", mParameters.dump().string()); dprintf(fd, "\n State Information: %s", m_stateMachine.dump().string()); dprintf(fd, "\n Camera HAL information End \n"); /* send UPDATE_DEBUG_LEVEL to the backend so that they can read the debug level property */ mParameters.updateDebugLevel(); return NO_ERROR; } /*=========================================================================== * 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) { int ret = DEAD_OBJECT; if (m_smThreadActive) { ret = m_stateMachine.procAPI(api, api_payload); } return ret; } /*=========================================================================== * 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; //peek into the event, if this is an eztune event from server, //then we don't need to post it to the SM Qs, we shud directly //spawn a thread and get the job done (jpeg or raw snapshot) switch (payload->server_event_type) { case CAM_EVENT_TYPE_INT_TAKE_JPEG: //Received JPEG trigger from eztune if (false == obj->m_bIntJpegEvtPending) { pthread_mutex_lock(&obj->m_int_lock); obj->m_bIntJpegEvtPending = true; pthread_mutex_unlock(&obj->m_int_lock); obj->takePictureInternal(); } free(payload); break; case CAM_EVENT_TYPE_INT_TAKE_RAW: //Received RAW trigger from eztune if (false == obj->m_bIntRawEvtPending) { pthread_mutex_lock(&obj->m_int_lock); obj->m_bIntRawEvtPending = true; pthread_mutex_unlock(&obj->m_int_lock); obj->takePictureInternal(); } free(payload); break; case CAM_EVENT_TYPE_DAEMON_DIED: { Mutex::Autolock l(obj->mDefLock); obj->mDefCond.broadcast(); LOGH("broadcast mDefCond signal\n"); } default: obj->processEvt(QCAMERA_SM_EVT_EVT_NOTIFY, payload); break; } } } else { LOGE("NULL user_data"); } } /*=========================================================================== * 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 { LOGE("NULL user_data"); } } /*=========================================================================== * 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) { if (!mCameraOpened) { LOGH("Camera is not opened, no need to handle thermal evt"); return NO_ERROR; } // Make sure thermal events are logged LOGH("level = %d, userdata = %p, data = %p", *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 : processAEInfo * * DESCRIPTION: process AE updates * * PARAMETERS : * @ae_params: current AE parameters * * RETURN : None *==========================================================================*/ int32_t QCamera2HardwareInterface::processAEInfo(cam_3a_params_t &ae_params) { mParameters.updateAEInfo(ae_params); if (mParameters.isInstantAECEnabled()) { // Reset Instant AEC info only if instant aec enabled. bool bResetInstantAec = false; if (ae_params.settled) { // If AEC settled, reset instant AEC bResetInstantAec = true; } else if ((mParameters.isInstantCaptureEnabled()) && (mInstantAecFrameCount >= mParameters.getAecFrameBoundValue())) { // if AEC not settled, and instant capture enabled, // reset instant AEC only when frame count is // more or equal to AEC frame bound value. bResetInstantAec = true; } else if ((mParameters.isInstantAECEnabled()) && (mInstantAecFrameCount >= mParameters.getAecSkipDisplayFrameBound())) { // if AEC not settled, and only instant AEC enabled, // reset instant AEC only when frame count is // more or equal to AEC skip display frame bound value. bResetInstantAec = true; } if (bResetInstantAec) { LOGD("setting instant AEC to false"); mParameters.setInstantAEC(false, true); mInstantAecFrameCount = 0; } } return NO_ERROR; } /*=========================================================================== * FUNCTION : processFocusPositionInfo * * DESCRIPTION: process AF updates * * PARAMETERS : * @cur_pos_info: current lens position * * RETURN : None *==========================================================================*/ int32_t QCamera2HardwareInterface::processFocusPositionInfo(cam_focus_pos_info_t &cur_pos_info) { mParameters.updateCurrentFocusPosition(cur_pos_info); return NO_ERROR; } /*=========================================================================== * 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; LOGH("E"); if (getRelatedCamSyncInfo()->mode == CAM_MODE_SECONDARY) { // Ignore focus updates LOGH("X Secondary Camera, no need to process!! "); return ret; } cam_focus_mode_type focusMode = mParameters.getFocusMode(); LOGH("[AF_DBG] focusMode=%d, focusState=%d", focusMode, focus_data.focus_state); switch (focusMode) { case CAM_FOCUS_MODE_AUTO: case CAM_FOCUS_MODE_MACRO: // ignore AF event if AF was already cancelled meanwhile if (!mActiveAF) { break; } // If the HAL focus mode is different from AF INFINITY focus mode, send event to app if ((focus_data.focus_mode == CAM_FOCUS_MODE_INFINITY) && (focus_data.focus_state == CAM_AF_STATE_INACTIVE)) { ret = sendEvtNotify(CAMERA_MSG_FOCUS, true, 0); mActiveAF = false; // reset the mActiveAF in this special case break; } //while transitioning from CAF->Auto/Macro, we might receive CAF related //events (PASSIVE_*) due to timing. Ignore such events if any. if ((focus_data.focus_state == CAM_AF_STATE_PASSIVE_SCAN) || (focus_data.focus_state == CAM_AF_STATE_PASSIVE_FOCUSED) || (focus_data.focus_state == CAM_AF_STATE_PASSIVE_UNFOCUSED)) { break; } //This is just an intermediate update to HAL indicating focus is in progress. No need //to send this event to app. Same applies to INACTIVE state as well. if ((focus_data.focus_state == CAM_AF_STATE_ACTIVE_SCAN) || (focus_data.focus_state == CAM_AF_STATE_INACTIVE)) { break; } // update focus distance mParameters.updateFocusDistances(&focus_data.focus_dist); //flush any old snapshot frames in ZSL Q which are not focused. if (mParameters.isZSLMode() && focus_data.flush_info.needFlush ) { QCameraPicChannel *pZSLChannel = (QCameraPicChannel *)m_channels[QCAMERA_CH_TYPE_ZSL]; if (NULL != pZSLChannel) { //flush the zsl-buffer uint32_t flush_frame_idx = focus_data.flush_info.focused_frame_idx; LOGD("flush the zsl-buffer before frame = %u.", flush_frame_idx); pZSLChannel->flushSuperbuffer(flush_frame_idx); } } //send event to app finally LOGI("Send AF DOne event to app"); ret = sendEvtNotify(CAMERA_MSG_FOCUS, (focus_data.focus_state == CAM_AF_STATE_FOCUSED_LOCKED), 0); break; case CAM_FOCUS_MODE_CONTINOUS_VIDEO: case CAM_FOCUS_MODE_CONTINOUS_PICTURE: // If the HAL focus mode is different from AF INFINITY focus mode, send event to app if ((focus_data.focus_mode == CAM_FOCUS_MODE_INFINITY) && (focus_data.focus_state == CAM_AF_STATE_INACTIVE)) { ret = sendEvtNotify(CAMERA_MSG_FOCUS, false, 0); mActiveAF = false; // reset the mActiveAF in this special case break; } //If AutoFocus() is triggered while in CAF mode, ignore all CAF events (PASSIVE_*) and //process/wait for only ACTIVE_* events. if (((focus_data.focus_state == CAM_AF_STATE_PASSIVE_FOCUSED) || (focus_data.focus_state == CAM_AF_STATE_PASSIVE_UNFOCUSED) || (focus_data.focus_state == CAM_AF_STATE_PASSIVE_SCAN)) && mActiveAF) { break; } //These are the AF states for which we need to send notification to app in CAF mode. //This includes both regular CAF (PASSIVE) events as well as ACTIVE events ( in case //AF is triggered while in CAF mode) if ((focus_data.focus_state == CAM_AF_STATE_PASSIVE_FOCUSED) || (focus_data.focus_state == CAM_AF_STATE_PASSIVE_UNFOCUSED) || (focus_data.focus_state == CAM_AF_STATE_FOCUSED_LOCKED) || (focus_data.focus_state == CAM_AF_STATE_NOT_FOCUSED_LOCKED)) { // update focus distance mParameters.updateFocusDistances(&focus_data.focus_dist); if (mParameters.isZSLMode() && focus_data.flush_info.needFlush ) { QCameraPicChannel *pZSLChannel = (QCameraPicChannel *)m_channels[QCAMERA_CH_TYPE_ZSL]; if (NULL != pZSLChannel) { //flush the zsl-buffer uint32_t flush_frame_idx = focus_data.flush_info.focused_frame_idx; LOGD("flush the zsl-buffer before frame = %u.", flush_frame_idx); pZSLChannel->flushSuperbuffer(flush_frame_idx); } } if (mActiveAF) { LOGI("Send AF Done event to app"); } ret = sendEvtNotify(CAMERA_MSG_FOCUS, ((focus_data.focus_state == CAM_AF_STATE_PASSIVE_FOCUSED) || (focus_data.focus_state == CAM_AF_STATE_FOCUSED_LOCKED)), 0); } ret = sendEvtNotify(CAMERA_MSG_FOCUS_MOVE, (focus_data.focus_state == CAM_AF_STATE_PASSIVE_SCAN), 0); break; case CAM_FOCUS_MODE_INFINITY: case CAM_FOCUS_MODE_FIXED: case CAM_FOCUS_MODE_EDOF: default: LOGH("no ops for autofocus event in focusmode %d", focusMode); break; } //Reset mActiveAF once we receive focus done event if ((focus_data.focus_state == CAM_AF_STATE_FOCUSED_LOCKED) || (focus_data.focus_state == CAM_AF_STATE_NOT_FOCUSED_LOCKED)) { mActiveAF = false; } LOGH("X"); 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 : processZSLCaptureDone * * DESCRIPTION: process ZSL capture done events * * PARAMETERS : None * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::processZSLCaptureDone() { int rc = NO_ERROR; if (++mInputCount >= mParameters.getBurstCountForAdvancedCapture()) { rc = unconfigureAdvancedCapture(); } return rc; } /*=========================================================================== * FUNCTION : processRetroAECUnlock * * DESCRIPTION: process retro burst AEC unlock events * * PARAMETERS : None * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::processRetroAECUnlock() { int rc = NO_ERROR; LOGH("LED assisted AF Release AEC Lock"); rc = mParameters.setAecLock("false"); if (NO_ERROR != rc) { LOGE("Error setting AEC lock"); return rc; } rc = mParameters.commitParameters(); if (NO_ERROR != rc) { LOGE("Error during camera parameter commit"); } else { m_bLedAfAecLock = FALSE; } return rc; } /*=========================================================================== * FUNCTION : processHDRData * * DESCRIPTION: process HDR scene events * * PARAMETERS : * @hdr_scene : HDR scene event data * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::processHDRData( __unused cam_asd_hdr_scene_data_t hdr_scene) { int rc = NO_ERROR; #ifndef VANILLA_HAL if (hdr_scene.is_hdr_scene && (hdr_scene.hdr_confidence > HDR_CONFIDENCE_THRESHOLD) && mParameters.isAutoHDREnabled()) { m_HDRSceneEnabled = true; } else { m_HDRSceneEnabled = false; } mParameters.setHDRSceneEnable(m_HDRSceneEnabled); if ( msgTypeEnabled(CAMERA_MSG_META_DATA) ) { size_t data_len = sizeof(int); size_t buffer_len = 1 *sizeof(int) //meta type + 1 *sizeof(int) //data len + 1 *sizeof(int); //data camera_memory_t *hdrBuffer = mGetMemory(-1, buffer_len, 1, mCallbackCookie); if ( NULL == hdrBuffer ) { LOGE("Not enough memory for auto HDR data"); return NO_MEMORY; } int *pHDRData = (int *)hdrBuffer->data; if (pHDRData == NULL) { LOGE("memory data ptr is NULL"); return UNKNOWN_ERROR; } pHDRData[0] = CAMERA_META_DATA_HDR; pHDRData[1] = (int)data_len; pHDRData[2] = m_HDRSceneEnabled; qcamera_callback_argm_t cbArg; memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); cbArg.cb_type = QCAMERA_DATA_CALLBACK; cbArg.msg_type = CAMERA_MSG_META_DATA; cbArg.data = hdrBuffer; cbArg.user_data = hdrBuffer; cbArg.cookie = this; cbArg.release_cb = releaseCameraMemory; rc = m_cbNotifier.notifyCallback(cbArg); if (rc != NO_ERROR) { LOGE("fail sending auto HDR notification"); hdrBuffer->release(hdrBuffer); } } LOGH("hdr_scene_data: processHDRData: %d %f", hdr_scene.is_hdr_scene, hdr_scene.hdr_confidence); #endif return rc; } /*=========================================================================== * FUNCTION : transAwbMetaToParams * * DESCRIPTION: translate awb params from metadata callback to QCameraParametersIntf * * PARAMETERS : * @awb_params : awb params from metadata callback * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::transAwbMetaToParams(cam_awb_params_t &awb_params) { mParameters.updateAWBParams(awb_params); return NO_ERROR; } /*=========================================================================== * 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; LOGI("[KPI Perf]: Received PREPARE SANSPHOT Done event state = %d", prep_snapshot_state); if (m_channels[QCAMERA_CH_TYPE_ZSL] && prep_snapshot_state == NEED_FUTURE_FRAME) { LOGH("already handled in mm-camera-intf, no ops here"); if (isRetroPicture()) { mParameters.setAecLock("true"); mParameters.commitParameters(); m_bLedAfAecLock = TRUE; } } return ret; } /*=========================================================================== * FUNCTION : processASDUpdate * * DESCRIPTION: process ASD update event * * PARAMETERS : * @scene: selected scene mode * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::processASDUpdate( __unused cam_asd_decision_t asd_decision) { #ifndef VANILLA_HAL if ( msgTypeEnabled(CAMERA_MSG_META_DATA) ) { size_t data_len = sizeof(cam_auto_scene_t); size_t buffer_len = 1 *sizeof(int) //meta type + 1 *sizeof(int) //data len + data_len; //data camera_memory_t *asdBuffer = mGetMemory(-1, buffer_len, 1, mCallbackCookie); if ( NULL == asdBuffer ) { LOGE("Not enough memory for histogram data"); return NO_MEMORY; } int *pASDData = (int *)asdBuffer->data; if (pASDData == NULL) { LOGE("memory data ptr is NULL"); return UNKNOWN_ERROR; } pASDData[0] = CAMERA_META_DATA_ASD; pASDData[1] = (int)data_len; pASDData[2] = asd_decision.detected_scene; qcamera_callback_argm_t cbArg; memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); cbArg.cb_type = QCAMERA_DATA_CALLBACK; cbArg.msg_type = CAMERA_MSG_META_DATA; cbArg.data = asdBuffer; cbArg.user_data = asdBuffer; cbArg.cookie = this; cbArg.release_cb = releaseCameraMemory; int32_t rc = m_cbNotifier.notifyCallback(cbArg); if (rc != NO_ERROR) { LOGE("fail sending notification"); asdBuffer->release(asdBuffer); } } #endif return NO_ERROR; } /*=========================================================================== * 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, qcamera_api_result_t *apiResult) { LOGD("wait for API result of evt (%d)", api_evt); int resultReceived = 0; while (!resultReceived) { pthread_cond_wait(&m_cond, &m_lock); if (m_apiResultList != NULL) { api_result_list *apiResultList = m_apiResultList; api_result_list *apiResultListPrevious = m_apiResultList; while (apiResultList != NULL) { if (apiResultList->result.request_api == api_evt) { resultReceived = 1; *apiResult = apiResultList->result; apiResultListPrevious->next = apiResultList->next; if (apiResultList == m_apiResultList) { m_apiResultList = apiResultList->next; } free(apiResultList); break; } else { apiResultListPrevious = apiResultList; apiResultList = apiResultList->next; } } } } LOGD("return (%d) from API result wait for evt (%d)", 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); api_result_list *apiResult = (api_result_list *)malloc(sizeof(api_result_list)); if (apiResult == NULL) { LOGE("ERROR: malloc for api result failed, Result will not be sent"); goto malloc_failed; } apiResult->result = *result; apiResult->next = NULL; if (m_apiResultList == NULL) m_apiResultList = apiResult; else { api_result_list *apiResultList = m_apiResultList; while(apiResultList->next != NULL) apiResultList = apiResultList->next; apiResultList->next = apiResult; } malloc_failed: pthread_cond_broadcast(&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); } int32_t QCamera2HardwareInterface::prepareRawStream(QCameraChannel *curChannel) { int32_t rc = NO_ERROR; cam_dimension_t str_dim,max_dim; QCameraChannel *pChannel; max_dim.width = 0; max_dim.height = 0; for (int j = 0; j < QCAMERA_CH_TYPE_MAX; j++) { if (m_channels[j] != NULL) { pChannel = m_channels[j]; for (uint8_t i = 0; i < pChannel->getNumOfStreams(); i++) { QCameraStream *pStream = pChannel->getStreamByIndex(i); if (pStream != NULL) { if ((pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) || (pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW))) { continue; } pStream->getFrameDimension(str_dim); if (str_dim.width > max_dim.width) { max_dim.width = str_dim.width; } if (str_dim.height > max_dim.height) { max_dim.height = str_dim.height; } } } } } for (uint8_t i = 0; i < curChannel->getNumOfStreams(); i++) { QCameraStream *pStream = curChannel->getStreamByIndex(i); if (pStream != NULL) { if ((pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) || (pStream->isTypeOf(CAM_STREAM_TYPE_POSTVIEW))) { continue; } pStream->getFrameDimension(str_dim); if (str_dim.width > max_dim.width) { max_dim.width = str_dim.width; } if (str_dim.height > max_dim.height) { max_dim.height = str_dim.height; } } } rc = mParameters.updateRAW(max_dim); return rc; } /*=========================================================================== * 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; if (streamType == CAM_STREAM_TYPE_RAW) { prepareRawStream(pChannel); } QCameraHeapMemory *pStreamInfo = allocateStreamInfoBuf(streamType); if (pStreamInfo == NULL) { LOGE("no mem for stream info buf"); return NO_MEMORY; } uint8_t minStreamBufNum = getBufNumRequired(streamType); bool bDynAllocBuf = false; if (isZSLMode() && streamType == CAM_STREAM_TYPE_SNAPSHOT) { bDynAllocBuf = true; } cam_padding_info_t padding_info; if (streamType == CAM_STREAM_TYPE_ANALYSIS) { cam_analysis_info_t analysisInfo; cam_feature_mask_t featureMask; featureMask = 0; mParameters.getStreamPpMask(CAM_STREAM_TYPE_ANALYSIS, featureMask); rc = mParameters.getAnalysisInfo( ((mParameters.getRecordingHintValue() == true) && mParameters.fdModeInVideo()), FALSE, featureMask, &analysisInfo); if (rc != NO_ERROR) { LOGE("getAnalysisInfo failed, ret = %d", rc); return rc; } padding_info = analysisInfo.analysis_padding_info; } else { padding_info = gCamCapability[mCameraId]->padding_info; if (streamType == CAM_STREAM_TYPE_PREVIEW) { padding_info.width_padding = mSurfaceStridePadding; padding_info.height_padding = CAM_PAD_TO_2; } if((!needReprocess()) || (streamType != CAM_STREAM_TYPE_SNAPSHOT) || (!mParameters.isLLNoiseEnabled())) { padding_info.offset_info.offset_x = 0; padding_info.offset_info.offset_y = 0; } } bool deferAllocation = needDeferred(streamType); LOGD("deferAllocation = %d bDynAllocBuf = %d, stream type = %d", deferAllocation, bDynAllocBuf, streamType); rc = pChannel->addStream(*this, pStreamInfo, NULL, minStreamBufNum, &padding_info, streamCB, userData, bDynAllocBuf, deferAllocation); if (rc != NO_ERROR) { LOGE("add stream type (%d) failed, ret = %d", streamType, rc); 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; char value[PROPERTY_VALUE_MAX]; bool raw_yuv = false; 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) { LOGE("no mem for preview channel"); return NO_MEMORY; } // preview only channel, don't need bundle attr and cb rc = pChannel->init(NULL, NULL, NULL); if (rc != NO_ERROR) { LOGE("init preview channel failed, ret = %d", rc); 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) { LOGE("add metadata stream failed, ret = %d", rc); return rc; } if (isRdiMode()) { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_RAW, rdi_mode_stream_cb_routine, this); } else { 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); pChannel->setStreamSyncCB(CAM_STREAM_TYPE_PREVIEW, synchronous_stream_cb_routine); } } if (((mParameters.fdModeInVideo()) || (mParameters.getDcrf() == true) || (mParameters.getRecordingHintValue() != true)) && (!mParameters.isSecureMode())) { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_ANALYSIS, NULL, this); if (rc != NO_ERROR) { LOGE("add Analysis stream failed, ret = %d", rc); return rc; } } property_get("persist.camera.raw_yuv", value, "0"); raw_yuv = atoi(value) > 0 ? true : false; if ( raw_yuv ) { rc = addStreamToChannel(pChannel,CAM_STREAM_TYPE_RAW, preview_raw_stream_cb_routine,this); if ( rc != NO_ERROR ) { LOGE("add raw stream failed, ret = %d", __FUNCTION__, rc); delete pChannel; return rc; } } if (rc != NO_ERROR) { LOGE("add preview stream failed, ret = %d", 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) { LOGE("no mem for video channel"); return NO_MEMORY; } if (isLowPowerMode()) { 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 = 0; //wait for future frame for liveshot attr.post_frame_skip = mParameters.getZSLBurstInterval(); attr.water_mark = 1; //hold min buffers possible in Q attr.max_unmatched_frames = mParameters.getMaxUnmatchedFramesInQueue(); rc = pChannel->init(&attr, snapshot_channel_cb_routine, this); } else { // preview only channel, don't need bundle attr and cb rc = pChannel->init(NULL, NULL, NULL); } if (rc != 0) { LOGE("init video channel failed, ret = %d", rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_VIDEO, video_stream_cb_routine, this); if (rc != NO_ERROR) { LOGE("add video stream failed, ret = %d", 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) { LOGE("no mem for snapshot channel"); return NO_MEMORY; } 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.look_back = 0; //wait for future frame for liveshot attr.post_frame_skip = mParameters.getZSLBurstInterval(); attr.water_mark = 1; //hold min buffers possible in Q attr.max_unmatched_frames = mParameters.getMaxUnmatchedFramesInQueue(); attr.priority = MM_CAMERA_SUPER_BUF_PRIORITY_LOW; rc = pChannel->init(&attr, snapshot_channel_cb_routine, this); if (rc != NO_ERROR) { LOGE("init snapshot channel failed, ret = %d", rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_SNAPSHOT, NULL, NULL); if (rc != NO_ERROR) { LOGE("add snapshot stream failed, ret = %d", 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) { LOGE("no mem for raw channel"); return NO_MEMORY; } if (mParameters.getofflineRAW()) { 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 = 1; attr.max_unmatched_frames = mParameters.getMaxUnmatchedFramesInQueue(); rc = pChannel->init(&attr, raw_channel_cb_routine, this); if (rc != NO_ERROR) { LOGE("init RAW channel failed, ret = %d", rc); delete pChannel; return rc; } } else { rc = pChannel->init(NULL, NULL, NULL); if (rc != NO_ERROR) { LOGE("init raw channel failed, ret = %d", rc); delete pChannel; return rc; } } if (!mParameters.isZSLMode()) { // 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) { LOGE("add metadata stream failed, ret = %d", rc); delete pChannel; return rc; } } if (mParameters.getofflineRAW()) { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_RAW, NULL, this); } else { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_RAW, raw_stream_cb_routine, this); } if (rc != NO_ERROR) { LOGE("add snapshot stream failed, ret = %d", 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; char value[PROPERTY_VALUE_MAX]; bool raw_yuv = false; 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) { LOGE("no mem for ZSL channel"); 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)); if (mParameters.isSceneSelectionEnabled()) { attr.notify_mode = MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS; } else { attr.notify_mode = MM_CAMERA_SUPER_BUF_NOTIFY_BURST; } attr.look_back = mParameters.getZSLBackLookCount(); attr.post_frame_skip = mParameters.getZSLBurstInterval(); if (mParameters.isOEMFeatEnabled()) { attr.post_frame_skip++; } attr.water_mark = mParameters.getZSLQueueDepth(); attr.max_unmatched_frames = mParameters.getMaxUnmatchedFramesInQueue(); attr.user_expected_frame_id = mParameters.isInstantCaptureEnabled() ? (uint8_t)mParameters.getAecFrameBoundValue() : 0; //Enabled matched queue if (isFrameSyncEnabled()) { LOGH("Enabling frame sync for dual camera, camera Id: %d", mCameraId); attr.enable_frame_sync = 1; } rc = pChannel->init(&attr, zsl_channel_cb, this); if (rc != 0) { LOGE("init ZSL channel failed, ret = %d", 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) { LOGE("add metadata stream failed, ret = %d", 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); pChannel->setStreamSyncCB(CAM_STREAM_TYPE_PREVIEW, synchronous_stream_cb_routine); } if (rc != NO_ERROR) { LOGE("add preview stream failed, ret = %d", rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_SNAPSHOT, NULL, this); if (rc != NO_ERROR) { LOGE("add snapshot stream failed, ret = %d", rc); delete pChannel; return rc; } if (!mParameters.isSecureMode()) { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_ANALYSIS, NULL, this); if (rc != NO_ERROR) { LOGE("add Analysis stream failed, ret = %d", rc); delete pChannel; return rc; } } property_get("persist.camera.raw_yuv", value, "0"); raw_yuv = atoi(value) > 0 ? true : false; if (raw_yuv) { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_RAW, NULL, this); if (rc != NO_ERROR) { LOGE("add raw stream failed, ret = %d", 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; QCameraPicChannel *pChannel = NULL; char value[PROPERTY_VALUE_MAX]; bool raw_yuv = false; if (m_channels[QCAMERA_CH_TYPE_CAPTURE] != NULL) { delete m_channels[QCAMERA_CH_TYPE_CAPTURE]; m_channels[QCAMERA_CH_TYPE_CAPTURE] = NULL; } pChannel = new QCameraPicChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { LOGE("no mem for capture channel"); 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)); if ( mLongshotEnabled ) { attr.notify_mode = MM_CAMERA_SUPER_BUF_NOTIFY_BURST; attr.look_back = mParameters.getZSLBackLookCount(); attr.water_mark = mParameters.getZSLQueueDepth(); } else { 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) { LOGE("init capture channel failed, ret = %d", rc); 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) { LOGE("add metadata stream failed, ret = %d", rc); return rc; } if (!mLongshotEnabled) { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_POSTVIEW, NULL, this); if (rc != NO_ERROR) { LOGE("add postview stream failed, ret = %d", rc); return rc; } } else { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_PREVIEW, preview_stream_cb_routine, this); if (rc != NO_ERROR) { LOGE("add preview stream failed, ret = %d", rc); return rc; } pChannel->setStreamSyncCB(CAM_STREAM_TYPE_PREVIEW, synchronous_stream_cb_routine); } if (!mParameters.getofflineRAW()) { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_SNAPSHOT, NULL, this); if (rc != NO_ERROR) { LOGE("add snapshot stream failed, ret = %d", rc); return rc; } } stream_cb_routine stream_cb = NULL; property_get("persist.camera.raw_yuv", value, "0"); raw_yuv = atoi(value) > 0 ? true : false; if (raw_yuv) { stream_cb = snapshot_raw_stream_cb_routine; } if ((raw_yuv) || (mParameters.getofflineRAW())) { rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_RAW, stream_cb, this); if (rc != NO_ERROR) { LOGE("add raw stream failed, ret = %d", rc); 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) { LOGE("no mem for metadata channel"); return NO_MEMORY; } rc = pChannel->init(NULL, NULL, NULL); if (rc != NO_ERROR) { LOGE("init metadata channel failed, ret = %d", rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_METADATA, metadata_stream_cb_routine, this); if (rc != NO_ERROR) { LOGE("add metadata stream failed, ret = %d", rc); delete pChannel; return rc; } m_channels[QCAMERA_CH_TYPE_METADATA] = pChannel; return rc; } /*=========================================================================== * FUNCTION : addCallbackChannel * * DESCRIPTION: add a callback channel that contains a callback stream * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::addCallbackChannel() { int32_t rc = NO_ERROR; QCameraChannel *pChannel = NULL; if (m_channels[QCAMERA_CH_TYPE_CALLBACK] != NULL) { delete m_channels[QCAMERA_CH_TYPE_CALLBACK]; m_channels[QCAMERA_CH_TYPE_CALLBACK] = NULL; } pChannel = new QCameraChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { LOGE("no mem for callback channel"); return NO_MEMORY; } rc = pChannel->init(NULL, NULL, this); if (rc != NO_ERROR) { LOGE("init callback channel failed, ret = %d", rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_CALLBACK, callback_stream_cb_routine, this); if (rc != NO_ERROR) { LOGE("add callback stream failed, ret = %d", rc); delete pChannel; return rc; } m_channels[QCAMERA_CH_TYPE_CALLBACK] = pChannel; return rc; } /*=========================================================================== * FUNCTION : addAnalysisChannel * * DESCRIPTION: add a analysis channel that contains a analysis stream * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::addAnalysisChannel() { int32_t rc = NO_ERROR; QCameraChannel *pChannel = NULL; if (m_channels[QCAMERA_CH_TYPE_ANALYSIS] != NULL) { delete m_channels[QCAMERA_CH_TYPE_ANALYSIS]; m_channels[QCAMERA_CH_TYPE_ANALYSIS] = NULL; } pChannel = new QCameraChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { LOGE("no mem for metadata channel"); return NO_MEMORY; } rc = pChannel->init(NULL, NULL, this); if (rc != NO_ERROR) { LOGE("init Analysis channel failed, ret = %d", rc); delete pChannel; return rc; } rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_ANALYSIS, NULL, this); if (rc != NO_ERROR) { LOGE("add Analysis stream failed, ret = %d", rc); delete pChannel; return rc; } m_channels[QCAMERA_CH_TYPE_ANALYSIS] = pChannel; return rc; } /*=========================================================================== * FUNCTION : getPPConfig * * DESCRIPTION: get Post processing configaration data * * PARAMETERS : * @pp config: pp config structure pointer, * @curIndex: current pp channel index * @multipass: Flag if multipass prcessing enabled. * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::getPPConfig(cam_pp_feature_config_t &pp_config, int8_t curIndex, bool multipass) { int32_t rc = NO_ERROR; if (multipass) { LOGW("Multi pass enabled. Total Pass = %d, cur index = %d", mParameters.getReprocCount(), curIndex); } LOGH("Supported pproc feature mask = %llx", gCamCapability[mCameraId]->qcom_supported_feature_mask); cam_feature_mask_t feature_mask = gCamCapability[mCameraId]->qcom_supported_feature_mask; int32_t zoomLevel = mParameters.getParmZoomLevel(); uint32_t rotation = mParameters.getJpegRotation(); int32_t effect = mParameters.getEffectValue(); pp_config.cur_reproc_count = curIndex + 1; pp_config.total_reproc_count = mParameters.getReprocCount(); switch(curIndex) { case 0: //Configure feature mask for first pass of reprocessing //check if any effects are enabled if ((CAM_EFFECT_MODE_OFF != effect) && (feature_mask & CAM_QCOM_FEATURE_EFFECT)) { pp_config.feature_mask |= CAM_QCOM_FEATURE_EFFECT; pp_config.effect = effect; } //check for features that need to be enabled by default like sharpness //(if supported by hw). if ((feature_mask & CAM_QCOM_FEATURE_SHARPNESS) && !mParameters.isOptiZoomEnabled()) { pp_config.feature_mask |= CAM_QCOM_FEATURE_SHARPNESS; pp_config.sharpness = mParameters.getSharpness(); } //check if zoom is enabled if ((zoomLevel > 0) && (feature_mask & CAM_QCOM_FEATURE_CROP)) { pp_config.feature_mask |= CAM_QCOM_FEATURE_CROP; } if (mParameters.isWNREnabled() && (feature_mask & CAM_QCOM_FEATURE_DENOISE2D)) { pp_config.feature_mask |= CAM_QCOM_FEATURE_DENOISE2D; pp_config.denoise2d.denoise_enable = 1; pp_config.denoise2d.process_plates = mParameters.getDenoiseProcessPlate(CAM_INTF_PARM_WAVELET_DENOISE); } if (isCACEnabled()) { pp_config.feature_mask |= CAM_QCOM_FEATURE_CAC; } //check if rotation is required if ((feature_mask & CAM_QCOM_FEATURE_ROTATION) && (rotation > 0)) { pp_config.feature_mask |= CAM_QCOM_FEATURE_ROTATION; 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; } } if (mParameters.isHDREnabled()){ pp_config.feature_mask |= CAM_QCOM_FEATURE_HDR; pp_config.hdr_param.hdr_enable = 1; pp_config.hdr_param.hdr_need_1x = mParameters.isHDR1xFrameEnabled(); pp_config.hdr_param.hdr_mode = CAM_HDR_MODE_MULTIFRAME; } else { pp_config.feature_mask &= ~CAM_QCOM_FEATURE_HDR; pp_config.hdr_param.hdr_enable = 0; } //check if scaling is enabled if ((feature_mask & CAM_QCOM_FEATURE_SCALE) && mParameters.isReprocScaleEnabled() && mParameters.isUnderReprocScaling()){ pp_config.feature_mask |= CAM_QCOM_FEATURE_SCALE; mParameters.getPicSizeFromAPK( pp_config.scale_param.output_width, pp_config.scale_param.output_height); } if(mParameters.isUbiFocusEnabled()) { pp_config.feature_mask |= CAM_QCOM_FEATURE_UBIFOCUS; } else { pp_config.feature_mask &= ~CAM_QCOM_FEATURE_UBIFOCUS; } if(mParameters.isUbiRefocus()) { pp_config.feature_mask |= CAM_QCOM_FEATURE_REFOCUS; pp_config.misc_buf_param.misc_buffer_index = 0; } else { pp_config.feature_mask &= ~CAM_QCOM_FEATURE_REFOCUS; } if(mParameters.isChromaFlashEnabled()) { pp_config.feature_mask |= CAM_QCOM_FEATURE_CHROMA_FLASH; pp_config.flash_value = CAM_FLASH_ON; } else { pp_config.feature_mask &= ~CAM_QCOM_FEATURE_CHROMA_FLASH; } if(mParameters.isOptiZoomEnabled() && (0 <= zoomLevel)) { pp_config.feature_mask |= CAM_QCOM_FEATURE_OPTIZOOM; pp_config.zoom_level = (uint8_t) zoomLevel; } else { pp_config.feature_mask &= ~CAM_QCOM_FEATURE_OPTIZOOM; } if (mParameters.getofflineRAW()) { pp_config.feature_mask |= CAM_QCOM_FEATURE_RAW_PROCESSING; } if (mParameters.isTruePortraitEnabled()) { pp_config.feature_mask |= CAM_QCOM_FEATURE_TRUEPORTRAIT; pp_config.misc_buf_param.misc_buffer_index = 0; } else { pp_config.feature_mask &= ~CAM_QCOM_FEATURE_TRUEPORTRAIT; } if(mParameters.isStillMoreEnabled()) { pp_config.feature_mask |= CAM_QCOM_FEATURE_STILLMORE; } else { pp_config.feature_mask &= ~CAM_QCOM_FEATURE_STILLMORE; } if (mParameters.isOEMFeatEnabled()) { pp_config.feature_mask |= CAM_OEM_FEATURE_1; } if (mParameters.getCDSMode() != CAM_CDS_MODE_OFF) { if (feature_mask & CAM_QCOM_FEATURE_DSDN) { pp_config.feature_mask |= CAM_QCOM_FEATURE_DSDN; } else { pp_config.feature_mask |= CAM_QCOM_FEATURE_CDS; } } if ((multipass) && (m_postprocessor.getPPChannelCount() > 1)) { pp_config.feature_mask &= ~CAM_QCOM_FEATURE_PP_PASS_2; pp_config.feature_mask &= ~CAM_QCOM_FEATURE_ROTATION; pp_config.feature_mask &= ~CAM_QCOM_FEATURE_CDS; pp_config.feature_mask &= ~CAM_QCOM_FEATURE_DSDN; pp_config.feature_mask |= CAM_QCOM_FEATURE_CROP; } else { pp_config.feature_mask |= CAM_QCOM_FEATURE_SCALE; } cam_dimension_t thumb_src_dim; cam_dimension_t thumb_dst_dim; mParameters.getThumbnailSize(&(thumb_dst_dim.width), &(thumb_dst_dim.height)); mParameters.getStreamDimension(CAM_STREAM_TYPE_POSTVIEW,thumb_src_dim); if ((thumb_dst_dim.width != thumb_src_dim.width) || (thumb_dst_dim.height != thumb_src_dim.height)) { if (thumb_dst_dim.width != 0 && thumb_dst_dim.height != 0) { pp_config.feature_mask |= CAM_QCOM_FEATURE_CROP; } } break; case 1: //Configure feature mask for second pass of reprocessing pp_config.feature_mask |= CAM_QCOM_FEATURE_PP_PASS_2; if ((feature_mask & CAM_QCOM_FEATURE_ROTATION) && (rotation > 0)) { pp_config.feature_mask |= CAM_QCOM_FEATURE_ROTATION; 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; } } if (mParameters.getCDSMode() != CAM_CDS_MODE_OFF) { if (feature_mask & CAM_QCOM_FEATURE_DSDN) { pp_config.feature_mask |= CAM_QCOM_FEATURE_DSDN; } else { pp_config.feature_mask |= CAM_QCOM_FEATURE_CDS; } } pp_config.feature_mask &= ~CAM_QCOM_FEATURE_RAW_PROCESSING; pp_config.feature_mask &= ~CAM_QCOM_FEATURE_METADATA_PROCESSING; break; } LOGH("pproc feature mask set = %llx pass count = %d", pp_config.feature_mask, curIndex); return rc; } /*=========================================================================== * FUNCTION : addReprocChannel * * DESCRIPTION: add a reprocess channel that will do reprocess on frames * coming from input channel * * PARAMETERS : * @pInputChannel : ptr to input channel whose frames will be post-processed * @cur_channel_index : Current channel index in multipass * * RETURN : Ptr to the newly created channel obj. NULL if failed. *==========================================================================*/ QCameraReprocessChannel *QCamera2HardwareInterface::addReprocChannel( QCameraChannel *pInputChannel, int8_t cur_channel_index) { int32_t rc = NO_ERROR; QCameraReprocessChannel *pChannel = NULL; uint32_t burst_cnt = mParameters.getNumOfSnapshots(); if (pInputChannel == NULL) { LOGE("input channel obj is NULL"); return NULL; } pChannel = new QCameraReprocessChannel(mCameraHandle->camera_handle, mCameraHandle->ops); if (NULL == pChannel) { LOGE("no mem for reprocess channel"); 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) { LOGE("init reprocess channel failed, ret = %d", 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)); rc = getPPConfig(pp_config, cur_channel_index, ((mParameters.getReprocCount() > 1) ? TRUE : FALSE)); if (rc != NO_ERROR){ LOGE("Error while creating PP config"); delete pChannel; return NULL; } uint8_t minStreamBufNum = getBufNumRequired(CAM_STREAM_TYPE_OFFLINE_PROC); //WNR and HDR happen inline. No extra buffers needed. cam_feature_mask_t temp_feature_mask = pp_config.feature_mask; temp_feature_mask &= ~CAM_QCOM_FEATURE_HDR; if (temp_feature_mask && mParameters.isHDREnabled()) { minStreamBufNum = (uint8_t)(1 + mParameters.getNumOfExtraHDRInBufsIfNeeded()); } if (mParameters.isStillMoreEnabled()) { cam_still_more_t stillmore_config = mParameters.getStillMoreSettings(); pp_config.burst_cnt = stillmore_config.burst_count; LOGH("Stillmore burst %d", pp_config.burst_cnt); // getNumOfExtraBuffersForImageProc returns 1 less buffer assuming // number of capture is already added. In the case of liveshot, // stillmore burst is 1. This is to account for the premature decrement if (mParameters.getNumOfExtraBuffersForImageProc() == 0) { minStreamBufNum += 1; } } if (mParameters.getManualCaptureMode() >= CAM_MANUAL_CAPTURE_TYPE_3) { minStreamBufNum += mParameters.getReprocCount() - 1; burst_cnt = mParameters.getReprocCount(); if (cur_channel_index == 0) { pChannel->setReprocCount(2); } else { pChannel->setReprocCount(1); } } else { pChannel->setReprocCount(1); } // Add non inplace image lib buffers only when ppproc is present, // becuase pproc is non inplace and input buffers for img lib // are output for pproc and this number of extra buffers is required // If pproc is not there, input buffers for imglib are from snapshot stream uint8_t imglib_extra_bufs = mParameters.getNumOfExtraBuffersForImageProc(); if (temp_feature_mask && imglib_extra_bufs) { // 1 is added because getNumOfExtraBuffersForImageProc returns extra // buffers assuming number of capture is already added minStreamBufNum = (uint8_t)(minStreamBufNum + imglib_extra_bufs + 1); } //Mask out features that are already processed in snapshot stream. cam_feature_mask_t snapshot_feature_mask = 0; mParameters.getStreamPpMask(CAM_STREAM_TYPE_SNAPSHOT, snapshot_feature_mask); pp_config.feature_mask &= ~snapshot_feature_mask; LOGH("Snapshot feature mask: 0x%llx, reproc feature mask: 0x%llx", snapshot_feature_mask, pp_config.feature_mask); bool offlineReproc = isRegularCapture(); if (m_postprocessor.mOfflineDataBufs != NULL) { offlineReproc = TRUE; } cam_padding_info_t paddingInfo = gCamCapability[mCameraId]->padding_info; paddingInfo.offset_info.offset_x = 0; paddingInfo.offset_info.offset_y = 0; rc = pChannel->addReprocStreamsFromSource(*this, pp_config, pInputChannel, minStreamBufNum, burst_cnt, &paddingInfo, mParameters, mLongshotEnabled, offlineReproc); 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) { LOGE("no mem for reprocess channel"); return NULL; } rc = pChannel->init(NULL, NULL, NULL); if (rc != NO_ERROR) { LOGE("init reprocess channel failed, ret = %d", rc); delete pChannel; return NULL; } QCameraHeapMemory *pStreamInfo = allocateStreamInfoBuf(CAM_STREAM_TYPE_OFFLINE_PROC); if (pStreamInfo == NULL) { LOGE("no mem for stream info buf"); 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, NULL, img_config.num_of_bufs, &gCamCapability[mCameraId]->padding_info, stream_cb, userdata, false); if (rc != NO_ERROR) { LOGE("add reprocess stream failed, ret = %d", rc); 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; case QCAMERA_CH_TYPE_CALLBACK: rc = addCallbackChannel(); break; case QCAMERA_CH_TYPE_ANALYSIS: rc = addAnalysisChannel(); break; default: break; } return rc; } /*=========================================================================== * FUNCTION : delChannel * * DESCRIPTION: delete a channel by its type * * PARAMETERS : * @ch_type : channel type * @destroy : delete context as well * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::delChannel(qcamera_ch_type_enum_t ch_type, bool destroy) { if (m_channels[ch_type] != NULL) { if (destroy) { delete m_channels[ch_type]; m_channels[ch_type] = NULL; } else { m_channels[ch_type]->deleteChannel(); } } 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() { ATRACE_CALL(); int32_t rc = NO_ERROR; LOGI("E"); rc = mParameters.setStreamConfigure(false, false, false); if (rc != NO_ERROR) { LOGE("setStreamConfigure failed %d", rc); return rc; } if (mParameters.isZSLMode() && mParameters.getRecordingHintValue() != true) { rc = addChannel(QCAMERA_CH_TYPE_ZSL); if (rc != NO_ERROR) { LOGE("failed!! rc = %d", rc); return rc; } if (mParameters.isUBWCEnabled()) { cam_format_t fmt; mParameters.getStreamFormat(CAM_STREAM_TYPE_PREVIEW, fmt); if (fmt == CAM_FORMAT_YUV_420_NV12_UBWC) { rc = addChannel(QCAMERA_CH_TYPE_CALLBACK); if (rc != NO_ERROR) { delChannel(QCAMERA_CH_TYPE_ZSL); LOGE("failed!! rc = %d", rc); return rc; } } } if (mParameters.getofflineRAW()) { addChannel(QCAMERA_CH_TYPE_RAW); } } else { bool recordingHint = mParameters.getRecordingHintValue(); if(!isRdiMode() && recordingHint) { //stop face detection,longshot,etc if turned ON in Camera mode #ifndef VANILLA_HAL int32_t arg; //dummy arg if (isLongshotEnabled()) { sendCommand(CAMERA_CMD_LONGSHOT_OFF, arg, arg); } if (mParameters.isFaceDetectionEnabled() && (!mParameters.fdModeInVideo())) { sendCommand(CAMERA_CMD_STOP_FACE_DETECTION, arg, arg); } if (mParameters.isHistogramEnabled()) { sendCommand(CAMERA_CMD_HISTOGRAM_OFF, arg, arg); } #endif //Don't create snapshot channel for liveshot, if low power mode is set. //Use video stream instead. if (!isLowPowerMode()) { 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); LOGE("failed!! rc = %d", rc); return rc; } } rc = addChannel(QCAMERA_CH_TYPE_PREVIEW); if (!isRdiMode() && (rc != NO_ERROR)) { if (recordingHint) { delChannel(QCAMERA_CH_TYPE_SNAPSHOT); delChannel(QCAMERA_CH_TYPE_VIDEO); } } if (mParameters.isUBWCEnabled() && !recordingHint) { cam_format_t fmt; mParameters.getStreamFormat(CAM_STREAM_TYPE_PREVIEW, fmt); if (fmt == CAM_FORMAT_YUV_420_NV12_UBWC) { rc = addChannel(QCAMERA_CH_TYPE_CALLBACK); if (rc != NO_ERROR) { delChannel(QCAMERA_CH_TYPE_PREVIEW); if (!isRdiMode()) { delChannel(QCAMERA_CH_TYPE_SNAPSHOT); delChannel(QCAMERA_CH_TYPE_VIDEO); } LOGE("failed!! rc = %d", rc); return rc; } } } if (NO_ERROR != rc) { delChannel(QCAMERA_CH_TYPE_PREVIEW); LOGE("failed!! rc = %d", rc); } } LOGI("X rc = %d", rc); return rc; } /*=========================================================================== * FUNCTION : unpreparePreview * * DESCRIPTION: delete channels for preview * * PARAMETERS : none * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::unpreparePreview() { delChannel(QCAMERA_CH_TYPE_ZSL); delChannel(QCAMERA_CH_TYPE_PREVIEW); delChannel(QCAMERA_CH_TYPE_VIDEO); delChannel(QCAMERA_CH_TYPE_SNAPSHOT); delChannel(QCAMERA_CH_TYPE_CALLBACK); delChannel(QCAMERA_CH_TYPE_RAW); } /*=========================================================================== * FUNCTION : playShutter * * DESCRIPTION: send request to play shutter sound * * PARAMETERS : none * * RETURN : none *==========================================================================*/ void QCamera2HardwareInterface::playShutter(){ if (mNotifyCb == NULL || msgTypeEnabledWithLock(CAMERA_MSG_SHUTTER) == 0){ LOGD("shutter msg not enabled or NULL cb"); return; } LOGH("CAMERA_MSG_SHUTTER "); 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; cbArg.ext2 = false; m_cbNotifier.notifyCallback(cbArg); } /*=========================================================================== * 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 : needPreviewFDCallback * * DESCRIPTION: decides if needPreviewFDCallback * * PARAMETERS : * @num_faces : number of faces * * RETURN : bool type of status * true -- success * fale -- failure code *==========================================================================*/ bool QCamera2HardwareInterface::needPreviewFDCallback(uint8_t num_faces) { if (num_faces == 0 && mNumPreviewFaces == 0) { return false; } return true; } /*=========================================================================== * FUNCTION : processFaceDetectionReuslt * * DESCRIPTION: process face detection reuslt * * PARAMETERS : * @faces_data : ptr to face processing result struct * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::processFaceDetectionResult(cam_faces_data_t *faces_data) { if (!mParameters.isFaceDetectionEnabled()) { LOGH("FaceDetection not enabled, no ops here"); return NO_ERROR; } qcamera_face_detect_type_t fd_type = faces_data->detection_data.fd_type; cam_face_detection_data_t *detect_data = &(faces_data->detection_data); if ((NULL == mDataCb) || (fd_type == QCAMERA_FD_PREVIEW && !msgTypeEnabled(CAMERA_MSG_PREVIEW_METADATA)) || (!needPreviewFDCallback(detect_data->num_faces_detected)) #ifndef VANILLA_HAL || (fd_type == QCAMERA_FD_SNAPSHOT && !msgTypeEnabled(CAMERA_MSG_META_DATA)) #endif ) { LOGH("metadata msgtype not enabled, no ops here"); return NO_ERROR; } if ((fd_type == QCAMERA_FD_PREVIEW) && (detect_data->update_flag == FALSE)) { // Don't send callback to app if this is skipped by fd at backend 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) { LOGE("Invalid preview width or height (%d x %d)", display_dim.width, display_dim.height); return UNKNOWN_ERROR; } // process face detection result // need separate face detection in preview or snapshot type size_t faceResultSize = 0; size_t data_len = 0; if(fd_type == QCAMERA_FD_PREVIEW){ //fd for preview frames faceResultSize = sizeof(camera_frame_metadata_t); faceResultSize += sizeof(camera_face_t) * MAX_ROI; }else if(fd_type == QCAMERA_FD_SNAPSHOT){ #ifndef VANILLA_HAL // fd for snapshot frames //check if face is detected in this frame if(detect_data->num_faces_detected > 0){ data_len = sizeof(camera_frame_metadata_t) + sizeof(camera_face_t) * detect_data->num_faces_detected; }else{ //no face data_len = 0; } #endif faceResultSize = 1 *sizeof(int) //meta data type + 1 *sizeof(int) // meta data len + data_len; //data } camera_memory_t *faceResultBuffer = mGetMemory(-1, faceResultSize, 1, mCallbackCookie); if ( NULL == faceResultBuffer ) { LOGE("Not enough memory for face result data"); return NO_MEMORY; } unsigned char *pFaceResult = ( unsigned char * ) faceResultBuffer->data; memset(pFaceResult, 0, faceResultSize); unsigned char *faceData = NULL; if(fd_type == QCAMERA_FD_PREVIEW){ faceData = pFaceResult; mNumPreviewFaces = detect_data->num_faces_detected; }else if(fd_type == QCAMERA_FD_SNAPSHOT){ #ifndef VANILLA_HAL //need fill meta type and meta data len first int *data_header = (int* )pFaceResult; data_header[0] = CAMERA_META_DATA_FD; data_header[1] = (int)data_len; if(data_len <= 0){ //if face is not valid or do not have face, return qcamera_callback_argm_t cbArg; memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); cbArg.cb_type = QCAMERA_DATA_CALLBACK; cbArg.msg_type = CAMERA_MSG_META_DATA; cbArg.data = faceResultBuffer; cbArg.user_data = faceResultBuffer; cbArg.cookie = this; cbArg.release_cb = releaseCameraMemory; int32_t rc = m_cbNotifier.notifyCallback(cbArg); if (rc != NO_ERROR) { LOGE("fail sending notification"); faceResultBuffer->release(faceResultBuffer); } return rc; } #endif faceData = pFaceResult + 2 *sizeof(int); //skip two int length } 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 = detect_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 = detect_data->faces[i].face_id; faces[i].score = detect_data->faces[i].score; // left faces[i].rect[0] = MAP_TO_DRIVER_COORDINATE( detect_data->faces[i].face_boundary.left, display_dim.width, 2000, -1000); // top faces[i].rect[1] = MAP_TO_DRIVER_COORDINATE( detect_data->faces[i].face_boundary.top, display_dim.height, 2000, -1000); // right faces[i].rect[2] = faces[i].rect[0] + MAP_TO_DRIVER_COORDINATE( detect_data->faces[i].face_boundary.width, display_dim.width, 2000, 0); // bottom faces[i].rect[3] = faces[i].rect[1] + MAP_TO_DRIVER_COORDINATE( detect_data->faces[i].face_boundary.height, display_dim.height, 2000, 0); if (faces_data->landmark_valid) { // Center of left eye faces[i].left_eye[0] = MAP_TO_DRIVER_COORDINATE( faces_data->landmark_data.face_landmarks[i].left_eye_center.x, display_dim.width, 2000, -1000); faces[i].left_eye[1] = MAP_TO_DRIVER_COORDINATE( faces_data->landmark_data.face_landmarks[i].left_eye_center.y, display_dim.height, 2000, -1000); // Center of right eye faces[i].right_eye[0] = MAP_TO_DRIVER_COORDINATE( faces_data->landmark_data.face_landmarks[i].right_eye_center.x, display_dim.width, 2000, -1000); faces[i].right_eye[1] = MAP_TO_DRIVER_COORDINATE( faces_data->landmark_data.face_landmarks[i].right_eye_center.y, display_dim.height, 2000, -1000); // Center of mouth faces[i].mouth[0] = MAP_TO_DRIVER_COORDINATE( faces_data->landmark_data.face_landmarks[i].mouth_center.x, display_dim.width, 2000, -1000); faces[i].mouth[1] = MAP_TO_DRIVER_COORDINATE( faces_data->landmark_data.face_landmarks[i].mouth_center.y, display_dim.height, 2000, -1000); } else { // return -2000 if invalid faces[i].left_eye[0] = -2000; faces[i].left_eye[1] = -2000; faces[i].right_eye[0] = -2000; faces[i].right_eye[1] = -2000; faces[i].mouth[0] = -2000; faces[i].mouth[1] = -2000; } #ifndef VANILLA_HAL #ifdef TARGET_TS_MAKEUP mFaceRect.left = detect_data->faces[i].face_boundary.left; mFaceRect.top = detect_data->faces[i].face_boundary.top; mFaceRect.right = detect_data->faces[i].face_boundary.width+mFaceRect.left; mFaceRect.bottom = detect_data->faces[i].face_boundary.height+mFaceRect.top; #endif if (faces_data->smile_valid) { faces[i].smile_degree = faces_data->smile_data.smile[i].smile_degree; faces[i].smile_score = faces_data->smile_data.smile[i].smile_confidence; } if (faces_data->blink_valid) { faces[i].blink_detected = faces_data->blink_data.blink[i].blink_detected; faces[i].leye_blink = faces_data->blink_data.blink[i].left_blink; faces[i].reye_blink = faces_data->blink_data.blink[i].right_blink; } if (faces_data->recog_valid) { faces[i].face_recognised = faces_data->recog_data.face_rec[i].face_recognised; } if (faces_data->gaze_valid) { faces[i].gaze_angle = faces_data->gaze_data.gaze[i].gaze_angle; faces[i].updown_dir = faces_data->gaze_data.gaze[i].updown_dir; faces[i].leftright_dir = faces_data->gaze_data.gaze[i].leftright_dir; faces[i].roll_dir = faces_data->gaze_data.gaze[i].roll_dir; faces[i].left_right_gaze = faces_data->gaze_data.gaze[i].left_right_gaze; faces[i].top_bottom_gaze = faces_data->gaze_data.gaze[i].top_bottom_gaze; } #endif } } else{ #ifdef TARGET_TS_MAKEUP memset(&mFaceRect,-1,sizeof(mFaceRect)); #endif } qcamera_callback_argm_t cbArg; memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); cbArg.cb_type = QCAMERA_DATA_CALLBACK; if(fd_type == QCAMERA_FD_PREVIEW){ cbArg.msg_type = CAMERA_MSG_PREVIEW_METADATA; } #ifndef VANILLA_HAL else if(fd_type == QCAMERA_FD_SNAPSHOT){ cbArg.msg_type = CAMERA_MSG_META_DATA; } #endif cbArg.data = faceResultBuffer; cbArg.metadata = roiData; cbArg.user_data = faceResultBuffer; cbArg.cookie = this; cbArg.release_cb = releaseCameraMemory; int32_t rc = m_cbNotifier.notifyCallback(cbArg); if (rc != NO_ERROR) { LOGE("fail sending notification"); faceResultBuffer->release(faceResultBuffer); } return rc; } /*=========================================================================== * FUNCTION : releaseCameraMemory * * DESCRIPTION: releases camera memory objects * * PARAMETERS : * @data : buffer to be released * @cookie : context data * @cbStatus: callback status * * RETURN : None *==========================================================================*/ void QCamera2HardwareInterface::releaseCameraMemory(void *data, void */*cookie*/, int32_t /*cbStatus*/) { 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 * @cbStatus: callback status * * RETURN : None *==========================================================================*/ void QCamera2HardwareInterface::returnStreamBuffer(void *data, void *cookie, int32_t /*cbStatus*/) { QCameraStream *stream = ( QCameraStream * ) cookie; int idx = *((int *)data); if ((NULL != stream) && (0 <= idx)) { stream->bufDone((uint32_t)idx); } else { LOGE("Cannot return buffer %d %p", idx, cookie); } } /*=========================================================================== * 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( __unused cam_hist_stats_t &stats_data) { #ifndef VANILLA_HAL if (!mParameters.isHistogramEnabled()) { LOGH("Histogram not enabled, no ops here"); return NO_ERROR; } camera_memory_t *histBuffer = mGetMemory(-1, sizeof(cam_histogram_data_t), 1, mCallbackCookie); if ( NULL == histBuffer ) { LOGE("Not enough memory for histogram data"); return NO_MEMORY; } cam_histogram_data_t *pHistData = (cam_histogram_data_t *)histBuffer->data; if (pHistData == NULL) { LOGE("memory data ptr is NULL"); return UNKNOWN_ERROR; } switch (stats_data.type) { case CAM_HISTOGRAM_TYPE_BAYER: *pHistData = stats_data.bayer_stats.gb_stats; break; case CAM_HISTOGRAM_TYPE_YUV: *pHistData = stats_data.yuv_stats; break; } qcamera_callback_argm_t cbArg; memset(&cbArg, 0, sizeof(qcamera_callback_argm_t)); cbArg.cb_type = QCAMERA_DATA_CALLBACK; cbArg.msg_type = CAMERA_MSG_STATS_DATA; cbArg.data = histBuffer; cbArg.user_data = histBuffer; cbArg.cookie = this; cbArg.release_cb = releaseCameraMemory; int32_t rc = m_cbNotifier.notifyCallback(cbArg); if (rc != NO_ERROR) { LOGE("fail sending notification"); histBuffer->release(histBuffer); } #endif return NO_ERROR; } /*=========================================================================== * FUNCTION : calcThermalLevel * * DESCRIPTION: Calculates the target fps range depending on * the thermal level. * Note that this function can be called from QCameraParametersIntf * while mutex is held. So it should not call back into * QCameraParametersIntf causing deadlock. * * PARAMETERS : * @level : received thermal level * @minFPS : minimum configured fps range * @maxFPS : maximum configured fps range * @minVideoFps: minimum configured fps range * @maxVideoFps: maximum configured fps range * @adjustedRange : target fps range * @skipPattern : target skip pattern * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::calcThermalLevel( qcamera_thermal_level_enum_t level, const int minFPSi, const int maxFPSi, const float &minVideoFps, const float &maxVideoFps, cam_fps_range_t &adjustedRange, enum msm_vfe_frame_skip_pattern &skipPattern) { const float minFPS = (float)minFPSi; const float maxFPS = (float)maxFPSi; LOGH("level: %d, preview minfps %f, preview maxfpS %f, " "video minfps %f, video maxfpS %f", level, minFPS, maxFPS, minVideoFps, maxVideoFps); switch(level) { case QCAMERA_THERMAL_NO_ADJUSTMENT: { adjustedRange.min_fps = minFPS / 1000.0f; adjustedRange.max_fps = maxFPS / 1000.0f; adjustedRange.video_min_fps = minVideoFps / 1000.0f; adjustedRange.video_max_fps = maxVideoFps / 1000.0f; skipPattern = NO_SKIP; } break; case QCAMERA_THERMAL_SLIGHT_ADJUSTMENT: { adjustedRange.min_fps = minFPS / 1000.0f; adjustedRange.max_fps = maxFPS / 1000.0f; adjustedRange.min_fps -= 0.1f * adjustedRange.min_fps; adjustedRange.max_fps -= 0.1f * adjustedRange.max_fps; adjustedRange.video_min_fps = minVideoFps / 1000.0f; adjustedRange.video_max_fps = maxVideoFps / 1000.0f; adjustedRange.video_min_fps -= 0.1f * adjustedRange.video_min_fps; adjustedRange.video_max_fps -= 0.1f * adjustedRange.video_max_fps; if ( adjustedRange.min_fps < 1 ) { adjustedRange.min_fps = 1; } if ( adjustedRange.max_fps < 1 ) { adjustedRange.max_fps = 1; } if ( adjustedRange.video_min_fps < 1 ) { adjustedRange.video_min_fps = 1; } if ( adjustedRange.video_max_fps < 1 ) { adjustedRange.video_max_fps = 1; } skipPattern = EVERY_2FRAME; } break; case QCAMERA_THERMAL_BIG_ADJUSTMENT: { adjustedRange.min_fps = minFPS / 1000.0f; adjustedRange.max_fps = maxFPS / 1000.0f; adjustedRange.min_fps -= 0.2f * adjustedRange.min_fps; adjustedRange.max_fps -= 0.2f * adjustedRange.max_fps; adjustedRange.video_min_fps = minVideoFps / 1000.0f; adjustedRange.video_max_fps = maxVideoFps / 1000.0f; adjustedRange.video_min_fps -= 0.2f * adjustedRange.video_min_fps; adjustedRange.video_max_fps -= 0.2f * adjustedRange.video_max_fps; if ( adjustedRange.min_fps < 1 ) { adjustedRange.min_fps = 1; } if ( adjustedRange.max_fps < 1 ) { adjustedRange.max_fps = 1; } if ( adjustedRange.video_min_fps < 1 ) { adjustedRange.video_min_fps = 1; } if ( adjustedRange.video_max_fps < 1 ) { adjustedRange.video_max_fps = 1; } skipPattern = EVERY_4FRAME; } break; case QCAMERA_THERMAL_MAX_ADJUSTMENT: { // Stop Preview? // Set lowest min FPS for now adjustedRange.min_fps = minFPS/1000.0f; adjustedRange.max_fps = minFPS/1000.0f; cam_capability_t *capability = gCamCapability[mCameraId]; for (size_t i = 0; i < capability->fps_ranges_tbl_cnt; i++) { if (capability->fps_ranges_tbl[i].min_fps < adjustedRange.min_fps) { adjustedRange.min_fps = capability->fps_ranges_tbl[i].min_fps; adjustedRange.max_fps = adjustedRange.min_fps; } } skipPattern = MAX_SKIP; adjustedRange.video_min_fps = adjustedRange.min_fps; adjustedRange.video_max_fps = adjustedRange.max_fps; } break; case QCAMERA_THERMAL_SHUTDOWN: { // send error notify LOGE("Received shutdown thermal level. Closing camera"); sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, 0); } break; default: { LOGW("Invalid thermal level %d", level); return BAD_VALUE; } break; } return NO_ERROR; } /*=========================================================================== * FUNCTION : recalcFPSRange * * DESCRIPTION: adjust the configured fps range regarding * the last thermal level. * * PARAMETERS : * @minFPS : minimum configured fps range * @maxFPS : maximum configured fps range * @minVideoFPS : minimum configured video fps * @maxVideoFPS : maximum configured video fps * @adjustedRange : target fps range * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int QCamera2HardwareInterface::recalcFPSRange(int &minFPS, int &maxFPS, const float &minVideoFPS, const float &maxVideoFPS, cam_fps_range_t &adjustedRange) { enum msm_vfe_frame_skip_pattern skipPattern; calcThermalLevel(mThermalLevel, minFPS, maxFPS, minVideoFPS, maxVideoFPS, adjustedRange, skipPattern); 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(void *thermal_level) { int ret = NO_ERROR; cam_fps_range_t adjustedRange; int minFPS, maxFPS; float minVideoFPS, maxVideoFPS; enum msm_vfe_frame_skip_pattern skipPattern; qcamera_thermal_level_enum_t level = *(qcamera_thermal_level_enum_t *)thermal_level; if (!mCameraOpened) { LOGH("Camera is not opened, no need to update camera parameters"); return NO_ERROR; } if (mParameters.getRecordingHintValue()) { LOGH("Thermal mitigation isn't enabled in camcorder mode"); return NO_ERROR; } mParameters.getPreviewFpsRange(&minFPS, &maxFPS); qcamera_thermal_mode thermalMode = mParameters.getThermalMode(); if (mParameters.isHfrMode()) { cam_fps_range_t hfrFpsRange; mParameters.getHfrFps(hfrFpsRange); minVideoFPS = hfrFpsRange.video_min_fps; maxVideoFPS = hfrFpsRange.video_max_fps; } else { minVideoFPS = minFPS; maxVideoFPS = maxFPS; } calcThermalLevel(level, minFPS, maxFPS, minVideoFPS, maxVideoFPS, adjustedRange, skipPattern); mThermalLevel = level; if (thermalMode == QCAMERA_THERMAL_ADJUST_FPS) ret = mParameters.adjustPreviewFpsRange(&adjustedRange); else if (thermalMode == QCAMERA_THERMAL_ADJUST_FRAMESKIP) ret = mParameters.setFrameSkip(skipPattern); else LOGW("Incorrect thermal mode %d", 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) { int rc = NO_ERROR; String8 str = String8(parms); rc = mParameters.updateParameters(str, needRestart); setNeedRestart(needRestart); // update stream based parameter settings for (int i = 0; i < QCAMERA_CH_TYPE_MAX; i++) { if (m_channels[i] != NULL) { m_channels[i]->UpdateStreamBasedParameters(mParameters); } } return rc; } /*=========================================================================== * 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 = NO_ERROR; 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() { bool needFps = false; needFps = mParameters.isFpsDebugEnabled(); return needFps; } /*=========================================================================== * 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 : is4k2kResolution * * DESCRIPTION: if resolution is 4k x 2k or true 4k x 2k * * PARAMETERS : none * * RETURN : true: needed * false: no need *==========================================================================*/ bool QCamera2HardwareInterface::is4k2kResolution(cam_dimension_t* resolution) { bool enabled = false; if ((resolution->width == 4096 && resolution->height == 2160) || (resolution->width == 3840 && resolution->height == 2160) ) { enabled = true; } return enabled; } /*=========================================================================== * FUNCTION : isPreviewRestartEnabled * * DESCRIPTION: Check whether preview should be restarted automatically * during image capture. * * PARAMETERS : none * * RETURN : true: needed * false: no need *==========================================================================*/ bool QCamera2HardwareInterface::isPreviewRestartEnabled() { char prop[PROPERTY_VALUE_MAX]; memset(prop, 0, sizeof(prop)); property_get("persist.camera.feature.restart", prop, "0"); int earlyRestart = atoi(prop); return earlyRestart == 1; } /*=========================================================================== * FUNCTION : needReprocess * * DESCRIPTION: if reprocess is needed * * PARAMETERS : none * * RETURN : true: needed * false: no need *==========================================================================*/ bool QCamera2HardwareInterface::needReprocess() { bool needReprocess = false; if (!mParameters.isJpegPictureFormat() && !mParameters.isNV21PictureFormat()) { // RAW image, no need to reprocess return false; } //Disable reprocess for 4K liveshot case but enable if lowpower mode if (mParameters.is4k2kVideoResolution() && mParameters.getRecordingHintValue() && !isLowPowerMode()) { return false; } // pp feature config cam_pp_feature_config_t pp_config; memset(&pp_config, 0, sizeof(cam_pp_feature_config_t)); //Decide whether to do reprocess or not based on //ppconfig obtained in the first pass. getPPConfig(pp_config); if (pp_config.feature_mask > 0) { needReprocess = true; } LOGH("needReprocess %s", needReprocess ? "true" : "false"); return needReprocess; } /*=========================================================================== * 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() && !mParameters.isNV21PictureFormat()) { // RAW image, no need to reprocess return false; } //Disable reprocess for 4K liveshot case if (mParameters.is4k2kVideoResolution() && mParameters.getRecordingHintValue() && !isLowPowerMode()) { //Disable reprocess for 4K liveshot case 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 LOGH("need to do reprocess for rotation=%d", mParameters.getJpegRotation()); 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 *==========================================================================*/ uint32_t QCamera2HardwareInterface::getJpegQuality() { uint32_t quality = 0; quality = mParameters.getJpegQuality(); return quality; } /*=========================================================================== * 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) { LOGE("No memory for QCameraExif"); return NULL; } int32_t rc = NO_ERROR; // add exif entries String8 dateTime, subSecTime; rc = mParameters.getExifDateTime(dateTime, subSecTime); if(rc == NO_ERROR) { exif->addEntry(EXIFTAGID_DATE_TIME, EXIF_ASCII, (uint32_t)(dateTime.length() + 1), (void *)dateTime.string()); exif->addEntry(EXIFTAGID_EXIF_DATE_TIME_ORIGINAL, EXIF_ASCII, (uint32_t)(dateTime.length() + 1), (void *)dateTime.string()); exif->addEntry(EXIFTAGID_EXIF_DATE_TIME_DIGITIZED, EXIF_ASCII, (uint32_t)(dateTime.length() + 1), (void *)dateTime.string()); exif->addEntry(EXIFTAGID_SUBSEC_TIME, EXIF_ASCII, (uint32_t)(subSecTime.length() + 1), (void *)subSecTime.string()); exif->addEntry(EXIFTAGID_SUBSEC_TIME_ORIGINAL, EXIF_ASCII, (uint32_t)(subSecTime.length() + 1), (void *)subSecTime.string()); exif->addEntry(EXIFTAGID_SUBSEC_TIME_DIGITIZED, EXIF_ASCII, (uint32_t)(subSecTime.length() + 1), (void *)subSecTime.string()); } else { LOGW("getExifDateTime failed"); } rat_t focalLength; rc = mParameters.getExifFocalLength(&focalLength); if (rc == NO_ERROR) { exif->addEntry(EXIFTAGID_FOCAL_LENGTH, EXIF_RATIONAL, 1, (void *)&(focalLength)); } else { LOGW("getExifFocalLength failed"); } uint16_t isoSpeed = mParameters.getExifIsoSpeed(); if (getSensorType() != CAM_SENSOR_YUV) { exif->addEntry(EXIFTAGID_ISO_SPEED_RATING, EXIF_SHORT, 1, (void *)&(isoSpeed)); } char gpsProcessingMethod[EXIF_ASCII_PREFIX_SIZE + GPS_PROCESSING_METHOD_SIZE]; uint32_t count = 0; /*gps data might not be available */ rc = mParameters.getExifGpsProcessingMethod(gpsProcessingMethod, count); if(rc == NO_ERROR) { exif->addEntry(EXIFTAGID_GPS_PROCESSINGMETHOD, EXIF_ASCII, count, (void *)gpsProcessingMethod); } else { LOGW("getExifGpsProcessingMethod failed"); } 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 { LOGW("getExifLatitude failed"); } 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 { LOGW("getExifLongitude failed"); } 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 { LOGW("getExifAltitude failed"); } char gpsDateStamp[20]; rat_t gpsTimeStamp[3]; rc = mParameters.getExifGpsDateTimeStamp(gpsDateStamp, 20, gpsTimeStamp); if(rc == NO_ERROR) { exif->addEntry(EXIFTAGID_GPS_DATESTAMP, EXIF_ASCII, (uint32_t)(strlen(gpsDateStamp) + 1), (void *)gpsDateStamp); exif->addEntry(EXIFTAGID_GPS_TIMESTAMP, EXIF_RATIONAL, 3, (void *)gpsTimeStamp); } else { LOGW("getExifGpsDataTimeStamp failed"); } #ifdef ENABLE_MODEL_INFO_EXIF char value[PROPERTY_VALUE_MAX]; if (property_get("persist.sys.exif.make", value, "") > 0 || property_get("ro.product.manufacturer", value, "QCOM-AA") > 0) { exif->addEntry(EXIFTAGID_MAKE, EXIF_ASCII, strlen(value) + 1, (void *)value); } else { LOGW("getExifMaker failed"); } if (property_get("persist.sys.exif.model", value, "") > 0 || property_get("ro.product.model", value, "QCAM-AA") > 0) { exif->addEntry(EXIFTAGID_MODEL, EXIF_ASCII, strlen(value) + 1, (void *)value); } else { LOGW("getExifModel failed"); } if (property_get("ro.build.description", value, "QCAM-AA") > 0) { exif->addEntry(EXIFTAGID_SOFTWARE, EXIF_ASCII, (uint32_t)(strlen(value) + 1), (void *)value); } else { LOGW("getExifSoftware failed"); } #endif if (mParameters.useJpegExifRotation()) { int16_t orientation; switch (mParameters.getJpegExifRotation()) { case 0: orientation = 1; break; case 90: orientation = 6; break; case 180: orientation = 3; break; case 270: orientation = 8; break; default: orientation = 1; break; } exif->addEntry(EXIFTAGID_ORIENTATION, EXIF_SHORT, 1, (void *)&orientation); exif->addEntry(EXIFTAGID_TN_ORIENTATION, EXIF_SHORT, 1, (void *)&orientation); } 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, true); } /*=========================================================================== * FUNCTION : isCaptureShutterEnabled * * DESCRIPTION: Check whether shutter should be triggered immediately after * capture * * PARAMETERS : * * RETURN : true - regular capture * false - other type of capture *==========================================================================*/ bool QCamera2HardwareInterface::isCaptureShutterEnabled() { char prop[PROPERTY_VALUE_MAX]; memset(prop, 0, sizeof(prop)); property_get("persist.camera.feature.shutter", prop, "0"); int enableShutter = atoi(prop); return enableShutter == 1; } /*=========================================================================== * FUNCTION : needProcessPreviewFrame * * DESCRIPTION: returns whether preview frame need to be displayed * * PARAMETERS : * @frameID : frameID of frame to be processed * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ bool QCamera2HardwareInterface::needProcessPreviewFrame(uint32_t frameID) { return ((m_stateMachine.isPreviewRunning()) && (!isDisplayFrameToSkip(frameID)) && (!mParameters.isInstantAECEnabled())); } /*=========================================================================== * FUNCTION : needSendPreviewCallback * * DESCRIPTION: returns whether preview frame need to callback to APP * * PARAMETERS : * * RETURN : true - need preview frame callbck * false - not send preview frame callback *==========================================================================*/ bool QCamera2HardwareInterface::needSendPreviewCallback() { return m_stateMachine.isPreviewRunning() && (mDataCb != NULL) && (msgTypeEnabledWithLock(CAMERA_MSG_PREVIEW_FRAME) > 0) && m_stateMachine.isPreviewCallbackNeeded(); }; /*=========================================================================== * FUNCTION : setDisplaySkip * * DESCRIPTION: set range of frames to skip for preview * * PARAMETERS : * @enabled : TRUE to start skipping frame to display FALSE to stop skipping frame to display * @skipCnt : Number of frame to skip. 0 by default * * RETURN : None *==========================================================================*/ void QCamera2HardwareInterface::setDisplaySkip(bool enabled, uint8_t skipCnt) { pthread_mutex_lock(&mGrallocLock); if (enabled) { setDisplayFrameSkip(); setDisplayFrameSkip(mLastPreviewFrameID + skipCnt + 1); } else { setDisplayFrameSkip(mFrameSkipStart, (mLastPreviewFrameID + skipCnt + 1)); } pthread_mutex_unlock(&mGrallocLock); } /*=========================================================================== * FUNCTION : setDisplayFrameSkip * * DESCRIPTION: set range of frames to skip for preview * * PARAMETERS : * @start : frameId to start skip * @end : frameId to stop skip * * RETURN : None *==========================================================================*/ void QCamera2HardwareInterface::setDisplayFrameSkip(uint32_t start, uint32_t end) { if (start == 0) { mFrameSkipStart = 0; mFrameSkipEnd = 0; return; } if ((mFrameSkipStart == 0) || (mFrameSkipStart > start)) { mFrameSkipStart = start; } if ((end == 0) || (end > mFrameSkipEnd)) { mFrameSkipEnd = end; } } /*=========================================================================== * FUNCTION : isDisplayFrameToSkip * * DESCRIPTION: function to determin if input frame falls under skip range * * PARAMETERS : * @frameId : frameId to verify * * RETURN : true : need to skip * false: no need to skip *==========================================================================*/ bool QCamera2HardwareInterface::isDisplayFrameToSkip(uint32_t frameId) { return ((mFrameSkipStart != 0) && (frameId >= mFrameSkipStart) && (frameId <= mFrameSkipEnd || mFrameSkipEnd == 0)) ? TRUE : FALSE; } /*=========================================================================== * 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) { ATRACE_CALL(); LOGI("[KPI Perf]: Send PREPARE SANSPHOT event"); return mCameraHandle->ops->prepare_snapshot(mCameraHandle->camera_handle, afNeeded); } /*=========================================================================== * FUNCTION : needFDMetadata * * DESCRIPTION: check whether we need process Face Detection metadata in this chanel * * PARAMETERS : * @channel_type: channel type * * RETURN : true: needed * false: no need *==========================================================================*/ bool QCamera2HardwareInterface::needFDMetadata(qcamera_ch_type_enum_t channel_type) { //Note: Currently we only process ZSL channel bool value = false; if(channel_type == QCAMERA_CH_TYPE_ZSL){ //check if FD requirement is enabled if(mParameters.isSnapshotFDNeeded() && mParameters.isFaceDetectionEnabled()){ value = true; LOGH("Face Detection metadata is required in ZSL mode."); } } return value; } /*=========================================================================== * FUNCTION : deferredWorkRoutine * * DESCRIPTION: data process routine that executes deferred tasks * * PARAMETERS : * @data : user data ptr (QCamera2HardwareInterface) * * RETURN : None *==========================================================================*/ void *QCamera2HardwareInterface::deferredWorkRoutine(void *obj) { int running = 1; int ret; uint8_t is_active = FALSE; int32_t job_status = 0; QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)obj; QCameraCmdThread *cmdThread = &pme->mDeferredWorkThread; cmdThread->setName("CAM_defrdWrk"); do { do { ret = cam_sem_wait(&cmdThread->cmd_sem); if (ret != 0 && errno != EINVAL) { LOGE("cam_sem_wait error (%s)", strerror(errno)); return NULL; } } while (ret != 0); // we got notified about new cmd avail in cmd queue camera_cmd_type_t cmd = cmdThread->getCmd(); LOGD("cmd: %d", cmd); switch (cmd) { case CAMERA_CMD_TYPE_START_DATA_PROC: LOGH("start data proc"); is_active = TRUE; break; case CAMERA_CMD_TYPE_STOP_DATA_PROC: LOGH("stop data proc"); is_active = FALSE; // signal cmd is completed cam_sem_post(&cmdThread->sync_sem); break; case CAMERA_CMD_TYPE_DO_NEXT_JOB: { DefWork *dw = reinterpret_cast<DefWork *>(pme->mCmdQueue.dequeue()); if ( NULL == dw ) { LOGE("Invalid deferred work"); break; } switch( dw->cmd ) { case CMD_DEF_ALLOCATE_BUFF: { QCameraChannel * pChannel = dw->args.allocArgs.ch; if ( NULL == pChannel ) { LOGE("Invalid deferred work channel"); job_status = BAD_VALUE; break; } cam_stream_type_t streamType = dw->args.allocArgs.type; LOGH("Deferred buffer allocation started for stream type: %d", streamType); uint32_t iNumOfStreams = pChannel->getNumOfStreams(); QCameraStream *pStream = NULL; for ( uint32_t i = 0; i < iNumOfStreams; ++i) { pStream = pChannel->getStreamByIndex(i); if ( NULL == pStream ) { job_status = BAD_VALUE; break; } if ( pStream->isTypeOf(streamType)) { if ( pStream->allocateBuffers() ) { LOGE("Error allocating buffers !!!"); job_status = NO_MEMORY; pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); } break; } } } break; case CMD_DEF_PPROC_START: { int32_t ret = pme->getDefJobStatus(pme->mInitPProcJob); if (ret != NO_ERROR) { job_status = ret; LOGE("PPROC Start failed"); pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); break; } QCameraChannel * pChannel = dw->args.pprocArgs; assert(pChannel); if (pme->m_postprocessor.start(pChannel) != NO_ERROR) { LOGE("cannot start postprocessor"); job_status = BAD_VALUE; pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); } } break; case CMD_DEF_METADATA_ALLOC: { int32_t ret = pme->getDefJobStatus(pme->mParamAllocJob); if (ret != NO_ERROR) { job_status = ret; LOGE("Metadata alloc failed"); pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); break; } pme->mMetadataMem = new QCameraMetadataStreamMemory( QCAMERA_ION_USE_CACHE); if (pme->mMetadataMem == NULL) { LOGE("Unable to allocate metadata buffers"); job_status = BAD_VALUE; pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); } else { int32_t rc = pme->mMetadataMem->allocate( dw->args.metadataAllocArgs.bufferCnt, dw->args.metadataAllocArgs.size, NON_SECURE); if (rc < 0) { delete pme->mMetadataMem; pme->mMetadataMem = NULL; } } } break; case CMD_DEF_CREATE_JPEG_SESSION: { QCameraChannel * pChannel = dw->args.pprocArgs; assert(pChannel); int32_t ret = pme->getDefJobStatus(pme->mReprocJob); if (ret != NO_ERROR) { job_status = ret; LOGE("Jpeg create failed"); break; } if (pme->m_postprocessor.createJpegSession(pChannel) != NO_ERROR) { LOGE("cannot create JPEG session"); job_status = UNKNOWN_ERROR; pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); } } break; case CMD_DEF_PPROC_INIT: { int32_t rc = NO_ERROR; jpeg_encode_callback_t jpegEvtHandle = dw->args.pprocInitArgs.jpeg_cb; void* user_data = dw->args.pprocInitArgs.user_data; QCameraPostProcessor *postProcessor = &(pme->m_postprocessor); uint32_t cameraId = pme->mCameraId; cam_capability_t *capability = gCamCapability[cameraId]; cam_padding_info_t padding_info; cam_padding_info_t& cam_capability_padding_info = capability->padding_info; if(!pme->mJpegClientHandle) { rc = pme->initJpegHandle(); if (rc != NO_ERROR) { LOGE("Error!! creating JPEG handle failed"); job_status = UNKNOWN_ERROR; pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); break; } } LOGH("mJpegClientHandle : %d", pme->mJpegClientHandle); rc = postProcessor->setJpegHandle(&pme->mJpegHandle, &pme->mJpegMpoHandle, pme->mJpegClientHandle); if (rc != 0) { LOGE("Error!! set JPEG handle failed"); job_status = UNKNOWN_ERROR; pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); break; } /* get max pic size for jpeg work buf calculation*/ rc = postProcessor->init(jpegEvtHandle, user_data); if (rc != NO_ERROR) { LOGE("cannot init postprocessor"); job_status = UNKNOWN_ERROR; pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); break; } // update padding info from jpeg postProcessor->getJpegPaddingReq(padding_info); if (cam_capability_padding_info.width_padding < padding_info.width_padding) { cam_capability_padding_info.width_padding = padding_info.width_padding; } if (cam_capability_padding_info.height_padding < padding_info.height_padding) { cam_capability_padding_info.height_padding = padding_info.height_padding; } if (cam_capability_padding_info.plane_padding != padding_info.plane_padding) { cam_capability_padding_info.plane_padding = mm_stream_calc_lcm( cam_capability_padding_info.plane_padding, padding_info.plane_padding); } if (cam_capability_padding_info.offset_info.offset_x != padding_info.offset_info.offset_x) { cam_capability_padding_info.offset_info.offset_x = mm_stream_calc_lcm ( cam_capability_padding_info.offset_info.offset_x, padding_info.offset_info.offset_x); } if (cam_capability_padding_info.offset_info.offset_y != padding_info.offset_info.offset_y) { cam_capability_padding_info.offset_info.offset_y = mm_stream_calc_lcm ( cam_capability_padding_info.offset_info.offset_y, padding_info.offset_info.offset_y); } } break; case CMD_DEF_PARAM_ALLOC: { int32_t rc = pme->mParameters.allocate(); // notify routine would not be initialized by this time. // So, just update error job status if (rc != NO_ERROR) { job_status = rc; LOGE("Param allocation failed"); break; } } break; case CMD_DEF_PARAM_INIT: { int32_t rc = pme->getDefJobStatus(pme->mParamAllocJob); if (rc != NO_ERROR) { job_status = rc; LOGE("Param init failed"); pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); break; } uint32_t camId = pme->mCameraId; cam_capability_t * cap = gCamCapability[camId]; if (pme->mCameraHandle == NULL) { LOGE("Camera handle is null"); job_status = BAD_VALUE; pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); break; } // Now PostProc need calibration data as initialization // time for jpeg_open and calibration data is a // get param for now, so params needs to be initialized // before postproc init rc = pme->mParameters.init(cap, pme->mCameraHandle, pme); if (rc != 0) { job_status = UNKNOWN_ERROR; LOGE("Parameter Initialization failed"); pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); break; } // Get related cam calibration only in // dual camera mode if (pme->getRelatedCamSyncInfo()->sync_control == CAM_SYNC_RELATED_SENSORS_ON) { rc = pme->mParameters.getRelatedCamCalibration( &(pme->mJpegMetadata.otp_calibration_data)); LOGD("Dumping Calibration Data Version Id %f rc %d", pme->mJpegMetadata.otp_calibration_data.calibration_format_version, rc); if (rc != 0) { job_status = UNKNOWN_ERROR; LOGE("getRelatedCamCalibration failed"); pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); break; } pme->m_bRelCamCalibValid = true; } pme->mJpegMetadata.sensor_mount_angle = cap->sensor_mount_angle; pme->mJpegMetadata.default_sensor_flip = FLIP_NONE; pme->mParameters.setMinPpMask( cap->qcom_supported_feature_mask); pme->mExifParams.debug_params = (mm_jpeg_debug_exif_params_t *) malloc(sizeof(mm_jpeg_debug_exif_params_t)); if (!pme->mExifParams.debug_params) { LOGE("Out of Memory. Allocation failed for " "3A debug exif params"); job_status = NO_MEMORY; pme->sendEvtNotify(CAMERA_MSG_ERROR, CAMERA_ERROR_UNKNOWN, 0); break; } memset(pme->mExifParams.debug_params, 0, sizeof(mm_jpeg_debug_exif_params_t)); } break; case CMD_DEF_GENERIC: { BackgroundTask *bgTask = dw->args.genericArgs; job_status = bgTask->bgFunction(bgTask->bgArgs); } break; default: LOGE("Incorrect command : %d", dw->cmd); } pme->dequeueDeferredWork(dw, job_status); } break; case CAMERA_CMD_TYPE_EXIT: running = 0; break; default: break; } } while (running); return NULL; } /*=========================================================================== * FUNCTION : queueDeferredWork * * DESCRIPTION: function which queues deferred tasks * * PARAMETERS : * @cmd : deferred task * @args : deferred task arguments * * RETURN : job id of deferred job * : 0 in case of error *==========================================================================*/ uint32_t QCamera2HardwareInterface::queueDeferredWork(DeferredWorkCmd cmd, DeferWorkArgs args) { Mutex::Autolock l(mDefLock); for (int32_t i = 0; i < MAX_ONGOING_JOBS; ++i) { if (mDefOngoingJobs[i].mDefJobId == 0) { DefWork *dw = new DefWork(cmd, sNextJobId, args); if (!dw) { LOGE("out of memory."); return 0; } if (mCmdQueue.enqueue(dw)) { mDefOngoingJobs[i].mDefJobId = sNextJobId++; mDefOngoingJobs[i].mDefJobStatus = 0; if (sNextJobId == 0) { // handle overflow sNextJobId = 1; } mDeferredWorkThread.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); return mDefOngoingJobs[i].mDefJobId; } else { LOGD("Command queue not active! cmd = %d", cmd); delete dw; return 0; } } } return 0; } /*=========================================================================== * FUNCTION : initJpegHandle * * DESCRIPTION: Opens JPEG client and gets a handle. * Sends Dual cam calibration info if present * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::initJpegHandle() { // Check if JPEG client handle is present LOGH("E"); if(!mJpegClientHandle) { mm_dimension max_size = {0, 0}; cam_dimension_t size; mParameters.getMaxPicSize(size); max_size.w = size.width; max_size.h = size.height; if (getRelatedCamSyncInfo()->sync_control == CAM_SYNC_RELATED_SENSORS_ON) { if (m_bRelCamCalibValid) { mJpegClientHandle = jpeg_open(&mJpegHandle, &mJpegMpoHandle, max_size, &mJpegMetadata); } else { mJpegClientHandle = jpeg_open(&mJpegHandle, &mJpegMpoHandle, max_size, NULL); } } else { mJpegClientHandle = jpeg_open(&mJpegHandle, NULL, max_size, NULL); } if (!mJpegClientHandle) { LOGE("Error !! jpeg_open failed!! "); return UNKNOWN_ERROR; } // Set JPEG initialized as true to signify that this camera // has initialized the handle mJpegHandleOwner = true; } LOGH("X mJpegHandleOwner: %d, mJpegClientHandle: %d camera id: %d", mJpegHandleOwner, mJpegClientHandle, mCameraId); return NO_ERROR; } /*=========================================================================== * FUNCTION : deinitJpegHandle * * DESCRIPTION: Closes JPEG client using handle * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::deinitJpegHandle() { int32_t rc = NO_ERROR; LOGH("E"); // Check if JPEG client handle is present and inited by this camera if(mJpegHandleOwner && mJpegClientHandle) { rc = mJpegHandle.close(mJpegClientHandle); if (rc != NO_ERROR) { LOGE("Error!! Closing mJpegClientHandle: %d failed", mJpegClientHandle); } memset(&mJpegHandle, 0, sizeof(mJpegHandle)); memset(&mJpegMpoHandle, 0, sizeof(mJpegMpoHandle)); mJpegHandleOwner = false; } mJpegClientHandle = 0; LOGH("X rc = %d", rc); return rc; } /*=========================================================================== * FUNCTION : setJpegHandleInfo * * DESCRIPTION: sets JPEG client handle info * * PARAMETERS: * @ops : JPEG ops * @mpo_ops : Jpeg MPO ops * @pJpegClientHandle : o/p Jpeg Client Handle * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::setJpegHandleInfo(mm_jpeg_ops_t *ops, mm_jpeg_mpo_ops_t *mpo_ops, uint32_t pJpegClientHandle) { if (pJpegClientHandle && ops && mpo_ops) { LOGH("Setting JPEG client handle %d", pJpegClientHandle); memcpy(&mJpegHandle, ops, sizeof(mm_jpeg_ops_t)); memcpy(&mJpegMpoHandle, mpo_ops, sizeof(mm_jpeg_mpo_ops_t)); mJpegClientHandle = pJpegClientHandle; return NO_ERROR; } else { LOGE("Error!! No Handle found: %d", pJpegClientHandle); return BAD_VALUE; } } /*=========================================================================== * FUNCTION : getJpegHandleInfo * * DESCRIPTION: gets JPEG client handle info * * PARAMETERS: * @ops : JPEG ops * @mpo_ops : Jpeg MPO ops * @pJpegClientHandle : o/p Jpeg Client Handle * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::getJpegHandleInfo(mm_jpeg_ops_t *ops, mm_jpeg_mpo_ops_t *mpo_ops, uint32_t *pJpegClientHandle) { if (NO_ERROR != waitDeferredWork(mInitPProcJob)) { LOGE("Init PProc Deferred work failed"); return UNKNOWN_ERROR; } // Copy JPEG ops if present if (ops && mpo_ops && pJpegClientHandle) { memcpy(ops, &mJpegHandle, sizeof(mm_jpeg_ops_t)); memcpy(mpo_ops, &mJpegMpoHandle, sizeof(mm_jpeg_mpo_ops_t)); *pJpegClientHandle = mJpegClientHandle; LOGH("Getting JPEG client handle %d", pJpegClientHandle); return NO_ERROR; } else { return BAD_VALUE; } } /*=========================================================================== * FUNCTION : dequeueDeferredWork * * DESCRIPTION: function which dequeues deferred tasks * * PARAMETERS : * @dw : deferred work * @jobStatus: deferred task job status * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ uint32_t QCamera2HardwareInterface::dequeueDeferredWork(DefWork* dw, int32_t jobStatus) { Mutex::Autolock l(mDefLock); for (uint32_t i = 0; i < MAX_ONGOING_JOBS; i++) { if (mDefOngoingJobs[i].mDefJobId == dw->id) { if (jobStatus != NO_ERROR) { mDefOngoingJobs[i].mDefJobStatus = jobStatus; LOGH("updating job status %d for id %d", jobStatus, dw->id); } else { mDefOngoingJobs[i].mDefJobId = 0; mDefOngoingJobs[i].mDefJobStatus = 0; } delete dw; mDefCond.broadcast(); return NO_ERROR; } } return UNKNOWN_ERROR; } /*=========================================================================== * FUNCTION : getDefJobStatus * * DESCRIPTION: Gets if a deferred task is success/fail * * PARAMETERS : * @job_id : deferred task id * * RETURN : NO_ERROR if the job success, otherwise false * * PRECONDITION : mDefLock is held by current thread *==========================================================================*/ int32_t QCamera2HardwareInterface::getDefJobStatus(uint32_t &job_id) { for (uint32_t i = 0; i < MAX_ONGOING_JOBS; i++) { if (mDefOngoingJobs[i].mDefJobId == job_id) { if ( NO_ERROR != mDefOngoingJobs[i].mDefJobStatus ) { LOGE("job_id (%d) was failed", job_id); return mDefOngoingJobs[i].mDefJobStatus; } else return NO_ERROR; } } return NO_ERROR; } /*=========================================================================== * FUNCTION : checkDeferredWork * * DESCRIPTION: checks if a deferred task is in progress * * PARAMETERS : * @job_id : deferred task id * * RETURN : true if the task exists, otherwise false * * PRECONDITION : mDefLock is held by current thread *==========================================================================*/ bool QCamera2HardwareInterface::checkDeferredWork(uint32_t &job_id) { for (uint32_t i = 0; i < MAX_ONGOING_JOBS; i++) { if (mDefOngoingJobs[i].mDefJobId == job_id) { return (NO_ERROR == mDefOngoingJobs[i].mDefJobStatus); } } return false; } /*=========================================================================== * FUNCTION : waitDeferredWork * * DESCRIPTION: waits for a deferred task to finish * * PARAMETERS : * @job_id : deferred task id * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::waitDeferredWork(uint32_t &job_id) { Mutex::Autolock l(mDefLock); if (job_id == 0) { LOGD("Invalid job id %d", job_id); return NO_ERROR; } while (checkDeferredWork(job_id) == true ) { mDefCond.waitRelative(mDefLock, CAMERA_DEFERRED_THREAD_TIMEOUT); } return getDefJobStatus(job_id); } /*=========================================================================== * FUNCTION : scheduleBackgroundTask * * DESCRIPTION: Run a requested task in the deferred thread * * PARAMETERS : * @bgTask : Task to perform in the background * * RETURN : job id of deferred job * : 0 in case of error *==========================================================================*/ uint32_t QCamera2HardwareInterface::scheduleBackgroundTask(BackgroundTask* bgTask) { DeferWorkArgs args; memset(&args, 0, sizeof(DeferWorkArgs)); args.genericArgs = bgTask; return queueDeferredWork(CMD_DEF_GENERIC, args); } /*=========================================================================== * FUNCTION : waitForBackgroundTask * * DESCRIPTION: Wait for a background task to complete * * PARAMETERS : * @taskId : Task id to wait for * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::waitForBackgroundTask(uint32_t& taskId) { return waitDeferredWork(taskId); } /*=========================================================================== * FUNCTION : needDeferedAllocation * * DESCRIPTION: Function to decide background task for streams * * PARAMETERS : * @stream_type : stream type * * RETURN : true - if background task is needed * false - if background task is NOT needed *==========================================================================*/ bool QCamera2HardwareInterface::needDeferred(cam_stream_type_t stream_type) { if ((stream_type == CAM_STREAM_TYPE_PREVIEW && mPreviewWindow == NULL) || (stream_type == CAM_STREAM_TYPE_ANALYSIS)) { return FALSE; } if ((stream_type == CAM_STREAM_TYPE_RAW) && (mParameters.getofflineRAW())) { return FALSE; } if ((stream_type == CAM_STREAM_TYPE_SNAPSHOT) && (!mParameters.getRecordingHintValue())){ return TRUE; } if ((stream_type == CAM_STREAM_TYPE_PREVIEW) || (stream_type == CAM_STREAM_TYPE_METADATA) || (stream_type == CAM_STREAM_TYPE_RAW) || (stream_type == CAM_STREAM_TYPE_POSTVIEW)) { return TRUE; } if (stream_type == CAM_STREAM_TYPE_VIDEO) { return FALSE; } return FALSE; } /*=========================================================================== * FUNCTION : isRegularCapture * * DESCRIPTION: Check configuration for regular catpure * * PARAMETERS : * * RETURN : true - regular capture * false - other type of capture *==========================================================================*/ bool QCamera2HardwareInterface::isRegularCapture() { bool ret = false; if (numOfSnapshotsExpected() == 1 && !isLongshotEnabled() && !mParameters.isHDREnabled() && !mParameters.getRecordingHintValue() && !isZSLMode() && !mParameters.getofflineRAW()) { ret = true; } return ret; } /*=========================================================================== * FUNCTION : getLogLevel * * DESCRIPTION: Reads the log level property into a variable * * PARAMETERS : * None * * RETURN : * None *==========================================================================*/ void QCamera2HardwareInterface::getLogLevel() { char prop[PROPERTY_VALUE_MAX]; property_get("persist.camera.kpi.debug", prop, "1"); gKpiDebugLevel = atoi(prop); return; } /*=========================================================================== * FUNCTION : getSensorType * * DESCRIPTION: Returns the type of sensor being used whether YUV or Bayer * * PARAMETERS : * None * * RETURN : Type of sensor - bayer or YUV * *==========================================================================*/ cam_sensor_t QCamera2HardwareInterface::getSensorType() { return gCamCapability[mCameraId]->sensor_type.sens_type; } /*=========================================================================== * FUNCTION : startRAWChannel * * DESCRIPTION: start RAW Channel * * PARAMETERS : * @pChannel : Src channel to link this RAW channel. * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::startRAWChannel(QCameraChannel *pMetaChannel) { int32_t rc = NO_ERROR; QCameraChannel *pChannel = m_channels[QCAMERA_CH_TYPE_RAW]; if ((NULL != pChannel) && (mParameters.getofflineRAW())) { // Find and try to link a metadata stream from preview channel QCameraStream *pMetaStream = NULL; if (pMetaChannel != NULL) { uint32_t streamNum = pMetaChannel->getNumOfStreams(); QCameraStream *pStream = NULL; for (uint32_t i = 0 ; i < streamNum ; i++ ) { pStream = pMetaChannel->getStreamByIndex(i); if ((NULL != pStream) && (CAM_STREAM_TYPE_METADATA == pStream->getMyType())) { pMetaStream = pStream; break; } } if (NULL != pMetaStream) { rc = pChannel->linkStream(pMetaChannel, pMetaStream); if (NO_ERROR != rc) { LOGE("Metadata stream link failed %d", rc); } } } rc = pChannel->start(); } return rc; } /*=========================================================================== * FUNCTION : startRecording * * DESCRIPTION: start recording impl * * PARAMETERS : none * * RETURN : int32_t type of status * NO_ERROR -- success * none-zero failure code *==========================================================================*/ int32_t QCamera2HardwareInterface::stopRAWChannel() { int32_t rc = NO_ERROR; rc = stopChannel(QCAMERA_CH_TYPE_RAW); return rc; } /*=========================================================================== * FUNCTION : isLowPowerMode * * DESCRIPTION: Returns TRUE if low power mode settings are to be applied for video recording * * PARAMETERS : * None * * RETURN : TRUE/FALSE * *==========================================================================*/ bool QCamera2HardwareInterface::isLowPowerMode() { cam_dimension_t dim; mParameters.getStreamDimension(CAM_STREAM_TYPE_VIDEO, dim); char prop[PROPERTY_VALUE_MAX]; property_get("camera.lowpower.record.enable", prop, "0"); int enable = atoi(prop); //Enable low power mode if : //1. Video resolution is 2k (2048x1080) or above and //2. camera.lowpower.record.enable is set bool isLowpower = mParameters.getRecordingHintValue() && enable && ((dim.width * dim.height) >= (2048 * 1080)); return isLowpower; } }; // namespace qcamera