android_device_lenovo_karate/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp
Sampath Vangaveti dc89a99bdd QCamera2: HAL/HAL3: Convert Boottime from ISP to MONOTONIC
Issue:
Diplay freeze observed sometimes, if there is any
suspend/resume of the device.
The issue found to be with differences in the timesources
used by display and camera for timestamp calculation.

Fix:
Measure the clock offset between BOOTTIME and MONOTONIC.
The clock domain source for ISP is BOOTTIME and
for display, it is MONOTONIC.
The offset is used to convert from clock domain of
camera to display.
Added following set prop to switch between camera time sources.

	persist.camera.time.monotonic <value>
Default value is 1.
value 0 indicates Boot time from camera.
value 1 indicates Monotonic time from camera.

Change-Id: I733aa17e89ccaa7f5ea6d2eae5e1cd6428c81a85
CRs-Fixed: 1005906
2018-07-15 06:58:15 +02:00

3426 lines
131 KiB
C++

/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#define LOG_TAG "QCamera2HWI"
// System dependencies
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#define STAT_H <SYSTEM_HEADER_PREFIX/stat.h>
#include STAT_H
#include <utils/Errors.h>
// Camera dependencies
#include "QCamera2HWI.h"
#include "QCameraTrace.h"
extern "C" {
#include "mm_camera_dbg.h"
}
namespace qcamera {
/*===========================================================================
* FUNCTION : zsl_channel_cb
*
* DESCRIPTION: helper function to handle ZSL superbuf callback directly from
* mm-camera-interface
*
* PARAMETERS :
* @recvd_frame : received super buffer
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : recvd_frame will be released after this call by caller, so if
* async operation needed for recvd_frame, it's our responsibility
* to save a copy for this variable to be used later.
*==========================================================================*/
void QCamera2HardwareInterface::zsl_channel_cb(mm_camera_super_buf_t *recvd_frame,
void *userdata)
{
ATRACE_CALL();
LOGH("[KPI Perf]: E");
char value[PROPERTY_VALUE_MAX];
bool dump_raw = false;
bool log_matching = false;
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != recvd_frame->camera_handle){
LOGE("camera obj not valid");
return;
}
QCameraChannel *pChannel = pme->m_channels[QCAMERA_CH_TYPE_ZSL];
if (pChannel == NULL ||
pChannel->getMyHandle() != recvd_frame->ch_id) {
LOGE("ZSL channel doesn't exist, return here");
return;
}
if(pme->mParameters.isSceneSelectionEnabled() &&
!pme->m_stateMachine.isCaptureRunning()) {
pme->selectScene(pChannel, recvd_frame);
pChannel->bufDone(recvd_frame);
return;
}
LOGD("Frame CB Unlock : %d, is AEC Locked: %d",
recvd_frame->bUnlockAEC, pme->m_bLedAfAecLock);
if(recvd_frame->bUnlockAEC && pme->m_bLedAfAecLock) {
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_RETRO_AEC_UNLOCK;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGE("processEvt for retro AEC unlock failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for retro AEC event");
}
}
// Check if retro-active frames are completed and camera is
// ready to go ahead with LED estimation for regular frames
if (recvd_frame->bReadyForPrepareSnapshot) {
// Send an event
LOGD("Ready for Prepare Snapshot, signal ");
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_READY_FOR_SNAPSHOT;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("processEvt Ready for Snaphot failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for prepare signal event detect"
" qcamera_sm_internal_evt_payload_t");
}
}
/* indicate the parent that capture is done */
pme->captureDone();
// save a copy for the superbuf
mm_camera_super_buf_t* frame =
(mm_camera_super_buf_t *)malloc(sizeof(mm_camera_super_buf_t));
if (frame == NULL) {
LOGE("Error allocating memory to save received_frame structure.");
pChannel->bufDone(recvd_frame);
return;
}
*frame = *recvd_frame;
if (recvd_frame->num_bufs > 0) {
LOGI("[KPI Perf]: superbuf frame_idx %d",
recvd_frame->bufs[0]->frame_idx);
}
// DUMP RAW if available
property_get("persist.camera.zsl_raw", value, "0");
dump_raw = atoi(value) > 0 ? true : false;
if (dump_raw) {
for (uint32_t i = 0; i < recvd_frame->num_bufs; i++) {
if (recvd_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_RAW) {
mm_camera_buf_def_t * raw_frame = recvd_frame->bufs[i];
QCameraStream *pStream = pChannel->getStreamByHandle(raw_frame->stream_id);
if (NULL != pStream) {
pme->dumpFrameToFile(pStream, raw_frame, QCAMERA_DUMP_FRM_RAW);
}
break;
}
}
}
for (uint32_t i = 0; i < recvd_frame->num_bufs; i++) {
if (recvd_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_SNAPSHOT) {
mm_camera_buf_def_t * yuv_frame = recvd_frame->bufs[i];
QCameraStream *pStream = pChannel->getStreamByHandle(yuv_frame->stream_id);
if (NULL != pStream) {
pme->dumpFrameToFile(pStream, yuv_frame, QCAMERA_DUMP_FRM_INPUT_REPROCESS);
}
break;
}
}
//
// whether need FD Metadata along with Snapshot frame in ZSL mode
if(pme->needFDMetadata(QCAMERA_CH_TYPE_ZSL)){
//Need Face Detection result for snapshot frames
//Get the Meta Data frames
mm_camera_buf_def_t *pMetaFrame = NULL;
for (uint32_t i = 0; i < frame->num_bufs; i++) {
QCameraStream *pStream = pChannel->getStreamByHandle(frame->bufs[i]->stream_id);
if (pStream != NULL) {
if (pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) {
pMetaFrame = frame->bufs[i]; //find the metadata
break;
}
}
}
if(pMetaFrame != NULL){
metadata_buffer_t *pMetaData = (metadata_buffer_t *)pMetaFrame->buffer;
//send the face detection info
cam_faces_data_t faces_data;
pme->fillFacesData(faces_data, pMetaData);
//HARD CODE here before MCT can support
faces_data.detection_data.fd_type = QCAMERA_FD_SNAPSHOT;
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_FACE_DETECT_RESULT;
payload->faces_data = faces_data;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("processEvt face_detection_result failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for face_detection_result qcamera_sm_internal_evt_payload_t");
}
}
}
property_get("persist.camera.dumpmetadata", value, "0");
int32_t enabled = atoi(value);
if (enabled) {
mm_camera_buf_def_t *pMetaFrame = NULL;
QCameraStream *pStream = NULL;
for (uint32_t i = 0; i < frame->num_bufs; i++) {
pStream = pChannel->getStreamByHandle(frame->bufs[i]->stream_id);
if (pStream != NULL) {
if (pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) {
pMetaFrame = frame->bufs[i];
if (pMetaFrame != NULL &&
((metadata_buffer_t *)pMetaFrame->buffer)->is_tuning_params_valid) {
pme->dumpMetadataToFile(pStream, pMetaFrame, (char *) "ZSL_Snapshot");
}
break;
}
}
}
}
property_get("persist.camera.zsl_matching", value, "0");
log_matching = atoi(value) > 0 ? true : false;
if (log_matching) {
LOGH("ZSL super buffer contains:");
QCameraStream *pStream = NULL;
for (uint32_t i = 0; i < frame->num_bufs; i++) {
pStream = pChannel->getStreamByHandle(frame->bufs[i]->stream_id);
if (pStream != NULL ) {
LOGH("Buffer with V4L index %d frame index %d of type %d Timestamp: %ld %ld ",
frame->bufs[i]->buf_idx,
frame->bufs[i]->frame_idx,
pStream->getMyType(),
frame->bufs[i]->ts.tv_sec,
frame->bufs[i]->ts.tv_nsec);
}
}
}
// Wait on Postproc initialization if needed
if (NO_ERROR != pme->waitDeferredWork(pme->mReprocJob)) {
LOGE("Reprocess Deferred work failed");
return;
}
// send to postprocessor
if (NO_ERROR != pme->m_postprocessor.processData(frame)) {
LOGE("Failed to trigger process data");
pChannel->bufDone(recvd_frame);
free(frame);
frame = NULL;
return;
}
LOGH("[KPI Perf]: X");
}
/*===========================================================================
* FUNCTION : selectScene
*
* DESCRIPTION: send a preview callback when a specific selected scene is applied
*
* PARAMETERS :
* @pChannel: Camera channel
* @frame : Bundled super buffer
*
* RETURN : int32_t type of status
* NO_ERROR -- success
* none-zero failure code
*==========================================================================*/
int32_t QCamera2HardwareInterface::selectScene(QCameraChannel *pChannel,
mm_camera_super_buf_t *frame)
{
mm_camera_buf_def_t *pMetaFrame = NULL;
QCameraStream *pStream = NULL;
int32_t rc = NO_ERROR;
if ((NULL == frame) || (NULL == pChannel)) {
LOGE("Invalid scene select input");
return BAD_VALUE;
}
cam_scene_mode_type selectedScene = mParameters.getSelectedScene();
if (CAM_SCENE_MODE_MAX == selectedScene) {
LOGL("No selected scene");
return NO_ERROR;
}
for (uint32_t i = 0; i < frame->num_bufs; i++) {
pStream = pChannel->getStreamByHandle(frame->bufs[i]->stream_id);
if (pStream != NULL) {
if (pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) {
pMetaFrame = frame->bufs[i];
break;
}
}
}
if (NULL == pMetaFrame) {
LOGE("No metadata buffer found in scene select super buffer");
return NO_INIT;
}
metadata_buffer_t *pMetaData = (metadata_buffer_t *)pMetaFrame->buffer;
IF_META_AVAILABLE(cam_scene_mode_type, scene, CAM_INTF_META_CURRENT_SCENE, pMetaData) {
if ((*scene == selectedScene) &&
(mDataCb != NULL) &&
(msgTypeEnabledWithLock(CAMERA_MSG_PREVIEW_FRAME) > 0)) {
mm_camera_buf_def_t *preview_frame = NULL;
for (uint32_t i = 0; i < frame->num_bufs; i++) {
pStream = pChannel->getStreamByHandle(frame->bufs[i]->stream_id);
if (pStream != NULL) {
if (pStream->isTypeOf(CAM_STREAM_TYPE_PREVIEW)) {
preview_frame = frame->bufs[i];
break;
}
}
}
if (preview_frame) {
QCameraGrallocMemory *memory = (QCameraGrallocMemory *)preview_frame->mem_info;
uint32_t idx = preview_frame->buf_idx;
rc = sendPreviewCallback(pStream, memory, idx);
if (NO_ERROR != rc) {
LOGE("Error triggering scene select preview callback");
} else {
mParameters.setSelectedScene(CAM_SCENE_MODE_MAX);
}
} else {
LOGE("No preview buffer found in scene select super buffer");
return NO_INIT;
}
}
} else {
LOGE("No current scene metadata!");
rc = NO_INIT;
}
return rc;
}
/*===========================================================================
* FUNCTION : capture_channel_cb_routine
*
* DESCRIPTION: helper function to handle snapshot superbuf callback directly from
* mm-camera-interface
*
* PARAMETERS :
* @recvd_frame : received super buffer
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : recvd_frame will be released after this call by caller, so if
* async operation needed for recvd_frame, it's our responsibility
* to save a copy for this variable to be used later.
*==========================================================================*/
void QCamera2HardwareInterface::capture_channel_cb_routine(mm_camera_super_buf_t *recvd_frame,
void *userdata)
{
KPI_ATRACE_CALL();
char value[PROPERTY_VALUE_MAX];
LOGH("[KPI Perf]: E PROFILE_YUV_CB_TO_HAL");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != recvd_frame->camera_handle){
LOGE("camera obj not valid");
return;
}
QCameraChannel *pChannel = pme->m_channels[QCAMERA_CH_TYPE_CAPTURE];
if (pChannel == NULL ||
pChannel->getMyHandle() != recvd_frame->ch_id) {
LOGE("Capture channel doesn't exist, return here");
return;
}
// save a copy for the superbuf
mm_camera_super_buf_t* frame =
(mm_camera_super_buf_t *)malloc(sizeof(mm_camera_super_buf_t));
if (frame == NULL) {
LOGE("Error allocating memory to save received_frame structure.");
pChannel->bufDone(recvd_frame);
return;
}
*frame = *recvd_frame;
if (recvd_frame->num_bufs > 0) {
LOGI("[KPI Perf]: superbuf frame_idx %d",
recvd_frame->bufs[0]->frame_idx);
}
for ( uint32_t i= 0 ; i < recvd_frame->num_bufs ; i++ ) {
if ( recvd_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_SNAPSHOT ) {
mm_camera_buf_def_t * yuv_frame = recvd_frame->bufs[i];
QCameraStream *pStream = pChannel->getStreamByHandle(yuv_frame->stream_id);
if ( NULL != pStream ) {
pme->dumpFrameToFile(pStream, yuv_frame, QCAMERA_DUMP_FRM_INPUT_REPROCESS);
}
break;
}
}
property_get("persist.camera.dumpmetadata", value, "0");
int32_t enabled = atoi(value);
if (enabled) {
mm_camera_buf_def_t *pMetaFrame = NULL;
QCameraStream *pStream = NULL;
for (uint32_t i = 0; i < frame->num_bufs; i++) {
pStream = pChannel->getStreamByHandle(frame->bufs[i]->stream_id);
if (pStream != NULL) {
if (pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) {
pMetaFrame = frame->bufs[i]; //find the metadata
if (pMetaFrame != NULL &&
((metadata_buffer_t *)pMetaFrame->buffer)->is_tuning_params_valid) {
pme->dumpMetadataToFile(pStream, pMetaFrame, (char *) "Snapshot");
}
break;
}
}
}
}
// Wait on Postproc initialization if needed
pme->waitDeferredWork(pme->mReprocJob);
// send to postprocessor
if (NO_ERROR != pme->m_postprocessor.processData(frame)) {
LOGE("Failed to trigger process data");
pChannel->bufDone(recvd_frame);
free(frame);
frame = NULL;
return;
}
/* START of test register face image for face authentication */
#ifdef QCOM_TEST_FACE_REGISTER_FACE
static uint8_t bRunFaceReg = 1;
if (bRunFaceReg > 0) {
// find snapshot frame
QCameraStream *main_stream = NULL;
mm_camera_buf_def_t *main_frame = NULL;
for (int i = 0; i < recvd_frame->num_bufs; i++) {
QCameraStream *pStream =
pChannel->getStreamByHandle(recvd_frame->bufs[i]->stream_id);
if (pStream != NULL) {
if (pStream->isTypeOf(CAM_STREAM_TYPE_SNAPSHOT)) {
main_stream = pStream;
main_frame = recvd_frame->bufs[i];
break;
}
}
}
if (main_stream != NULL && main_frame != NULL) {
int32_t faceId = -1;
cam_pp_offline_src_config_t config;
memset(&config, 0, sizeof(cam_pp_offline_src_config_t));
config.num_of_bufs = 1;
main_stream->getFormat(config.input_fmt);
main_stream->getFrameDimension(config.input_dim);
main_stream->getFrameOffset(config.input_buf_planes.plane_info);
LOGH("DEBUG: registerFaceImage E");
int32_t rc = pme->registerFaceImage(main_frame->buffer, &config, faceId);
LOGH("DEBUG: registerFaceImage X, ret=%d, faceId=%d", rc, faceId);
bRunFaceReg = 0;
}
}
#endif
/* END of test register face image for face authentication */
LOGH("[KPI Perf]: X");
}
#ifdef TARGET_TS_MAKEUP
bool QCamera2HardwareInterface::TsMakeupProcess_Preview(mm_camera_buf_def_t *pFrame,
QCameraStream * pStream) {
LOGD("begin");
bool bRet = false;
if (pStream == NULL || pFrame == NULL) {
bRet = false;
LOGH("pStream == NULL || pFrame == NULL");
} else {
bRet = TsMakeupProcess(pFrame, pStream, mFaceRect);
}
LOGD("end bRet = %d ",bRet);
return bRet;
}
bool QCamera2HardwareInterface::TsMakeupProcess_Snapshot(mm_camera_buf_def_t *pFrame,
QCameraStream * pStream) {
LOGD("begin");
bool bRet = false;
if (pStream == NULL || pFrame == NULL) {
bRet = false;
LOGH("pStream == NULL || pFrame == NULL");
} else {
cam_frame_len_offset_t offset;
memset(&offset, 0, sizeof(cam_frame_len_offset_t));
pStream->getFrameOffset(offset);
cam_dimension_t dim;
pStream->getFrameDimension(dim);
unsigned char *yBuf = (unsigned char*)pFrame->buffer;
unsigned char *uvBuf = yBuf + offset.mp[0].len;
TSMakeupDataEx inMakeupData;
inMakeupData.frameWidth = dim.width;
inMakeupData.frameHeight = dim.height;
inMakeupData.yBuf = yBuf;
inMakeupData.uvBuf = uvBuf;
inMakeupData.yStride = offset.mp[0].stride;
inMakeupData.uvStride = offset.mp[1].stride;
LOGD("detect begin");
TSHandle fd_handle = ts_detectface_create_context();
if (fd_handle != NULL) {
cam_format_t fmt;
pStream->getFormat(fmt);
int iret = ts_detectface_detectEx(fd_handle, &inMakeupData);
LOGD("ts_detectface_detect iret = %d",iret);
if (iret <= 0) {
bRet = false;
} else {
TSRect faceRect;
memset(&faceRect,-1,sizeof(TSRect));
iret = ts_detectface_get_face_info(fd_handle, 0, &faceRect, NULL,NULL,NULL);
LOGD("ts_detectface_get_face_info iret=%d,faceRect.left=%ld,"
"faceRect.top=%ld,faceRect.right=%ld,faceRect.bottom=%ld"
,iret,faceRect.left,faceRect.top,faceRect.right,faceRect.bottom);
bRet = TsMakeupProcess(pFrame,pStream,faceRect);
}
ts_detectface_destroy_context(&fd_handle);
fd_handle = NULL;
} else {
LOGH("fd_handle == NULL");
}
LOGD("detect end");
}
LOGD("end bRet = %d ",bRet);
return bRet;
}
bool QCamera2HardwareInterface::TsMakeupProcess(mm_camera_buf_def_t *pFrame,
QCameraStream * pStream,TSRect& faceRect) {
bool bRet = false;
LOGD("begin");
if (pStream == NULL || pFrame == NULL) {
LOGH("pStream == NULL || pFrame == NULL ");
return false;
}
int whiteLevel, cleanLevel;
bool enableMakeup = (faceRect.left > -1) &&
(mParameters.getTsMakeupInfo(whiteLevel, cleanLevel));
if (enableMakeup) {
cam_dimension_t dim;
cam_frame_len_offset_t offset;
pStream->getFrameDimension(dim);
pStream->getFrameOffset(offset);
unsigned char *tempOriBuf = NULL;
tempOriBuf = (unsigned char*)pFrame->buffer;
unsigned char *yBuf = tempOriBuf;
unsigned char *uvBuf = tempOriBuf + offset.mp[0].len;
unsigned char *tmpBuf = new unsigned char[offset.frame_len];
if (tmpBuf == NULL) {
LOGH("tmpBuf == NULL ");
return false;
}
TSMakeupDataEx inMakeupData, outMakeupData;
whiteLevel = whiteLevel <= 0 ? 0 : (whiteLevel >= 100 ? 100 : whiteLevel);
cleanLevel = cleanLevel <= 0 ? 0 : (cleanLevel >= 100 ? 100 : cleanLevel);
inMakeupData.frameWidth = dim.width; // NV21 Frame width > 0
inMakeupData.frameHeight = dim.height; // NV21 Frame height > 0
inMakeupData.yBuf = yBuf; // Y buffer pointer
inMakeupData.uvBuf = uvBuf; // VU buffer pointer
inMakeupData.yStride = offset.mp[0].stride;
inMakeupData.uvStride = offset.mp[1].stride;
outMakeupData.frameWidth = dim.width; // NV21 Frame width > 0
outMakeupData.frameHeight = dim.height; // NV21 Frame height > 0
outMakeupData.yBuf = tmpBuf; // Y buffer pointer
outMakeupData.uvBuf = tmpBuf + offset.mp[0].len; // VU buffer pointer
outMakeupData.yStride = offset.mp[0].stride;
outMakeupData.uvStride = offset.mp[1].stride;
LOGD("faceRect:left 2:%ld,,right:%ld,,top:%ld,,bottom:%ld,,Level:%dx%d",
faceRect.left,faceRect.right,faceRect.top,faceRect.bottom,cleanLevel,whiteLevel);
ts_makeup_skin_beautyEx(&inMakeupData, &outMakeupData, &(faceRect),cleanLevel,whiteLevel);
memcpy((unsigned char*)pFrame->buffer, tmpBuf, offset.frame_len);
QCameraMemory *memory = (QCameraMemory *)pFrame->mem_info;
memory->cleanCache(pFrame->buf_idx);
if (tmpBuf != NULL) {
delete[] tmpBuf;
tmpBuf = NULL;
}
}
LOGD("end bRet = %d ",bRet);
return bRet;
}
#endif
/*===========================================================================
* FUNCTION : postproc_channel_cb_routine
*
* DESCRIPTION: helper function to handle postprocess superbuf callback directly from
* mm-camera-interface
*
* PARAMETERS :
* @recvd_frame : received super buffer
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : recvd_frame will be released after this call by caller, so if
* async operation needed for recvd_frame, it's our responsibility
* to save a copy for this variable to be used later.
*==========================================================================*/
void QCamera2HardwareInterface::postproc_channel_cb_routine(mm_camera_super_buf_t *recvd_frame,
void *userdata)
{
ATRACE_CALL();
LOGH("[KPI Perf]: E");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != recvd_frame->camera_handle){
LOGE("camera obj not valid");
return;
}
// save a copy for the superbuf
mm_camera_super_buf_t* frame =
(mm_camera_super_buf_t *)malloc(sizeof(mm_camera_super_buf_t));
if (frame == NULL) {
LOGE("Error allocating memory to save received_frame structure.");
return;
}
*frame = *recvd_frame;
if (recvd_frame->num_bufs > 0) {
LOGI("[KPI Perf]: frame_idx %d", recvd_frame->bufs[0]->frame_idx);
}
// Wait on JPEG create session
pme->waitDeferredWork(pme->mJpegJob);
// send to postprocessor
pme->m_postprocessor.processPPData(frame);
ATRACE_INT("Camera:Reprocess", 0);
LOGH("[KPI Perf]: X");
}
/*===========================================================================
* FUNCTION : synchronous_stream_cb_routine
*
* DESCRIPTION: Function to handle STREAM SYNC CALLBACKS
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : This Function is excecuted in mm-interface context.
* Avoid adding latency on this thread.
*==========================================================================*/
void QCamera2HardwareInterface::synchronous_stream_cb_routine(
mm_camera_super_buf_t *super_frame, QCameraStream * stream,
void *userdata)
{
nsecs_t frameTime = 0, mPreviewTimestamp = 0;
int err = NO_ERROR;
ATRACE_CALL();
LOGH("[KPI Perf] : BEGIN");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
QCameraGrallocMemory *memory = NULL;
if (pme == NULL) {
LOGE("Invalid hardware object");
return;
}
if (super_frame == NULL) {
LOGE("Invalid super buffer");
return;
}
mm_camera_buf_def_t *frame = super_frame->bufs[0];
if (NULL == frame) {
LOGE("Frame is NULL");
return;
}
if (stream->getMyType() != CAM_STREAM_TYPE_PREVIEW) {
LOGE("This is only for PREVIEW stream for now");
return;
}
if(pme->m_bPreviewStarted) {
LOGI("[KPI Perf] : PROFILE_FIRST_PREVIEW_FRAME");
pme->m_bPreviewStarted = false;
}
if (!pme->needProcessPreviewFrame()) {
pthread_mutex_lock(&pme->mGrallocLock);
// Increment the counter here to make sure,
// these many frames will be skipped in preview channel cb as well
pme->mIgnoredPreviewCount++;
pthread_mutex_unlock(&pme->mGrallocLock);
LOGH("preview is not running, no need to process");
return;
}
frameTime = nsecs_t(frame->ts.tv_sec) * 1000000000LL + frame->ts.tv_nsec;
// Convert Boottime from camera to Monotime for display if needed.
// Otherwise, mBootToMonoTimestampOffset value will be 0.
frameTime = frameTime - pme->mBootToMonoTimestampOffset;
// Calculate the future presentation time stamp for displaying frames at regular interval
//mPreviewTimestamp = pme->mCameraDisplay.computePresentationTimeStamp(frameTime);
stream->mStreamTimestamp = frameTime;
memory = (QCameraGrallocMemory *)super_frame->bufs[0]->mem_info;
#ifdef TARGET_TS_MAKEUP
pme->TsMakeupProcess_Preview(frame,stream);
#endif
// Enqueue buffer to gralloc.
uint32_t idx = frame->buf_idx;
LOGD("%p Enqueue Buffer to display %d frame Time = %lld Display Time = %lld",
pme, idx, frameTime, mPreviewTimestamp);
err = memory->enqueueBuffer(idx, mPreviewTimestamp);
if (err == NO_ERROR) {
pthread_mutex_lock(&pme->mGrallocLock);
pme->mEnqueuedBuffers++;
pthread_mutex_unlock(&pme->mGrallocLock);
} else {
LOGE("Enqueue Buffer failed");
}
LOGH("[KPI Perf] : END");
return;
}
/*===========================================================================
* FUNCTION : preview_stream_cb_routine
*
* DESCRIPTION: helper function to handle preview frame from preview stream in
* normal case with display.
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : caller passes the ownership of super_frame, it's our
* responsibility to free super_frame once it's done. The new
* preview frame will be sent to display, and an older frame
* will be dequeued from display and needs to be returned back
* to kernel for future use.
*==========================================================================*/
void QCamera2HardwareInterface::preview_stream_cb_routine(mm_camera_super_buf_t *super_frame,
QCameraStream * stream,
void *userdata)
{
KPI_ATRACE_CALL();
LOGH("[KPI Perf] : BEGIN");
int err = NO_ERROR;
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
QCameraGrallocMemory *memory = (QCameraGrallocMemory *)super_frame->bufs[0]->mem_info;
uint8_t dequeueCnt = 0;
if (pme == NULL) {
LOGE("Invalid hardware object");
free(super_frame);
return;
}
if (memory == NULL) {
LOGE("Invalid memory object");
free(super_frame);
return;
}
mm_camera_buf_def_t *frame = super_frame->bufs[0];
if (NULL == frame) {
LOGE("preview frame is NLUL");
free(super_frame);
return;
}
pthread_mutex_lock(&pme->mGrallocLock);
if (!pme->needProcessPreviewFrame() ||
pme->mIgnoredPreviewCount > 0) {
if (pme->mIgnoredPreviewCount > 0) {
pme->mIgnoredPreviewCount--;
}
pthread_mutex_unlock(&pme->mGrallocLock);
LOGH("preview is not running, no need to process");
stream->bufDone(frame->buf_idx);
free(super_frame);
return;
} else {
pthread_mutex_unlock(&pme->mGrallocLock);
}
if (pme->needDebugFps()) {
pme->debugShowPreviewFPS();
}
uint32_t idx = frame->buf_idx;
pme->dumpFrameToFile(stream, frame, QCAMERA_DUMP_FRM_PREVIEW);
if(pme->m_bPreviewStarted) {
LOGI("[KPI Perf] : PROFILE_FIRST_PREVIEW_FRAME");
pme->m_bPreviewStarted = false ;
}
if (!stream->isSyncCBEnabled()) {
LOGD("Enqueue Buffer to display %d", idx);
#ifdef TARGET_TS_MAKEUP
pme->TsMakeupProcess_Preview(frame,stream);
#endif
err = memory->enqueueBuffer(idx);
if (err == NO_ERROR) {
pthread_mutex_lock(&pme->mGrallocLock);
pme->mEnqueuedBuffers++;
dequeueCnt = pme->mEnqueuedBuffers;
pthread_mutex_unlock(&pme->mGrallocLock);
} else {
LOGE("Enqueue Buffer failed");
}
} else {
pthread_mutex_lock(&pme->mGrallocLock);
dequeueCnt = pme->mEnqueuedBuffers;
pthread_mutex_unlock(&pme->mGrallocLock);
}
// Display the buffer.
LOGD("%p displayBuffer %d E", pme, idx);
uint8_t numMapped = memory->getMappable();
for (uint8_t i = 0; i < dequeueCnt; i++) {
int dequeuedIdx = memory->dequeueBuffer();
if (dequeuedIdx < 0 || dequeuedIdx >= memory->getCnt()) {
LOGE("Invalid dequeued buffer index %d from display",
dequeuedIdx);
break;
} else {
pthread_mutex_lock(&pme->mGrallocLock);
pme->mEnqueuedBuffers--;
pthread_mutex_unlock(&pme->mGrallocLock);
if (dequeuedIdx >= numMapped) {
// This buffer has not yet been mapped to the backend
err = stream->mapNewBuffer((uint32_t)dequeuedIdx);
if (memory->checkIfAllBuffersMapped()) {
// check if mapping is done for all the buffers
// Signal the condition for create jpeg session
Mutex::Autolock l(pme->mMapLock);
pme->mMapCond.signal();
LOGH("Mapping done for all bufs");
} else {
LOGH("All buffers are not yet mapped");
}
}
}
if (err < 0) {
LOGE("buffer mapping failed %d", err);
} else {
// Return dequeued buffer back to driver
err = stream->bufDone((uint32_t)dequeuedIdx);
if ( err < 0) {
LOGW("stream bufDone failed %d", err);
}
}
}
// Handle preview data callback
if (pme->m_channels[QCAMERA_CH_TYPE_CALLBACK] == NULL) {
if (pme->needSendPreviewCallback() &&
(!pme->mParameters.isSceneSelectionEnabled())) {
int32_t rc = pme->sendPreviewCallback(stream, memory, idx);
if (NO_ERROR != rc) {
LOGW("Preview callback was not sent succesfully");
}
}
}
free(super_frame);
LOGH("[KPI Perf] : END");
return;
}
/*===========================================================================
* FUNCTION : sendPreviewCallback
*
* DESCRIPTION: helper function for triggering preview callbacks
*
* PARAMETERS :
* @stream : stream object
* @memory : Stream memory allocator
* @idx : buffer index
*
* RETURN : int32_t type of status
* NO_ERROR -- success
* none-zero failure code
*==========================================================================*/
int32_t QCamera2HardwareInterface::sendPreviewCallback(QCameraStream *stream,
QCameraMemory *memory, uint32_t idx)
{
camera_memory_t *previewMem = NULL;
camera_memory_t *data = NULL;
camera_memory_t *dataToApp = NULL;
size_t previewBufSize = 0;
size_t previewBufSizeFromCallback = 0;
cam_dimension_t preview_dim;
cam_format_t previewFmt;
int32_t rc = NO_ERROR;
int32_t yStride = 0;
int32_t yScanline = 0;
int32_t uvStride = 0;
int32_t uvScanline = 0;
int32_t uStride = 0;
int32_t uScanline = 0;
int32_t vStride = 0;
int32_t vScanline = 0;
int32_t yStrideToApp = 0;
int32_t uvStrideToApp = 0;
int32_t yScanlineToApp = 0;
int32_t uvScanlineToApp = 0;
int32_t srcOffset = 0;
int32_t dstOffset = 0;
int32_t srcBaseOffset = 0;
int32_t dstBaseOffset = 0;
int i;
if ((NULL == stream) || (NULL == memory)) {
LOGE("Invalid preview callback input");
return BAD_VALUE;
}
cam_stream_info_t *streamInfo =
reinterpret_cast<cam_stream_info_t *>(stream->getStreamInfoBuf()->getPtr(0));
if (NULL == streamInfo) {
LOGE("Invalid streamInfo");
return BAD_VALUE;
}
stream->getFrameDimension(preview_dim);
stream->getFormat(previewFmt);
/* The preview buffer size in the callback should be
* (width*height*bytes_per_pixel). As all preview formats we support,
* use 12 bits per pixel, buffer size = previewWidth * previewHeight * 3/2.
* We need to put a check if some other formats are supported in future. */
if ((previewFmt == CAM_FORMAT_YUV_420_NV21) ||
(previewFmt == CAM_FORMAT_YUV_420_NV12) ||
(previewFmt == CAM_FORMAT_YUV_420_YV12) ||
(previewFmt == CAM_FORMAT_YUV_420_NV12_VENUS) ||
(previewFmt == CAM_FORMAT_YUV_420_NV21_VENUS) ||
(previewFmt == CAM_FORMAT_YUV_420_NV21_ADRENO)) {
if(previewFmt == CAM_FORMAT_YUV_420_YV12) {
yStride = streamInfo->buf_planes.plane_info.mp[0].stride;
yScanline = streamInfo->buf_planes.plane_info.mp[0].scanline;
uStride = streamInfo->buf_planes.plane_info.mp[1].stride;
uScanline = streamInfo->buf_planes.plane_info.mp[1].scanline;
vStride = streamInfo->buf_planes.plane_info.mp[2].stride;
vScanline = streamInfo->buf_planes.plane_info.mp[2].scanline;
previewBufSize = (size_t)
(yStride * yScanline + uStride * uScanline + vStride * vScanline);
previewBufSizeFromCallback = previewBufSize;
} else {
yStride = streamInfo->buf_planes.plane_info.mp[0].stride;
yScanline = streamInfo->buf_planes.plane_info.mp[0].scanline;
uvStride = streamInfo->buf_planes.plane_info.mp[1].stride;
uvScanline = streamInfo->buf_planes.plane_info.mp[1].scanline;
yStrideToApp = preview_dim.width;
yScanlineToApp = preview_dim.height;
uvStrideToApp = yStrideToApp;
uvScanlineToApp = yScanlineToApp / 2;
previewBufSize = (size_t)
((yStrideToApp * yScanlineToApp) + (uvStrideToApp * uvScanlineToApp));
previewBufSizeFromCallback = (size_t)
((yStride * yScanline) + (uvStride * uvScanline));
}
if(previewBufSize == previewBufSizeFromCallback) {
previewMem = mGetMemory(memory->getFd(idx),
previewBufSize, 1, mCallbackCookie);
if (!previewMem || !previewMem->data) {
LOGE("mGetMemory failed.\n");
return NO_MEMORY;
} else {
data = previewMem;
}
} else {
data = memory->getMemory(idx, false);
dataToApp = mGetMemory(-1, previewBufSize, 1, mCallbackCookie);
if (!dataToApp || !dataToApp->data) {
LOGE("mGetMemory failed.\n");
return NO_MEMORY;
}
for (i = 0; i < preview_dim.height; i++) {
srcOffset = i * yStride;
dstOffset = i * yStrideToApp;
memcpy((unsigned char *) dataToApp->data + dstOffset,
(unsigned char *) data->data + srcOffset,
(size_t)yStrideToApp);
}
srcBaseOffset = yStride * yScanline;
dstBaseOffset = yStrideToApp * yScanlineToApp;
for (i = 0; i < preview_dim.height/2; i++) {
srcOffset = i * uvStride + srcBaseOffset;
dstOffset = i * uvStrideToApp + dstBaseOffset;
memcpy((unsigned char *) dataToApp->data + dstOffset,
(unsigned char *) data->data + srcOffset,
(size_t)yStrideToApp);
}
}
} else {
LOGE("Invalid preview format for preview callback");
return BAD_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_PREVIEW_FRAME;
if (previewBufSize != 0 && previewBufSizeFromCallback != 0 &&
previewBufSize == previewBufSizeFromCallback) {
cbArg.data = data;
} else {
cbArg.data = dataToApp;
}
if ( previewMem ) {
cbArg.user_data = previewMem;
cbArg.release_cb = releaseCameraMemory;
} else if (dataToApp) {
cbArg.user_data = dataToApp;
cbArg.release_cb = releaseCameraMemory;
}
cbArg.cookie = this;
rc = m_cbNotifier.notifyCallback(cbArg);
if (rc != NO_ERROR) {
LOGW("fail sending notification");
if (previewMem) {
previewMem->release(previewMem);
} else if (dataToApp) {
dataToApp->release(dataToApp);
}
}
return rc;
}
/*===========================================================================
* FUNCTION : nodisplay_preview_stream_cb_routine
*
* DESCRIPTION: helper function to handle preview frame from preview stream in
* no-display case
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : caller passes the ownership of super_frame, it's our
* responsibility to free super_frame once it's done.
*==========================================================================*/
void QCamera2HardwareInterface::nodisplay_preview_stream_cb_routine(
mm_camera_super_buf_t *super_frame,
QCameraStream *stream,
void * userdata)
{
ATRACE_CALL();
LOGH("[KPI Perf] E");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != super_frame->camera_handle){
LOGE("camera obj not valid");
// simply free super frame
free(super_frame);
return;
}
mm_camera_buf_def_t *frame = super_frame->bufs[0];
if (NULL == frame) {
LOGE("preview frame is NULL");
free(super_frame);
return;
}
if (!pme->needProcessPreviewFrame()) {
LOGH("preview is not running, no need to process");
stream->bufDone(frame->buf_idx);
free(super_frame);
return;
}
if (pme->needDebugFps()) {
pme->debugShowPreviewFPS();
}
QCameraMemory *previewMemObj = (QCameraMemory *)frame->mem_info;
camera_memory_t *preview_mem = NULL;
if (previewMemObj != NULL) {
preview_mem = previewMemObj->getMemory(frame->buf_idx, false);
}
if (NULL != previewMemObj && NULL != preview_mem) {
pme->dumpFrameToFile(stream, frame, QCAMERA_DUMP_FRM_PREVIEW);
if ((pme->needProcessPreviewFrame()) &&
pme->needSendPreviewCallback() &&
(pme->getRelatedCamSyncInfo()->mode != CAM_MODE_SECONDARY)) {
qcamera_callback_argm_t cbArg;
memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
cbArg.cb_type = QCAMERA_DATA_CALLBACK;
cbArg.msg_type = CAMERA_MSG_PREVIEW_FRAME;
cbArg.data = preview_mem;
cbArg.user_data = (void *) &frame->buf_idx;
cbArg.cookie = stream;
cbArg.release_cb = returnStreamBuffer;
int32_t rc = pme->m_cbNotifier.notifyCallback(cbArg);
if (rc != NO_ERROR) {
LOGE ("fail sending data notify");
stream->bufDone(frame->buf_idx);
}
} else {
stream->bufDone(frame->buf_idx);
}
}
free(super_frame);
LOGH("[KPI Perf] X");
}
/*===========================================================================
* FUNCTION : rdi_mode_stream_cb_routine
*
* DESCRIPTION: helper function to handle RDI frame from preview stream in
* rdi mode case
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : caller passes the ownership of super_frame, it's our
* responsibility to free super_frame once it's done.
*==========================================================================*/
void QCamera2HardwareInterface::rdi_mode_stream_cb_routine(
mm_camera_super_buf_t *super_frame,
QCameraStream *stream,
void * userdata)
{
ATRACE_CALL();
LOGH("RDI_DEBUG Enter");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != super_frame->camera_handle){
LOGE("camera obj not valid");
free(super_frame);
return;
}
mm_camera_buf_def_t *frame = super_frame->bufs[0];
if (NULL == frame) {
LOGE("preview frame is NLUL");
goto end;
}
if (!pme->needProcessPreviewFrame()) {
LOGE("preview is not running, no need to process");
stream->bufDone(frame->buf_idx);
goto end;
}
if (pme->needDebugFps()) {
pme->debugShowPreviewFPS();
}
// Non-secure Mode
if (!pme->isSecureMode()) {
QCameraMemory *previewMemObj = (QCameraMemory *)frame->mem_info;
if (NULL == previewMemObj) {
LOGE("previewMemObj is NULL");
stream->bufDone(frame->buf_idx);
goto end;
}
camera_memory_t *preview_mem = previewMemObj->getMemory(frame->buf_idx, false);
if (NULL != preview_mem) {
previewMemObj->cleanCache(frame->buf_idx);
// Dump RAW frame
pme->dumpFrameToFile(stream, frame, QCAMERA_DUMP_FRM_RAW);
// Notify Preview callback frame
if (pme->needProcessPreviewFrame() &&
pme->mDataCb != NULL &&
pme->msgTypeEnabledWithLock(CAMERA_MSG_PREVIEW_FRAME) > 0) {
qcamera_callback_argm_t cbArg;
memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
cbArg.cb_type = QCAMERA_DATA_CALLBACK;
cbArg.msg_type = CAMERA_MSG_PREVIEW_FRAME;
cbArg.data = preview_mem;
cbArg.user_data = (void *) &frame->buf_idx;
cbArg.cookie = stream;
cbArg.release_cb = returnStreamBuffer;
pme->m_cbNotifier.notifyCallback(cbArg);
} else {
LOGE("preview_mem is NULL");
stream->bufDone(frame->buf_idx);
}
}
else {
LOGE("preview_mem is NULL");
stream->bufDone(frame->buf_idx);
}
} else {
// Secure Mode
// We will do QCAMERA_NOTIFY_CALLBACK and share FD in case of secure mode
QCameraMemory *previewMemObj = (QCameraMemory *)frame->mem_info;
if (NULL == previewMemObj) {
LOGE("previewMemObj is NULL");
stream->bufDone(frame->buf_idx);
goto end;
}
int fd = previewMemObj->getFd(frame->buf_idx);
LOGD("Preview frame fd =%d for index = %d ", fd, frame->buf_idx);
if (pme->needProcessPreviewFrame() &&
pme->mDataCb != NULL &&
pme->msgTypeEnabledWithLock(CAMERA_MSG_PREVIEW_FRAME) > 0) {
// Prepare Callback structure
qcamera_callback_argm_t cbArg;
memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
cbArg.cb_type = QCAMERA_NOTIFY_CALLBACK;
cbArg.msg_type = CAMERA_MSG_PREVIEW_FRAME;
#ifndef VANILLA_HAL
cbArg.ext1 = CAMERA_FRAME_DATA_FD;
cbArg.ext2 = fd;
#endif
cbArg.user_data = (void *) &frame->buf_idx;
cbArg.cookie = stream;
cbArg.release_cb = returnStreamBuffer;
pme->m_cbNotifier.notifyCallback(cbArg);
} else {
LOGH("No need to process preview frame, return buffer");
stream->bufDone(frame->buf_idx);
}
}
end:
free(super_frame);
LOGH("RDI_DEBUG Exit");
return;
}
/*===========================================================================
* FUNCTION : postview_stream_cb_routine
*
* DESCRIPTION: helper function to handle post frame from postview stream
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : caller passes the ownership of super_frame, it's our
* responsibility to free super_frame once it's done.
*==========================================================================*/
void QCamera2HardwareInterface::postview_stream_cb_routine(mm_camera_super_buf_t *super_frame,
QCameraStream *stream,
void *userdata)
{
ATRACE_CALL();
int err = NO_ERROR;
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
QCameraGrallocMemory *memory = (QCameraGrallocMemory *)super_frame->bufs[0]->mem_info;
if (pme == NULL) {
LOGE("Invalid hardware object");
free(super_frame);
return;
}
if (memory == NULL) {
LOGE("Invalid memory object");
free(super_frame);
return;
}
LOGH("[KPI Perf] : BEGIN");
mm_camera_buf_def_t *frame = super_frame->bufs[0];
if (NULL == frame) {
LOGE("preview frame is NULL");
free(super_frame);
return;
}
QCameraMemory *memObj = (QCameraMemory *)frame->mem_info;
if (NULL != memObj) {
pme->dumpFrameToFile(stream, frame, QCAMERA_DUMP_FRM_THUMBNAIL);
}
// Return buffer back to driver
err = stream->bufDone(frame->buf_idx);
if ( err < 0) {
LOGE("stream bufDone failed %d", err);
}
free(super_frame);
LOGH("[KPI Perf] : END");
return;
}
/*===========================================================================
* FUNCTION : video_stream_cb_routine
*
* DESCRIPTION: helper function to handle video frame from video stream
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : caller passes the ownership of super_frame, it's our
* responsibility to free super_frame once it's done. video
* frame will be sent to video encoder. Once video encoder is
* done with the video frame, it will call another API
* (release_recording_frame) to return the frame back
*==========================================================================*/
void QCamera2HardwareInterface::video_stream_cb_routine(mm_camera_super_buf_t *super_frame,
QCameraStream *stream,
void *userdata)
{
ATRACE_CALL();
QCameraVideoMemory *videoMemObj = NULL;
camera_memory_t *video_mem = NULL;
nsecs_t timeStamp = 0;
bool triggerTCB = FALSE;
LOGD("[KPI Perf] : BEGIN");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != super_frame->camera_handle){
LOGE("camera obj not valid");
// simply free super frame
free(super_frame);
return;
}
mm_camera_buf_def_t *frame = super_frame->bufs[0];
if (pme->needDebugFps()) {
pme->debugShowVideoFPS();
}
if(pme->m_bRecordStarted) {
LOGI("[KPI Perf] : PROFILE_FIRST_RECORD_FRAME");
pme->m_bRecordStarted = false ;
}
LOGD("Stream(%d), Timestamp: %ld %ld",
frame->stream_id,
frame->ts.tv_sec,
frame->ts.tv_nsec);
if (frame->buf_type == CAM_STREAM_BUF_TYPE_MPLANE) {
if (pme->mParameters.getVideoBatchSize() == 0) {
timeStamp = nsecs_t(frame->ts.tv_sec) * 1000000000LL
+ frame->ts.tv_nsec;
pme->dumpFrameToFile(stream, frame, QCAMERA_DUMP_FRM_VIDEO);
videoMemObj = (QCameraVideoMemory *)frame->mem_info;
video_mem = NULL;
if (NULL != videoMemObj) {
video_mem = videoMemObj->getMemory(frame->buf_idx,
(pme->mStoreMetaDataInFrame > 0)? true : false);
triggerTCB = TRUE;
LOGH("Video frame TimeStamp : %lld batch = 0 index = %d",
timeStamp, frame->buf_idx);
}
} else {
//Handle video batch callback
native_handle_t *nh = NULL;
pme->dumpFrameToFile(stream, frame, QCAMERA_DUMP_FRM_VIDEO);
QCameraVideoMemory *videoMemObj = (QCameraVideoMemory *)frame->mem_info;
if ((stream->mCurMetaMemory == NULL)
|| (stream->mCurBufIndex == -1)) {
//get Free metadata available
for (int i = 0; i < CAMERA_MIN_VIDEO_BATCH_BUFFERS; i++) {
if (stream->mStreamMetaMemory[i].consumerOwned == 0) {
stream->mCurMetaMemory = videoMemObj->getMemory(i,true);
stream->mCurBufIndex = 0;
stream->mCurMetaIndex = i;
stream->mStreamMetaMemory[i].numBuffers = 0;
break;
}
}
}
video_mem = stream->mCurMetaMemory;
nh = videoMemObj->getNativeHandle(stream->mCurMetaIndex);
if (video_mem == NULL || nh == NULL) {
LOGE("No Free metadata. Drop this frame");
stream->mCurBufIndex = -1;
stream->bufDone(frame->buf_idx);
free(super_frame);
return;
}
int index = stream->mCurBufIndex;
int fd_cnt = pme->mParameters.getVideoBatchSize();
nsecs_t frame_ts = nsecs_t(frame->ts.tv_sec) * 1000000000LL
+ frame->ts.tv_nsec;
if (index == 0) {
stream->mFirstTimeStamp = frame_ts;
}
stream->mStreamMetaMemory[stream->mCurMetaIndex].buf_index[index]
= (uint8_t)frame->buf_idx;
stream->mStreamMetaMemory[stream->mCurMetaIndex].numBuffers++;
stream->mStreamMetaMemory[stream->mCurMetaIndex].consumerOwned
= TRUE;
/*
* data[0] => FD
* data[mNumFDs + 1] => OFFSET
* data[mNumFDs + 2] => SIZE
* data[mNumFDs + 3] => Usage Flag (Color format/Compression)
* data[mNumFDs + 4] => TIMESTAMP
* data[mNumFDs + 5] => FORMAT
*/
nh->data[index] = videoMemObj->getFd(frame->buf_idx);
nh->data[index + fd_cnt] = 0;
nh->data[index + (fd_cnt * 2)] = (int)videoMemObj->getSize(frame->buf_idx);
nh->data[index + (fd_cnt * 3)] = videoMemObj->getUsage();
nh->data[index + (fd_cnt * 4)] = (int)(frame_ts - stream->mFirstTimeStamp);
nh->data[index + (fd_cnt * 5)] = videoMemObj->getFormat();
stream->mCurBufIndex++;
if (stream->mCurBufIndex == fd_cnt) {
timeStamp = stream->mFirstTimeStamp;
LOGH("Video frame to encoder TimeStamp : %lld batch = %d Buffer idx = %d",
timeStamp, fd_cnt,
nh->data[nh->numFds + nh->numInts - VIDEO_METADATA_NUM_COMMON_INTS]);
stream->mCurBufIndex = -1;
stream->mCurMetaIndex = -1;
stream->mCurMetaMemory = NULL;
triggerTCB = TRUE;
}
}
} else {
videoMemObj = (QCameraVideoMemory *)frame->mem_info;
video_mem = NULL;
native_handle_t *nh = NULL;
int fd_cnt = frame->user_buf.bufs_used;
if (NULL != videoMemObj) {
video_mem = videoMemObj->getMemory(frame->buf_idx, true);
nh = videoMemObj->getNativeHandle(frame->buf_idx);
} else {
LOGE("videoMemObj NULL");
}
if (nh != NULL) {
timeStamp = nsecs_t(frame->ts.tv_sec) * 1000000000LL
+ frame->ts.tv_nsec;
for (int i = 0; i < fd_cnt; i++) {
if (frame->user_buf.buf_idx[i] >= 0) {
mm_camera_buf_def_t *plane_frame =
&frame->user_buf.plane_buf[frame->user_buf.buf_idx[i]];
QCameraVideoMemory *frameobj =
(QCameraVideoMemory *)plane_frame->mem_info;
int usage = frameobj->getUsage();
nsecs_t frame_ts = nsecs_t(plane_frame->ts.tv_sec) * 1000000000LL
+ plane_frame->ts.tv_nsec;
/*
data[0] => FD
data[mNumFDs + 1] => OFFSET
data[mNumFDs + 2] => SIZE
data[mNumFDs + 3] => Usage Flag (Color format/Compression)
data[mNumFDs + 4] => TIMESTAMP
data[mNumFDs + 5] => FORMAT
*/
nh->data[i] = frameobj->getFd(plane_frame->buf_idx);
nh->data[fd_cnt + i] = 0;
nh->data[(2 * fd_cnt) + i] = (int)frameobj->getSize(plane_frame->buf_idx);
nh->data[(3 * fd_cnt) + i] = usage;
nh->data[(4 * fd_cnt) + i] = (int)(frame_ts - timeStamp);
nh->data[(5 * fd_cnt) + i] = frameobj->getFormat();
LOGD("Send Video frames to services/encoder delta : %lld FD = %d index = %d",
(frame_ts - timeStamp), plane_frame->fd, plane_frame->buf_idx);
pme->dumpFrameToFile(stream, plane_frame, QCAMERA_DUMP_FRM_VIDEO);
}
}
triggerTCB = TRUE;
LOGH("Batch buffer TimeStamp : %lld FD = %d index = %d fd_cnt = %d",
timeStamp, frame->fd, frame->buf_idx, fd_cnt);
} else {
LOGE("No Video Meta Available. Return Buffer");
stream->bufDone(super_frame->bufs[0]->buf_idx);
}
}
if ((NULL != video_mem) && (triggerTCB == TRUE)) {
if ((pme->mDataCbTimestamp != NULL) &&
pme->msgTypeEnabledWithLock(CAMERA_MSG_VIDEO_FRAME) > 0) {
qcamera_callback_argm_t cbArg;
memset(&cbArg, 0, sizeof(qcamera_callback_argm_t));
cbArg.cb_type = QCAMERA_DATA_TIMESTAMP_CALLBACK;
cbArg.msg_type = CAMERA_MSG_VIDEO_FRAME;
cbArg.data = video_mem;
// Convert Boottime from camera to Monotime for video if needed.
// Otherwise, mBootToMonoTimestampOffset value will be 0.
timeStamp = timeStamp - pme->mBootToMonoTimestampOffset;
LOGD("Final video buffer TimeStamp : %lld ", timeStamp);
cbArg.timestamp = timeStamp;
int32_t rc = pme->m_cbNotifier.notifyCallback(cbArg);
if (rc != NO_ERROR) {
LOGE("fail sending data notify");
stream->bufDone(frame->buf_idx);
}
}
}
free(super_frame);
LOGD("[KPI Perf] : END");
}
/*===========================================================================
* FUNCTION : snapshot_channel_cb_routine
*
* DESCRIPTION: helper function to handle snapshot frame from snapshot channel
*
* PARAMETERS :
* @super_frame : received super buffer
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : recvd_frame will be released after this call by caller, so if
* async operation needed for recvd_frame, it's our responsibility
* to save a copy for this variable to be used later.
*==========================================================================*/
void QCamera2HardwareInterface::snapshot_channel_cb_routine(mm_camera_super_buf_t *super_frame,
void *userdata)
{
ATRACE_CALL();
char value[PROPERTY_VALUE_MAX];
QCameraChannel *pChannel = NULL;
LOGH("[KPI Perf]: E");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != super_frame->camera_handle){
LOGE("camera obj not valid");
// simply free super frame
free(super_frame);
return;
}
if (pme->isLowPowerMode()) {
pChannel = pme->m_channels[QCAMERA_CH_TYPE_VIDEO];
} else {
pChannel = pme->m_channels[QCAMERA_CH_TYPE_SNAPSHOT];
}
if ((pChannel == NULL) || (pChannel->getMyHandle() != super_frame->ch_id)) {
LOGE("Snapshot channel doesn't exist, return here");
return;
}
property_get("persist.camera.dumpmetadata", value, "0");
int32_t enabled = atoi(value);
if (enabled) {
if (pChannel == NULL ||
pChannel->getMyHandle() != super_frame->ch_id) {
LOGE("Capture channel doesn't exist, return here");
return;
}
mm_camera_buf_def_t *pMetaFrame = NULL;
QCameraStream *pStream = NULL;
for (uint32_t i = 0; i < super_frame->num_bufs; i++) {
pStream = pChannel->getStreamByHandle(super_frame->bufs[i]->stream_id);
if (pStream != NULL) {
if (pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) {
pMetaFrame = super_frame->bufs[i]; //find the metadata
if (pMetaFrame != NULL &&
((metadata_buffer_t *)pMetaFrame->buffer)->is_tuning_params_valid) {
pme->dumpMetadataToFile(pStream, pMetaFrame, (char *) "Snapshot");
}
break;
}
}
}
}
// save a copy for the superbuf
mm_camera_super_buf_t* frame = (mm_camera_super_buf_t *)malloc(sizeof(mm_camera_super_buf_t));
if (frame == NULL) {
LOGE("Error allocating memory to save received_frame structure.");
pChannel->bufDone(super_frame);
return;
}
*frame = *super_frame;
if (frame->num_bufs > 0) {
LOGI("[KPI Perf]: superbuf frame_idx %d",
frame->bufs[0]->frame_idx);
}
if (NO_ERROR != pme->m_postprocessor.processData(frame)) {
LOGE("Failed to trigger process data");
pChannel->bufDone(super_frame);
free(frame);
frame = NULL;
return;
}
LOGH("[KPI Perf]: X");
}
/*===========================================================================
* FUNCTION : raw_stream_cb_routine
*
* DESCRIPTION: helper function to handle raw dump frame from raw stream
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : caller passes the ownership of super_frame, it's our
* responsibility to free super_frame once it's done. For raw
* frame, there is no need to send to postprocessor for jpeg
* encoding. this function will play shutter and send the data
* callback to upper layer. Raw frame buffer will be returned
* back to kernel, and frame will be free after use.
*==========================================================================*/
void QCamera2HardwareInterface::raw_stream_cb_routine(mm_camera_super_buf_t * super_frame,
QCameraStream * /*stream*/,
void * userdata)
{
ATRACE_CALL();
LOGH("[KPI Perf] : BEGIN");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != super_frame->camera_handle){
LOGE("camera obj not valid");
// simply free super frame
free(super_frame);
return;
}
pme->m_postprocessor.processRawData(super_frame);
LOGH("[KPI Perf] : END");
}
/*===========================================================================
* FUNCTION : raw_channel_cb_routine
*
* DESCRIPTION: helper function to handle RAW superbuf callback directly from
* mm-camera-interface
*
* PARAMETERS :
* @super_frame : received super buffer
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : recvd_frame will be released after this call by caller, so if
* async operation needed for recvd_frame, it's our responsibility
* to save a copy for this variable to be used later.
*==========================================================================*/
void QCamera2HardwareInterface::raw_channel_cb_routine(mm_camera_super_buf_t *super_frame,
void *userdata)
{
ATRACE_CALL();
char value[PROPERTY_VALUE_MAX];
LOGH("[KPI Perf]: E");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != super_frame->camera_handle){
LOGE("camera obj not valid");
// simply free super frame
free(super_frame);
return;
}
QCameraChannel *pChannel = pme->m_channels[QCAMERA_CH_TYPE_RAW];
if (pChannel == NULL) {
LOGE("RAW channel doesn't exist, return here");
return;
}
if (pChannel->getMyHandle() != super_frame->ch_id) {
LOGE("Invalid Input super buffer");
pChannel->bufDone(super_frame);
return;
}
property_get("persist.camera.dumpmetadata", value, "0");
int32_t enabled = atoi(value);
if (enabled) {
mm_camera_buf_def_t *pMetaFrame = NULL;
QCameraStream *pStream = NULL;
for (uint32_t i = 0; i < super_frame->num_bufs; i++) {
pStream = pChannel->getStreamByHandle(super_frame->bufs[i]->stream_id);
if (pStream != NULL) {
if (pStream->isTypeOf(CAM_STREAM_TYPE_METADATA)) {
pMetaFrame = super_frame->bufs[i]; //find the metadata
if (pMetaFrame != NULL &&
((metadata_buffer_t *)pMetaFrame->buffer)->is_tuning_params_valid) {
pme->dumpMetadataToFile(pStream, pMetaFrame, (char *) "raw");
}
break;
}
}
}
}
// save a copy for the superbuf
mm_camera_super_buf_t* frame = (mm_camera_super_buf_t *)malloc(sizeof(mm_camera_super_buf_t));
if (frame == NULL) {
LOGE("Error allocating memory to save received_frame structure.");
pChannel->bufDone(super_frame);
return;
}
*frame = *super_frame;
if (frame->num_bufs > 0) {
LOGI("[KPI Perf]: superbuf frame_idx %d",
frame->bufs[0]->frame_idx);
}
// Wait on Postproc initialization if needed
if (NO_ERROR != pme->waitDeferredWork(pme->mReprocJob)) {
LOGE("Reprocess Deferred work failed");
pChannel->bufDone(super_frame);
free(frame);
frame = NULL;
return;
}
if (NO_ERROR != pme->m_postprocessor.processData(frame)) {
LOGE("Failed to trigger process data");
pChannel->bufDone(super_frame);
free(frame);
frame = NULL;
return;
}
LOGH("[KPI Perf]: X");
}
/*===========================================================================
* FUNCTION : preview_raw_stream_cb_routine
*
* DESCRIPTION: helper function to handle raw frame during standard preview
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : caller passes the ownership of super_frame, it's our
* responsibility to free super_frame once it's done.
*==========================================================================*/
void QCamera2HardwareInterface::preview_raw_stream_cb_routine(mm_camera_super_buf_t * super_frame,
QCameraStream * stream,
void * userdata)
{
ATRACE_CALL();
LOGH("[KPI Perf] : BEGIN");
char value[PROPERTY_VALUE_MAX];
bool dump_preview_raw = false, dump_video_raw = false;
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != super_frame->camera_handle){
LOGE("camera obj not valid");
// simply free super frame
free(super_frame);
return;
}
mm_camera_buf_def_t *raw_frame = super_frame->bufs[0];
if (raw_frame != NULL) {
property_get("persist.camera.preview_raw", value, "0");
dump_preview_raw = atoi(value) > 0 ? true : false;
property_get("persist.camera.video_raw", value, "0");
dump_video_raw = atoi(value) > 0 ? true : false;
if (dump_preview_raw || (pme->mParameters.getRecordingHintValue()
&& dump_video_raw)) {
pme->dumpFrameToFile(stream, raw_frame, QCAMERA_DUMP_FRM_RAW);
}
stream->bufDone(raw_frame->buf_idx);
}
free(super_frame);
LOGH("[KPI Perf] : END");
}
/*===========================================================================
* FUNCTION : snapshot_raw_stream_cb_routine
*
* DESCRIPTION: helper function to handle raw frame during standard capture
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : caller passes the ownership of super_frame, it's our
* responsibility to free super_frame once it's done.
*==========================================================================*/
void QCamera2HardwareInterface::snapshot_raw_stream_cb_routine(mm_camera_super_buf_t * super_frame,
QCameraStream * stream,
void * userdata)
{
ATRACE_CALL();
LOGH("[KPI Perf] : BEGIN");
char value[PROPERTY_VALUE_MAX];
bool dump_raw = false;
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != super_frame->camera_handle){
LOGE("camera obj not valid");
// simply free super frame
free(super_frame);
return;
}
property_get("persist.camera.snapshot_raw", value, "0");
dump_raw = atoi(value) > 0 ? true : false;
for (uint32_t i = 0; i < super_frame->num_bufs; i++) {
if (super_frame->bufs[i]->stream_type == CAM_STREAM_TYPE_RAW) {
mm_camera_buf_def_t * raw_frame = super_frame->bufs[i];
if (NULL != stream) {
if (dump_raw) {
pme->dumpFrameToFile(stream, raw_frame, QCAMERA_DUMP_FRM_RAW);
}
stream->bufDone(super_frame->bufs[i]->buf_idx);
}
break;
}
}
free(super_frame);
LOGH("[KPI Perf] : END");
}
/*===========================================================================
* FUNCTION : updateMetadata
*
* DESCRIPTION: Frame related parameter can be updated here
*
* PARAMETERS :
* @pMetaData : pointer to metadata buffer
*
* RETURN : int32_t type of status
* NO_ERROR -- success
* none-zero failure code
*==========================================================================*/
int32_t QCamera2HardwareInterface::updateMetadata(metadata_buffer_t *pMetaData)
{
int32_t rc = NO_ERROR;
if (pMetaData == NULL) {
LOGE("Null Metadata buffer");
return rc;
}
// Sharpness
cam_edge_application_t edge_application;
memset(&edge_application, 0x00, sizeof(cam_edge_application_t));
edge_application.sharpness = mParameters.getSharpness();
if (edge_application.sharpness != 0) {
edge_application.edge_mode = CAM_EDGE_MODE_FAST;
} else {
edge_application.edge_mode = CAM_EDGE_MODE_OFF;
}
ADD_SET_PARAM_ENTRY_TO_BATCH(pMetaData,
CAM_INTF_META_EDGE_MODE, edge_application);
//Effect
int32_t prmEffect = mParameters.getEffect();
ADD_SET_PARAM_ENTRY_TO_BATCH(pMetaData, CAM_INTF_PARM_EFFECT, prmEffect);
//flip
int32_t prmFlip = mParameters.getFlipMode(CAM_STREAM_TYPE_SNAPSHOT);
ADD_SET_PARAM_ENTRY_TO_BATCH(pMetaData, CAM_INTF_PARM_FLIP, prmFlip);
//denoise
uint8_t prmDenoise = (uint8_t)mParameters.isWNREnabled();
ADD_SET_PARAM_ENTRY_TO_BATCH(pMetaData,
CAM_INTF_META_NOISE_REDUCTION_MODE, prmDenoise);
//rotation & device rotation
uint32_t prmRotation = mParameters.getJpegRotation();
cam_rotation_info_t rotation_info;
if (prmRotation == 0) {
rotation_info.rotation = ROTATE_0;
} else if (prmRotation == 90) {
rotation_info.rotation = ROTATE_90;
} else if (prmRotation == 180) {
rotation_info.rotation = ROTATE_180;
} else if (prmRotation == 270) {
rotation_info.rotation = ROTATE_270;
}
uint32_t device_rotation = mParameters.getDeviceRotation();
if (device_rotation == 0) {
rotation_info.device_rotation = ROTATE_0;
} else if (device_rotation == 90) {
rotation_info.device_rotation = ROTATE_90;
} else if (device_rotation == 180) {
rotation_info.device_rotation = ROTATE_180;
} else if (device_rotation == 270) {
rotation_info.device_rotation = ROTATE_270;
} else {
rotation_info.device_rotation = ROTATE_0;
}
ADD_SET_PARAM_ENTRY_TO_BATCH(pMetaData, CAM_INTF_PARM_ROTATION, rotation_info);
// Imglib Dynamic Scene Data
cam_dyn_img_data_t dyn_img_data = mParameters.getDynamicImgData();
if (mParameters.isStillMoreEnabled()) {
cam_still_more_t stillmore_cap = mParameters.getStillMoreSettings();
dyn_img_data.input_count = stillmore_cap.burst_count;
}
ADD_SET_PARAM_ENTRY_TO_BATCH(pMetaData,
CAM_INTF_META_IMG_DYN_FEAT, dyn_img_data);
//CPP CDS
int32_t prmCDSMode = mParameters.getCDSMode();
ADD_SET_PARAM_ENTRY_TO_BATCH(pMetaData,
CAM_INTF_PARM_CDS_MODE, prmCDSMode);
return rc;
}
/*===========================================================================
* FUNCTION : metadata_stream_cb_routine
*
* DESCRIPTION: helper function to handle metadata frame from metadata stream
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : caller passes the ownership of super_frame, it's our
* responsibility to free super_frame once it's done. Metadata
* could have valid entries for face detection result or
* histogram statistics information.
*==========================================================================*/
void QCamera2HardwareInterface::metadata_stream_cb_routine(mm_camera_super_buf_t * super_frame,
QCameraStream * stream,
void * userdata)
{
ATRACE_CALL();
LOGD("[KPI Perf] : BEGIN");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != super_frame->camera_handle){
LOGE("camera obj not valid");
// simply free super frame
free(super_frame);
return;
}
mm_camera_buf_def_t *frame = super_frame->bufs[0];
metadata_buffer_t *pMetaData = (metadata_buffer_t *)frame->buffer;
if(pme->m_stateMachine.isNonZSLCaptureRunning()&&
!pme->mLongshotEnabled) {
//Make shutter call back in non ZSL mode once raw frame is received from VFE.
pme->playShutter();
}
if (pMetaData->is_tuning_params_valid && pme->mParameters.getRecordingHintValue() == true) {
//Dump Tuning data for video
pme->dumpMetadataToFile(stream,frame,(char *)"Video");
}
IF_META_AVAILABLE(cam_hist_stats_t, stats_data, CAM_INTF_META_HISTOGRAM, pMetaData) {
// process histogram statistics info
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_HISTOGRAM_STATS;
payload->stats_data = *stats_data;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("processEvt histogram failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for histogram qcamera_sm_internal_evt_payload_t");
}
}
IF_META_AVAILABLE(cam_face_detection_data_t, detection_data,
CAM_INTF_META_FACE_DETECTION, pMetaData) {
cam_faces_data_t faces_data;
pme->fillFacesData(faces_data, pMetaData);
faces_data.detection_data.fd_type = QCAMERA_FD_PREVIEW; //HARD CODE here before MCT can support
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_FACE_DETECT_RESULT;
payload->faces_data = faces_data;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("%s: processEvt face detection failed", __func__);
free(payload);
payload = NULL;
}
} else {
LOGE("%s: No memory for face detect qcamera_sm_internal_evt_payload_t", __func__);
}
}
IF_META_AVAILABLE(uint32_t, afState, CAM_INTF_META_AF_STATE, pMetaData) {
uint8_t forceAFUpdate = FALSE;
//1. Earlier HAL used to rely on AF done flags set in metadata to generate callbacks to
//upper layers. But in scenarios where metadata drops especially which contain important
//AF information, APP will wait indefinitely for focus result resulting in capture hang.
//2. HAL can check for AF state transitions to generate AF state callbacks to upper layers.
//This will help overcome metadata drop issue with the earlier approach.
//3. But sometimes AF state transitions can happen so fast within same metadata due to
//which HAL will receive only the final AF state. HAL may perceive this as no change in AF
//state depending on the state transitions happened (for example state A -> B -> A).
//4. To overcome the drawbacks of both the approaches, we go for a hybrid model in which
//we check state transition at both HAL level and AF module level. We rely on
//'state transition' meta field set by AF module for the state transition detected by it.
IF_META_AVAILABLE(uint8_t, stateChange, CAM_INTF_AF_STATE_TRANSITION, pMetaData) {
forceAFUpdate = *stateChange;
}
//This is a special scenario in which when scene modes like landscape are selected, AF mode
//gets changed to INFINITY at backend, but HAL will not be aware of it. Also, AF state in
//such cases will be set to CAM_AF_STATE_INACTIVE by backend. So, detect the AF mode
//change here and trigger AF callback @ processAutoFocusEvent().
IF_META_AVAILABLE(uint32_t, afFocusMode, CAM_INTF_PARM_FOCUS_MODE, pMetaData) {
if (((cam_focus_mode_type)(*afFocusMode) == CAM_FOCUS_MODE_INFINITY) &&
pme->mActiveAF){
forceAFUpdate = TRUE;
}
}
if ((pme->m_currentFocusState != (*afState)) || forceAFUpdate) {
pme->m_currentFocusState = (cam_af_state_t)(*afState);
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_FOCUS_UPDATE;
payload->focus_data.focus_state = (cam_af_state_t)(*afState);
payload->focus_data.focused_frame_idx = frame->frame_idx;
IF_META_AVAILABLE(float, focusDistance,
CAM_INTF_META_LENS_FOCUS_DISTANCE, pMetaData) {
payload->focus_data.focus_dist.
focus_distance[CAM_FOCUS_DISTANCE_OPTIMAL_INDEX] = *focusDistance;
}
IF_META_AVAILABLE(float, focusRange, CAM_INTF_META_LENS_FOCUS_RANGE, pMetaData) {
payload->focus_data.focus_dist.
focus_distance[CAM_FOCUS_DISTANCE_NEAR_INDEX] = focusRange[0];
payload->focus_data.focus_dist.
focus_distance[CAM_FOCUS_DISTANCE_FAR_INDEX] = focusRange[1];
}
IF_META_AVAILABLE(uint32_t, focusMode, CAM_INTF_PARM_FOCUS_MODE, pMetaData) {
payload->focus_data.focus_mode = (cam_focus_mode_type)(*focusMode);
}
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("processEvt focus failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for focus qcamera_sm_internal_evt_payload_t");
}
}
}
IF_META_AVAILABLE(cam_crop_data_t, crop_data, CAM_INTF_META_CROP_DATA, pMetaData) {
if (crop_data->num_of_streams > MAX_NUM_STREAMS) {
LOGE("Invalid num_of_streams %d in crop_data",
crop_data->num_of_streams);
} else {
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_CROP_INFO;
payload->crop_data = *crop_data;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGE("processEvt crop info failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for prep_snapshot qcamera_sm_internal_evt_payload_t");
}
}
}
IF_META_AVAILABLE(int32_t, prep_snapshot_done_state,
CAM_INTF_META_PREP_SNAPSHOT_DONE, pMetaData) {
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_PREP_SNAPSHOT_DONE;
payload->prep_snapshot_state = (cam_prep_snapshot_state_t)*prep_snapshot_done_state;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("processEvt prep_snapshot failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for prep_snapshot qcamera_sm_internal_evt_payload_t");
}
}
IF_META_AVAILABLE(cam_asd_hdr_scene_data_t, hdr_scene_data,
CAM_INTF_META_ASD_HDR_SCENE_DATA, pMetaData) {
LOGH("hdr_scene_data: %d %f\n",
hdr_scene_data->is_hdr_scene, hdr_scene_data->hdr_confidence);
//Handle this HDR meta data only if capture is not in process
if (!pme->m_stateMachine.isCaptureRunning()) {
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_HDR_UPDATE;
payload->hdr_data = *hdr_scene_data;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("processEvt hdr update failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for hdr update qcamera_sm_internal_evt_payload_t");
}
}
}
IF_META_AVAILABLE(int32_t, scene, CAM_INTF_META_ASD_SCENE_TYPE, pMetaData) {
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_ASD_UPDATE;
payload->asd_data = (cam_auto_scene_t)*scene;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("processEvt asd_update failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for asd_update qcamera_sm_internal_evt_payload_t");
}
}
IF_META_AVAILABLE(cam_awb_params_t, awb_params, CAM_INTF_META_AWB_INFO, pMetaData) {
LOGH(", metadata for awb params.");
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_AWB_UPDATE;
payload->awb_data = *awb_params;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("processEvt awb_update failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for awb_update qcamera_sm_internal_evt_payload_t");
}
}
IF_META_AVAILABLE(uint32_t, flash_mode, CAM_INTF_META_FLASH_MODE, pMetaData) {
pme->mExifParams.sensor_params.flash_mode = (cam_flash_mode_t)*flash_mode;
}
IF_META_AVAILABLE(int32_t, flash_state, CAM_INTF_META_FLASH_STATE, pMetaData) {
pme->mExifParams.sensor_params.flash_state = (cam_flash_state_t) *flash_state;
}
IF_META_AVAILABLE(float, aperture_value, CAM_INTF_META_LENS_APERTURE, pMetaData) {
pme->mExifParams.sensor_params.aperture_value = *aperture_value;
}
IF_META_AVAILABLE(cam_3a_params_t, ae_params, CAM_INTF_META_AEC_INFO, pMetaData) {
pme->mExifParams.cam_3a_params = *ae_params;
pme->mExifParams.cam_3a_params_valid = TRUE;
pme->mFlashNeeded = ae_params->flash_needed;
pme->mExifParams.cam_3a_params.brightness = (float) pme->mParameters.getBrightness();
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_AE_UPDATE;
payload->ae_data = *ae_params;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("processEvt ae_update failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for ae_update qcamera_sm_internal_evt_payload_t");
}
}
IF_META_AVAILABLE(int32_t, wb_mode, CAM_INTF_PARM_WHITE_BALANCE, pMetaData) {
pme->mExifParams.cam_3a_params.wb_mode = (cam_wb_mode_type) *wb_mode;
}
IF_META_AVAILABLE(cam_sensor_params_t, sensor_params, CAM_INTF_META_SENSOR_INFO, pMetaData) {
pme->mExifParams.sensor_params = *sensor_params;
}
IF_META_AVAILABLE(cam_ae_exif_debug_t, ae_exif_debug_params,
CAM_INTF_META_EXIF_DEBUG_AE, pMetaData) {
if (pme->mExifParams.debug_params) {
pme->mExifParams.debug_params->ae_debug_params = *ae_exif_debug_params;
pme->mExifParams.debug_params->ae_debug_params_valid = TRUE;
}
}
IF_META_AVAILABLE(cam_awb_exif_debug_t, awb_exif_debug_params,
CAM_INTF_META_EXIF_DEBUG_AWB, pMetaData) {
if (pme->mExifParams.debug_params) {
pme->mExifParams.debug_params->awb_debug_params = *awb_exif_debug_params;
pme->mExifParams.debug_params->awb_debug_params_valid = TRUE;
}
}
IF_META_AVAILABLE(cam_af_exif_debug_t, af_exif_debug_params,
CAM_INTF_META_EXIF_DEBUG_AF, pMetaData) {
if (pme->mExifParams.debug_params) {
pme->mExifParams.debug_params->af_debug_params = *af_exif_debug_params;
pme->mExifParams.debug_params->af_debug_params_valid = TRUE;
}
}
IF_META_AVAILABLE(cam_asd_exif_debug_t, asd_exif_debug_params,
CAM_INTF_META_EXIF_DEBUG_ASD, pMetaData) {
if (pme->mExifParams.debug_params) {
pme->mExifParams.debug_params->asd_debug_params = *asd_exif_debug_params;
pme->mExifParams.debug_params->asd_debug_params_valid = TRUE;
}
}
IF_META_AVAILABLE(cam_stats_buffer_exif_debug_t, stats_exif_debug_params,
CAM_INTF_META_EXIF_DEBUG_STATS, pMetaData) {
if (pme->mExifParams.debug_params) {
pme->mExifParams.debug_params->stats_debug_params = *stats_exif_debug_params;
pme->mExifParams.debug_params->stats_debug_params_valid = TRUE;
}
}
IF_META_AVAILABLE(uint32_t, led_mode, CAM_INTF_META_LED_MODE_OVERRIDE, pMetaData) {
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_LED_MODE_OVERRIDE;
payload->led_data = (cam_flash_mode_t)*led_mode;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("processEvt led mode override failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for focus qcamera_sm_internal_evt_payload_t");
}
}
cam_edge_application_t edge_application;
memset(&edge_application, 0x00, sizeof(cam_edge_application_t));
edge_application.sharpness = pme->mParameters.getSharpness();
if (edge_application.sharpness != 0) {
edge_application.edge_mode = CAM_EDGE_MODE_FAST;
} else {
edge_application.edge_mode = CAM_EDGE_MODE_OFF;
}
ADD_SET_PARAM_ENTRY_TO_BATCH(pMetaData, CAM_INTF_META_EDGE_MODE, edge_application);
IF_META_AVAILABLE(cam_focus_pos_info_t, cur_pos_info,
CAM_INTF_META_FOCUS_POSITION, pMetaData) {
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_FOCUS_POS_UPDATE;
payload->focus_pos = *cur_pos_info;
int32_t rc = pme->processEvt(QCAMERA_SM_EVT_EVT_INTERNAL, payload);
if (rc != NO_ERROR) {
LOGW("processEvt focus_pos_update failed");
free(payload);
payload = NULL;
}
} else {
LOGE("No memory for focus_pos_update qcamera_sm_internal_evt_payload_t");
}
}
if (pme->mParameters.getLowLightCapture()) {
IF_META_AVAILABLE(cam_low_light_mode_t, low_light_level,
CAM_INTF_META_LOW_LIGHT, pMetaData) {
pme->mParameters.setLowLightLevel(*low_light_level);
}
}
IF_META_AVAILABLE(cam_dyn_img_data_t, dyn_img_data,
CAM_INTF_META_IMG_DYN_FEAT, pMetaData) {
pme->mParameters.setDynamicImgData(*dyn_img_data);
}
IF_META_AVAILABLE(int32_t, touch_ae_status, CAM_INTF_META_TOUCH_AE_RESULT, pMetaData) {
LOGD("touch_ae_status: %d", *touch_ae_status);
}
stream->bufDone(frame->buf_idx);
free(super_frame);
LOGD("[KPI Perf] : END");
}
/*===========================================================================
* FUNCTION : reprocess_stream_cb_routine
*
* DESCRIPTION: helper function to handle reprocess frame from reprocess stream
(after reprocess, e.g., ZSL snapshot frame after WNR if
* WNR is enabled)
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*
* NOTE : caller passes the ownership of super_frame, it's our
* responsibility to free super_frame once it's done. In this
* case, reprocessed frame need to be passed to postprocessor
* for jpeg encoding.
*==========================================================================*/
void QCamera2HardwareInterface::reprocess_stream_cb_routine(mm_camera_super_buf_t * super_frame,
QCameraStream * /*stream*/,
void * userdata)
{
ATRACE_CALL();
LOGH("[KPI Perf]: E");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != super_frame->camera_handle){
LOGE("camera obj not valid");
// simply free super frame
free(super_frame);
return;
}
pme->m_postprocessor.processPPData(super_frame);
LOGH("[KPI Perf]: X");
}
/*===========================================================================
* FUNCTION : callback_stream_cb_routine
*
* DESCRIPTION: function to process CALBACK stream data
Frame will processed and sent to framework
*
* PARAMETERS :
* @super_frame : received super buffer
* @stream : stream object
* @userdata : user data ptr
*
* RETURN : None
*==========================================================================*/
void QCamera2HardwareInterface::callback_stream_cb_routine(mm_camera_super_buf_t *super_frame,
QCameraStream *stream, void *userdata)
{
ATRACE_CALL();
LOGH("[KPI Perf]: E");
QCamera2HardwareInterface *pme = (QCamera2HardwareInterface *)userdata;
if (pme == NULL ||
pme->mCameraHandle == NULL ||
pme->mCameraHandle->camera_handle != super_frame->camera_handle) {
LOGE("camera obj not valid");
// simply free super frame
free(super_frame);
return;
}
mm_camera_buf_def_t *frame = super_frame->bufs[0];
if (NULL == frame) {
LOGE("preview callback frame is NULL");
free(super_frame);
return;
}
if (!pme->needProcessPreviewFrame()) {
LOGH("preview is not running, no need to process");
stream->bufDone(frame->buf_idx);
free(super_frame);
return;
}
QCameraMemory *previewMemObj = (QCameraMemory *)frame->mem_info;
// Handle preview data callback
if (pme->mDataCb != NULL &&
(pme->msgTypeEnabledWithLock(CAMERA_MSG_PREVIEW_FRAME) > 0) &&
(!pme->mParameters.isSceneSelectionEnabled())) {
int32_t rc = pme->sendPreviewCallback(stream, previewMemObj, frame->buf_idx);
if (NO_ERROR != rc) {
LOGE("Preview callback was not sent succesfully");
}
}
stream->bufDone(frame->buf_idx);
free(super_frame);
LOGH("[KPI Perf]: X");
}
/*===========================================================================
* FUNCTION : dumpFrameToFile
*
* DESCRIPTION: helper function to dump jpeg into file for debug purpose.
*
* PARAMETERS :
* @data : data ptr
* @size : length of data buffer
* @index : identifier for data
*
* RETURN : None
*==========================================================================*/
void QCamera2HardwareInterface::dumpJpegToFile(const void *data,
size_t size, uint32_t index)
{
char value[PROPERTY_VALUE_MAX];
property_get("persist.camera.dumpimg", value, "0");
uint32_t enabled = (uint32_t) atoi(value);
uint32_t frm_num = 0;
uint32_t skip_mode = 0;
char buf[32];
cam_dimension_t dim;
memset(buf, 0, sizeof(buf));
memset(&dim, 0, sizeof(dim));
if(((enabled & QCAMERA_DUMP_FRM_JPEG) && data) ||
((true == m_bIntJpegEvtPending) && data)) {
frm_num = ((enabled & 0xffff0000) >> 16);
if(frm_num == 0) {
frm_num = 10; //default 10 frames
}
if(frm_num > 256) {
frm_num = 256; //256 buffers cycle around
}
skip_mode = ((enabled & 0x0000ff00) >> 8);
if(skip_mode == 0) {
skip_mode = 1; //no-skip
}
if( mDumpSkipCnt % skip_mode == 0) {
if((frm_num == 256) && (mDumpFrmCnt >= frm_num)) {
// reset frame count if cycling
mDumpFrmCnt = 0;
}
if (mDumpFrmCnt <= frm_num) {
snprintf(buf, sizeof(buf), QCAMERA_DUMP_FRM_LOCATION "%d_%d.jpg",
mDumpFrmCnt, index);
if (true == m_bIntJpegEvtPending) {
strlcpy(m_BackendFileName, buf, QCAMERA_MAX_FILEPATH_LENGTH);
mBackendFileSize = size;
}
int file_fd = open(buf, O_RDWR | O_CREAT, 0777);
if (file_fd >= 0) {
ssize_t written_len = write(file_fd, data, size);
fchmod(file_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
LOGH("written number of bytes %zd\n",
written_len);
close(file_fd);
} else {
LOGE("fail to open file for image dumping");
}
if (false == m_bIntJpegEvtPending) {
mDumpFrmCnt++;
}
}
}
mDumpSkipCnt++;
}
}
void QCamera2HardwareInterface::dumpMetadataToFile(QCameraStream *stream,
mm_camera_buf_def_t *frame,char *type)
{
char value[PROPERTY_VALUE_MAX];
uint32_t frm_num = 0;
metadata_buffer_t *metadata = (metadata_buffer_t *)frame->buffer;
property_get("persist.camera.dumpmetadata", value, "0");
uint32_t enabled = (uint32_t) atoi(value);
if (stream == NULL) {
LOGH("No op");
return;
}
uint32_t dumpFrmCnt = stream->mDumpMetaFrame;
if(enabled){
frm_num = ((enabled & 0xffff0000) >> 16);
if (frm_num == 0) {
frm_num = 10; //default 10 frames
}
if (frm_num > 256) {
frm_num = 256; //256 buffers cycle around
}
if ((frm_num == 256) && (dumpFrmCnt >= frm_num)) {
// reset frame count if cycling
dumpFrmCnt = 0;
}
LOGH("dumpFrmCnt= %u, frm_num = %u", dumpFrmCnt, frm_num);
if (dumpFrmCnt < frm_num) {
char timeBuf[128];
char buf[32];
memset(buf, 0, sizeof(buf));
memset(timeBuf, 0, sizeof(timeBuf));
time_t current_time;
struct tm * timeinfo;
time (&current_time);
timeinfo = localtime (&current_time);
if (NULL != timeinfo) {
strftime(timeBuf, sizeof(timeBuf),
QCAMERA_DUMP_FRM_LOCATION "%Y%m%d%H%M%S", timeinfo);
}
String8 filePath(timeBuf);
snprintf(buf, sizeof(buf), "%um_%s_%d.bin", dumpFrmCnt, type, frame->frame_idx);
filePath.append(buf);
int file_fd = open(filePath.string(), O_RDWR | O_CREAT, 0777);
if (file_fd >= 0) {
ssize_t written_len = 0;
metadata->tuning_params.tuning_data_version = TUNING_DATA_VERSION;
void *data = (void *)((uint8_t *)&metadata->tuning_params.tuning_data_version);
written_len += write(file_fd, data, sizeof(uint32_t));
data = (void *)((uint8_t *)&metadata->tuning_params.tuning_sensor_data_size);
LOGH("tuning_sensor_data_size %d",(int)(*(int *)data));
written_len += write(file_fd, data, sizeof(uint32_t));
data = (void *)((uint8_t *)&metadata->tuning_params.tuning_vfe_data_size);
LOGH("tuning_vfe_data_size %d",(int)(*(int *)data));
written_len += write(file_fd, data, sizeof(uint32_t));
data = (void *)((uint8_t *)&metadata->tuning_params.tuning_cpp_data_size);
LOGH("tuning_cpp_data_size %d",(int)(*(int *)data));
written_len += write(file_fd, data, sizeof(uint32_t));
data = (void *)((uint8_t *)&metadata->tuning_params.tuning_cac_data_size);
LOGH("tuning_cac_data_size %d",(int)(*(int *)data));
written_len += write(file_fd, data, sizeof(uint32_t));
data = (void *)((uint8_t *)&metadata->tuning_params.tuning_cac_data_size2);
LOGH("< skrajago >tuning_cac_data_size %d",(int)(*(int *)data));
written_len += write(file_fd, data, sizeof(uint32_t));
size_t total_size = metadata->tuning_params.tuning_sensor_data_size;
data = (void *)((uint8_t *)&metadata->tuning_params.data);
written_len += write(file_fd, data, total_size);
total_size = metadata->tuning_params.tuning_vfe_data_size;
data = (void *)((uint8_t *)&metadata->tuning_params.data[TUNING_VFE_DATA_OFFSET]);
written_len += write(file_fd, data, total_size);
total_size = metadata->tuning_params.tuning_cpp_data_size;
data = (void *)((uint8_t *)&metadata->tuning_params.data[TUNING_CPP_DATA_OFFSET]);
written_len += write(file_fd, data, total_size);
total_size = metadata->tuning_params.tuning_cac_data_size;
data = (void *)((uint8_t *)&metadata->tuning_params.data[TUNING_CAC_DATA_OFFSET]);
written_len += write(file_fd, data, total_size);
close(file_fd);
}else {
LOGE("fail t open file for image dumping");
}
dumpFrmCnt++;
}
}
stream->mDumpMetaFrame = dumpFrmCnt;
}
/*===========================================================================
* FUNCTION : dumpFrameToFile
*
* DESCRIPTION: helper function to dump frame into file for debug purpose.
*
* PARAMETERS :
* @data : data ptr
* @size : length of data buffer
* @index : identifier for data
* @dump_type : type of the frame to be dumped. Only such
* dump type is enabled, the frame will be
* dumped into a file.
*
* RETURN : None
*==========================================================================*/
void QCamera2HardwareInterface::dumpFrameToFile(QCameraStream *stream,
mm_camera_buf_def_t *frame, uint32_t dump_type, const char *misc)
{
char value[PROPERTY_VALUE_MAX];
property_get("persist.camera.dumpimg", value, "0");
uint32_t enabled = (uint32_t) atoi(value);
uint32_t frm_num = 0;
uint32_t skip_mode = 0;
if (NULL == stream) {
LOGE("stream object is null");
return;
}
uint32_t dumpFrmCnt = stream->mDumpFrame;
if (true == m_bIntRawEvtPending) {
enabled = QCAMERA_DUMP_FRM_RAW;
}
if((enabled & QCAMERA_DUMP_FRM_MASK_ALL)) {
if((enabled & dump_type) && stream && frame) {
frm_num = ((enabled & 0xffff0000) >> 16);
if(frm_num == 0) {
frm_num = 10; //default 10 frames
}
if(frm_num > 256) {
frm_num = 256; //256 buffers cycle around
}
skip_mode = ((enabled & 0x0000ff00) >> 8);
if(skip_mode == 0) {
skip_mode = 1; //no-skip
}
if(stream->mDumpSkipCnt == 0)
stream->mDumpSkipCnt = 1;
if( stream->mDumpSkipCnt % skip_mode == 0) {
if((frm_num == 256) && (dumpFrmCnt >= frm_num)) {
// reset frame count if cycling
dumpFrmCnt = 0;
}
if (dumpFrmCnt <= frm_num) {
char buf[32];
char timeBuf[128];
time_t current_time;
struct tm * timeinfo;
memset(timeBuf, 0, sizeof(timeBuf));
time (&current_time);
timeinfo = localtime (&current_time);
memset(buf, 0, sizeof(buf));
cam_dimension_t dim;
memset(&dim, 0, sizeof(dim));
stream->getFrameDimension(dim);
cam_frame_len_offset_t offset;
memset(&offset, 0, sizeof(cam_frame_len_offset_t));
stream->getFrameOffset(offset);
if (NULL != timeinfo) {
strftime(timeBuf, sizeof(timeBuf),
QCAMERA_DUMP_FRM_LOCATION "%Y%m%d%H%M%S", timeinfo);
}
String8 filePath(timeBuf);
switch (dump_type) {
case QCAMERA_DUMP_FRM_PREVIEW:
{
snprintf(buf, sizeof(buf), "%dp_%dx%d_%d.yuv",
dumpFrmCnt, dim.width, dim.height, frame->frame_idx);
}
break;
case QCAMERA_DUMP_FRM_THUMBNAIL:
{
snprintf(buf, sizeof(buf), "%dt_%dx%d_%d.yuv",
dumpFrmCnt, dim.width, dim.height, frame->frame_idx);
}
break;
case QCAMERA_DUMP_FRM_SNAPSHOT:
{
if (!mParameters.isPostProcScaling()) {
mParameters.getStreamDimension(CAM_STREAM_TYPE_SNAPSHOT, dim);
} else {
stream->getFrameDimension(dim);
}
if (misc != NULL) {
snprintf(buf, sizeof(buf), "%ds_%dx%d_%d_%s.yuv",
dumpFrmCnt, dim.width, dim.height, frame->frame_idx, misc);
} else {
snprintf(buf, sizeof(buf), "%ds_%dx%d_%d.yuv",
dumpFrmCnt, dim.width, dim.height, frame->frame_idx);
}
}
break;
case QCAMERA_DUMP_FRM_INPUT_REPROCESS:
{
stream->getFrameDimension(dim);
if (misc != NULL) {
snprintf(buf, sizeof(buf), "%dir_%dx%d_%d_%s.yuv",
dumpFrmCnt, dim.width, dim.height, frame->frame_idx, misc);
} else {
snprintf(buf, sizeof(buf), "%dir_%dx%d_%d.yuv",
dumpFrmCnt, dim.width, dim.height, frame->frame_idx);
}
}
break;
case QCAMERA_DUMP_FRM_VIDEO:
{
snprintf(buf, sizeof(buf), "%dv_%dx%d_%d.yuv",
dumpFrmCnt, dim.width, dim.height, frame->frame_idx);
}
break;
case QCAMERA_DUMP_FRM_RAW:
{
mParameters.getStreamDimension(CAM_STREAM_TYPE_RAW, dim);
snprintf(buf, sizeof(buf), "%dr_%dx%d_%d.raw",
dumpFrmCnt, dim.width, dim.height, frame->frame_idx);
}
break;
case QCAMERA_DUMP_FRM_JPEG:
{
mParameters.getStreamDimension(CAM_STREAM_TYPE_SNAPSHOT, dim);
snprintf(buf, sizeof(buf), "%dj_%dx%d_%d.yuv",
dumpFrmCnt, dim.width, dim.height, frame->frame_idx);
}
break;
default:
LOGE("Not supported for dumping stream type %d",
dump_type);
return;
}
filePath.append(buf);
int file_fd = open(filePath.string(), O_RDWR | O_CREAT, 0777);
ssize_t written_len = 0;
if (file_fd >= 0) {
void *data = NULL;
fchmod(file_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
for (uint32_t i = 0; i < offset.num_planes; i++) {
uint32_t index = offset.mp[i].offset;
if (i > 0) {
index += offset.mp[i-1].len;
}
if (offset.mp[i].meta_len != 0) {
data = (void *)((uint8_t *)frame->buffer + index);
written_len += write(file_fd, data,
(size_t)offset.mp[i].meta_len);
index += (uint32_t)offset.mp[i].meta_len;
}
for (int j = 0; j < offset.mp[i].height; j++) {
data = (void *)((uint8_t *)frame->buffer + index);
written_len += write(file_fd, data,
(size_t)offset.mp[i].width);
index += (uint32_t)offset.mp[i].stride;
}
}
LOGH("written number of bytes %ld\n",
written_len);
close(file_fd);
} else {
LOGE("fail to open file for image dumping");
}
if (true == m_bIntRawEvtPending) {
strlcpy(m_BackendFileName, filePath.string(), QCAMERA_MAX_FILEPATH_LENGTH);
mBackendFileSize = (size_t)written_len;
} else {
dumpFrmCnt++;
}
}
}
stream->mDumpSkipCnt++;
}
} else {
dumpFrmCnt = 0;
}
stream->mDumpFrame = dumpFrmCnt;
}
/*===========================================================================
* FUNCTION : debugShowVideoFPS
*
* DESCRIPTION: helper function to log video frame FPS for debug purpose.
*
* PARAMETERS : None
*
* RETURN : None
*==========================================================================*/
void QCamera2HardwareInterface::debugShowVideoFPS()
{
mVFrameCount++;
nsecs_t now = systemTime();
nsecs_t diff = now - mVLastFpsTime;
if (diff > ms2ns(250)) {
mVFps = (((double)(mVFrameCount - mVLastFrameCount)) *
(double)(s2ns(1))) / (double)diff;
LOGI("[KPI Perf]: PROFILE_VIDEO_FRAMES_PER_SECOND: %.4f Cam ID = %d",
mVFps, mCameraId);
mVLastFpsTime = now;
mVLastFrameCount = mVFrameCount;
}
}
/*===========================================================================
* FUNCTION : debugShowPreviewFPS
*
* DESCRIPTION: helper function to log preview frame FPS for debug purpose.
*
* PARAMETERS : None
*
* RETURN : None
*==========================================================================*/
void QCamera2HardwareInterface::debugShowPreviewFPS()
{
mPFrameCount++;
nsecs_t now = systemTime();
nsecs_t diff = now - mPLastFpsTime;
if (diff > ms2ns(250)) {
mPFps = (((double)(mPFrameCount - mPLastFrameCount)) *
(double)(s2ns(1))) / (double)diff;
LOGI("[KPI Perf]: PROFILE_PREVIEW_FRAMES_PER_SECOND : %.4f Cam ID = %d",
mPFps, mCameraId);
mPLastFpsTime = now;
mPLastFrameCount = mPFrameCount;
}
}
/*===========================================================================
* FUNCTION : fillFacesData
*
* DESCRIPTION: helper function to fill in face related metadata into a struct.
*
* PARAMETERS :
* @faces_data : face features data to be filled
* @metadata : metadata structure to read face features from
*
* RETURN : None
*==========================================================================*/
void QCamera2HardwareInterface::fillFacesData(cam_faces_data_t &faces_data,
metadata_buffer_t *metadata)
{
memset(&faces_data, 0, sizeof(cam_faces_data_t));
IF_META_AVAILABLE(cam_face_detection_data_t, p_detection_data,
CAM_INTF_META_FACE_DETECTION, metadata) {
faces_data.detection_data = *p_detection_data;
if (faces_data.detection_data.num_faces_detected > MAX_ROI) {
faces_data.detection_data.num_faces_detected = MAX_ROI;
}
LOGH("[KPI Perf] %s: PROFILE_NUMBER_OF_FACES_DETECTED %d",
__func__,faces_data.detection_data.num_faces_detected);
IF_META_AVAILABLE(cam_face_recog_data_t, p_recog_data,
CAM_INTF_META_FACE_RECOG, metadata) {
faces_data.recog_valid = true;
faces_data.recog_data = *p_recog_data;
}
IF_META_AVAILABLE(cam_face_blink_data_t, p_blink_data,
CAM_INTF_META_FACE_BLINK, metadata) {
faces_data.blink_valid = true;
faces_data.blink_data = *p_blink_data;
}
IF_META_AVAILABLE(cam_face_gaze_data_t, p_gaze_data,
CAM_INTF_META_FACE_GAZE, metadata) {
faces_data.gaze_valid = true;
faces_data.gaze_data = *p_gaze_data;
}
IF_META_AVAILABLE(cam_face_smile_data_t, p_smile_data,
CAM_INTF_META_FACE_SMILE, metadata) {
faces_data.smile_valid = true;
faces_data.smile_data = *p_smile_data;
}
IF_META_AVAILABLE(cam_face_landmarks_data_t, p_landmarks,
CAM_INTF_META_FACE_LANDMARK, metadata) {
faces_data.landmark_valid = true;
faces_data.landmark_data = *p_landmarks;
}
IF_META_AVAILABLE(cam_face_contour_data_t, p_contour,
CAM_INTF_META_FACE_CONTOUR, metadata) {
faces_data.contour_valid = true;
faces_data.contour_data = *p_contour;
}
}
}
/*===========================================================================
* FUNCTION : ~QCameraCbNotifier
*
* DESCRIPTION: Destructor for exiting the callback context.
*
* PARAMETERS : None
*
* RETURN : None
*==========================================================================*/
QCameraCbNotifier::~QCameraCbNotifier()
{
}
/*===========================================================================
* FUNCTION : exit
*
* DESCRIPTION: exit notify thread.
*
* PARAMETERS : None
*
* RETURN : None
*==========================================================================*/
void QCameraCbNotifier::exit()
{
mActive = false;
mProcTh.exit();
}
/*===========================================================================
* FUNCTION : releaseNotifications
*
* DESCRIPTION: callback for releasing data stored in the callback queue.
*
* PARAMETERS :
* @data : data to be released
* @user_data : context data
*
* RETURN : None
*==========================================================================*/
void QCameraCbNotifier::releaseNotifications(void *data, void *user_data)
{
qcamera_callback_argm_t *arg = ( qcamera_callback_argm_t * ) data;
if ( ( NULL != arg ) && ( NULL != user_data ) ) {
if ( arg->release_cb ) {
arg->release_cb(arg->user_data, arg->cookie, FAILED_TRANSACTION);
}
}
}
/*===========================================================================
* FUNCTION : matchSnapshotNotifications
*
* DESCRIPTION: matches snapshot data callbacks
*
* PARAMETERS :
* @data : data to match
* @user_data : context data
*
* RETURN : bool match
* true - match found
* false- match not found
*==========================================================================*/
bool QCameraCbNotifier::matchSnapshotNotifications(void *data,
void */*user_data*/)
{
qcamera_callback_argm_t *arg = ( qcamera_callback_argm_t * ) data;
if ( NULL != arg ) {
if ( QCAMERA_DATA_SNAPSHOT_CALLBACK == arg->cb_type ) {
return true;
}
}
return false;
}
/*===========================================================================
* FUNCTION : matchPreviewNotifications
*
* DESCRIPTION: matches preview data callbacks
*
* PARAMETERS :
* @data : data to match
* @user_data : context data
*
* RETURN : bool match
* true - match found
* false- match not found
*==========================================================================*/
bool QCameraCbNotifier::matchPreviewNotifications(void *data,
void */*user_data*/)
{
qcamera_callback_argm_t *arg = ( qcamera_callback_argm_t * ) data;
if (NULL != arg) {
if ((QCAMERA_DATA_CALLBACK == arg->cb_type) &&
(CAMERA_MSG_PREVIEW_FRAME == arg->msg_type)) {
return true;
}
}
return false;
}
/*===========================================================================
* FUNCTION : cbNotifyRoutine
*
* DESCRIPTION: callback thread which interfaces with the upper layers
* given input commands.
*
* PARAMETERS :
* @data : context data
*
* RETURN : None
*==========================================================================*/
void * QCameraCbNotifier::cbNotifyRoutine(void * data)
{
int running = 1;
int ret;
QCameraCbNotifier *pme = (QCameraCbNotifier *)data;
QCameraCmdThread *cmdThread = &pme->mProcTh;
cmdThread->setName("CAM_cbNotify");
uint8_t isSnapshotActive = FALSE;
bool longShotEnabled = false;
uint32_t numOfSnapshotExpected = 0;
uint32_t numOfSnapshotRcvd = 0;
int32_t cbStatus = NO_ERROR;
LOGD("E");
do {
do {
ret = cam_sem_wait(&cmdThread->cmd_sem);
if (ret != 0 && errno != EINVAL) {
LOGD("cam_sem_wait error (%s)",
strerror(errno));
return NULL;
}
} while (ret != 0);
camera_cmd_type_t cmd = cmdThread->getCmd();
LOGD("get cmd %d", cmd);
switch (cmd) {
case CAMERA_CMD_TYPE_START_DATA_PROC:
{
isSnapshotActive = TRUE;
numOfSnapshotExpected = pme->mParent->numOfSnapshotsExpected();
longShotEnabled = pme->mParent->isLongshotEnabled();
LOGD("Num Snapshots Expected = %d",
numOfSnapshotExpected);
numOfSnapshotRcvd = 0;
}
break;
case CAMERA_CMD_TYPE_STOP_DATA_PROC:
{
pme->mDataQ.flushNodes(matchSnapshotNotifications);
isSnapshotActive = FALSE;
numOfSnapshotExpected = 0;
numOfSnapshotRcvd = 0;
}
break;
case CAMERA_CMD_TYPE_DO_NEXT_JOB:
{
qcamera_callback_argm_t *cb =
(qcamera_callback_argm_t *)pme->mDataQ.dequeue();
cbStatus = NO_ERROR;
if (NULL != cb) {
LOGD("cb type %d received",
cb->cb_type);
if (pme->mParent->msgTypeEnabledWithLock(cb->msg_type)) {
switch (cb->cb_type) {
case QCAMERA_NOTIFY_CALLBACK:
{
if (cb->msg_type == CAMERA_MSG_FOCUS) {
KPI_ATRACE_INT("Camera:AutoFocus", 0);
LOGH("[KPI Perf] : PROFILE_SENDING_FOCUS_EVT_TO APP");
}
if (pme->mNotifyCb) {
pme->mNotifyCb(cb->msg_type,
cb->ext1,
cb->ext2,
pme->mCallbackCookie);
} else {
LOGE("notify callback not set!");
}
if (cb->release_cb) {
cb->release_cb(cb->user_data, cb->cookie,
cbStatus);
}
}
break;
case QCAMERA_DATA_CALLBACK:
{
if (pme->mDataCb) {
pme->mDataCb(cb->msg_type,
cb->data,
cb->index,
cb->metadata,
pme->mCallbackCookie);
} else {
LOGE("data callback not set!");
}
if (cb->release_cb) {
cb->release_cb(cb->user_data, cb->cookie,
cbStatus);
}
}
break;
case QCAMERA_DATA_TIMESTAMP_CALLBACK:
{
if(pme->mDataCbTimestamp) {
pme->mDataCbTimestamp(cb->timestamp,
cb->msg_type,
cb->data,
cb->index,
pme->mCallbackCookie);
} else {
LOGE("Timestamp data callback not set!");
}
if (cb->release_cb) {
cb->release_cb(cb->user_data, cb->cookie,
cbStatus);
}
}
break;
case QCAMERA_DATA_SNAPSHOT_CALLBACK:
{
if (TRUE == isSnapshotActive && pme->mDataCb ) {
if (!longShotEnabled) {
numOfSnapshotRcvd++;
LOGI("Num Snapshots Received = %d Expected = %d",
numOfSnapshotRcvd, numOfSnapshotExpected);
if (numOfSnapshotExpected > 0 &&
(numOfSnapshotExpected == numOfSnapshotRcvd)) {
LOGI("Received all snapshots");
// notify HWI that snapshot is done
pme->mParent->processSyncEvt(QCAMERA_SM_EVT_SNAPSHOT_DONE,
NULL);
}
}
if (pme->mJpegCb) {
LOGI("Calling JPEG Callback!! for camera %d"
"release_data %p",
"frame_idx %d",
pme->mParent->getCameraId(),
cb->user_data,
cb->frame_index);
pme->mJpegCb(cb->msg_type, cb->data,
cb->index, cb->metadata,
pme->mJpegCallbackCookie,
cb->frame_index, cb->release_cb,
cb->cookie, cb->user_data);
// incase of non-null Jpeg cb we transfer
// ownership of buffer to muxer. hence
// release_cb should not be called
// muxer will release after its done with
// processing the buffer
}
else {
pme->mDataCb(cb->msg_type, cb->data, cb->index,
cb->metadata, pme->mCallbackCookie);
if (cb->release_cb) {
cb->release_cb(cb->user_data, cb->cookie,
cbStatus);
}
}
}
}
break;
default:
{
LOGE("invalid cb type %d",
cb->cb_type);
cbStatus = BAD_VALUE;
if (cb->release_cb) {
cb->release_cb(cb->user_data, cb->cookie,
cbStatus);
}
}
break;
};
} else {
LOGE("cb message type %d not enabled!",
cb->msg_type);
cbStatus = INVALID_OPERATION;
if (cb->release_cb) {
cb->release_cb(cb->user_data, cb->cookie, cbStatus);
}
}
delete cb;
} else {
LOGE("invalid cb type passed");
}
}
break;
case CAMERA_CMD_TYPE_EXIT:
{
running = 0;
pme->mDataQ.flush();
}
break;
default:
break;
}
} while (running);
LOGD("X");
return NULL;
}
/*===========================================================================
* FUNCTION : notifyCallback
*
* DESCRIPTION: Enqueus pending callback notifications for the upper layers.
*
* PARAMETERS :
* @cbArgs : callback arguments
*
* RETURN : int32_t type of status
* NO_ERROR -- success
* none-zero failure code
*==========================================================================*/
int32_t QCameraCbNotifier::notifyCallback(qcamera_callback_argm_t &cbArgs)
{
if (!mActive) {
LOGE("notify thread is not active");
return UNKNOWN_ERROR;
}
qcamera_callback_argm_t *cbArg = new qcamera_callback_argm_t();
if (NULL == cbArg) {
LOGE("no mem for qcamera_callback_argm_t");
return NO_MEMORY;
}
memset(cbArg, 0, sizeof(qcamera_callback_argm_t));
*cbArg = cbArgs;
if (mDataQ.enqueue((void *)cbArg)) {
return mProcTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE);
} else {
LOGE("Error adding cb data into queue");
delete cbArg;
return UNKNOWN_ERROR;
}
}
/*===========================================================================
* FUNCTION : setCallbacks
*
* DESCRIPTION: Initializes the callback functions, which would be used for
* communication with the upper layers and launches the callback
* context in which the callbacks will occur.
*
* PARAMETERS :
* @notifyCb : notification callback
* @dataCb : data callback
* @dataCbTimestamp : data with timestamp callback
* @callbackCookie : callback context data
*
* RETURN : None
*==========================================================================*/
void QCameraCbNotifier::setCallbacks(camera_notify_callback notifyCb,
camera_data_callback dataCb,
camera_data_timestamp_callback dataCbTimestamp,
void *callbackCookie)
{
if ( ( NULL == mNotifyCb ) &&
( NULL == mDataCb ) &&
( NULL == mDataCbTimestamp ) &&
( NULL == mCallbackCookie ) ) {
mNotifyCb = notifyCb;
mDataCb = dataCb;
mDataCbTimestamp = dataCbTimestamp;
mCallbackCookie = callbackCookie;
mActive = true;
mProcTh.launch(cbNotifyRoutine, this);
} else {
LOGE("Camera callback notifier already initialized!");
}
}
/*===========================================================================
* FUNCTION : setJpegCallBacks
*
* DESCRIPTION: Initializes the JPEG callback function, which would be used for
* communication with the upper layers and launches the callback
* context in which the callbacks will occur.
*
* PARAMETERS :
* @jpegCb : notification callback
* @callbackCookie : callback context data
*
* RETURN : None
*==========================================================================*/
void QCameraCbNotifier::setJpegCallBacks(
jpeg_data_callback jpegCb, void *callbackCookie)
{
LOGH("Setting JPEG Callback notifier");
mJpegCb = jpegCb;
mJpegCallbackCookie = callbackCookie;
}
/*===========================================================================
* FUNCTION : flushPreviewNotifications
*
* DESCRIPTION: flush all pending preview notifications
* from the notifier queue
*
* PARAMETERS : None
*
* RETURN : int32_t type of status
* NO_ERROR -- success
* none-zero failure code
*==========================================================================*/
int32_t QCameraCbNotifier::flushPreviewNotifications()
{
if (!mActive) {
LOGE("notify thread is not active");
return UNKNOWN_ERROR;
}
mDataQ.flushNodes(matchPreviewNotifications);
return NO_ERROR;
}
/*===========================================================================
* FUNCTION : startSnapshots
*
* DESCRIPTION: Enables snapshot mode
*
* PARAMETERS : None
*
* RETURN : int32_t type of status
* NO_ERROR -- success
* none-zero failure code
*==========================================================================*/
int32_t QCameraCbNotifier::startSnapshots()
{
return mProcTh.sendCmd(CAMERA_CMD_TYPE_START_DATA_PROC, FALSE, TRUE);
}
/*===========================================================================
* FUNCTION : stopSnapshots
*
* DESCRIPTION: Disables snapshot processing mode
*
* PARAMETERS : None
*
* RETURN : None
*==========================================================================*/
void QCameraCbNotifier::stopSnapshots()
{
mProcTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, FALSE, TRUE);
}
}; // namespace qcamera