You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
11413 lines
391 KiB
11413 lines
391 KiB
/* Copyright (c) 2012-2017, 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 CAMERA_MIN_DISPLAY_BUFFERS 2 |
|
#define CAMERA_DEFAULT_FPS 30000 |
|
|
|
#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_CAMSCOPE_CALL(CAMSCOPE_HAL1_SET_PREVIEW_WINDOW); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_SET_CALLBACKS); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_ENABLE_MSG_TYPE); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_DISABLE_MSG_TYPE); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_MSG_TYPE_ENABLED); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_PREPARE_PREVIEW); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_START_PREVIEW); |
|
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()); |
|
|
|
hw->m_perfLockMgr.acquirePerfLockIfExpired(PERF_LOCK_START_PREVIEW); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_STOP_PREVIEW); |
|
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_perfLockMgr.releasePerfLock(PERF_LOCK_POWERHINT_PREVIEW); |
|
|
|
hw->m_perfLockMgr.acquirePerfLockIfExpired(PERF_LOCK_STOP_PREVIEW); |
|
|
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_PREVIEW_ENABLED); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_RESTART_START_PREVIEW); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_RESTART_STOP_PREVIEW); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_PRE_START_RECORDING); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_START_RECORDING); |
|
int ret = NO_ERROR; |
|
QCamera2HardwareInterface *hw = |
|
reinterpret_cast<QCamera2HardwareInterface *>(device->priv); |
|
if (!hw) { |
|
LOGE("NULL camera device"); |
|
return BAD_VALUE; |
|
} |
|
|
|
hw->m_perfLockMgr.acquirePerfLockIfExpired(PERF_LOCK_START_RECORDING); |
|
|
|
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); |
|
hw->m_perfLockMgr.releasePerfLock(PERF_LOCK_START_RECORDING); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_STOP_RECORDING); |
|
QCamera2HardwareInterface *hw = |
|
reinterpret_cast<QCamera2HardwareInterface *>(device->priv); |
|
if (!hw) { |
|
LOGE("NULL camera device"); |
|
return; |
|
} |
|
|
|
hw->m_perfLockMgr.acquirePerfLockIfExpired(PERF_LOCK_STOP_RECORDING); |
|
|
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_RECORDING_ENABLED); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_REL_REC_FRAME); |
|
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()); |
|
|
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_CANCEL_AF); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_PRE_TAKE_PICTURE); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_TAKE_PICTURE); |
|
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()); |
|
|
|
// Acquire the perf lock for JPEG snapshot only |
|
if (hw->mParameters.isJpegPictureFormat()) { |
|
hw->m_perfLockMgr.acquirePerfLock(PERF_LOCK_TAKE_SNAPSHOT); |
|
} |
|
|
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_CANCEL_PICTURE); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_SET_PARAMETERS); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_STOP_AFTER_SET_PARAMS); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_COMMIT_PARAMS); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_RESTART_AFTER_SET_PARAMS); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_GET_PARAMETERS); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_PUT_PARAMETERS); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_SEND_COMMAND); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_SEND_COMMAND_RESTART); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_RELEASE); |
|
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_CAMSCOPE_BEGIN(CAMSCOPE_HAL1_CLOSECAMERA); |
|
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"); |
|
KPI_ATRACE_CAMSCOPE_END(CAMSCOPE_HAL1_CLOSECAMERA); |
|
CAMSCOPE_DESTROY(CAMSCOPE_SECTION_HAL); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_REGISTER_FACE_IMAGE); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_PREPARE_SNAPSHOT); |
|
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), |
|
mMasterCamera(CAM_TYPE_MAIN), |
|
mCameraOpened(false), |
|
mDualCamera(false), |
|
m_pFovControl(NULL), |
|
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_perfLockMgr(), |
|
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), |
|
mFlashConfigured(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), |
|
mLowLightConfigured(false), |
|
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), |
|
mCACDoneReceived(false), |
|
m_bNeedRestart(false), |
|
mBootToMonoTimestampOffset(0), |
|
bDepthAFCallbacks(true), |
|
m_bNeedHalPP(FALSE) |
|
{ |
|
#ifdef TARGET_TS_MAKEUP |
|
memset(&mFaceRect, -1, sizeof(mFaceRect)); |
|
#endif |
|
getLogLevel(); |
|
ATRACE_CAMSCOPE_CALL(CAMSCOPE_HAL1_QCAMERA2HWI); |
|
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; |
|
|
|
mDualCamera = is_dual_camera_by_idx(cameraId); |
|
|
|
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); |
|
|
|
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; |
|
} |
|
|
|
if (m_pFovControl) { |
|
delete m_pFovControl; |
|
m_pFovControl = NULL; |
|
} |
|
|
|
m_perfLockMgr.acquirePerfLock(PERF_LOCK_CLOSE_CAMERA); |
|
lockAPI(); |
|
m_smThreadActive = false; |
|
unlockAPI(); |
|
m_stateMachine.releaseThread(); |
|
closeCamera(); |
|
m_perfLockMgr.releasePerfLock(PERF_LOCK_CLOSE_CAMERA); |
|
|
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_OPENCAMERA); |
|
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_perfLockMgr.acquirePerfLock(PERF_LOCK_OPEN_CAMERA); |
|
|
|
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); |
|
} |
|
mBundledSnapshot = 0; |
|
mActiveCameras = MM_CAMERA_TYPE_MAIN; |
|
if (isDualCamera()) { |
|
mActiveCameras |= MM_CAMERA_TYPE_AUX; |
|
|
|
// Create and initialize FOV-control object |
|
m_pFovControl = QCameraFOVControl::create(gCamCapability[mCameraId]->main_cam_cap, |
|
gCamCapability[mCameraId]->aux_cam_cap); |
|
if (m_pFovControl) { |
|
*gCamCapability[mCameraId] = m_pFovControl->consolidateCapabilities( |
|
gCamCapability[mCameraId]->main_cam_cap, |
|
gCamCapability[mCameraId]->aux_cam_cap); |
|
} else { |
|
LOGE("FOV-control: Failed to create an object"); |
|
rc = NO_MEMORY; |
|
goto error_exit3; |
|
} |
|
} |
|
|
|
// 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); |
|
} |
|
|
|
// Setprop to decide the time source (whether boottime or monotonic). |
|
// By default, use monotonic time. |
|
property_get("persist.camera.time.monotonic", value, "1"); |
|
mBootToMonoTimestampOffset = 0; |
|
if (atoi(value) == 1) { |
|
// if monotonic is set, then need to use time in monotonic. |
|
// So, Measure the clock offset between BOOTTIME and MONOTONIC |
|
// The clock domain source for ISP is BOOTTIME and |
|
// for Video/display is MONOTONIC |
|
// The below offset is used to convert from clock domain of other subsystem |
|
// (video/hardware composer) to that of camera. Assumption is that this |
|
// offset won't change during the life cycle of the camera device. In other |
|
// words, camera device shouldn't be open during CPU suspend. |
|
mBootToMonoTimestampOffset = getBootToMonoTimeOffset(); |
|
} |
|
LOGH("mBootToMonoTimestampOffset = %lld", mBootToMonoTimestampOffset); |
|
|
|
memset(value, 0, sizeof(value)); |
|
property_get("persist.camera.depth.focus.cb", value, "1"); |
|
bDepthAFCallbacks = atoi(value); |
|
|
|
memset(value, 0, sizeof(value)); |
|
property_get("persist.camera.cache.optimize", value, "1"); |
|
m_bOptimizeCacheOps = atoi(value); |
|
|
|
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 |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int QCamera2HardwareInterface::bundleRelatedCameras(bool syncOn) |
|
{ |
|
int32_t rc = mParameters.bundleRelatedCameras(syncOn); |
|
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 : getCapabilities |
|
* |
|
* DESCRIPTION: query camera capability from back-end |
|
* |
|
* PARAMETERS : |
|
* @ops : mm-interface ops structure |
|
* @cam_handle : camera handle for which we need capability |
|
* |
|
* RETURN : ptr type of capability structure |
|
* capability for success |
|
* NULL for failure |
|
*==========================================================================*/ |
|
cam_capability_t *QCamera2HardwareInterface::getCapabilities(mm_camera_ops_t *ops, |
|
uint32_t cam_handle) |
|
{ |
|
ATRACE_CAMSCOPE_CALL(CAMSCOPE_HAL1_GET_CAP); |
|
int rc = NO_ERROR; |
|
QCameraHeapMemory *capabilityHeap = NULL; |
|
cam_capability_t *cap_ptr = NULL; |
|
|
|
if (ops == NULL) { |
|
LOGE("Invalid arguments"); |
|
return NULL; |
|
} |
|
|
|
capabilityHeap = new QCameraHeapMemory(1); |
|
if (capabilityHeap == NULL) { |
|
LOGE("creation of capabilityHeap failed"); |
|
return NULL; |
|
} |
|
|
|
/* Allocate memory for capability buffer */ |
|
rc = capabilityHeap->allocate(1, sizeof(cam_capability_t)); |
|
if(rc != OK) { |
|
LOGE("No memory for capability"); |
|
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 = ops->map_bufs(cam_handle, |
|
&bufMapList); |
|
} |
|
if(rc < 0) { |
|
LOGE("failed to map capability buffer"); |
|
goto map_failed; |
|
} |
|
|
|
/* Query Capability */ |
|
rc = ops->query_capability(cam_handle); |
|
if(rc < 0) { |
|
LOGE("failed to query capability"); |
|
rc = FAILED_TRANSACTION; |
|
goto query_failed; |
|
} |
|
|
|
cap_ptr = (cam_capability_t *)malloc(sizeof(cam_capability_t)); |
|
if (cap_ptr == NULL) { |
|
LOGE("out of memory"); |
|
rc = NO_MEMORY; |
|
goto query_failed; |
|
} |
|
|
|
memset(cap_ptr, 0, sizeof(cam_capability_t)); |
|
memcpy(cap_ptr, 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 = &cap_ptr->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; |
|
} |
|
|
|
query_failed: |
|
ops->unmap_buf(cam_handle, CAM_MAPPING_BUF_TYPE_CAPABILITY); |
|
map_failed: |
|
capabilityHeap->deallocate(); |
|
allocate_failed: |
|
delete capabilityHeap; |
|
|
|
if (rc != NO_ERROR) { |
|
return NULL; |
|
} else { |
|
return cap_ptr; |
|
} |
|
} |
|
|
|
/*=========================================================================== |
|
* 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_CAMSCOPE_CALL(CAMSCOPE_HAL1_INIT_CAP); |
|
int rc = 0; |
|
uint32_t handle = 0; |
|
|
|
rc = camera_open((uint8_t)cameraId, &cameraHandle); |
|
if (rc) { |
|
LOGE("camera_open failed. rc = %d", rc); |
|
goto open_failed; |
|
} |
|
if (!cameraHandle) { |
|
LOGE("camera_open failed. cameraHandle = %p", cameraHandle); |
|
goto open_failed; |
|
} |
|
|
|
handle = get_main_camera_handle(cameraHandle->camera_handle); |
|
gCamCapability[cameraId] = getCapabilities(cameraHandle->ops, handle); |
|
if (gCamCapability[cameraId] == NULL) { |
|
rc = FAILED_TRANSACTION; |
|
goto failed_op; |
|
} |
|
|
|
gCamCapability[cameraId]->camera_index = cameraId; |
|
if (is_dual_camera_by_idx(cameraId)) { |
|
handle = get_aux_camera_handle(cameraHandle->camera_handle); |
|
gCamCapability[cameraId]->aux_cam_cap = |
|
getCapabilities(cameraHandle->ops, handle); |
|
if (gCamCapability[cameraId]->aux_cam_cap == NULL) { |
|
rc = FAILED_TRANSACTION; |
|
free(gCamCapability[cameraId]); |
|
goto failed_op; |
|
} |
|
|
|
// Copy the main camera capability to main_cam_cap struct |
|
gCamCapability[cameraId]->main_cam_cap = |
|
(cam_capability_t *)malloc(sizeof(cam_capability_t)); |
|
if (gCamCapability[cameraId]->main_cam_cap == NULL) { |
|
LOGE("out of memory"); |
|
rc = NO_MEMORY; |
|
goto failed_op; |
|
} |
|
memcpy(gCamCapability[cameraId]->main_cam_cap, gCamCapability[cameraId], |
|
sizeof(cam_capability_t)); |
|
} |
|
failed_op: |
|
cameraHandle->ops->close_camera(cameraHandle->camera_handle); |
|
cameraHandle = NULL; |
|
open_failed: |
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : getCapabilities |
|
* |
|
* DESCRIPTION: query camera capabilities |
|
* |
|
* PARAMETERS : |
|
* @cameraId : camera Id |
|
* @info : camera info struct to be filled in with camera capabilities |
|
* |
|
* RETURN : 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_CAMSCOPE_CALL(CAMSCOPE_HAL1_GET_CAP); |
|
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 : getBufNumForAux |
|
* |
|
* DESCRIPTION: return number of stream buffers needed for aux camera given stream type |
|
* |
|
* PARAMETERS : |
|
* @stream_type : type of stream |
|
* |
|
* RETURN : number of buffers needed |
|
* NOTE : Based on the use cases and auxillary camera type, |
|
we can decide buffer count |
|
*==========================================================================*/ |
|
uint8_t QCamera2HardwareInterface::getBufNumForAux(cam_stream_type_t stream_type) |
|
{ |
|
if (!isDualCamera()) { |
|
return 0; |
|
} |
|
|
|
uint8_t bufferCnt = 1; |
|
switch (stream_type) { |
|
case CAM_STREAM_TYPE_PREVIEW: |
|
case CAM_STREAM_TYPE_VIDEO: |
|
case CAM_STREAM_TYPE_SNAPSHOT: |
|
case CAM_STREAM_TYPE_METADATA: |
|
case CAM_STREAM_TYPE_CALLBACK: |
|
case CAM_STREAM_TYPE_ANALYSIS: |
|
case CAM_STREAM_TYPE_POSTVIEW: |
|
case CAM_STREAM_TYPE_RAW: |
|
case CAM_STREAM_TYPE_OFFLINE_PROC: |
|
case CAM_STREAM_TYPE_DEFAULT: |
|
case CAM_STREAM_TYPE_MAX: |
|
//For wide & tele, we use same buffer count premary and aux streams. |
|
bufferCnt = getBufNumRequired(stream_type); |
|
break; |
|
default: |
|
break; |
|
} |
|
LOGH("Buffer Cnt for Aux Camera : %d", bufferCnt); |
|
return bufferCnt; |
|
} |
|
|
|
/*=========================================================================== |
|
* 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 minPrevFps, maxPrevFps; |
|
|
|
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(); |
|
if (isDualCamera()) { |
|
bufferCnt += zslQBuffers; |
|
} |
|
} 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; |
|
|
|
// Extra ZSL preview frames are not needed for HFR case. |
|
// Thumbnail will not be derived from preview for HFR live snapshot case. |
|
if ((mParameters.getRecordingHintValue() == true) |
|
&& (!mParameters.isHfrMode())) { |
|
bufferCnt += EXTRA_ZSL_PREVIEW_STREAM_BUF; |
|
} |
|
//Adding Extra preview buffers for 60FPS usecase. |
|
mParameters.getPreviewFpsRange(&minPrevFps, &maxPrevFps); |
|
if (maxPrevFps > CAMERA_DEFAULT_FPS) { |
|
bufferCnt += CAMERA_MIN_DISPLAY_BUFFERS; |
|
} |
|
|
|
// 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; |
|
} |
|
if (isDualCamera()) { |
|
bufferCnt += zslQBuffers; |
|
} |
|
} 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 || isSecureMode()) { |
|
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; |
|
if (isDualCamera()) { |
|
bufferCnt += zslQBuffers; |
|
} |
|
} 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 : getStreamRefCount |
|
* |
|
* DESCRIPTION: return number of instance of stream of stream type |
|
* |
|
* PARAMETERS : |
|
* @stream_type : type of stream |
|
* @cam_type : Type of camera for this stream |
|
* |
|
* RETURN : number of stream instances |
|
* NOTE : Based on the use cases and auxillary camera type, |
|
we can decide stream reference count. |
|
For example in wide and tele use case, we duplicate all stream |
|
streams from premary to auxillary. |
|
*==========================================================================*/ |
|
uint8_t QCamera2HardwareInterface::getStreamRefCount(cam_stream_type_t stream_type, |
|
uint32_t cam_type) |
|
{ |
|
uint8_t ref_cnt = 1; |
|
|
|
if (cam_type != MM_CAMERA_DUAL_CAM) { |
|
return ref_cnt; |
|
} |
|
|
|
switch (stream_type) { |
|
case CAM_STREAM_TYPE_PREVIEW: |
|
case CAM_STREAM_TYPE_SNAPSHOT: |
|
case CAM_STREAM_TYPE_VIDEO: |
|
case CAM_STREAM_TYPE_METADATA: |
|
case CAM_STREAM_TYPE_ANALYSIS: |
|
case CAM_STREAM_TYPE_CALLBACK: |
|
if (isDualCamera()) { |
|
ref_cnt++; |
|
} |
|
break; |
|
case CAM_STREAM_TYPE_POSTVIEW: |
|
case CAM_STREAM_TYPE_RAW: |
|
case CAM_STREAM_TYPE_OFFLINE_PROC: |
|
case CAM_STREAM_TYPE_DEFAULT: |
|
case CAM_STREAM_TYPE_MAX: |
|
default: |
|
break; |
|
} |
|
return ref_cnt; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : getCamHandleForChannel |
|
* |
|
* DESCRIPTION: return actual camera handle based on use case |
|
* |
|
* PARAMETERS : |
|
* @ch_type : type of channel |
|
* |
|
* RETURN : uint32_t type camera handle |
|
* NOTE : Based on the use cases and auxillary camera type, we can decide cam handle for channel. |
|
Incase, we want to avoid any channel for auxillary camera, we can decide here |
|
*==========================================================================*/ |
|
uint32_t QCamera2HardwareInterface::getCamHandleForChannel(qcamera_ch_type_enum_t ch_type) |
|
{ |
|
uint32_t handle = 0; |
|
if (!isDualCamera()) { |
|
return mCameraHandle->camera_handle; |
|
} |
|
|
|
/*Based on the use case, decide camera handle for channel*/ |
|
switch (ch_type) { |
|
case QCAMERA_CH_TYPE_ZSL: |
|
case QCAMERA_CH_TYPE_CAPTURE: |
|
case QCAMERA_CH_TYPE_PREVIEW: |
|
case QCAMERA_CH_TYPE_VIDEO: |
|
case QCAMERA_CH_TYPE_SNAPSHOT: |
|
case QCAMERA_CH_TYPE_RAW: |
|
case QCAMERA_CH_TYPE_METADATA: |
|
case QCAMERA_CH_TYPE_ANALYSIS: |
|
case QCAMERA_CH_TYPE_CALLBACK: |
|
case QCAMERA_CH_TYPE_MAX: |
|
default: |
|
handle = mCameraHandle->camera_handle; |
|
break; |
|
case QCAMERA_CH_TYPE_REPROCESSING: |
|
if (!mParameters.isDCmAsymmetricSnapMode()) { |
|
handle = get_main_camera_handle(mCameraHandle->camera_handle); |
|
} else { |
|
/*In Asymmetric mode, we create 2 reproc channels. But |
|
one stream is added per channel */ |
|
handle = mCameraHandle->camera_handle; |
|
} |
|
break; |
|
} |
|
return handle; |
|
} |
|
|
|
/*=========================================================================== |
|
* 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, |
|
mCallbackCookie, |
|
bCachedMem, |
|
(bPoolMem) ? &m_memoryPool : NULL, |
|
stream_type); |
|
} else { |
|
cam_dimension_t dim; |
|
int minFPS, maxFPS; |
|
QCameraGrallocMemory *grallocMemory = NULL; |
|
|
|
if (isSecureMode()) { |
|
grallocMemory = new QCameraGrallocMemory(mGetMemory, mCallbackCookie, QCAMERA_MEM_TYPE_SECURE); |
|
}else { |
|
grallocMemory = new QCameraGrallocMemory(mGetMemory, mCallbackCookie); |
|
} |
|
|
|
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, mCallbackCookie, bCachedMem); |
|
} else { |
|
cam_dimension_t dim; |
|
int minFPS, maxFPS; |
|
QCameraGrallocMemory *grallocMemory = |
|
new QCameraGrallocMemory(mGetMemory, mCallbackCookie); |
|
|
|
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_OFFLINE_PROC: |
|
mem = new QCameraStreamMemory(mGetMemory, |
|
mCallbackCookie, |
|
bCachedMem, |
|
(bPoolMem) ? &m_memoryPool : NULL, |
|
stream_type); |
|
break; |
|
case CAM_STREAM_TYPE_RAW: |
|
if(isSecureMode()) { |
|
mem = new QCameraStreamMemory(mGetMemory, |
|
mCallbackCookie, |
|
bCachedMem, |
|
(bPoolMem) ? &m_memoryPool : NULL, |
|
stream_type, |
|
QCAMERA_MEM_TYPE_SECURE); |
|
LOGH("Allocating %d secure buffers of size %d ", bufferCnt, size); |
|
} else { |
|
mem = new QCameraStreamMemory(mGetMemory, |
|
mCallbackCookie, |
|
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; |
|
int usage = 0; |
|
cam_format_t fmt; |
|
|
|
if (mParameters.getVideoBatchSize()) { |
|
videoMemory = new QCameraVideoMemory( |
|
mGetMemory, mCallbackCookie, FALSE, QCAMERA_MEM_TYPE_BATCH); |
|
if (videoMemory == NULL) { |
|
LOGE("Out of memory for video batching obj"); |
|
return NULL; |
|
} |
|
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); |
|
/* |
|
* numFDs = BATCH size |
|
* numInts = 5 // OFFSET, SIZE, USAGE, TIMESTAMP, FORMAT |
|
*/ |
|
rc = videoMemory->allocateMeta( |
|
CAMERA_MIN_VIDEO_BATCH_BUFFERS, |
|
mParameters.getVideoBatchSize()); |
|
if (rc < 0) { |
|
delete videoMemory; |
|
return NULL; |
|
} |
|
} else { |
|
videoMemory = |
|
new QCameraVideoMemory(mGetMemory, mCallbackCookie, bCachedMem); |
|
if (videoMemory == NULL) { |
|
LOGE("Out of memory for video obj"); |
|
return NULL; |
|
} |
|
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; |
|
} |
|
break; |
|
case CAM_STREAM_TYPE_CALLBACK: |
|
mem = new QCameraStreamMemory(mGetMemory, |
|
mCallbackCookie, |
|
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) { |
|
rc = mem->allocate(bufferCnt, size); |
|
if (rc < 0) { |
|
delete mem; |
|
return NULL; |
|
} |
|
bufferCnt = mem->getCnt(); |
|
} |
|
LOGH("rc = %d type = %d count = %d size = %d cache = %d, pool = %d mEnqueuedBuffers = %d", |
|
rc, stream_type, bufferCnt, size, bCachedMem, bPoolMem, mEnqueuedBuffers); |
|
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); |
|
if (rc < 0) { |
|
LOGE("Failed to allocate misc buffer memory"); |
|
delete miscBuf; |
|
return NULL; |
|
} |
|
} |
|
|
|
return miscBuf; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : initStreamInfoBuf |
|
* |
|
* DESCRIPTION: initialize stream info buffer based on stream type |
|
* |
|
* PARAMETERS : |
|
* @stream_type : type of stream |
|
* @cam_type : Camera type in case of dual camera |
|
* |
|
* RETURN : ptr to a memory obj that holds stream info buffer. |
|
* NULL if failed |
|
*==========================================================================*/ |
|
int QCamera2HardwareInterface::initStreamInfoBuf(cam_stream_type_t stream_type, |
|
cam_stream_info_t *streamInfo, uint32_t cam_type) |
|
{ |
|
int rc = NO_ERROR; |
|
int32_t dt = 0; |
|
int32_t vc = 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, cam_type); |
|
rc = mParameters.getStreamRotation(stream_type, streamInfo->pp_config, streamInfo->dim); |
|
streamInfo->num_bufs = getBufNumRequired(stream_type); |
|
streamInfo->buf_cnt = streamInfo->num_bufs; |
|
streamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS; |
|
streamInfo->is_secure = NON_SECURE; |
|
// Initialize cache ops |
|
if (!m_bOptimizeCacheOps) { |
|
streamInfo->cache_ops = CAM_STREAM_CACHE_OPS_DISABLED; |
|
} else { |
|
streamInfo->cache_ops = CAM_STREAM_CACHE_OPS_HONOUR_FLAGS; |
|
} |
|
|
|
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: { |
|
char value[PROPERTY_VALUE_MAX]; |
|
bool raw_yuv = false; |
|
property_get("persist.camera.raw_yuv", value, "0"); |
|
raw_yuv = atoi(value) > 0 ? true : false; |
|
if ((mParameters.isZSLMode()) || (isRdiMode()) || (raw_yuv) || isSecureMode()) { |
|
streamInfo->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS; |
|
} else { |
|
streamInfo->streaming_mode = CAM_STREAMING_MODE_BURST; |
|
streamInfo->num_of_burst = mParameters.getNumOfSnapshots(); |
|
} |
|
if (isSecureMode()) { |
|
streamInfo->is_secure = SECURE; |
|
} else { |
|
streamInfo->is_secure = NON_SECURE; |
|
} |
|
} |
|
if (CAM_FORMAT_META_RAW_10BIT == streamInfo->fmt) { |
|
mParameters.updateDtVc(&dt, &vc); |
|
if (dt) |
|
streamInfo->dt = dt; |
|
streamInfo->vc = vc; |
|
} |
|
|
|
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 = %d", |
|
streamInfo->user_buf_info.frame_buf_cnt, |
|
streamInfo->user_buf_info.frameInterval); |
|
} |
|
if (mParameters.getRecordingHintValue()) { |
|
if(mParameters.isDISEnabled()) { |
|
streamInfo->is_type = mParameters.getVideoISType(); |
|
} else { |
|
streamInfo->is_type = IS_TYPE_NONE; |
|
} |
|
} |
|
if (mParameters.isSecureMode()) { |
|
streamInfo->is_secure = SECURE; |
|
} |
|
break; |
|
case CAM_STREAM_TYPE_PREVIEW: |
|
if (mParameters.getRecordingHintValue()) { |
|
if(mParameters.isDISEnabled()) { |
|
streamInfo->is_type = mParameters.getPreviewISType(); |
|
} else { |
|
streamInfo->is_type = IS_TYPE_NONE; |
|
} |
|
} |
|
if (isSecureMode()) { |
|
streamInfo->is_secure = SECURE; |
|
} else { |
|
streamInfo->is_secure = NON_SECURE; |
|
} |
|
// If SAT enabled, don't add preview stream to Bundled queue |
|
if (isDualCamera()) { |
|
char prop[PROPERTY_VALUE_MAX]; |
|
memset(prop, 0, sizeof(prop)); |
|
bool satEnabledFlag = FALSE; |
|
property_get("persist.camera.sat.enable", prop, "0"); |
|
satEnabledFlag = atoi(prop); |
|
if (satEnabledFlag) { |
|
streamInfo->noFrameExpected = 1; |
|
} |
|
} |
|
break; |
|
case CAM_STREAM_TYPE_ANALYSIS: |
|
streamInfo->noFrameExpected = 1; |
|
break; |
|
case CAM_STREAM_TYPE_METADATA: |
|
streamInfo->cache_ops = CAM_STREAM_CACHE_OPS_CLEAR_FLAGS; |
|
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; |
|
} |
|
streamInfo->aux_str_info = NULL; |
|
|
|
LOGH("type %d, fmt %d, dim %dx%d, num_bufs %d mask = 0x%x is_type %d\n", |
|
stream_type, streamInfo->fmt, streamInfo->dim.width, |
|
streamInfo->dim.height, streamInfo->num_bufs, |
|
streamInfo->pp_config.feature_mask, |
|
streamInfo->is_type); |
|
|
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : allocateStreamInfoBuf |
|
* |
|
* DESCRIPTION: alocate stream info buffer |
|
* |
|
* PARAMETERS : |
|
* @stream_type : type of stream |
|
* @bufCount : stream info buffer count |
|
* @cam_type : Camera type in case of dual camera |
|
* |
|
* RETURN : ptr to a memory obj that holds stream info buffer. |
|
* NULL if failed |
|
*==========================================================================*/ |
|
QCameraHeapMemory *QCamera2HardwareInterface::allocateStreamInfoBuf( |
|
cam_stream_type_t stream_type, uint8_t bufCount, uint32_t cam_type) |
|
{ |
|
int rc = NO_ERROR; |
|
|
|
QCameraHeapMemory *streamInfoBuf = new QCameraHeapMemory(QCAMERA_ION_USE_CACHE); |
|
if (!streamInfoBuf) { |
|
LOGE("allocateStreamInfoBuf: Unable to allocate streamInfo object"); |
|
return NULL; |
|
} |
|
|
|
if (bufCount > MM_CAMERA_MAX_CAM_CNT) { |
|
LOGE("buffer count should be lesser than max camera : %d", bufCount); |
|
return NULL; |
|
} |
|
rc = streamInfoBuf->allocate(bufCount, sizeof(cam_stream_info_t)); |
|
if (rc < 0) { |
|
LOGE("allocateStreamInfoBuf: Failed to allocate stream info memory"); |
|
delete streamInfoBuf; |
|
return NULL; |
|
} |
|
|
|
for (uint8_t i = 0; i < bufCount; i++) { |
|
cam_stream_info_t *streamInfo = (cam_stream_info_t *)streamInfoBuf->getPtr(i); |
|
memset(streamInfo, 0, sizeof(cam_stream_info_t)); |
|
rc = initStreamInfoBuf(stream_type, streamInfo, cam_type); |
|
if (rc < 0) { |
|
LOGE("initStreamInfoBuf failed"); |
|
delete streamInfoBuf; |
|
return NULL; |
|
} |
|
} |
|
|
|
cam_stream_info_t *streamInfo = (cam_stream_info_t *)streamInfoBuf->getPtr(0); |
|
if (bufCount == MM_CAMERA_MAX_CAM_CNT) { |
|
cam_stream_info_t *s_streamInfo = (cam_stream_info_t *)streamInfoBuf->getPtr(1); |
|
streamInfo->aux_str_info = s_streamInfo; |
|
} |
|
|
|
if (streamInfo->aux_str_info != NULL) { |
|
/*Update StreamInfo for Aux camera*/ |
|
streamInfo->aux_str_info->buf_cnt = getBufNumForAux(stream_type); |
|
streamInfo->num_bufs += streamInfo->aux_str_info->buf_cnt; |
|
streamInfo->aux_str_info->num_bufs += streamInfo->aux_str_info->buf_cnt; |
|
} |
|
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, mCallbackCookie, FALSE, QCAMERA_MEM_TYPE_BATCH); |
|
if (video_mem == 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; |
|
} |
|
video_mem->setVideoInfo(usage, fmt); |
|
|
|
/* |
|
* numFDs = BATCH size |
|
* numInts = 5 // OFFSET, SIZE, USAGE, TIMESTAMP, FORMAT |
|
*/ |
|
rc = video_mem->allocateMeta(streamInfo->num_bufs, |
|
mParameters.getBufBatchCount()); |
|
if (rc < 0) { |
|
LOGE("allocateMeta failed"); |
|
delete video_mem; |
|
return NULL; |
|
} |
|
mem = static_cast<QCameraMemory *>(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); |
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_STARTPREVIEW); |
|
int32_t rc = NO_ERROR; |
|
|
|
LOGI("E ZSL = %d Recording Hint = %d", mParameters.isZSLMode(), |
|
mParameters.getRecordingHintValue()); |
|
|
|
m_perfLockMgr.acquirePerfLockIfExpired(PERF_LOCK_START_PREVIEW); |
|
|
|
updateThermalLevel((void *)&mThermalLevel); |
|
|
|
setDisplayFrameSkip(); |
|
|
|
// start preview stream |
|
if (mParameters.isZSLMode() && mParameters.getRecordingHintValue() != true) { |
|
rc = startChannel(QCAMERA_CH_TYPE_ZSL); |
|
} else if (isSecureMode()) { |
|
if (mParameters.getSecureStreamType() == CAM_STREAM_TYPE_RAW) { |
|
rc = startChannel(QCAMERA_CH_TYPE_RAW); |
|
}else { |
|
rc = startChannel(QCAMERA_CH_TYPE_PREVIEW); |
|
} |
|
} else { |
|
rc = startChannel(QCAMERA_CH_TYPE_PREVIEW); |
|
} |
|
|
|
if (isDualCamera()) { |
|
if (rc == NO_ERROR) { |
|
mParameters.setDeferCamera(CAM_DEFER_PROCESS); |
|
} else { |
|
mParameters.setDeferCamera(CAM_DEFER_FLUSH); |
|
} |
|
} |
|
|
|
if (rc != NO_ERROR) { |
|
LOGE("failed to start channels"); |
|
m_perfLockMgr.releasePerfLock(PERF_LOCK_START_PREVIEW); |
|
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_perfLockMgr.releasePerfLock(PERF_LOCK_START_PREVIEW); |
|
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_perfLockMgr.releasePerfLock(PERF_LOCK_START_PREVIEW); |
|
return rc; |
|
} |
|
} |
|
|
|
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_CAMSCOPE_CALL(CAMSCOPE_HAL1_STOPPREVIEW); |
|
LOGI("E"); |
|
mNumPreviewFaces = -1; |
|
mActiveAF = false; |
|
|
|
// Disable power Hint for preview |
|
m_perfLockMgr.releasePerfLock(PERF_LOCK_POWERHINT_PREVIEW); |
|
|
|
m_perfLockMgr.acquirePerfLockIfExpired(PERF_LOCK_STOP_PREVIEW); |
|
|
|
// 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_perfLockMgr.releasePerfLock(PERF_LOCK_STOP_PREVIEW); |
|
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"); |
|
|
|
m_perfLockMgr.acquirePerfLockIfExpired(PERF_LOCK_START_RECORDING); |
|
|
|
//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(); |
|
} |
|
|
|
m_perfLockMgr.releasePerfLock(PERF_LOCK_START_RECORDING); |
|
|
|
if (rc == NO_ERROR) { |
|
// Set power Hint for video encoding |
|
m_perfLockMgr.acquirePerfLock(PERF_LOCK_POWERHINT_ENCODE, 0); |
|
} |
|
|
|
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"); |
|
|
|
// Disable power hint for video encoding |
|
m_perfLockMgr.releasePerfLock(PERF_LOCK_POWERHINT_ENCODE); |
|
|
|
m_perfLockMgr.acquirePerfLockIfExpired(PERF_LOCK_STOP_RECORDING); |
|
|
|
// 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(); |
|
|
|
m_perfLockMgr.releasePerfLock(PERF_LOCK_STOP_RECORDING); |
|
|
|
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; |
|
|
|
/*Disable Quadra CFA mode*/ |
|
LOGH("Disabling Quadra CFA mode"); |
|
mParameters.setQuadraCfaMode(false, true); |
|
|
|
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()) |
|
|| (mFlashConfigured && !mLongshotEnabled) |
|
|| (mLowLightConfigured == true) |
|
|| (mParameters.getManualCaptureMode() >= CAM_MANUAL_CAPTURE_TYPE_2)) { |
|
rc = mParameters.resetFrameCapture(TRUE, mLowLightConfigured); |
|
} 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; |
|
} |
|
/*Enable Quadra CFA mode*/ |
|
LOGH("Enabling Quadra CFA mode"); |
|
mParameters.setQuadraCfaMode(true, true); |
|
|
|
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()) { |
|
bSkipDisplay = false; |
|
rc = configureStillMore(); |
|
} else if ((mParameters.isChromaFlashEnabled()) |
|
|| (mParameters.getLowLightLevel() != CAM_LOW_LIGHT_OFF) |
|
|| (mParameters.getManualCaptureMode() >= CAM_MANUAL_CAPTURE_TYPE_2)) { |
|
rc = mParameters.configFrameCapture(TRUE); |
|
if (mParameters.getLowLightLevel() != CAM_LOW_LIGHT_OFF) { |
|
mLowLightConfigured = true; |
|
} |
|
} else if (mFlashNeeded && !mLongshotEnabled) { |
|
rc = mParameters.configFrameCapture(TRUE); |
|
mFlashConfigured = true; |
|
bSkipDisplay = false; |
|
} else { |
|
LOGH("Advanced Capture feature not enabled!! "); |
|
mAdvancedCaptureConfigured = false; |
|
bSkipDisplay = false; |
|
} |
|
|
|
if (m_postprocessor.isHalPPEnabled()) { |
|
LOGH("HALPP is enabled, check if halpp is needed for current snapshot."); |
|
configureHalPostProcess(); |
|
} |
|
|
|
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 : configureHalPostProcess |
|
* |
|
* DESCRIPTION: config hal postproc (HALPP) for current snapshot. |
|
* |
|
* PARAMETERS : none |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCamera2HardwareInterface::configureHalPostProcess() |
|
{ |
|
LOGD("E"); |
|
int32_t rc = NO_ERROR; |
|
|
|
if (!m_postprocessor.isHalPPEnabled()) { |
|
m_bNeedHalPP = FALSE; |
|
return rc; |
|
} |
|
|
|
/* check if halpp is needed in dual camera mode */ |
|
if (isDualCamera()) { |
|
if (mActiveCameras == MM_CAMERA_DUAL_CAM && mBundledSnapshot == TRUE) { |
|
LOGH("Use HALPP for dual camera bundle snapshot."); |
|
m_bNeedHalPP = TRUE; |
|
} |
|
return rc; |
|
} |
|
|
|
return rc; |
|
LOGD("X"); |
|
} |
|
|
|
|
|
/*=========================================================================== |
|
* 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() |
|
|| (mFlashConfigured && !mLongshotEnabled) |
|
|| (mLowLightConfigured == true) |
|
|| (mParameters.getManualCaptureMode() >= CAM_MANUAL_CAPTURE_TYPE_2)) { |
|
rc = pChannel->stopAdvancedCapture(MM_CAMERA_FRAME_CAPTURE); |
|
mFlashConfigured = false; |
|
mLowLightConfigured = false; |
|
} 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; |
|
} |
|
|
|
m_bNeedHalPP = FALSE; |
|
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) |
|
|| (mLowLightConfigured == true) |
|
|| (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(); |
|
} |
|
|
|
if (mActiveCameras == MM_CAMERA_DUAL_CAM && mBundledSnapshot) { |
|
char prop[PROPERTY_VALUE_MAX]; |
|
memset(prop, 0, sizeof(prop)); |
|
property_get("persist.camera.dualfov.jpegnum", prop, "1"); |
|
int dualfov_snap_num = atoi(prop); |
|
|
|
memset(prop, 0, sizeof(prop)); |
|
property_get("persist.camera.halpp", prop, "0"); |
|
int halpp_enabled = atoi(prop); |
|
if(halpp_enabled == 0) { |
|
dualfov_snap_num = MM_CAMERA_MAX_CAM_CNT; |
|
} |
|
|
|
dualfov_snap_num = (dualfov_snap_num == 0) ? 1 : dualfov_snap_num; |
|
LOGD("dualfov_snap_num:%d", dualfov_snap_num); |
|
numSnapshots /= dualfov_snap_num; |
|
} |
|
|
|
LOGI("snap count = %d zsl = %d advanced = %d, active camera:%d", |
|
numSnapshots, mParameters.isZSLMode(), mAdvancedCaptureConfigured, mActiveCameras); |
|
|
|
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()) { |
|
mParameters.setQuadraCfaMode(false, true); |
|
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 (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; |
|
QCameraChannel *pPreviewChannel = NULL; |
|
QCameraStream *pPreviewStream = NULL; |
|
QCameraStream *pStream = 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; |
|
} |
|
|
|
// Check if all preview buffers are mapped before creating |
|
// a jpeg session as preview stream buffers are queried during the same |
|
pPreviewChannel = m_channels[QCAMERA_CH_TYPE_PREVIEW]; |
|
if (pPreviewChannel != NULL) { |
|
uint32_t numStreams = pPreviewChannel->getNumOfStreams(); |
|
|
|
for (uint8_t i = 0 ; i < numStreams ; i++ ) { |
|
pStream = pPreviewChannel->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); |
|
} |
|
} |
|
|
|
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()) |
|
&& (!mParameters.isHfrMode()) |
|
&& (mParameters.isLinkPreviewForLiveShot())) { |
|
// Do not link preview stream for |
|
// 1)HFR live snapshot,Thumbnail will not be derived from |
|
// preview for HFR live snapshot. |
|
// 2)persist.camera.linkpreview is 0 |
|
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); |
|
|
|
//wait for deferred (reprocess and jpeg) threads to finish |
|
waitDeferredWork(mReprocJob); |
|
waitDeferredWork(mJpegJob); |
|
//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: |
|
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: |
|
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); |
|
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); |
|
//Do cache ops before sending for reprocess |
|
imgBuf->cacheOps(0, ION_IOC_CLEAN_INV_CACHES); |
|
|
|
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 isDepth=%d", |
|
focusMode, focus_data.focus_state, focus_data.isDepth); |
|
|
|
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; |
|
} |
|
|
|
if (!bDepthAFCallbacks && focus_data.isDepth && |
|
(focus_data.focus_state == CAM_AF_STATE_PASSIVE_SCAN)) { |
|
LOGD("Skip sending scan state to app, if depth focus"); |
|
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 : processLEDCalibration |
|
* |
|
* DESCRIPTION: process LED calibration result |
|
* |
|
* PARAMETERS : |
|
* @value : Calibaration result |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCamera2HardwareInterface::processLEDCalibration(int32_t value) |
|
{ |
|
int32_t rc = NO_ERROR; |
|
#ifndef VANILLA_HAL |
|
if (mParameters.getDualLedCalibration()) { |
|
LOGH("Dual LED calibration value = %d", value); |
|
int32_t data_len = sizeof(value); |
|
int32_t buffer_len = sizeof(int) //meta type |
|
+ sizeof(int) //data len |
|
+ data_len; //data |
|
camera_memory_t *buffer = mGetMemory(-1, |
|
buffer_len, 1, mCallbackCookie); |
|
if ( NULL == buffer ) { |
|
LOGE("Not enough memory for data"); |
|
return NO_MEMORY; |
|
} |
|
|
|
int *pData = (int *)buffer->data; |
|
if (pData == NULL) { |
|
LOGE("memory data ptr is NULL"); |
|
buffer->release(buffer); |
|
return UNKNOWN_ERROR; |
|
} |
|
|
|
pData[0] = QCAMERA_METADATA_LED_CALIB; |
|
pData[1] = (int)data_len; |
|
pData[2] = value; |
|
|
|
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 = buffer; |
|
cbArg.user_data = buffer; |
|
cbArg.cookie = this; |
|
cbArg.release_cb = releaseCameraMemory; |
|
int32_t rc = m_cbNotifier.notifyCallback(cbArg); |
|
if (rc != NO_ERROR) { |
|
LOGE("fail sending notification"); |
|
buffer->release(buffer); |
|
} |
|
} |
|
#else |
|
(void)value; // unused |
|
#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 : processDualCamFovControl |
|
* |
|
* DESCRIPTION: Based on the result collected from FOV control- |
|
* 1. Switch the master camera if needed |
|
* 2. Toggle the Low Power Mode for slave camera |
|
* |
|
* PARAMETERS : none |
|
* |
|
* RETURN : none |
|
*==========================================================================*/ |
|
void QCamera2HardwareInterface::processDualCamFovControl() |
|
{ |
|
uint32_t activeCameras; |
|
bool bundledSnapshot; |
|
fov_control_result_t fovControlResult; |
|
cam_sync_type_t camMasterSnapshot; |
|
|
|
if (!isDualCamera()) { |
|
return; |
|
} |
|
|
|
fovControlResult = m_pFovControl->getFovControlResult(); |
|
|
|
if (fovControlResult.isValid) { |
|
activeCameras = fovControlResult.activeCameras; |
|
bundledSnapshot = fovControlResult.snapshotPostProcess; |
|
camMasterSnapshot = fovControlResult.camMasterPreview; |
|
|
|
processCameraControl(activeCameras, bundledSnapshot); |
|
switchCameraCb(fovControlResult.camMasterPreview); |
|
} |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : processCameraControl |
|
* |
|
* DESCRIPTION: Suspend and resume camera |
|
* |
|
* PARAMETERS : |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCamera2HardwareInterface::processCameraControl( |
|
uint32_t activeCameras, |
|
bool bundledSnapshot) |
|
{ |
|
int32_t ret = NO_ERROR; |
|
|
|
//Update camera status to internal channel |
|
for (int i = 0; i < QCAMERA_CH_TYPE_MAX; i++) { |
|
if (m_channels[i] != NULL && m_channels[i]->isDualChannel()) { |
|
ret = m_channels[i]->processCameraControl(activeCameras, bundledSnapshot); |
|
if (ret != NO_ERROR) { |
|
LOGE("Channel Switch Failed"); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if ((activeCameras != mActiveCameras) || |
|
((activeCameras == MM_CAMERA_DUAL_CAM) && (bundledSnapshot != mBundledSnapshot))) { |
|
|
|
if (activeCameras != mActiveCameras) { |
|
//Set camera controls to parameter and back-end |
|
ret = mParameters.setCameraControls(activeCameras); |
|
} |
|
|
|
mParameters.setBundledSnapshot(bundledSnapshot); |
|
mParameters.setNumOfSnapshot(); |
|
|
|
LOGH("mActiveCameras = %d to %d, bundledSnapshot = %d to %d", |
|
mActiveCameras, activeCameras, mBundledSnapshot, bundledSnapshot); |
|
mActiveCameras = activeCameras; |
|
mBundledSnapshot = bundledSnapshot; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : switchCameraCb |
|
* |
|
* DESCRIPTION: switch camera's in case of dual camera |
|
* |
|
* PARAMETERS : |
|
* @camMaster : Master camera |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCamera2HardwareInterface::switchCameraCb(uint32_t camMaster) |
|
{ |
|
int32_t ret = NO_ERROR; |
|
|
|
if (mActiveCameras & camMaster) { |
|
for (int i = 0; i < QCAMERA_CH_TYPE_MAX; i++) { |
|
if (m_channels[i] != NULL && m_channels[i]->isDualChannel()) { |
|
ret = m_channels[i]->switchChannelCb(camMaster); |
|
if (ret != NO_ERROR) { |
|
LOGE("Channel Switch Failed"); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (mMasterCamera != camMaster) { |
|
if (ret == NO_ERROR) { |
|
//Trigger Event to modules to update Master info |
|
mParameters.setSwitchCamera(camMaster); |
|
} |
|
} |
|
// Update master camera |
|
mMasterCamera = camMaster; |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
/*=========================================================================== |
|
* 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 : getPaddingInfo |
|
* |
|
* DESCRIPTION: calculate padding per stream |
|
* |
|
* PARAMETERS : |
|
* @streamType : type of stream to be added |
|
* @padding_info : Padding info. Output |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCamera2HardwareInterface::getPaddingInfo(cam_stream_type_t streamType, |
|
cam_padding_info_t *padding_info) |
|
{ |
|
int32_t rc = NO_ERROR; |
|
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()), |
|
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 || streamType == CAM_STREAM_TYPE_POSTVIEW) { |
|
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; |
|
} |
|
} |
|
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; |
|
QCameraHeapMemory *pStreamInfo = NULL; |
|
uint32_t cam_type = MM_CAMERA_TYPE_MAIN; |
|
bool needAuxStream = FALSE; |
|
|
|
if (streamType == CAM_STREAM_TYPE_RAW) { |
|
prepareRawStream(pChannel); |
|
} |
|
|
|
if (isDualCamera()) { |
|
if (!((mParameters.isDCmAsymmetricSnapMode()) && |
|
(streamType == CAM_STREAM_TYPE_SNAPSHOT))) { |
|
cam_type |= MM_CAMERA_TYPE_AUX; |
|
} else { |
|
needAuxStream = TRUE; |
|
} |
|
} |
|
|
|
pStreamInfo = allocateStreamInfoBuf(streamType, |
|
getStreamRefCount(streamType, cam_type), cam_type); |
|
if (pStreamInfo == NULL) { |
|
LOGE("no mem for stream info buf"); |
|
return NO_MEMORY; |
|
} |
|
|
|
bool bDynAllocBuf = false; |
|
if (isZSLMode() && streamType == CAM_STREAM_TYPE_SNAPSHOT) { |
|
bDynAllocBuf = true; |
|
} |
|
|
|
cam_padding_info_t padding_info; |
|
getPaddingInfo(streamType, &padding_info); |
|
|
|
bool deferAllocation = needDeferred(streamType); |
|
LOGD("deferAllocation = %d bDynAllocBuf = %d, stream type = %d", |
|
deferAllocation, bDynAllocBuf, streamType); |
|
rc = pChannel->addStream(*this, |
|
pStreamInfo, NULL, &padding_info, |
|
streamCB, userData, bDynAllocBuf, |
|
deferAllocation, ROTATE_0, cam_type); |
|
|
|
if (rc != NO_ERROR) { |
|
LOGE("add stream type (%d) cam = %d failed, ret = %d", |
|
streamType, cam_type, rc); |
|
return rc; |
|
} |
|
|
|
/*Add stream for Asymmetric dual camera use case*/ |
|
if (needAuxStream) { |
|
cam_type = MM_CAMERA_TYPE_AUX; |
|
pStreamInfo = allocateStreamInfoBuf(streamType, |
|
getStreamRefCount(streamType, cam_type), cam_type); |
|
if (pStreamInfo == NULL) { |
|
LOGE("no mem for stream info buf"); |
|
return NO_MEMORY; |
|
} |
|
rc = pChannel->addStream(*this, |
|
pStreamInfo, NULL, &padding_info, |
|
streamCB, userData, bDynAllocBuf, |
|
deferAllocation, ROTATE_0, cam_type); |
|
if (rc != NO_ERROR) { |
|
LOGE("add stream type (%d) cam = %d failed, ret = %d", |
|
streamType, cam_type, 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; |
|
} |
|
|
|
uint32_t handle = getCamHandleForChannel(QCAMERA_CH_TYPE_PREVIEW); |
|
pChannel = new QCameraChannel(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); |
|
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 (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); |
|
if (needSyncCB(CAM_STREAM_TYPE_PREVIEW) == TRUE) { |
|
pChannel->setStreamSyncCB(CAM_STREAM_TYPE_PREVIEW, |
|
synchronous_stream_cb_routine); |
|
} |
|
} |
|
} |
|
|
|
if (rc != NO_ERROR) { |
|
LOGE("add raw/preview stream failed, ret = %d", rc); |
|
delete pChannel; |
|
return rc; |
|
} |
|
|
|
if (((mParameters.fdModeInVideo()) |
|
|| (mParameters.getDcrf() == true) |
|
|| (mParameters.getRecordingHintValue() != true)) |
|
&& (!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, |
|
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; |
|
} |
|
|
|
uint32_t handle = getCamHandleForChannel(QCAMERA_CH_TYPE_VIDEO); |
|
pChannel = new QCameraVideoChannel(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; |
|
} |
|
|
|
uint32_t handle = getCamHandleForChannel(QCAMERA_CH_TYPE_SNAPSHOT); |
|
pChannel = new QCameraChannel(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; |
|
} |
|
|
|
uint32_t handle = getCamHandleForChannel(QCAMERA_CH_TYPE_RAW); |
|
pChannel = new QCameraChannel(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 if(isSecureMode()) { |
|
rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_RAW, |
|
secure_stream_cb_routine, 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; |
|
} |
|
|
|
uint32_t handle = getCamHandleForChannel(QCAMERA_CH_TYPE_ZSL); |
|
pChannel = new QCameraPicChannel(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()) { |
|
LOGD("EDGE SMOOTH frameskip enabled"); |
|
attr.post_frame_skip += mParameters.isOEMFeatFrameSkipEnabled(); |
|
} |
|
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); |
|
if (needSyncCB(CAM_STREAM_TYPE_PREVIEW) == TRUE) { |
|
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 (!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, |
|
preview_raw_stream_cb_routine, |
|
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; |
|
} |
|
|
|
uint32_t handle = getCamHandleForChannel(QCAMERA_CH_TYPE_CAPTURE); |
|
pChannel = new QCameraPicChannel(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); |
|
delete pChannel; |
|
return rc; |
|
} |
|
|
|
// meta data stream always coexists with snapshot in regular capture case |
|
rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_METADATA, |
|
metadata_stream_cb_routine, this); |
|
if (rc != NO_ERROR) { |
|
LOGE("add metadata stream failed, ret = %d", rc); |
|
delete pChannel; |
|
return rc; |
|
} |
|
|
|
if (mLongshotEnabled) { |
|
rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_PREVIEW, |
|
preview_stream_cb_routine, this); |
|
if (rc != NO_ERROR) { |
|
LOGE("add preview stream failed, ret = %d", rc); |
|
delete pChannel; |
|
return rc; |
|
} |
|
if (needSyncCB(CAM_STREAM_TYPE_PREVIEW) == TRUE) { |
|
pChannel->setStreamSyncCB(CAM_STREAM_TYPE_PREVIEW, |
|
synchronous_stream_cb_routine); |
|
} |
|
//Not adding the postview stream to the capture channel if Quadra CFA is enabled. |
|
} else if (!mParameters.getQuadraCfa()) { |
|
rc = addStreamToChannel(pChannel, CAM_STREAM_TYPE_POSTVIEW, |
|
NULL, this); |
|
if (rc != NO_ERROR) { |
|
LOGE("add postview stream failed, ret = %d", rc); |
|
delete pChannel; |
|
return rc; |
|
} |
|
} |
|
|
|
if (!mParameters.getofflineRAW()) { |
|
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; |
|
} |
|
} |
|
|
|
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); |
|
delete pChannel; |
|
return rc; |
|
} |
|
} |
|
|
|
m_channels[QCAMERA_CH_TYPE_CAPTURE] = pChannel; |
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : addMetaDataChannel |
|
* |
|
* DESCRIPTION: add a meta data channel that contains a metadata stream |
|
* |
|
* PARAMETERS : none |
|
* |
|
* RETURN : int32_t type of status |
|
* NO_ERROR -- success |
|
* none-zero failure code |
|
*==========================================================================*/ |
|
int32_t QCamera2HardwareInterface::addMetaDataChannel() |
|
{ |
|
int32_t rc = NO_ERROR; |
|
QCameraChannel *pChannel = NULL; |
|
|
|
if (m_channels[QCAMERA_CH_TYPE_METADATA] != NULL) { |
|
delete m_channels[QCAMERA_CH_TYPE_METADATA]; |
|
m_channels[QCAMERA_CH_TYPE_METADATA] = NULL; |
|
} |
|
|
|
uint32_t handle = getCamHandleForChannel(QCAMERA_CH_TYPE_METADATA); |
|
pChannel = new QCameraChannel(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; |
|
} |
|
|
|
uint32_t handle = getCamHandleForChannel(QCAMERA_CH_TYPE_CALLBACK); |
|
pChannel = new QCameraChannel(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; |
|
} |
|
|
|
uint32_t handle = getCamHandleForChannel(QCAMERA_CH_TYPE_ANALYSIS); |
|
pChannel = new QCameraChannel(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; |
|
int32_t feature_set = 0; |
|
|
|
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(); |
|
|
|
//Checking what feature mask to enable |
|
if (curIndex == 0) { |
|
if (mParameters.getQuadraCfa()) { |
|
feature_set = 2; |
|
} else { |
|
feature_set = 0; |
|
} |
|
} else if (curIndex == 1) { |
|
if (mParameters.getQuadraCfa()) { |
|
feature_set = 0; |
|
} else { |
|
feature_set = 1; |
|
} |
|
} |
|
|
|
switch(feature_set) { |
|
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) |
|
&& (!mParameters.getQuadraCfa())) { |
|
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; |
|
pp_config.feature_mask &= ~CAM_QCOM_FEATURE_METADATA_BYPASS; |
|
break; |
|
|
|
case 2: |
|
//Setting feature for Quadra CFA |
|
pp_config.feature_mask |= CAM_QCOM_FEATURE_QUADRA_CFA; |
|
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(); |
|
uint32_t pHandle = getCamHandleForChannel(QCAMERA_CH_TYPE_REPROCESSING); |
|
|
|
if (pInputChannel == NULL) { |
|
LOGE("input channel obj is NULL"); |
|
return NULL; |
|
} |
|
|
|
pChannel = new QCameraReprocessChannel(pHandle, 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); |
|
} |
|
|
|
if (isDualCamera() && mBundledSnapshot) { |
|
minStreamBufNum += 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 minStreamBufNum = %d", |
|
snapshot_feature_mask, pp_config.feature_mask, minStreamBufNum); |
|
|
|
bool offlineReproc = needOfflineReprocessing(); |
|
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; |
|
streamInfoBuf->num_bufs = img_config.num_of_bufs; |
|
|
|
rc = pChannel->addStream(*this, |
|
pStreamInfo, NULL, |
|
&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_CAMSCOPE_CALL(CAMSCOPE_HAL1_PREPAREPREVIEW); |
|
int32_t rc = NO_ERROR; |
|
|
|
LOGI("E"); |
|
rc = mParameters.setStreamConfigure(false, false, false); |
|
if (rc != NO_ERROR) { |
|
LOGE("setStreamConfigure failed %d", rc); |
|
return rc; |
|
} |
|
|
|
//Trigger deferred job second camera |
|
if (isDualCamera()) { |
|
mParameters.setDeferCamera(CAM_DEFER_START); |
|
} |
|
|
|
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() && !mParameters.getQuadraCfa()) { |
|
addChannel(QCAMERA_CH_TYPE_RAW); |
|
} |
|
} else if(isSecureMode()) { |
|
if (mParameters.getSecureStreamType() == CAM_STREAM_TYPE_RAW) { |
|
rc = addChannel(QCAMERA_CH_TYPE_RAW); |
|
} else { |
|
rc = addChannel(QCAMERA_CH_TYPE_PREVIEW); |
|
} |
|
} 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); |
|
} |
|
} |
|
|
|
if ((rc != NO_ERROR) && (isDualCamera())) { |
|
mParameters.setDeferCamera(CAM_DEFER_FLUSH); |
|
} |
|
|
|
LOGI("X rc = %d", rc); |
|
return rc; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : unpreparePreview |
|
* |
|
* DESCRIPTION: delete channels for preview |
|
* |
|
* PARAMETERS : none |
|
* |
|
* RETURN : none |
|
*==========================================================================*/ |
|
void QCamera2HardwareInterface::unpreparePreview() |
|
{ |
|
if (isDualCamera()) { |
|
mParameters.setDeferCamera(CAM_DEFER_FLUSH); |
|
} |
|
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 && |
|
(validate_handle(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; |
|
LOGL("FD_DEBUG : Frame[%d] : number_of_faces=%d, display_dim=%d %d", |
|
detect_data->frame_id, detect_data->num_faces_detected, |
|
display_dim.width, display_dim.height); |
|
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); |
|
|
|
LOGL("FD_DEBUG : Frame[%d] : Face[%d] : id=%d, score=%d, " |
|
"CAM[left=%d, top=%d, w=%d, h=%d], " |
|
"APP[left=%d, top=%d, right=%d, bottom=%d] ", |
|
detect_data->frame_id, i, faces[i].id, faces[i].score, |
|
detect_data->faces[i].face_boundary.left, |
|
detect_data->faces[i].face_boundary.top, |
|
detect_data->faces[i].face_boundary.width, |
|
detect_data->faces[i].face_boundary.height, |
|
faces[i].rect[0], faces[i].rect[1], |
|
faces[i].rect[2], faces[i].rect[3]); |
|
|
|
if (faces_data->landmark_valid) { |
|
// Center of left eye |
|
if (faces_data->landmark_data.face_landmarks[i].is_left_eye_valid) { |
|
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); |
|
} else { |
|
faces[i].left_eye[0] = FACE_INVALID_POINT; |
|
faces[i].left_eye[1] = FACE_INVALID_POINT; |
|
} |
|
|
|
// Center of right eye |
|
if (faces_data->landmark_data.face_landmarks[i].is_right_eye_valid) { |
|
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); |
|
} else { |
|
faces[i].right_eye[0] = FACE_INVALID_POINT; |
|
faces[i].right_eye[1] = FACE_INVALID_POINT; |
|
} |
|
|
|
// Center of mouth |
|
if (faces_data->landmark_data.face_landmarks[i].is_mouth_valid) { |
|
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 { |
|
faces[i].mouth[0] = FACE_INVALID_POINT; |
|
faces[i].mouth[1] = FACE_INVALID_POINT; |
|
} |
|
|
|
LOGL("FD_DEBUG LANDMARK : Frame[%d] : Face[%d] : " |
|
"eye : left(%d, %d) right(%d, %d), mouth(%d, %d)", |
|
detect_data->frame_id, i, faces[i].left_eye[0], faces[i].left_eye[1], |
|
faces[i].right_eye[0], faces[i].right_eye[1], |
|
faces[i].mouth[0], faces[i].mouth[1]); |
|
} else { |
|
// return -2000 if invalid |
|
faces[i].left_eye[0] = FACE_INVALID_POINT; |
|
faces[i].left_eye[1] = FACE_INVALID_POINT; |
|
|
|
faces[i].right_eye[0] = FACE_INVALID_POINT; |
|
faces[i].right_eye[1] = FACE_INVALID_POINT; |
|
|
|
faces[i].mouth[0] = FACE_INVALID_POINT; |
|
faces[i].mouth[1] = FACE_INVALID_POINT; |
|
} |
|
|
|
#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; |
|
|
|
LOGL("FD_DEBUG LANDMARK : Frame[%d] : Face[%d] : smile_degree=%d, smile_score=%d", |
|
detect_data->frame_id, i, faces[i].smile_degree, faces[i].smile_score); |
|
} |
|
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; |
|
|
|
LOGL("FD_DEBUG LANDMARK : Frame[%d] : Face[%d] : " |
|
"blink_detected=%d, leye_blink=%d, reye_blink=%d", |
|
detect_data->frame_id, i, faces[i].blink_detected, faces[i].leye_blink, |
|
faces[i].reye_blink); |
|
} |
|
if (faces_data->recog_valid) { |
|
faces[i].face_recognised = faces_data->recog_data.face_rec[i].face_recognised; |
|
|
|
LOGL("FD_DEBUG LANDMARK : Frame[%d] : Face[%d] : face_recognised=%d", |
|
detect_data->frame_id, i, faces[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; |
|
|
|
LOGL("FD_DEBUG LANDMARK : Frame[%d] : Face[%d] : gaze_angle=%d, updown_dir=%d, " |
|
"leftright_dir=%d,, roll_dir=%d, left_right_gaze=%d, top_bottom_gaze=%d", |
|
detect_data->frame_id, i, faces[i].gaze_angle, faces[i].updown_dir, |
|
faces[i].leftright_dir, faces[i].roll_dir, faces[i].left_right_gaze, |
|
faces[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: |
|
switch (stats_data.bayer_stats.data_type) { |
|
case CAM_STATS_CHANNEL_Y: |
|
case CAM_STATS_CHANNEL_R: |
|
*pHistData = stats_data.bayer_stats.r_stats; |
|
break; |
|
case CAM_STATS_CHANNEL_GR: |
|
*pHistData = stats_data.bayer_stats.gr_stats; |
|
break; |
|
case CAM_STATS_CHANNEL_GB: |
|
case CAM_STATS_CHANNEL_ALL: |
|
*pHistData = stats_data.bayer_stats.gb_stats; |
|
break; |
|
case CAM_STATS_CHANNEL_B: |
|
*pHistData = stats_data.bayer_stats.b_stats; |
|
break; |
|
default: |
|
*pHistData = stats_data.bayer_stats.r_stats; |
|
break; |
|
} |
|
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 |
|
* @bRecordingHint : recording hint value |
|
* |
|
* 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, |
|
bool bRecordingHint) |
|
{ |
|
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; |
|
} |
|
if (level >= QCAMERA_THERMAL_NO_ADJUSTMENT && level <= QCAMERA_THERMAL_MAX_ADJUSTMENT) { |
|
if (bRecordingHint) { |
|
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; |
|
LOGH("No FPS mitigation in camcorder mode"); |
|
} |
|
LOGH("Thermal level %d, FPS [%3.2f,%3.2f, %3.2f,%3.2f], frameskip %d", |
|
level, adjustedRange.min_fps, adjustedRange.max_fps, |
|
adjustedRange.video_min_fps, adjustedRange.video_max_fps, skipPattern); |
|
} |
|
|
|
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 |
|
* @bRecordingHint : recording hint value |
|
* |
|
* 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, bool bRecordingHint) |
|
{ |
|
enum msm_vfe_frame_skip_pattern skipPattern; |
|
calcThermalLevel(mThermalLevel, |
|
minFPS, |
|
maxFPS, |
|
minVideoFPS, |
|
maxVideoFPS, |
|
adjustedRange, |
|
skipPattern, |
|
bRecordingHint); |
|
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; |
|
bool value; |
|
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; |
|
} |
|
|
|
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; |
|
} |
|
|
|
value = mParameters.getRecordingHintValue(); |
|
calcThermalLevel(level, minFPS, maxFPS, minVideoFPS, maxVideoFPS, |
|
adjustedRange, skipPattern, value ); |
|
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(); |
|
} |
|
|
|
if (isDualCamera() && |
|
mParameters.isZoomChanged()) { |
|
// If zoom changes, get the updated FOV-control result and if needed send the dual |
|
// camera parameters to backend |
|
processDualCamFovControl(); |
|
} |
|
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 small jpeg size or 4K liveshot case but enable if lowpower mode |
|
if ((mParameters.is4k2kVideoResolution() && mParameters.getRecordingHintValue() |
|
&& !isLowPowerMode()) || mParameters.isSmallJpegSizeEnabled()) { |
|
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()) || mParameters.isSmallJpegSizeEnabled()) { |
|
//Disable reprocess for 4K liveshot case or small jpeg size |
|
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())) || |
|
(isPreviewRestartEnabled())); |
|
} |
|
|
|
/*=========================================================================== |
|
* 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 : getSnapshotHandle |
|
* |
|
* DESCRIPTION: Get the camera handle for snapshot based on the bundlesnapshot |
|
* flag and active camera state |
|
* |
|
* PARAMETERS : None |
|
* |
|
* RETURN : camera handle for snapshot |
|
* |
|
*==========================================================================*/ |
|
uint32_t QCamera2HardwareInterface::getSnapshotHandle() |
|
{ |
|
uint32_t snapshotHandle = 0; |
|
|
|
if ((mActiveCameras == MM_CAMERA_DUAL_CAM) && mBundledSnapshot) { |
|
snapshotHandle = mCameraHandle->camera_handle; |
|
} else { |
|
snapshotHandle = (mMasterCamera == MM_CAMERA_TYPE_MAIN) ? |
|
get_main_camera_handle(mCameraHandle->camera_handle) : |
|
get_aux_camera_handle(mCameraHandle->camera_handle); |
|
} |
|
|
|
return snapshotHandle; |
|
} |
|
|
|
/*=========================================================================== |
|
* 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_CAMSCOPE_CALL(CAMSCOPE_HAL1_PREPARE_HW_FOR_SNAPSHOT); |
|
LOGI("[KPI Perf]: Send PREPARE SANSPHOT event"); |
|
return mCameraHandle->ops->prepare_snapshot(getSnapshotHandle(), |
|
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); |
|
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 = NO_ERROR; |
|
if (pme->isDualCamera()) { |
|
rc = pme->mParameters.allocate(MM_CAMERA_MAX_CAM_CNT); |
|
} else { |
|
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, pme->m_pFovControl); |
|
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) || pme->isDualCamera()){ |
|
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() && !mParameters.getQuadraCfa())) { |
|
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 : needSyncCB |
|
* |
|
* DESCRIPTION: Decide syncronous callback per stream |
|
* |
|
* PARAMETERS : |
|
* @stream_type: stream type |
|
* |
|
* RETURN : true - if background task is needed |
|
* false - if background task is NOT needed |
|
*==========================================================================*/ |
|
bool QCamera2HardwareInterface::needSyncCB(cam_stream_type_t stream_type) |
|
{ |
|
#ifdef TARGET_TS_MAKEUP |
|
int whiteLevel, cleanLevel; |
|
if(mParameters.getTsMakeupInfo(whiteLevel, cleanLevel) == TRUE) { |
|
return FALSE; |
|
} |
|
#endif |
|
|
|
char value[PROPERTY_VALUE_MAX]; |
|
property_get("persist.camera.preview.sync_cb", value, "1"); |
|
if ((atoi(value) == 1) && (stream_type == CAM_STREAM_TYPE_PREVIEW)) { |
|
return TRUE; |
|
} |
|
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()|| mParameters.getQuadraCfa())) { |
|
ret = true; |
|
} |
|
return ret; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : needOfflineReprocessing |
|
* |
|
* DESCRIPTION: Check for offline reprocessing |
|
* |
|
* PARAMETERS : |
|
* |
|
* RETURN : true - regular capture |
|
* false - other type of capture |
|
*==========================================================================*/ |
|
bool QCamera2HardwareInterface::needOfflineReprocessing() |
|
{ |
|
bool ret = false; |
|
if (isRegularCapture() |
|
|| isDualCamera()) { |
|
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, "0"); |
|
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; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : getBootToMonoTimeOffset |
|
* |
|
* DESCRIPTION: Calculate offset that is used to convert from |
|
* clock domain of boot to monotonic |
|
* |
|
* PARAMETERS : |
|
* None |
|
* |
|
* RETURN : clock offset between boottime and monotonic time. |
|
* |
|
*==========================================================================*/ |
|
nsecs_t QCamera2HardwareInterface::getBootToMonoTimeOffset() |
|
{ |
|
// try three times to get the clock offset, choose the one |
|
// with the minimum gap in measurements. |
|
const int tries = 3; |
|
nsecs_t bestGap, measured; |
|
for (int i = 0; i < tries; ++i) { |
|
const nsecs_t tmono = systemTime(SYSTEM_TIME_MONOTONIC); |
|
const nsecs_t tbase = systemTime(SYSTEM_TIME_BOOTTIME); |
|
const nsecs_t tmono2 = systemTime(SYSTEM_TIME_MONOTONIC); |
|
const nsecs_t gap = tmono2 - tmono; |
|
if (i == 0 || gap < bestGap) { |
|
bestGap = gap; |
|
measured = tbase - ((tmono + tmono2) >> 1); |
|
} |
|
} |
|
return measured; |
|
} |
|
|
|
/*=========================================================================== |
|
* FUNCTION : fillDualCameraFOVControl |
|
* |
|
* DESCRIPTION: Function to process FOV ctrl event from statemachine thread. |
|
* |
|
* PARAMETERS : none |
|
* |
|
* RETURN : none |
|
*==========================================================================*/ |
|
void QCamera2HardwareInterface::fillDualCameraFOVControl() |
|
{ |
|
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_DUAL_CAMERA_FOV_CONTROL; |
|
int32_t rc = processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload); |
|
if (rc != NO_ERROR) { |
|
LOGE("processEvt Dual camera fill FOV control failed"); |
|
free(payload); |
|
payload = NULL; |
|
} |
|
} else { |
|
LOGE("No memory for Dual camera fill FOV control event"); |
|
} |
|
} |
|
|
|
}; // namespace qcamera
|
|
|