blob: bad7393190e5d635ba3e239d513fc0249b5f0930 [file] [log] [blame]
/* 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);
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