diff options
Diffstat (limited to 'camera/QCamera2/HAL/QCameraMuxer.cpp')
-rw-r--r-- | camera/QCamera2/HAL/QCameraMuxer.cpp | 2823 |
1 files changed, 2823 insertions, 0 deletions
diff --git a/camera/QCamera2/HAL/QCameraMuxer.cpp b/camera/QCamera2/HAL/QCameraMuxer.cpp new file mode 100644 index 0000000..e2ec989 --- /dev/null +++ b/camera/QCamera2/HAL/QCameraMuxer.cpp @@ -0,0 +1,2823 @@ +/* Copyright (c) 2015-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 "QCameraMuxer" + +// System dependencies +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <utils/Errors.h> +#define STAT_H <SYSTEM_HEADER_PREFIX/stat.h> +#include STAT_H + +// Camera dependencies +#include "QCameraMuxer.h" +#include "QCamera2HWI.h" +#include "QCamera3HWI.h" + +extern "C" { +#include "mm_camera_dbg.h" +} + +/* Muxer implementation */ +using namespace android; +namespace qcamera { + +QCameraMuxer *gMuxer = NULL; + +//Error Check Macros +#define CHECK_MUXER() \ + if (!gMuxer) { \ + LOGE("Error getting muxer "); \ + return; \ + } \ + +#define CHECK_MUXER_ERROR() \ + if (!gMuxer) { \ + LOGE("Error getting muxer "); \ + return -ENODEV; \ + } \ + +#define CHECK_CAMERA(pCam) \ + if (!pCam) { \ + LOGE("Error getting physical camera"); \ + return; \ + } \ + +#define CHECK_CAMERA_ERROR(pCam) \ + if (!pCam) { \ + LOGE("Error getting physical camera"); \ + return -ENODEV; \ + } \ + +#define CHECK_HWI(hwi) \ + if (!hwi) { \ + LOGE("Error !! HWI not found!!"); \ + return; \ + } \ + +#define CHECK_HWI_ERROR(hwi) \ + if (!hwi) { \ + LOGE("Error !! HWI not found!!"); \ + return -ENODEV; \ + } \ + + +/*=========================================================================== + * FUNCTION : getCameraMuxer + * + * DESCRIPTION : Creates Camera Muxer if not created + * + * PARAMETERS: + * @pMuxer : Pointer to retrieve Camera Muxer + * @num_of_cameras : Number of Physical Cameras on device + * + * RETURN : NONE + *==========================================================================*/ +void QCameraMuxer::getCameraMuxer( + QCameraMuxer** pMuxer, uint32_t num_of_cameras) +{ + *pMuxer = NULL; + if (!gMuxer) { + gMuxer = new QCameraMuxer(num_of_cameras); + } + CHECK_MUXER(); + *pMuxer = gMuxer; + LOGH("gMuxer: %p ", gMuxer); + return; +} + +/*=========================================================================== + * FUNCTION : QCameraMuxer + * + * DESCRIPTION : QCameraMuxer Constructor + * + * PARAMETERS: + * @num_of_cameras : Number of Physical Cameras on device + * + *==========================================================================*/ +QCameraMuxer::QCameraMuxer(uint32_t num_of_cameras) + : mJpegClientHandle(0), + m_pPhyCamera(NULL), + m_pLogicalCamera(NULL), + m_pCallbacks(NULL), + m_bAuxCameraExposed(FALSE), + m_nPhyCameras(num_of_cameras), + m_nLogicalCameras(0), + m_MainJpegQ(releaseJpegInfo, this), + m_AuxJpegQ(releaseJpegInfo, this), + m_pRelCamMpoJpeg(NULL), + m_pMpoCallbackCookie(NULL), + m_pJpegCallbackCookie(NULL), + m_bDumpImages(FALSE), + m_bMpoEnabled(TRUE), + m_bFrameSyncEnabled(FALSE), + m_bRecordingHintInternallySet(FALSE) +{ + setupLogicalCameras(); + memset(&mJpegOps, 0, sizeof(mJpegOps)); + memset(&mJpegMpoOps, 0, sizeof(mJpegMpoOps)); + memset(&mGetMemoryCb, 0, sizeof(mGetMemoryCb)); + memset(&mDataCb, 0, sizeof(mDataCb)); + + // initialize mutex for MPO composition + pthread_mutex_init(&m_JpegLock, NULL); + // launch MPO composition thread + m_ComposeMpoTh.launch(composeMpoRoutine, this); + + //Check whether dual camera images need to be dumped + char prop[PROPERTY_VALUE_MAX]; + property_get("persist.camera.dual.camera.dump", prop, "0"); + m_bDumpImages = atoi(prop); + LOGH("dualCamera dump images:%d ", m_bDumpImages); +} + +/*=========================================================================== + * FUNCTION : ~QCameraMuxer + * + * DESCRIPTION : QCameraMuxer Desctructor + * + *==========================================================================*/ +QCameraMuxer::~QCameraMuxer() { + if (m_pLogicalCamera) { + delete [] m_pLogicalCamera; + m_pLogicalCamera = NULL; + } + if (m_pPhyCamera) { + delete [] m_pPhyCamera; + m_pPhyCamera = NULL; + } + + if (NULL != m_pRelCamMpoJpeg) { + m_pRelCamMpoJpeg->release(m_pRelCamMpoJpeg); + m_pRelCamMpoJpeg = NULL; + } + // flush Jpeg Queues + m_MainJpegQ.flush(); + m_AuxJpegQ.flush(); + + // stop and exit MPO composition thread + m_ComposeMpoTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, TRUE, FALSE); + m_ComposeMpoTh.exit(); + + pthread_mutex_destroy(&m_JpegLock); +} + +/*=========================================================================== + * FUNCTION : get_number_of_cameras + * + * DESCRIPTION : Provide number of Logical Cameras + * + * RETURN : Number of logical Cameras + *==========================================================================*/ +int QCameraMuxer::get_number_of_cameras() +{ + return gMuxer->getNumberOfCameras(); +} + +/*=========================================================================== + * FUNCTION : get_camera_info + * + * DESCRIPTION : get logical camera info + * + * PARAMETERS: + * @camera_id : Logical Camera ID + * @info : Logical Main Camera Info + * + * RETURN : + * NO_ERROR : success + * ENODEV : Camera not found + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::get_camera_info(int camera_id, struct camera_info *info) +{ + int rc = NO_ERROR; + LOGH("E"); + cam_sync_type_t type; + if ((camera_id < 0) || (camera_id >= gMuxer->getNumberOfCameras())) { + LOGE("Camera id %d not found!", camera_id); + return -ENODEV; + } + if(info) { + rc = gMuxer->getCameraInfo(camera_id, info, &type); + } + LOGH("X, rc: %d", rc); + return rc; +} + + +/*=========================================================================== + * FUNCTION : set_callbacks + * + * DESCRIPTION : Not Implemented + * + * PARAMETERS: + * @callbacks : Camera Module Callbacks + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::set_callbacks(__unused const camera_module_callbacks_t *callbacks) +{ + // Not implemented + return NO_ERROR; +} + +/*=========================================================================== + * FUNCTION : camera_device_open + * + * DESCRIPTION: static function to open a camera device by its ID + * + * PARAMETERS : + * @modue: hw module + * @id : camera ID + * @hw_device : ptr to struct storing camera hardware device info + * + * RETURN : + * NO_ERROR : success + * BAD_VALUE : Invalid Camera ID + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::camera_device_open( + __unused const struct hw_module_t *module, const char *id, + struct hw_device_t **hw_device) +{ + int rc = NO_ERROR; + LOGH("id= %d",atoi(id)); + if (!id) { + LOGE("Invalid camera id"); + return BAD_VALUE; + } + + rc = gMuxer->cameraDeviceOpen(atoi(id), hw_device); + LOGH("id= %d, rc: %d", atoi(id), rc); + return rc; +} + +/*=========================================================================== + * FUNCTION : open_legacy + * + * DESCRIPTION: static function to open a camera device by its ID + * + * PARAMETERS : + * @modue: hw module + * @id : camera ID + * @halVersion: hal version + * @hw_device : ptr to struct storing camera hardware device info + * + * RETURN : + * NO_ERROR : success + * BAD_VALUE : Invalid Camera ID + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::open_legacy(__unused const struct hw_module_t* module, + const char* id, __unused uint32_t halVersion, struct hw_device_t** hw_device) +{ + int rc = NO_ERROR; + LOGH("id= %d", atoi(id)); + if (!id) { + LOGE("Invalid camera id"); + return BAD_VALUE; + } + + rc = gMuxer->cameraDeviceOpen(atoi(id), hw_device); + LOGH("id= %d, rc: %d", atoi(id), rc); + return rc; +} + +/*=========================================================================== + * FUNCTION : set_preview_window + * + * DESCRIPTION: Set Preview window for main camera + * + * PARAMETERS : + * @device : camera hardware device info + * @window: Preview window ops + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::set_preview_window(struct camera_device * device, + struct preview_stream_ops *window) +{ + int rc = NO_ERROR; + CHECK_MUXER_ERROR(); + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + // Set preview window only for primary camera + if (pCam->mode == CAM_MODE_PRIMARY) { + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + rc = hwi->set_preview_window(pCam->dev, window); + if (rc != NO_ERROR) { + LOGE("Error!! setting preview window"); + return rc; + } + break; + } + } + return rc; +} + +/*=========================================================================== + * FUNCTION : set_callBacks + * + * DESCRIPTION: Set Framework callbacks to notify various frame data asynchronously + * + * PARAMETERS : + * @device : camera hardware device info + * @notify_cb: Notification callback + * @data_cb: data callback + * @data_cb_timestamp: data timestamp callback + * @get_memory: callback to obtain memory + * @user : userdata + * + * RETURN : None + *==========================================================================*/ +void QCameraMuxer::set_callBacks(struct camera_device * device, + camera_notify_callback notify_cb, + camera_data_callback data_cb, + camera_data_timestamp_callback data_cb_timestamp, + camera_request_memory get_memory, + void *user) +{ + LOGH("E"); + CHECK_MUXER(); + int rc = NO_ERROR; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA(cam); + + // Set callbacks to HWI + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI(hwi); + + hwi->set_CallBacks(pCam->dev, notify_cb, data_cb, data_cb_timestamp, + get_memory, user); + + // Set JPG callbacks + // sending the physical camera description with the Jpeg callback + // this will be retrieved in callbacks to get the cam instance + // delivering JPEGs + hwi->setJpegCallBacks(jpeg_data_callback, (void*)pCam); + + if (pCam->mode == CAM_MODE_PRIMARY) { + rc = gMuxer->setMainJpegCallbackCookie((void*)(pCam)); + if(rc != NO_ERROR) { + LOGW("Error setting Jpeg callback cookie"); + } + } + } + // Store callback in Muxer to send data callbacks + rc = gMuxer->setDataCallback(data_cb); + if(rc != NO_ERROR) { + LOGW("Error setting data callback"); + } + // memory callback stored to allocate memory for MPO buffer + rc = gMuxer->setMemoryCallback(get_memory); + if(rc != NO_ERROR) { + LOGW("Error setting memory callback"); + } + // actual user callback cookie is saved in Muxer + // this will be used to deliver final MPO callback to the framework + rc = gMuxer->setMpoCallbackCookie(user); + if(rc != NO_ERROR) { + LOGW("Error setting mpo cookie"); + } + + LOGH("X"); + +} + +/*=========================================================================== + * FUNCTION : enable_msg_type + * + * DESCRIPTION: Enable msg_type to send callbacks + * + * PARAMETERS : + * @device : camera hardware device info + * @msg_type: callback Message type to be enabled + * + * RETURN : None + *==========================================================================*/ +void QCameraMuxer::enable_msg_type(struct camera_device * device, int32_t msg_type) +{ + LOGH("E"); + CHECK_MUXER(); + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA(pCam); + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI(hwi); + hwi->enable_msg_type(pCam->dev, msg_type); + } + LOGH("X"); +} + +/*=========================================================================== + * FUNCTION : disable_msg_type + * + * DESCRIPTION: disable msg_type to send callbacks + * + * PARAMETERS : + * @device : camera hardware device info + * @msg_type: callback Message type to be disabled + * + * RETURN : None + *==========================================================================*/ +void QCameraMuxer::disable_msg_type(struct camera_device * device, int32_t msg_type) +{ + LOGH("E"); + CHECK_MUXER(); + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA(pCam); + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI(hwi); + hwi->disable_msg_type(pCam->dev, msg_type); + } + LOGH("X"); +} + +/*=========================================================================== + * FUNCTION : msg_type_enabled + * + * DESCRIPTION: Check if message type enabled + * + * PARAMETERS : + * @device : camera hardware device info + * @msg_type: message type + * + * RETURN : true/false + *==========================================================================*/ +int QCameraMuxer::msg_type_enabled(struct camera_device * device, int32_t msg_type) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + if (pCam->mode == CAM_MODE_PRIMARY) { + return hwi->msg_type_enabled(pCam->dev, msg_type); + } + } + LOGH("X"); + return false; +} + +/*=========================================================================== + * FUNCTION : start_preview + * + * DESCRIPTION: Starts logical camera preview + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::start_preview(struct camera_device * device) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + int rc = NO_ERROR; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + // prepare preview first for all cameras + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = hwi->prepare_preview(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error preparing preview !! "); + return rc; + } + } + + if (cam->numCameras > 1) { + uint sessionId = 0; + // Set up sync for camera sessions + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + if(pCam->mode == CAM_MODE_PRIMARY) { + // bundle primary cam with all aux cameras + for (uint32_t j = 0; j < cam->numCameras; j++) { + if (j == cam->nPrimaryPhyCamIndex) { + continue; + } + sessionId = cam->sId[j]; + LOGH("Related cam id: %d, server id: %d sync ON" + " related session_id %d", + cam->pId[i], cam->sId[i], sessionId); + rc = hwi->bundleRelatedCameras(true, sessionId); + if (rc != NO_ERROR) { + LOGE("Error Bundling physical cameras !! "); + return rc; + } + } + } + + if (pCam->mode == CAM_MODE_SECONDARY) { + // bundle all aux cam with primary cams + sessionId = cam->sId[cam->nPrimaryPhyCamIndex]; + LOGH("Related cam id: %d, server id: %d sync ON" + " related session_id %d", + cam->pId[i], cam->sId[i], sessionId); + rc = hwi->bundleRelatedCameras(true, sessionId); + if (rc != NO_ERROR) { + LOGE("Error Bundling physical cameras !! "); + return rc; + } + } + } + + // Remember Sync is ON + cam->bSyncOn = true; + } + // Start Preview for all cameras + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + rc = hwi->start_preview(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error starting preview !! "); + return rc; + } + } + LOGH("X"); + return rc; +} + +/*=========================================================================== + * FUNCTION : stop_preview + * + * DESCRIPTION: Stops logical camera preview + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : None + *==========================================================================*/ +void QCameraMuxer::stop_preview(struct camera_device * device) +{ + LOGH("E"); + CHECK_MUXER(); + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI(hwi); + + QCamera2HardwareInterface::stop_preview(pCam->dev); + } + + //Flush JPEG Queues. Nodes in Main and Aux JPEGQ are not valid after preview stopped. + gMuxer->m_MainJpegQ.flush(); + gMuxer->m_AuxJpegQ.flush(); + LOGH(" X"); +} + +/*=========================================================================== + * FUNCTION : preview_enabled + * + * DESCRIPTION: Checks preview enabled + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : true/false + *==========================================================================*/ +int QCameraMuxer::preview_enabled(struct camera_device * device) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + if (pCam->mode == CAM_MODE_PRIMARY) { + return hwi->preview_enabled(pCam->dev); + } + } + LOGH("X"); + return false; +} + +/*=========================================================================== + * FUNCTION : store_meta_data_in_buffers + * + * DESCRIPTION: Stores metadata in buffers + * + * PARAMETERS : + * @device : camera hardware device info + * @enable: Enable/disable metadata + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::store_meta_data_in_buffers(struct camera_device * device, int enable) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + int rc = NO_ERROR; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = hwi->store_meta_data_in_buffers(pCam->dev, enable); + if (rc != NO_ERROR) { + LOGE("Error storing metat data !! "); + return rc; + } + } + LOGH("X"); + return rc; +} + +/*=========================================================================== + * FUNCTION : start_recording + * + * DESCRIPTION: Starts recording on camcorder + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::start_recording(struct camera_device * device) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + int rc = NO_ERROR; + bool previewRestartNeeded = false; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + // In cases where recording hint is not set, hwi->start_recording will + // internally restart the preview. + // To take the preview restart control in muxer, + // 1. call pre_start_recording first + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = hwi->pre_start_recording(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error preparing recording start!! "); + return rc; + } + } + + // 2. Check if preview restart is needed. Check all cameras. + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + if (hwi->isPreviewRestartNeeded()) { + previewRestartNeeded = hwi->isPreviewRestartNeeded(); + break; + } + } + + if (previewRestartNeeded) { + // 3. if preview restart needed. stop the preview first + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = hwi->restart_stop_preview(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error in restart stop preview!! "); + return rc; + } + } + + //4. Update the recording hint value to TRUE + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = hwi->setRecordingHintValue(TRUE); + if (rc != NO_ERROR) { + LOGE("Error in setting recording hint value!! "); + return rc; + } + gMuxer->m_bRecordingHintInternallySet = TRUE; + } + + // 5. start the preview + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = hwi->restart_start_preview(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error in restart start preview!! "); + return rc; + } + } + } + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + if (pCam->mode == CAM_MODE_PRIMARY) { + rc = hwi->start_recording(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error starting recording!! "); + } + break; + } + } + LOGH("X"); + return rc; +} + +/*=========================================================================== + * FUNCTION : stop_recording + * + * DESCRIPTION: Stops recording on camcorder + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : None + *==========================================================================*/ +void QCameraMuxer::stop_recording(struct camera_device * device) +{ + + int rc = NO_ERROR; + LOGH("E"); + + CHECK_MUXER(); + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI(hwi); + + if (pCam->mode == CAM_MODE_PRIMARY) { + QCamera2HardwareInterface::stop_recording(pCam->dev); + break; + } + } + + // If recording hint is set internally to TRUE, + // we need to set it to FALSE. + // preview restart is needed in between + if (gMuxer->m_bRecordingHintInternallySet) { + // stop the preview first + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI(hwi); + + rc = hwi->restart_stop_preview(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error in restart stop preview!! "); + return; + } + } + + // Update the recording hint value to FALSE + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI(hwi); + + rc = hwi->setRecordingHintValue(FALSE); + if (rc != NO_ERROR) { + LOGE("Error in setting recording hint value!! "); + return; + } + gMuxer->m_bRecordingHintInternallySet = FALSE; + } + + // start the preview + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI(hwi); + + rc = hwi->restart_start_preview(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error in restart start preview!! "); + return; + } + } + } + LOGH("X"); +} + +/*=========================================================================== + * FUNCTION : recording_enabled + * + * DESCRIPTION: Checks for recording enabled + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : true/false + *==========================================================================*/ +int QCameraMuxer::recording_enabled(struct camera_device * device) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + if (pCam->mode == CAM_MODE_PRIMARY) { + return hwi->recording_enabled(pCam->dev); + } + } + LOGH("X"); + return false; +} + +/*=========================================================================== + * FUNCTION : release_recording_frame + * + * DESCRIPTION: Release the recording frame + * + * PARAMETERS : + * @device : camera hardware device info + * @opaque: Frame to be released + * + * RETURN : None + *==========================================================================*/ +void QCameraMuxer::release_recording_frame(struct camera_device * device, + const void *opaque) +{ + LOGH("E"); + CHECK_MUXER(); + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI(hwi); + + if (pCam->mode == CAM_MODE_PRIMARY) { + QCamera2HardwareInterface::release_recording_frame(pCam->dev, opaque); + break; + } + } + LOGH("X"); +} + +/*=========================================================================== + * FUNCTION : auto_focus + * + * DESCRIPTION: Performs auto focus on camera + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::auto_focus(struct camera_device * device) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + int rc = NO_ERROR; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + // Call auto focus on main camera + if (pCam->mode == CAM_MODE_PRIMARY) { + rc = QCamera2HardwareInterface::auto_focus(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error auto focusing !! "); + return rc; + } + break; + } + } + LOGH("X"); + return rc; +} + +/*=========================================================================== + * FUNCTION : cancel_auto_focus + * + * DESCRIPTION: Cancels auto focus + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::cancel_auto_focus(struct camera_device * device) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + int rc = NO_ERROR; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + // Cancel auto focus on primary camera + if (pCam->mode == CAM_MODE_PRIMARY) { + rc = QCamera2HardwareInterface::cancel_auto_focus(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error cancelling auto focus !! "); + return rc; + } + break; + } + } + LOGH("X"); + return rc; +} + +/*=========================================================================== + * FUNCTION : take_picture + * + * DESCRIPTION: Take snapshots on device + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::take_picture(struct camera_device * device) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + int rc = NO_ERROR; + bool previewRestartNeeded = false; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + char prop[PROPERTY_VALUE_MAX]; + property_get("persist.camera.dual.camera.mpo", prop, "1"); + gMuxer->m_bMpoEnabled = atoi(prop); + // If only one Physical Camera included in Logical, disable MPO + int numOfAcitvePhyCam = 0; + gMuxer->getActiveNumOfPhyCam(cam, numOfAcitvePhyCam); + if (gMuxer->m_bMpoEnabled && numOfAcitvePhyCam <= 1) { + gMuxer->m_bMpoEnabled = 0; + } + LOGH("dualCamera MPO Enabled:%d ", gMuxer->m_bMpoEnabled); + + if (!gMuxer->mJpegClientHandle) { + // set up jpeg handles + pCam = gMuxer->getPhysicalCamera(cam, 0); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = hwi->getJpegHandleInfo(&gMuxer->mJpegOps, &gMuxer->mJpegMpoOps, + &gMuxer->mJpegClientHandle); + if (rc != NO_ERROR) { + LOGE("Error retrieving jpeg handle!"); + return rc; + } + + for (uint32_t i = 1; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = hwi->setJpegHandleInfo(&gMuxer->mJpegOps, &gMuxer->mJpegMpoOps, + gMuxer->mJpegClientHandle); + if (rc != NO_ERROR) { + LOGE("Error setting jpeg handle %d!", i); + return rc; + } + } + } + + // prepare snapshot for main camera + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + if (pCam->mode == CAM_MODE_PRIMARY) { + rc = hwi->prepare_snapshot(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error preparing for snapshot !! "); + return rc; + } + } + // set Mpo composition for each session + rc = hwi->setMpoComposition(gMuxer->m_bMpoEnabled); + //disable MPO if AOST features are enabled + if (rc != NO_ERROR) { + gMuxer->m_bMpoEnabled = 0; + rc = NO_ERROR; + } + } + + // initialize Jpeg Queues + gMuxer->m_MainJpegQ.init(); + gMuxer->m_AuxJpegQ.init(); + gMuxer->m_ComposeMpoTh.sendCmd( + CAMERA_CMD_TYPE_START_DATA_PROC, FALSE, FALSE); + + // In cases where recording hint is set, preview is running, + // hwi->take_picture will internally restart the preview. + // To take the preview restart control in muxer, + // 1. call pre_take_picture first + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + // no need to call pre_take_pic on Aux if not MPO (for AOST,liveshot...etc.) + if ( (gMuxer->m_bMpoEnabled == 1) || (pCam->mode == CAM_MODE_PRIMARY) ) { + rc = hwi->pre_take_picture(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error preparing take_picture!! "); + return rc; + } + } + } + + // 2. Check if preview restart is needed. Check all cameras. + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + if (hwi->isPreviewRestartNeeded()) { + previewRestartNeeded = hwi->isPreviewRestartNeeded(); + break; + } + } + + if (previewRestartNeeded) { + // 3. if preview restart needed. stop the preview first + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = hwi->restart_stop_preview(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error in restart stop preview!! "); + return rc; + } + } + + //4. Update the recording hint value to FALSE + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = hwi->setRecordingHintValue(FALSE); + if (rc != NO_ERROR) { + LOGE("Error in setting recording hint value!! "); + return rc; + } + } + + // 5. start the preview + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = hwi->restart_start_preview(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error in restart start preview!! "); + return rc; + } + } + } + + // As frame sync for dual cameras is enabled, the take picture call + // for secondary camera is handled only till HAL level to init corresponding + // pproc channel and update statemachine. + // This call is forwarded to mm-camera-intf only for primary camera + // Primary camera should receive the take picture call after all secondary + // camera statemachines are updated + for (int32_t i = cam->numCameras-1 ; i >= 0; i--) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + // no need to call take_pic on Aux if not MPO (for AOST) + if ( (gMuxer->m_bMpoEnabled == 1) || (pCam->mode == CAM_MODE_PRIMARY) ) { + rc = QCamera2HardwareInterface::take_picture(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error taking picture !! "); + return rc; + } + } + } + LOGH("X"); + return rc; +} + +/*=========================================================================== + * FUNCTION : cancel_picture + * + * DESCRIPTION: Cancel the take picture call + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::cancel_picture(struct camera_device * device) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + int rc = NO_ERROR; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = QCamera2HardwareInterface::cancel_picture(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error cancelling picture !! "); + return rc; + } + } + gMuxer->m_ComposeMpoTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, FALSE, FALSE); + // flush Jpeg Queues + gMuxer->m_MainJpegQ.flush(); + gMuxer->m_AuxJpegQ.flush(); + + LOGH("X"); + return rc; +} + +/*=========================================================================== + * FUNCTION : set_parameters + * + * DESCRIPTION: Sets the parameters on camera + * + * PARAMETERS : + * @device : camera hardware device info + * @parms : Parameters to be set on camera + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::set_parameters(struct camera_device * device, + const char *parms) + +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + int rc = NO_ERROR; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + bool needRestart = false; + CHECK_CAMERA_ERROR(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = QCamera2HardwareInterface::set_parameters(pCam->dev, parms); + if (rc != NO_ERROR) { + LOGE("Error setting parameters !! "); + return rc; + } + + needRestart |= hwi->getNeedRestart(); + } + + if (needRestart) { + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + LOGD("stopping preview for cam %d", i); + rc = QCamera2HardwareInterface::stop_after_set_params(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error stopping camera rc=%d!! ", rc); + return rc; + } + } + } + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + LOGD("commiting parameters for cam %d", i); + rc = QCamera2HardwareInterface::commit_params(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error committing parameters rc=%d!! ", rc); + return rc; + } + } + + if (needRestart) { + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + LOGD("restarting preview for cam %d", i); + rc = QCamera2HardwareInterface::restart_after_set_params(pCam->dev); + if (rc != NO_ERROR) { + LOGE("Error restarting camera rc=%d!! ", rc); + return rc; + } + } + } + + LOGH(" X"); + return rc; +} + +/*=========================================================================== + * FUNCTION : get_parameters + * + * DESCRIPTION: Gets the parameters on camera + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : Parameter string or NULL + *==========================================================================*/ +char* QCameraMuxer::get_parameters(struct camera_device * device) +{ + LOGH("E"); + + if (!gMuxer) + return NULL; + + char* ret = NULL; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + if (!cam) { + LOGE("Error getting logical camera"); + return NULL; + } + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + if (!pCam) { + LOGE("Error getting physical camera"); + return NULL; + } + QCamera2HardwareInterface *hwi = pCam->hwi; + if (!hwi) { + LOGE("Allocation of hardware interface failed"); + return NULL; + } + if (pCam->mode == CAM_MODE_PRIMARY) { + // Get only primary camera parameters + ret = QCamera2HardwareInterface::get_parameters(pCam->dev); + break; + } + } + + LOGH("X"); + return ret; +} + +/*=========================================================================== + * FUNCTION : put_parameters + * + * DESCRIPTION: Puts parameters on camera + * + * PARAMETERS : + * @device : camera hardware device info + * @parm : parameters + * + * RETURN : None + *==========================================================================*/ +void QCameraMuxer::put_parameters(struct camera_device * device, char *parm) +{ + LOGH("E"); + CHECK_MUXER(); + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI(hwi); + + if (pCam->mode == CAM_MODE_PRIMARY) { + // Parameters are not used in HWI and hence freed + QCamera2HardwareInterface::put_parameters(pCam->dev, parm); + break; + } + } + LOGH("X"); +} + +/*=========================================================================== + * FUNCTION : send_command + * + * DESCRIPTION: Send command to camera + * + * PARAMETERS : + * @device : camera hardware device info + * @cmd : Command + * @arg1/arg2 : command arguments + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::send_command(struct camera_device * device, + int32_t cmd, int32_t arg1, int32_t arg2) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + int rc = NO_ERROR; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = QCamera2HardwareInterface::send_command(pCam->dev, cmd, arg1, arg2); + if (rc != NO_ERROR) { + LOGE("Error sending command !! "); + return rc; + } + } + + switch (cmd) { +#ifndef VANILLA_HAL + case CAMERA_CMD_LONGSHOT_ON: + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = QCamera2HardwareInterface::send_command_restart(pCam->dev, + cmd, arg1, arg2); + if (rc != NO_ERROR) { + LOGE("Error sending command restart !! "); + return rc; + } + } + break; + case CAMERA_CMD_LONGSHOT_OFF: + gMuxer->m_ComposeMpoTh.sendCmd(CAMERA_CMD_TYPE_STOP_DATA_PROC, + FALSE, FALSE); + // flush Jpeg Queues + gMuxer->m_MainJpegQ.flush(); + gMuxer->m_AuxJpegQ.flush(); + break; +#endif + default: + // do nothing + rc = NO_ERROR; + break; + } + + LOGH("X"); + return rc; +} + +/*=========================================================================== + * FUNCTION : release + * + * DESCRIPTION: Release the camera + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : None + *==========================================================================*/ +void QCameraMuxer::release(struct camera_device * device) +{ + LOGH("E"); + CHECK_MUXER(); + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI(hwi); + + QCamera2HardwareInterface::release(pCam->dev); + } + LOGH("X"); +} + +/*=========================================================================== + * FUNCTION : dump + * + * DESCRIPTION: Dump the camera info + * + * PARAMETERS : + * @device : camera hardware device info + * @fd : fd + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::dump(struct camera_device * device, int fd) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + int rc = NO_ERROR; + qcamera_physical_descriptor_t *pCam = NULL; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(device); + CHECK_CAMERA_ERROR(cam); + + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + rc = QCamera2HardwareInterface::dump(pCam->dev, fd); + if (rc != NO_ERROR) { + LOGE("Error dumping"); + return rc; + } + } + LOGH("X"); + return rc; +} + +/*=========================================================================== + * FUNCTION : close_camera_device + * + * DESCRIPTION: Close the camera + * + * PARAMETERS : + * @hw_dev : camera hardware device info + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::close_camera_device(hw_device_t *hw_dev) +{ + LOGH("E"); + CHECK_MUXER_ERROR(); + int rc = NO_ERROR; + qcamera_physical_descriptor_t *pCam = NULL; + camera_device_t *cam_dev = (camera_device_t*)hw_dev; + qcamera_logical_descriptor_t *cam = gMuxer->getLogicalCamera(cam_dev); + CHECK_CAMERA_ERROR(cam); + + // Unlink camera sessions + if (cam->bSyncOn) { + if (cam->numCameras > 1) { + uint sessionId = 0; + // unbundle primary camera with all aux cameras + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + if(pCam->mode == CAM_MODE_PRIMARY) { + // bundle primary cam with all aux cameras + for (uint32_t j = 0; j < cam->numCameras; j++) { + if (j == cam->nPrimaryPhyCamIndex) { + continue; + } + sessionId = cam->sId[j]; + LOGH("Related cam id: %d, server id: %d sync OFF" + " related session_id %d", + cam->pId[i], cam->sId[i], sessionId); + rc = hwi->bundleRelatedCameras(false, sessionId); + if (rc != NO_ERROR) { + LOGE("Error Bundling physical cameras !! "); + break; + } + } + } + + if (pCam->mode == CAM_MODE_SECONDARY) { + // unbundle all aux cam with primary cams + sessionId = cam->sId[cam->nPrimaryPhyCamIndex]; + LOGH("Related cam id: %d, server id: %d sync OFF" + " related session_id %d", + cam->pId[i], cam->sId[i], sessionId); + rc = hwi->bundleRelatedCameras(false, sessionId); + if (rc != NO_ERROR) { + LOGE("Error Bundling physical cameras !! "); + break; + } + } + } + } + cam->bSyncOn = false; + } + + // Attempt to close all cameras regardless of unbundle results + for (uint32_t i = 0; i < cam->numCameras; i++) { + pCam = gMuxer->getPhysicalCamera(cam, i); + CHECK_CAMERA_ERROR(pCam); + + hw_device_t *dev = (hw_device_t*)(pCam->dev); + LOGH("hw device %x, hw %x", dev, pCam->hwi); + + rc = QCamera2HardwareInterface::close_camera_device(dev); + if (rc != NO_ERROR) { + LOGE("Error closing camera"); + } + pCam->hwi = NULL; + pCam->dev = NULL; + } + + // Reset JPEG client handle + gMuxer->setJpegHandle(0); + LOGH("X, rc: %d", rc); + return rc; +} + +/*=========================================================================== + * FUNCTION : setupLogicalCameras + * + * DESCRIPTION : Creates Camera Muxer if not created + * + * RETURN : + * NO_ERROR : success + * other: non-zero failure code + *==========================================================================*/ +int QCameraMuxer::setupLogicalCameras() +{ + int rc = NO_ERROR; + char prop[PROPERTY_VALUE_MAX]; + int i = 0; + int primaryType = CAM_TYPE_MAIN; + + LOGH("[%d] E: rc = %d", rc); + // Signifies whether AUX camera has to be exposed as physical camera + property_get("persist.camera.aux.camera", prop, "0"); + m_bAuxCameraExposed = atoi(prop); + + // Signifies whether AUX camera needs to be swapped + property_get("persist.camera.auxcamera.swap", prop, "0"); + int swapAux = atoi(prop); + if (swapAux != 0) { + primaryType = CAM_TYPE_AUX; + } + + // Check for number of camera present on device + if (!m_nPhyCameras || (m_nPhyCameras > MM_CAMERA_MAX_NUM_SENSORS)) { + LOGE("Error!! Invalid number of cameras: %d", + m_nPhyCameras); + return BAD_VALUE; + } + + m_pPhyCamera = new qcamera_physical_descriptor_t[m_nPhyCameras]; + if (!m_pPhyCamera) { + LOGE("Error allocating camera info buffer!!"); + return NO_MEMORY; + } + memset(m_pPhyCamera, 0x00, + (m_nPhyCameras * sizeof(qcamera_physical_descriptor_t))); + uint32_t cameraId = 0; + m_nLogicalCameras = 0; + + // Enumerate physical cameras and logical + for (i = 0; i < m_nPhyCameras ; i++, cameraId++) { + camera_info *info = &m_pPhyCamera[i].cam_info; + rc = QCamera2HardwareInterface::getCapabilities(cameraId, + info, &m_pPhyCamera[i].type); + m_pPhyCamera[i].id = cameraId; + m_pPhyCamera[i].device_version = CAMERA_DEVICE_API_VERSION_1_0; + m_pPhyCamera[i].mode = CAM_MODE_PRIMARY; + + if (!m_bAuxCameraExposed && (m_pPhyCamera[i].type != primaryType)) { + m_pPhyCamera[i].mode = CAM_MODE_SECONDARY; + LOGH("Camera ID: %d, Aux Camera, type: %d, facing: %d", + cameraId, m_pPhyCamera[i].type, + m_pPhyCamera[i].cam_info.facing); + } + else { + m_nLogicalCameras++; + LOGH("Camera ID: %d, Main Camera, type: %d, facing: %d", + cameraId, m_pPhyCamera[i].type, + m_pPhyCamera[i].cam_info.facing); + } + } + + if (!m_nLogicalCameras) { + // No Main camera detected, return from here + LOGE("Error !!!! detecting main camera!!"); + delete [] m_pPhyCamera; + m_pPhyCamera = NULL; + return -ENODEV; + } + // Allocate Logical Camera descriptors + m_pLogicalCamera = new qcamera_logical_descriptor_t[m_nLogicalCameras]; + if (!m_pLogicalCamera) { + LOGE("Error !!!! allocating camera info buffer!!"); + delete [] m_pPhyCamera; + m_pPhyCamera = NULL; + return NO_MEMORY; + } + memset(m_pLogicalCamera, 0x00, + (m_nLogicalCameras * sizeof(qcamera_logical_descriptor_t))); + // Assign MAIN cameras for each logical camera + int index = 0; + for (i = 0; i < m_nPhyCameras ; i++) { + if (m_pPhyCamera[i].mode == CAM_MODE_PRIMARY) { + m_pLogicalCamera[index].nPrimaryPhyCamIndex = 0; + m_pLogicalCamera[index].id = index; + m_pLogicalCamera[index].device_version = CAMERA_DEVICE_API_VERSION_1_0; + m_pLogicalCamera[index].pId[0] = i; + m_pLogicalCamera[index].type[0] = CAM_TYPE_MAIN; + m_pLogicalCamera[index].mode[0] = CAM_MODE_PRIMARY; + m_pLogicalCamera[index].facing = m_pPhyCamera[i].cam_info.facing; + m_pLogicalCamera[index].numCameras++; + LOGH("Logical Main Camera ID: %d, facing: %d," + "Phy Id: %d type: %d mode: %d", + m_pLogicalCamera[index].id, + m_pLogicalCamera[index].facing, + m_pLogicalCamera[index].pId[0], + m_pLogicalCamera[index].type[0], + m_pLogicalCamera[index].mode[0]); + + index++; + } + } + //Now assign AUX cameras to logical camera + for (i = 0; i < m_nPhyCameras ; i++) { + if (m_pPhyCamera[i].mode == CAM_MODE_SECONDARY) { + for (int j = 0; j < m_nLogicalCameras; j++) { + int n = m_pLogicalCamera[j].numCameras; + ///@note n can only be 1 at this point + if ((n < MAX_NUM_CAMERA_PER_BUNDLE) && + (m_pLogicalCamera[j].facing == + m_pPhyCamera[i].cam_info.facing)) { + m_pLogicalCamera[j].pId[n] = i; + m_pLogicalCamera[j].type[n] = CAM_TYPE_AUX; + m_pLogicalCamera[j].mode[n] = CAM_MODE_SECONDARY; + m_pLogicalCamera[j].numCameras++; + LOGH("Aux %d for Logical Camera ID: %d," + "aux phy id:%d, type: %d mode: %d", + n, j, m_pLogicalCamera[j].pId[n], + m_pLogicalCamera[j].type[n], m_pLogicalCamera[j].mode[n]); + } + } + } + } + //Print logical and physical camera tables + for (i = 0; i < m_nLogicalCameras ; i++) { + for (uint8_t j = 0; j < m_pLogicalCamera[i].numCameras; j++) { + LOGH("Logical Camera ID: %d, index: %d, " + "facing: %d, Phy Id: %d type: %d mode: %d", + i, j, m_pLogicalCamera[i].facing, + m_pLogicalCamera[i].pId[j], m_pLogicalCamera[i].type[j], + m_pLogicalCamera[i].mode[j]); + } + } + LOGH("[%d] X: rc = %d", rc); + return rc; +} + +/*=========================================================================== + * FUNCTION : getNumberOfCameras + * + * DESCRIPTION: query number of logical cameras detected + * + * RETURN : number of cameras detected + *==========================================================================*/ +int QCameraMuxer::getNumberOfCameras() +{ + return m_nLogicalCameras; +} + +/*=========================================================================== + * FUNCTION : getCameraInfo + * + * DESCRIPTION: query camera information with its ID + * + * PARAMETERS : + * @camera_id : camera ID + * @info : ptr to camera info struct + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int QCameraMuxer::getCameraInfo(int camera_id, + struct camera_info *info, __unused cam_sync_type_t *p_cam_type) +{ + int rc = NO_ERROR; + LOGH("E, camera_id = %d", camera_id); + cam_sync_type_t cam_type = CAM_TYPE_MAIN; + + if (!m_nLogicalCameras || (camera_id >= m_nLogicalCameras) || + !info || (camera_id < 0)) { + LOGE("m_nLogicalCameras: %d, camera id: %d", + m_nLogicalCameras, camera_id); + return -ENODEV; + } + + if (!m_pLogicalCamera || !m_pPhyCamera) { + LOGE("Error! Cameras not initialized!"); + return NO_INIT; + } + uint32_t phy_id = + m_pLogicalCamera[camera_id].pId[ + m_pLogicalCamera[camera_id].nPrimaryPhyCamIndex]; + // Call HAL3 getCamInfo to get the flash light info through static metatdata + // regardless of HAL version + rc = QCamera3HardwareInterface::getCamInfo(phy_id, info); + info->device_version = CAMERA_DEVICE_API_VERSION_1_0; // Hardcode the HAL to HAL1 + LOGH("X"); + return rc; +} + +/*=========================================================================== + * FUNCTION : setCallbacks + * + * DESCRIPTION: set callback functions to send asynchronous notifications to + * frameworks. + * + * PARAMETERS : + * @callbacks : callback function pointer + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCameraMuxer::setCallbacks(const camera_module_callbacks_t *callbacks) +{ + if(callbacks) { + m_pCallbacks = callbacks; + return NO_ERROR; + } else { + return BAD_TYPE; + } +} + +/*=========================================================================== + * FUNCTION : setDataCallback + * + * DESCRIPTION: set data callback function for snapshots + * + * PARAMETERS : + * @data_cb : callback function pointer + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCameraMuxer::setDataCallback(camera_data_callback data_cb) +{ + if(data_cb) { + mDataCb = data_cb; + return NO_ERROR; + } else { + return BAD_TYPE; + } +} + +/*=========================================================================== + * FUNCTION : setMemoryCallback + * + * DESCRIPTION: set get memory callback for memory allocations + * + * PARAMETERS : + * @get_memory : callback function pointer + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCameraMuxer::setMemoryCallback(camera_request_memory get_memory) +{ + if(get_memory) { + mGetMemoryCb = get_memory; + return NO_ERROR; + } else { + return BAD_TYPE; + } +} + +/*=========================================================================== + * FUNCTION : setMpoCallbackCookie + * + * DESCRIPTION: set mpo callback cookie. will be used for sending final MPO callbacks + * to framework + * + * PARAMETERS : + * @mpoCbCookie : callback function pointer + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCameraMuxer::setMpoCallbackCookie(void* mpoCbCookie) +{ + if(mpoCbCookie) { + m_pMpoCallbackCookie = mpoCbCookie; + return NO_ERROR; + } else { + return BAD_TYPE; + } +} + +/*=========================================================================== + * FUNCTION : getMpoCallbackCookie + * + * DESCRIPTION: gets the mpo callback cookie. will be used for sending final MPO callbacks + * to framework + * + * PARAMETERS :none + * + * RETURN :void ptr to the mpo callback cookie + *==========================================================================*/ +void* QCameraMuxer::getMpoCallbackCookie(void) +{ + return m_pMpoCallbackCookie; +} + +/*=========================================================================== + * FUNCTION : setMainJpegCallbackCookie + * + * DESCRIPTION: set jpeg callback cookie. + * set to phy cam instance of the primary related cam instance + * + * PARAMETERS : + * @jpegCbCookie : ptr to jpeg cookie + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCameraMuxer::setMainJpegCallbackCookie(void* jpegCbCookie) +{ + if(jpegCbCookie) { + m_pJpegCallbackCookie = jpegCbCookie; + return NO_ERROR; + } else { + return BAD_TYPE; + } +} + +/*=========================================================================== + * FUNCTION : getMainJpegCallbackCookie + * + * DESCRIPTION: gets the jpeg callback cookie for primary related cam instance + * set to phy cam instance of the primary related cam instance + * + * PARAMETERS :none + * + * RETURN :void ptr to the jpeg callback cookie + *==========================================================================*/ +void* QCameraMuxer::getMainJpegCallbackCookie(void) +{ + return m_pJpegCallbackCookie; +} + +/*=========================================================================== + * FUNCTION : cameraDeviceOpen + * + * DESCRIPTION: open a camera device with its ID + * + * PARAMETERS : + * @camera_id : camera ID + * @hw_device : ptr to struct storing camera hardware device info + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int QCameraMuxer::cameraDeviceOpen(int camera_id, + struct hw_device_t **hw_device) +{ + int rc = NO_ERROR; + uint32_t phyId = 0; + qcamera_logical_descriptor_t *cam = NULL; + + if (camera_id < 0 || camera_id >= m_nLogicalCameras) { + LOGE("Camera id %d not found!", camera_id); + return -ENODEV; + } + + if ( NULL == m_pLogicalCamera) { + LOGE("Hal descriptor table is not initialized!"); + return NO_INIT; + } + + char prop[PROPERTY_VALUE_MAX]; + property_get("persist.camera.dc.frame.sync", prop, "1"); + m_bFrameSyncEnabled = atoi(prop); + + // Get logical camera + cam = &m_pLogicalCamera[camera_id]; + + if (m_pLogicalCamera[camera_id].device_version == + CAMERA_DEVICE_API_VERSION_1_0) { + // HW Dev Holders + hw_device_t *hw_dev[cam->numCameras]; + + if (m_pPhyCamera[cam->pId[0]].type != CAM_TYPE_MAIN) { + LOGE("Physical camera at index 0 is not main!"); + return UNKNOWN_ERROR; + } + + // Open all physical cameras + for (uint32_t i = 0; i < cam->numCameras; i++) { + phyId = cam->pId[i]; + QCamera2HardwareInterface *hw = + new QCamera2HardwareInterface((uint32_t)phyId); + if (!hw) { + LOGE("Allocation of hardware interface failed"); + return NO_MEMORY; + } + hw_dev[i] = NULL; + + // Make Camera HWI aware of its mode + cam_sync_related_sensors_event_info_t info; + info.sync_control = CAM_SYNC_RELATED_SENSORS_ON; + info.mode = m_pPhyCamera[phyId].mode; + info.type = m_pPhyCamera[phyId].type; + rc = hw->setRelatedCamSyncInfo(&info); + hw->setFrameSyncEnabled(m_bFrameSyncEnabled); + if (rc != NO_ERROR) { + LOGE("setRelatedCamSyncInfo failed %d", rc); + delete hw; + return rc; + } + + rc = hw->openCamera(&hw_dev[i]); + if (rc != NO_ERROR) { + delete hw; + return rc; + } + hw->getCameraSessionId(&m_pPhyCamera[phyId].camera_server_id); + m_pPhyCamera[phyId].dev = reinterpret_cast<camera_device_t*>(hw_dev[i]); + m_pPhyCamera[phyId].hwi = hw; + cam->sId[i] = m_pPhyCamera[phyId].camera_server_id; + LOGH("camera id %d server id : %d hw device %x, hw %x", + phyId, cam->sId[i], hw_dev[i], hw); + } + } else { + LOGE("Device version for camera id %d invalid %d", + camera_id, m_pLogicalCamera[camera_id].device_version); + return BAD_VALUE; + } + + cam->dev.common.tag = HARDWARE_DEVICE_TAG; + cam->dev.common.version = HARDWARE_DEVICE_API_VERSION(1, 0); + cam->dev.common.close = close_camera_device; + cam->dev.ops = &mCameraMuxerOps; + cam->dev.priv = (void*)cam; + *hw_device = &cam->dev.common; + return rc; +} + + +/*=========================================================================== + * FUNCTION : getLogicalCamera + * + * DESCRIPTION: Get logical camera descriptor + * + * PARAMETERS : + * @device : camera hardware device info + * + * RETURN : logical camera descriptor or NULL + *==========================================================================*/ +qcamera_logical_descriptor_t* QCameraMuxer::getLogicalCamera( + struct camera_device * device) +{ + if(device && device->priv){ + return (qcamera_logical_descriptor_t*)(device->priv); + } + return NULL; +} + +/*=========================================================================== + * FUNCTION : getPhysicalCamera + * + * DESCRIPTION: Get physical camera descriptor + * + * PARAMETERS : + * @log_cam : Logical camera descriptor + * @index : physical camera index + * + * RETURN : physical camera descriptor or NULL + *==========================================================================*/ +qcamera_physical_descriptor_t* QCameraMuxer::getPhysicalCamera( + qcamera_logical_descriptor_t* log_cam, uint32_t index) +{ + if(!log_cam){ + return NULL; + } + return &m_pPhyCamera[log_cam->pId[index]]; +} + +/*=========================================================================== + * FUNCTION : getActiveNumOfPhyCam + * + * DESCRIPTION: Get active physical camera number in Logical Camera + * + * PARAMETERS : + * @log_cam : Logical camera descriptor + * @numOfAcitvePhyCam : number of active physical camera in Logical Camera. + * + * RETURN : + * NO_ERROR : success + * ENODEV : Camera not found + * other: non-zero failure code + *==========================================================================*/ +int32_t QCameraMuxer::getActiveNumOfPhyCam( + qcamera_logical_descriptor_t* log_cam, int& numOfAcitvePhyCam) +{ + CHECK_CAMERA_ERROR(log_cam); + + numOfAcitvePhyCam = log_cam->numCameras; + return NO_ERROR; +} + + +/*=========================================================================== + * FUNCTION : sendEvtNotify + * + * DESCRIPTION: send event notify to HWI for error callbacks + * + * PARAMETERS : + * @msg_type: msg type to be sent + * @ext1 : optional extension1 + * @ext2 : optional extension2 + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCameraMuxer::sendEvtNotify(int32_t msg_type, int32_t ext1, + int32_t ext2) +{ + LOGH("E"); + + CHECK_MUXER_ERROR(); + + qcamera_physical_descriptor_t *pCam = NULL; + pCam = (qcamera_physical_descriptor_t*)(gMuxer->getMainJpegCallbackCookie()); + + CHECK_CAMERA_ERROR(pCam); + + QCamera2HardwareInterface *hwi = pCam->hwi; + CHECK_HWI_ERROR(hwi); + + LOGH("X"); + return pCam->hwi->sendEvtNotify(msg_type, ext1, ext2); +} + +/*=========================================================================== + * FUNCTION : composeMpo + * + * DESCRIPTION: Composition of the 2 MPOs + * + * PARAMETERS : none + * @main_Jpeg: pointer to info to Main Jpeg + * @aux_Jpeg : pointer to info to Aux JPEG + * + * RETURN : none + *==========================================================================*/ +void QCameraMuxer::composeMpo(cam_compose_jpeg_info_t* main_Jpeg, + cam_compose_jpeg_info_t* aux_Jpeg) +{ + LOGH("E Main Jpeg %p Aux Jpeg %p", main_Jpeg, aux_Jpeg); + + CHECK_MUXER(); + if(main_Jpeg == NULL || aux_Jpeg == NULL) { + LOGE("input buffers invalid, ret = NO_MEMORY"); + gMuxer->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); + return; + } + + pthread_mutex_lock(&m_JpegLock); + + m_pRelCamMpoJpeg = mGetMemoryCb(-1, main_Jpeg->buffer->size + + aux_Jpeg->buffer->size, 1, m_pMpoCallbackCookie); + if (NULL == m_pRelCamMpoJpeg) { + LOGE("getMemory for mpo, ret = NO_MEMORY"); + gMuxer->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); + pthread_mutex_unlock(&m_JpegLock); + return; + } + + // fill all structures to send for composition + mm_jpeg_mpo_info_t mpo_compose_info; + mpo_compose_info.num_of_images = 2; + mpo_compose_info.primary_image.buf_filled_len = main_Jpeg->buffer->size; + mpo_compose_info.primary_image.buf_vaddr = + (uint8_t*)(main_Jpeg->buffer->data); + mpo_compose_info.aux_images[0].buf_filled_len = aux_Jpeg->buffer->size; + mpo_compose_info.aux_images[0].buf_vaddr = + (uint8_t*)(aux_Jpeg->buffer->data); + mpo_compose_info.output_buff.buf_vaddr = + (uint8_t*)m_pRelCamMpoJpeg->data; + mpo_compose_info.output_buff.buf_filled_len = 0; + mpo_compose_info.output_buff_size = main_Jpeg->buffer->size + + aux_Jpeg->buffer->size; + + LOGD("MPO buffer size %d\n" + "expected size %d, mpo_compose_info.output_buff_size %d", + m_pRelCamMpoJpeg->size, + main_Jpeg->buffer->size + aux_Jpeg->buffer->size, + mpo_compose_info.output_buff_size); + + LOGD("MPO primary buffer filled lengths\n" + "mpo_compose_info.primary_image.buf_filled_len %d\n" + "mpo_compose_info.primary_image.buf_vaddr %p", + mpo_compose_info.primary_image.buf_filled_len, + mpo_compose_info.primary_image.buf_vaddr); + + LOGD("MPO aux buffer filled lengths\n" + "mpo_compose_info.aux_images[0].buf_filled_len %d" + "mpo_compose_info.aux_images[0].buf_vaddr %p", + mpo_compose_info.aux_images[0].buf_filled_len, + mpo_compose_info.aux_images[0].buf_vaddr); + + if(m_bDumpImages) { + LOGD("Dumping Main Image for MPO"); + char buf_main[QCAMERA_MAX_FILEPATH_LENGTH]; + memset(buf_main, 0, sizeof(buf_main)); + snprintf(buf_main, sizeof(buf_main), + QCAMERA_DUMP_FRM_LOCATION "Main.jpg"); + + int file_fd_main = open(buf_main, O_RDWR | O_CREAT, 0777); + if (file_fd_main >= 0) { + ssize_t written_len = write(file_fd_main, + mpo_compose_info.primary_image.buf_vaddr, + mpo_compose_info.primary_image.buf_filled_len); + fchmod(file_fd_main, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + LOGD("written number of bytes for main Image %zd\n", + written_len); + close(file_fd_main); + } + + LOGD("Dumping Aux Image for MPO"); + char buf_aux[QCAMERA_MAX_FILEPATH_LENGTH]; + memset(buf_aux, 0, sizeof(buf_aux)); + snprintf(buf_aux, sizeof(buf_aux), + QCAMERA_DUMP_FRM_LOCATION "Aux.jpg"); + + int file_fd_aux = open(buf_aux, O_RDWR | O_CREAT, 0777); + if (file_fd_aux >= 0) { + ssize_t written_len = write(file_fd_aux, + mpo_compose_info.aux_images[0].buf_vaddr, + mpo_compose_info.aux_images[0].buf_filled_len); + fchmod(file_fd_aux, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + LOGD("written number of bytes for Aux Image %zd\n", + written_len); + close(file_fd_aux); + } + } + + int32_t rc = mJpegMpoOps.compose_mpo(&mpo_compose_info); + LOGD("Compose mpo returned %d", rc); + + if(rc != NO_ERROR) { + LOGE("ComposeMpo failed, ret = %d", rc); + gMuxer->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); + pthread_mutex_unlock(&m_JpegLock); + return; + } + + if(m_bDumpImages) { + char buf_mpo[QCAMERA_MAX_FILEPATH_LENGTH]; + memset(buf_mpo, 0, sizeof(buf_mpo)); + snprintf(buf_mpo, sizeof(buf_mpo), + QCAMERA_DUMP_FRM_LOCATION "Composed.MPO"); + + int file_fd_mpo = open(buf_mpo, O_RDWR | O_CREAT, 0777); + if (file_fd_mpo >= 0) { + ssize_t written_len = write(file_fd_mpo, + m_pRelCamMpoJpeg->data, + m_pRelCamMpoJpeg->size); + fchmod(file_fd_mpo, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + LOGD("written number of bytes for MPO Image %zd\n", + written_len); + close(file_fd_mpo); + } + } + + mDataCb(main_Jpeg->msg_type, + m_pRelCamMpoJpeg, + main_Jpeg->index, + main_Jpeg->metadata, + m_pMpoCallbackCookie); + + if (NULL != m_pRelCamMpoJpeg) { + m_pRelCamMpoJpeg->release(m_pRelCamMpoJpeg); + m_pRelCamMpoJpeg = NULL; + } + + pthread_mutex_unlock(&m_JpegLock); + LOGH("X"); + return; +} + +/*=========================================================================== + * FUNCTION : matchFrameId + * + * DESCRIPTION: function to match frame ids within queue nodes + * + * PARAMETERS : + * @data: pointer to queue node to be matched for condition + * @user_data: caller can add more info here + * @match_data : value to be matched against + * + * RETURN : true or false based on whether match was successful or not + *==========================================================================*/ +bool QCameraMuxer::matchFrameId(void *data, __unused void *user_data, + void *match_data) +{ + LOGH("E"); + + if (!data || !match_data) { + return false; + } + + cam_compose_jpeg_info_t * node = (cam_compose_jpeg_info_t *) data; + uint32_t frame_idx = *((uint32_t *) match_data); + LOGH("X"); + return node->frame_idx == frame_idx; +} + +/*=========================================================================== + * FUNCTION : findPreviousJpegs + * + * DESCRIPTION: Finds Jpegs in the queue with index less than delivered one + * + * PARAMETERS : + * @data: pointer to queue node to be matched for condition + * @user_data: caller can add more info here + * @match_data : value to be matched against + * + * RETURN : true or false based on whether match was successful or not + *==========================================================================*/ +bool QCameraMuxer::findPreviousJpegs(void *data, __unused void *user_data, + void *match_data) +{ + LOGH("E"); + + if (!data || !match_data) { + return false; + } + cam_compose_jpeg_info_t * node = (cam_compose_jpeg_info_t *) data; + uint32_t frame_idx = *((uint32_t *) match_data); + LOGH("X"); + return node->frame_idx < frame_idx; +} + +/*=========================================================================== + * FUNCTION : releaseJpegInfo + * + * DESCRIPTION: callback function for the release of individual nodes + * in the JPEG queues. + * + * PARAMETERS : + * @data : ptr to the data to be released + * @user_data : caller can add more info here + * + * RETURN : None + *==========================================================================*/ +void QCameraMuxer::releaseJpegInfo(void *data, __unused void *user_data) +{ + LOGH("E"); + + cam_compose_jpeg_info_t *jpegInfo = (cam_compose_jpeg_info_t *)data; + if(jpegInfo && jpegInfo->release_cb) { + if (jpegInfo->release_data != NULL) { + jpegInfo->release_cb(jpegInfo->release_data, + jpegInfo->release_cookie, + NO_ERROR); + } + } + LOGH("X"); +} + +/*=========================================================================== + * FUNCTION : composeMpoRoutine + * + * DESCRIPTION: specialized thread for MPO composition + * + * PARAMETERS : + * @data : pointer to the thread owner + * + * RETURN : void* to thread + *==========================================================================*/ +void* QCameraMuxer::composeMpoRoutine(__unused void *data) +{ + LOGH("E"); + if (!gMuxer) { + LOGE("Error getting muxer "); + return NULL; + } + + int running = 1; + int ret; + uint8_t is_active = FALSE; + QCameraCmdThread *cmdThread = &gMuxer->m_ComposeMpoTh; + cmdThread->setName("CAM_ComposeMpo"); + + do { + do { + ret = cam_sem_wait(&cmdThread->cmd_sem); + if (ret != 0 && errno != EINVAL) { + LOGE("cam_sem_wait error (%s)", strerror(errno)); + return NULL; + } + } while (ret != 0); + + // we got notified about new cmd avail in cmd queue + camera_cmd_type_t cmd = cmdThread->getCmd(); + switch (cmd) { + case CAMERA_CMD_TYPE_START_DATA_PROC: + { + LOGH("start ComposeMpo processing"); + is_active = TRUE; + + // signal cmd is completed + cam_sem_post(&cmdThread->sync_sem); + } + break; + case CAMERA_CMD_TYPE_STOP_DATA_PROC: + { + LOGH("stop ComposeMpo processing"); + is_active = FALSE; + + // signal cmd is completed + cam_sem_post(&cmdThread->sync_sem); + } + break; + case CAMERA_CMD_TYPE_DO_NEXT_JOB: + { + if (is_active == TRUE) { + LOGH("Mpo Composition Requested"); + cam_compose_jpeg_info_t *main_jpeg_node = NULL; + cam_compose_jpeg_info_t *aux_jpeg_node = NULL; + bool foundMatch = false; + while (!gMuxer->m_MainJpegQ.isEmpty() && + !gMuxer->m_AuxJpegQ.isEmpty()) { + main_jpeg_node = (cam_compose_jpeg_info_t *) + gMuxer->m_MainJpegQ.dequeue(); + if (main_jpeg_node != NULL) { + LOGD("main_jpeg_node found frame idx %d" + "ptr %p buffer_ptr %p buffer_size %d", + main_jpeg_node->frame_idx, + main_jpeg_node, + main_jpeg_node->buffer->data, + main_jpeg_node->buffer->size); + // find matching aux node in Aux Jpeg Queue + aux_jpeg_node = + (cam_compose_jpeg_info_t *) gMuxer-> + m_AuxJpegQ.dequeue(); + if (aux_jpeg_node != NULL) { + LOGD("aux_jpeg_node found frame idx %d" + "ptr %p buffer_ptr %p buffer_size %d", + aux_jpeg_node->frame_idx, + aux_jpeg_node, + aux_jpeg_node->buffer->data, + aux_jpeg_node->buffer->size); + foundMatch = true; + // start MPO composition + gMuxer->composeMpo(main_jpeg_node, + aux_jpeg_node); + } + } + if (main_jpeg_node != NULL) { + if ( main_jpeg_node->release_cb ) { + main_jpeg_node->release_cb( + main_jpeg_node->release_data, + main_jpeg_node->release_cookie, + NO_ERROR); + } + free(main_jpeg_node); + main_jpeg_node = NULL; + } else { + LOGH("Mpo Match not found"); + } + if (aux_jpeg_node != NULL) { + if (aux_jpeg_node->release_cb) { + aux_jpeg_node->release_cb( + aux_jpeg_node->release_data, + aux_jpeg_node->release_cookie, + NO_ERROR); + } + free(aux_jpeg_node); + aux_jpeg_node = NULL; + } else { + LOGH("Mpo Match not found"); + } + } + } + break; + } + case CAMERA_CMD_TYPE_EXIT: + LOGH("ComposeMpo thread exit"); + running = 0; + break; + default: + break; + } + } while (running); + LOGH("X"); + return NULL; +} + +/*=========================================================================== + * FUNCTION : jpeg_data_callback + * + * DESCRIPTION: JPEG data callback for snapshot + * + * PARAMETERS : + * @msg_type : callback msg type + * @data : data ptr of the buffer + * @index : index of the frame + * @metadata : metadata associated with the buffer + * @user : callback cookie returned back to the user + * @frame_idx : frame index for matching frames + * @release_cb : callback function for releasing the data memory + * @release_cookie : cookie for the release callback function + * @release_data :pointer indicating what needs to be released + * + * RETURN : none + *==========================================================================*/ +void QCameraMuxer::jpeg_data_callback(int32_t msg_type, + const camera_memory_t *data, unsigned int index, + camera_frame_metadata_t *metadata, void *user, + uint32_t frame_idx, camera_release_callback release_cb, + void *release_cookie, void *release_data) +{ + LOGH("E"); + CHECK_MUXER(); + + if(data != NULL) { + LOGH("jpeg received: data %p size %d data ptr %p frameIdx %d", + data, data->size, data->data, frame_idx); + int rc = gMuxer->storeJpeg(((qcamera_physical_descriptor_t*)(user))->type, + msg_type, data, index, metadata, user, frame_idx, release_cb, + release_cookie, release_data); + if(rc != NO_ERROR) { + gMuxer->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); + } + } else { + gMuxer->sendEvtNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0); + } + LOGH("X"); + return; +} + +/*=========================================================================== + * FUNCTION : storeJpeg + * + * DESCRIPTION: Stores jpegs from multiple related cam instances into a common Queue + * + * PARAMETERS : + * @cam_type : indicates whether main or aux camera sent the Jpeg callback + * @msg_type : callback msg type + * @data : data ptr of the buffer + * @index : index of the frame + * @metadata : metadata associated with the buffer + * @user : callback cookie returned back to the user + * @frame_idx : frame index for matching frames + * @release_cb : callback function for releasing the data memory + * @release_cookie : cookie for the release callback function + * @release_data :pointer indicating what needs to be released + * + * RETURN : int32_t type of status + * NO_ERROR -- success + * none-zero failure code + *==========================================================================*/ +int32_t QCameraMuxer::storeJpeg(cam_sync_type_t cam_type, + int32_t msg_type, const camera_memory_t *data, unsigned int index, + camera_frame_metadata_t *metadata, void *user,uint32_t frame_idx, + camera_release_callback release_cb, void *release_cookie, + void *release_data) +{ + LOGH("E jpeg received: data %p size %d data ptr %p frameIdx %d", + data, data->size, data->data, frame_idx); + + CHECK_MUXER_ERROR(); + + if (!m_bMpoEnabled) { + if (cam_type == CAM_TYPE_MAIN) { + // send data callback only incase of main camera + // aux image is ignored and released back + mDataCb(msg_type, + data, + index, + metadata, + m_pMpoCallbackCookie); + } + if (release_cb) { + release_cb(release_data, release_cookie, NO_ERROR); + } + LOGH("X"); + return NO_ERROR; + } + + cam_compose_jpeg_info_t* pJpegFrame = + (cam_compose_jpeg_info_t*)malloc(sizeof(cam_compose_jpeg_info_t)); + if (!pJpegFrame) { + LOGE("Allocation failed for MPO nodes"); + return NO_MEMORY; + } + memset(pJpegFrame, 0, sizeof(*pJpegFrame)); + + pJpegFrame->msg_type = msg_type; + pJpegFrame->buffer = const_cast<camera_memory_t*>(data); + pJpegFrame->index = index; + pJpegFrame->metadata = metadata; + pJpegFrame->user = user; + pJpegFrame->valid = true; + pJpegFrame->frame_idx = frame_idx; + pJpegFrame->release_cb = release_cb; + pJpegFrame->release_cookie = release_cookie; + pJpegFrame->release_data = release_data; + if(cam_type == CAM_TYPE_MAIN) { + if (m_MainJpegQ.enqueue((void *)pJpegFrame)) { + LOGD("Main FrameIdx %d", pJpegFrame->frame_idx); + if (m_MainJpegQ.getCurrentSize() > 0) { + LOGD("Trigger Compose"); + m_ComposeMpoTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); + } + } else { + LOGE("Enqueue Failed for Main Jpeg Q"); + if ( pJpegFrame->release_cb ) { + // release other buffer also here + pJpegFrame->release_cb( + pJpegFrame->release_data, + pJpegFrame->release_cookie, + NO_ERROR); + } + free(pJpegFrame); + pJpegFrame = NULL; + return NO_MEMORY; + } + + } else { + if (m_AuxJpegQ.enqueue((void *)pJpegFrame)) { + LOGD("Aux FrameIdx %d", pJpegFrame->frame_idx); + if (m_AuxJpegQ.getCurrentSize() > 0) { + LOGD("Trigger Compose"); + m_ComposeMpoTh.sendCmd(CAMERA_CMD_TYPE_DO_NEXT_JOB, FALSE, FALSE); + } + } else { + LOGE("Enqueue Failed for Aux Jpeg Q"); + if ( pJpegFrame->release_cb ) { + // release other buffer also here + pJpegFrame->release_cb( + pJpegFrame->release_data, + pJpegFrame->release_cookie, + NO_ERROR); + } + free(pJpegFrame); + pJpegFrame = NULL; + return NO_MEMORY; + } + } + LOGH("X"); + + return NO_ERROR; +} + + +// Muxer Ops +camera_device_ops_t QCameraMuxer::mCameraMuxerOps = { + .set_preview_window = QCameraMuxer::set_preview_window, + .set_callbacks = QCameraMuxer::set_callBacks, + .enable_msg_type = QCameraMuxer::enable_msg_type, + .disable_msg_type = QCameraMuxer::disable_msg_type, + .msg_type_enabled = QCameraMuxer::msg_type_enabled, + + .start_preview = QCameraMuxer::start_preview, + .stop_preview = QCameraMuxer::stop_preview, + .preview_enabled = QCameraMuxer::preview_enabled, + .store_meta_data_in_buffers= QCameraMuxer::store_meta_data_in_buffers, + + .start_recording = QCameraMuxer::start_recording, + .stop_recording = QCameraMuxer::stop_recording, + .recording_enabled = QCameraMuxer::recording_enabled, + .release_recording_frame = QCameraMuxer::release_recording_frame, + + .auto_focus = QCameraMuxer::auto_focus, + .cancel_auto_focus = QCameraMuxer::cancel_auto_focus, + + .take_picture = QCameraMuxer::take_picture, + .cancel_picture = QCameraMuxer::cancel_picture, + + .set_parameters = QCameraMuxer::set_parameters, + .get_parameters = QCameraMuxer::get_parameters, + .put_parameters = QCameraMuxer::put_parameters, + .send_command = QCameraMuxer::send_command, + + .release = QCameraMuxer::release, + .dump = QCameraMuxer::dump, +}; + + +}; // namespace android |