669d233045
CAF revision: AU_LINUX_ANDROID_LA.UM.5.1_RB1.06.00.01.192.038 Change-Id: I87589fea5e9c00c3bdc9c79cc6b2d6453c3d09b3
2826 lines
91 KiB
C++
2826 lines
91 KiB
C++
/* 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_bDualCameraEnabled(FALSE),
|
|
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(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(
|
|
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(const struct hw_module_t* module,
|
|
const char* id, 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;
|
|
int rc = NO_ERROR;
|
|
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;
|
|
camera_info info;
|
|
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, 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;
|
|
info.is_frame_sync_enabled = m_bFrameSyncEnabled;
|
|
rc = hw->setRelatedCamSyncInfo(&info);
|
|
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");
|
|
int rc = NO_ERROR;
|
|
|
|
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, 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, 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, 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(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");
|
|
char saveName[PROPERTY_VALUE_MAX];
|
|
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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);
|
|
} else {
|
|
LOGH("Mpo Match not found");
|
|
}
|
|
if (aux_jpeg_node) {
|
|
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);
|
|
} 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
|