diff options
Diffstat (limited to '')
-rw-r--r-- | camera/QCamera2/HAL/QCamera2HWICallbacks.cpp | 3512 |
1 files changed, 3512 insertions, 0 deletions
diff --git a/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp b/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp new file mode 100644 index 0000000..ec05ec4 --- /dev/null +++ b/camera/QCamera2/HAL/QCamera2HWICallbacks.cpp @@ -0,0 +1,3512 @@ +/* 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 + // then send to postprocessor + if ((NO_ERROR != pme->waitDeferredWork(pme->mReprocJob)) || + (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 + // then send to postprocessor + if ((NO_ERROR != pme->waitDeferredWork(pme->mReprocJob)) || + (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(frame->frame_idx)) { + pthread_mutex_lock(&pme->mGrallocLock); + pme->mLastPreviewFrameID = frame->frame_idx; + 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; + // 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->mLastPreviewFrameID = frame->frame_idx; + 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; + } + + // For instant capture and for instant AEC, keep track of the frame counter. + // This count will be used to check against the corresponding bound values. + if (pme->mParameters.isInstantAECEnabled() || + pme->mParameters.isInstantCaptureEnabled()) { + pme->mInstantAecFrameCount++; + } + + pthread_mutex_lock(&pme->mGrallocLock); + if (!stream->isSyncCBEnabled()) { + pme->mLastPreviewFrameID = frame->frame_idx; + } + if (((!stream->isSyncCBEnabled()) && + (!pme->needProcessPreviewFrame(frame->frame_idx))) || + ((stream->isSyncCBEnabled()) && + (memory->isBufOwnedByCamera(frame->buf_idx)))) { + //If buffer owned by camera, then it is not enqueued to display. + // bufDone it back to backend. + 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); + + yStrideToApp = preview_dim.width; + yScanlineToApp = preview_dim.height; + uvStrideToApp = yStrideToApp; + uvScanlineToApp = yScanlineToApp / 2; + + /* 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; + + 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 { + /*Invalid Buffer content. But can be used as a first preview frame trigger in + framework/app */ + previewBufSize = (size_t) + ((yStrideToApp * yScanlineToApp) + + (uvStrideToApp * uvScanlineToApp)); + previewBufSizeFromCallback = 0; + LOGW("Invalid preview format. Buffer content cannot be processed size = %d", + previewBufSize); + dataToApp = mGetMemory(-1, previewBufSize, 1, mCallbackCookie); + if (!dataToApp || !dataToApp->data) { + LOGE("mGetMemory failed.\n"); + return NO_MEMORY; + } + } + 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(frame->frame_idx)) { + 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(frame->frame_idx)) && + 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(frame->frame_idx)) { + 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(frame->frame_idx) && + 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(frame->frame_idx) && + 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; + + 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; + } + + 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; + LOGD("Video frame to encoder TimeStamp : %lld batch = 0", + timeStamp); + 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); + videoMemObj->updateNativeHandle(frame->buf_idx); + triggerTCB = TRUE; + } + } 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->updateNativeHandle(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; + LOGD("Video frame to encoder TimeStamp : %lld batch = %d", + timeStamp, fd_cnt); + 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->updateNativeHandle(frame->buf_idx); + } else { + LOGE("videoMemObj NULL"); + } + + if (nh != NULL) { + timeStamp = nsecs_t(frame->ts.tv_sec) * 1000000000LL + + frame->ts.tv_nsec; + LOGD("Batch buffer TimeStamp : %lld FD = %d index = %d fd_cnt = %d", + timeStamp, frame->fd, frame->buf_idx, fd_cnt); + + 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; + } 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; + 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); + LOGH("[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->waitDeferredWork(pme->mReprocJob)) || + (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 + // then send to postprocessor + if ((NO_ERROR != pme->waitDeferredWork(pme->mReprocJob)) || + (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; + memset(&rotation_info, 0, sizeof(cam_rotation_info_t)); + 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("processEvt face detection failed"); + free(payload); + payload = NULL; + } + } else { + LOGE("No memory for face detect qcamera_sm_internal_evt_payload_t"); + } + } + + 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) { + cam_af_state_t prevFocusState = pme->m_currentFocusState; + 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); + //Need to flush ZSL Q only if we are transitioning from scanning state + //to focused/not focused state. + payload->focus_data.flush_info.needFlush = + ((prevFocusState == CAM_AF_STATE_PASSIVE_SCAN) || + (prevFocusState == CAM_AF_STATE_ACTIVE_SCAN)) && + ((pme->m_currentFocusState == CAM_AF_STATE_FOCUSED_LOCKED) || + (pme->m_currentFocusState == CAM_AF_STATE_NOT_FOCUSED_LOCKED)); + payload->focus_data.flush_info.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(cam_asd_decision_t, cam_asd_info, + CAM_INTF_META_ASD_SCENE_INFO, 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_asd_decision_t)*cam_asd_info; + 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(cam_bestats_buffer_exif_debug_t, bestats_exif_debug_params, + CAM_INTF_META_EXIF_DEBUG_BESTATS, pMetaData) { + if (pme->mExifParams.debug_params) { + pme->mExifParams.debug_params->bestats_debug_params = *bestats_exif_debug_params; + pme->mExifParams.debug_params->bestats_debug_params_valid = TRUE; + } + } + + IF_META_AVAILABLE(cam_bhist_buffer_exif_debug_t, bhist_exif_debug_params, + CAM_INTF_META_EXIF_DEBUG_BHIST, pMetaData) { + if (pme->mExifParams.debug_params) { + pme->mExifParams.debug_params->bhist_debug_params = *bhist_exif_debug_params; + pme->mExifParams.debug_params->bhist_debug_params_valid = TRUE; + } + } + + IF_META_AVAILABLE(cam_q3a_tuning_info_t, q3a_tuning_exif_debug_params, + CAM_INTF_META_EXIF_DEBUG_3A_TUNING, pMetaData) { + if (pme->mExifParams.debug_params) { + pme->mExifParams.debug_params->q3a_tuning_debug_params = *q3a_tuning_exif_debug_params; + pme->mExifParams.debug_params->q3a_tuning_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(frame->frame_idx)) { + 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 (¤t_time); + timeinfo = localtime (¤t_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 (¤t_time); + timeinfo = localtime (¤t_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] PROFILE_NUMBER_OF_FACES_DETECTED %d", + 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 : matchTimestampNotifications + * + * DESCRIPTION: matches timestamp data callbacks + * + * PARAMETERS : + * @data : data to match + * @user_data : context data + * + * RETURN : bool match + * true - match found + * false- match not found + *==========================================================================*/ +bool QCameraCbNotifier::matchTimestampNotifications(void *data, + void */*user_data*/) +{ + qcamera_callback_argm_t *arg = ( qcamera_callback_argm_t * ) data; + if (NULL != arg) { + if ((QCAMERA_DATA_TIMESTAMP_CALLBACK == arg->cb_type) && + (CAMERA_MSG_VIDEO_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 { + LOGW("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 { + LOGW("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 if(pme->mDataCb){ + 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 { + LOGW("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 { + LOGW("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 : flushVideoNotifications + * + * DESCRIPTION: flush all pending video notifications + * from the notifier queue + * + * PARAMETERS : None + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCameraCbNotifier::flushVideoNotifications() +{ + if (!mActive) { + LOGE("notify thread is not active"); + return UNKNOWN_ERROR; + } + mDataQ.flushNodes(matchTimestampNotifications); + 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 |