blob: fd90e8347a865321cd07de36beda925c53c46d97 [file] [log] [blame]
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
// System dependencies
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <fcntl.h>
#include <media/msm_media_info.h>
#define TIME_H <SYSTEM_HEADER_PREFIX/time.h>
#include TIME_H
#define IOCTL_H <SYSTEM_HEADER_PREFIX/ioctl.h>
#include IOCTL_H
// Camera dependencies
#include "cam_semaphore.h"
#include "mm_camera_dbg.h"
#include "mm_camera_interface.h"
#include "mm_camera.h"
/* internal function decalre */
int32_t mm_stream_qbuf(mm_stream_t *my_obj,
mm_camera_buf_def_t *buf);
int32_t mm_stream_set_ext_mode(mm_stream_t * my_obj);
int32_t mm_stream_set_fmt(mm_stream_t * my_obj);
int32_t mm_stream_sync_info(mm_stream_t *my_obj);
int32_t mm_stream_init_bufs(mm_stream_t * my_obj);
int32_t mm_stream_deinit_bufs(mm_stream_t * my_obj);
int32_t mm_stream_request_buf(mm_stream_t * my_obj);
int32_t mm_stream_unreg_buf(mm_stream_t * my_obj);
int32_t mm_stream_release(mm_stream_t *my_obj);
int32_t mm_stream_set_parm(mm_stream_t *my_obj,
cam_stream_parm_buffer_t *value);
int32_t mm_stream_get_parm(mm_stream_t *my_obj,
cam_stream_parm_buffer_t *value);
int32_t mm_stream_do_action(mm_stream_t *my_obj,
void *in_value);
int32_t mm_stream_streamon(mm_stream_t *my_obj);
int32_t mm_stream_streamoff(mm_stream_t *my_obj);
int32_t mm_stream_read_msm_frame(mm_stream_t * my_obj,
mm_camera_buf_info_t* buf_info,
uint8_t num_planes);
int32_t mm_stream_read_user_buf(mm_stream_t * my_obj,
mm_camera_buf_info_t* buf_info);
int32_t mm_stream_write_user_buf(mm_stream_t * my_obj,
mm_camera_buf_def_t *buf);
int32_t mm_stream_config(mm_stream_t *my_obj,
mm_camera_stream_config_t *config);
int32_t mm_stream_reg_buf(mm_stream_t * my_obj);
int32_t mm_stream_buf_done(mm_stream_t * my_obj,
mm_camera_buf_def_t *frame);
int32_t mm_stream_get_queued_buf_count(mm_stream_t * my_obj);
int32_t mm_stream_calc_offset(mm_stream_t *my_obj);
int32_t mm_stream_calc_offset_preview(cam_stream_info_t *stream_info,
cam_dimension_t *dim,
cam_padding_info_t *padding,
cam_stream_buf_plane_info_t *buf_planes);
int32_t mm_stream_calc_offset_post_view(cam_format_t fmt,
cam_dimension_t *dim,
cam_stream_buf_plane_info_t *buf_planes);
int32_t mm_stream_calc_offset_snapshot(cam_format_t fmt,
cam_dimension_t *dim,
cam_padding_info_t *padding,
cam_stream_buf_plane_info_t *buf_planes);
int32_t mm_stream_calc_offset_raw(cam_format_t fmt,
cam_dimension_t *dim,
cam_padding_info_t *padding,
cam_stream_buf_plane_info_t *buf_planes);
int32_t mm_stream_calc_offset_video(cam_format_t fmt,
cam_dimension_t *dim,
cam_stream_buf_plane_info_t *buf_planes);
int32_t mm_stream_calc_offset_metadata(cam_dimension_t *dim,
cam_padding_info_t *padding,
cam_stream_buf_plane_info_t *buf_planes);
int32_t mm_stream_calc_offset_postproc(cam_stream_info_t *stream_info,
cam_padding_info_t *padding,
cam_stream_buf_plane_info_t *plns);
uint32_t mm_stream_calc_lcm(int32_t num1, int32_t num2);
/* state machine function declare */
int32_t mm_stream_fsm_inited(mm_stream_t * my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val);
int32_t mm_stream_fsm_acquired(mm_stream_t * my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val);
int32_t mm_stream_fsm_cfg(mm_stream_t * my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val);
int32_t mm_stream_fsm_buffed(mm_stream_t * my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val);
int32_t mm_stream_fsm_reg(mm_stream_t * my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val);
int32_t mm_stream_fsm_active(mm_stream_t * my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val);
uint32_t mm_stream_get_v4l2_fmt(cam_format_t fmt);
/*===========================================================================
* FUNCTION : mm_stream_notify_channel
*
* DESCRIPTION: function to notify channel object on received buffer
*
* PARAMETERS :
* @ch_obj : channel object
* @buf_info: ptr to struct storing buffer information
*
* RETURN : int32_t type of status
* 0 -- success
* 0> -- failure
*==========================================================================*/
int32_t mm_stream_notify_channel(struct mm_channel* ch_obj,
mm_camera_buf_info_t *buf_info)
{
int32_t rc = 0;
mm_camera_cmdcb_t* node = NULL;
if ((NULL == ch_obj) || (NULL == buf_info)) {
LOGD("Invalid channel/buffer");
return -ENODEV;
}
/* send cam_sem_post to wake up channel cmd thread to enqueue
* to super buffer */
node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
if (NULL != node) {
memset(node, 0, sizeof(mm_camera_cmdcb_t));
node->cmd_type = MM_CAMERA_CMD_TYPE_DATA_CB;
node->u.buf = *buf_info;
/* enqueue to cmd thread */
cam_queue_enq(&(ch_obj->cmd_thread.cmd_queue), node);
/* wake up cmd thread */
cam_sem_post(&(ch_obj->cmd_thread.cmd_sem));
} else {
LOGE("No memory for mm_camera_node_t");
rc = -ENOMEM;
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_handle_rcvd_buf
*
* DESCRIPTION: function to handle newly received stream buffer
*
* PARAMETERS :
* @cam_obj : stream object
* @buf_info: ptr to struct storing buffer information
*
* RETURN : none
*==========================================================================*/
void mm_stream_handle_rcvd_buf(mm_stream_t *my_obj,
mm_camera_buf_info_t *buf_info,
uint8_t has_cb)
{
int32_t rc = 0;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
/* enqueue to super buf thread */
if (my_obj->is_bundled) {
rc = mm_stream_notify_channel(my_obj->ch_obj, buf_info);
if (rc < 0) {
LOGE("Unable to notify channel");
}
}
pthread_mutex_lock(&my_obj->buf_lock);
if(my_obj->is_linked) {
/* need to add into super buf for linking, add ref count */
my_obj->buf_status[buf_info->buf->buf_idx].buf_refcnt++;
rc = mm_stream_notify_channel(my_obj->linked_obj, buf_info);
if (rc < 0) {
LOGE("Unable to notify channel");
}
}
pthread_mutex_unlock(&my_obj->buf_lock);
pthread_mutex_lock(&my_obj->cmd_lock);
if(has_cb && my_obj->cmd_thread.is_active) {
mm_camera_cmdcb_t* node = NULL;
/* send cam_sem_post to wake up cmd thread to dispatch dataCB */
node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t));
if (NULL != node) {
memset(node, 0, sizeof(mm_camera_cmdcb_t));
node->cmd_type = MM_CAMERA_CMD_TYPE_DATA_CB;
node->u.buf = *buf_info;
/* enqueue to cmd thread */
cam_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
/* wake up cmd thread */
cam_sem_post(&(my_obj->cmd_thread.cmd_sem));
} else {
LOGE("No memory for mm_camera_node_t");
}
}
pthread_mutex_unlock(&my_obj->cmd_lock);
}
/*===========================================================================
* FUNCTION : mm_stream_dispatch_sync_data
*
* DESCRIPTION: dispatch stream buffer to registered users on poll thread
*
* PARAMETERS :
* @cmd_cb : ptr storing stream buffer information
* @userdata: user data ptr (stream object)
*
* RETURN : none
*==========================================================================*/
static void mm_stream_dispatch_sync_data(mm_stream_t * my_obj,
mm_stream_data_cb_t *buf_cb, mm_camera_buf_info_t *buf_info)
{
mm_camera_super_buf_t super_buf;
if (NULL == my_obj || buf_info == NULL ||
buf_cb == NULL) {
return;
}
memset(&super_buf, 0, sizeof(mm_camera_super_buf_t));
super_buf.num_bufs = 1;
super_buf.bufs[0] = buf_info->buf;
super_buf.camera_handle = my_obj->ch_obj->cam_obj->my_hdl;
super_buf.ch_id = my_obj->ch_obj->my_hdl;
if ((buf_cb != NULL) && (buf_cb->cb_type == MM_CAMERA_STREAM_CB_TYPE_SYNC)
&& (buf_cb->cb_count != 0)) {
/* callback */
buf_cb->cb(&super_buf, buf_cb->user_data);
/* if >0, reduce count by 1 every time we called CB until reaches 0
* when count reach 0, reset the buf_cb to have no CB */
if (buf_cb->cb_count > 0) {
buf_cb->cb_count--;
if (0 == buf_cb->cb_count) {
buf_cb->cb = NULL;
buf_cb->user_data = NULL;
}
}
}
}
/*===========================================================================
* FUNCTION : mm_stream_data_notify
*
* DESCRIPTION: callback to handle data notify from kernel
*
* PARAMETERS :
* @user_data : user data ptr (stream object)
*
* RETURN : none
*==========================================================================*/
static void mm_stream_data_notify(void* user_data)
{
mm_stream_t *my_obj = (mm_stream_t*)user_data;
int32_t i, rc;
uint8_t has_cb = 0, length = 0;
mm_camera_buf_info_t buf_info;
if (NULL == my_obj) {
return;
}
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
if (MM_STREAM_STATE_ACTIVE != my_obj->state) {
/* this Cb will only received in active_stream_on state
* if not so, return here */
LOGE("ERROR!! Wrong state (%d) to receive data notify!",
my_obj->state);
return;
}
if (my_obj->stream_info->streaming_mode == CAM_STREAMING_MODE_BATCH) {
length = 1;
} else {
length = my_obj->frame_offset.num_planes;
}
memset(&buf_info, 0, sizeof(mm_camera_buf_info_t));
rc = mm_stream_read_msm_frame(my_obj, &buf_info,
(uint8_t)length);
if (rc != 0) {
return;
}
uint32_t idx = buf_info.buf->buf_idx;
pthread_mutex_lock(&my_obj->cb_lock);
for (i = 0; i < MM_CAMERA_STREAM_BUF_CB_MAX; i++) {
if(NULL != my_obj->buf_cb[i].cb) {
if (my_obj->buf_cb[i].cb_type == MM_CAMERA_STREAM_CB_TYPE_SYNC) {
/*For every SYNC callback, send data*/
mm_stream_dispatch_sync_data(my_obj,
&my_obj->buf_cb[i], &buf_info);
} else {
/* for every ASYNC CB, need ref count */
has_cb = 1;
}
}
}
pthread_mutex_unlock(&my_obj->cb_lock);
pthread_mutex_lock(&my_obj->buf_lock);
/* update buffer location */
my_obj->buf_status[idx].in_kernel = 0;
/* update buf ref count */
if (my_obj->is_bundled) {
/* need to add into super buf since bundled, add ref count */
my_obj->buf_status[idx].buf_refcnt++;
}
my_obj->buf_status[idx].buf_refcnt =
(uint8_t)(my_obj->buf_status[idx].buf_refcnt + has_cb);
pthread_mutex_unlock(&my_obj->buf_lock);
mm_stream_handle_rcvd_buf(my_obj, &buf_info, has_cb);
}
/*===========================================================================
* FUNCTION : mm_stream_dispatch_app_data
*
* DESCRIPTION: dispatch stream buffer to registered users
*
* PARAMETERS :
* @cmd_cb : ptr storing stream buffer information
* @userdata: user data ptr (stream object)
*
* RETURN : none
*==========================================================================*/
static void mm_stream_dispatch_app_data(mm_camera_cmdcb_t *cmd_cb,
void* user_data)
{
int i;
mm_stream_t * my_obj = (mm_stream_t *)user_data;
mm_camera_buf_info_t* buf_info = NULL;
mm_camera_super_buf_t super_buf;
if (NULL == my_obj) {
return;
}
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
if (MM_CAMERA_CMD_TYPE_DATA_CB != cmd_cb->cmd_type) {
LOGE("Wrong cmd_type (%d) for dataCB",
cmd_cb->cmd_type);
return;
}
buf_info = &cmd_cb->u.buf;
memset(&super_buf, 0, sizeof(mm_camera_super_buf_t));
super_buf.num_bufs = 1;
super_buf.bufs[0] = buf_info->buf;
super_buf.camera_handle = my_obj->ch_obj->cam_obj->my_hdl;
super_buf.ch_id = my_obj->ch_obj->my_hdl;
pthread_mutex_lock(&my_obj->cb_lock);
for(i = 0; i < MM_CAMERA_STREAM_BUF_CB_MAX; i++) {
if(NULL != my_obj->buf_cb[i].cb
&& (my_obj->buf_cb[i].cb_type !=
MM_CAMERA_STREAM_CB_TYPE_SYNC)) {
if (my_obj->buf_cb[i].cb_count != 0) {
/* if <0, means infinite CB
* if >0, means CB for certain times
* both case we need to call CB */
/* increase buf ref cnt */
pthread_mutex_lock(&my_obj->buf_lock);
my_obj->buf_status[buf_info->buf->buf_idx].buf_refcnt++;
pthread_mutex_unlock(&my_obj->buf_lock);
/* callback */
my_obj->buf_cb[i].cb(&super_buf,
my_obj->buf_cb[i].user_data);
}
/* if >0, reduce count by 1 every time we called CB until reaches 0
* when count reach 0, reset the buf_cb to have no CB */
if (my_obj->buf_cb[i].cb_count > 0) {
my_obj->buf_cb[i].cb_count--;
if (0 == my_obj->buf_cb[i].cb_count) {
my_obj->buf_cb[i].cb = NULL;
my_obj->buf_cb[i].user_data = NULL;
}
}
}
}
pthread_mutex_unlock(&my_obj->cb_lock);
/* do buf_done since we increased refcnt by one when has_cb */
mm_stream_buf_done(my_obj, buf_info->buf);
}
/*===========================================================================
* FUNCTION : mm_stream_fsm_fn
*
* DESCRIPTION: stream finite state machine entry function. Depends on stream
* state, incoming event will be handled differently.
*
* PARAMETERS :
* @my_obj : ptr to a stream object
* @evt : stream event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_fsm_fn(mm_stream_t *my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = -1;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
switch (my_obj->state) {
case MM_STREAM_STATE_NOTUSED:
LOGD("Not handling evt in unused state");
break;
case MM_STREAM_STATE_INITED:
rc = mm_stream_fsm_inited(my_obj, evt, in_val, out_val);
break;
case MM_STREAM_STATE_ACQUIRED:
rc = mm_stream_fsm_acquired(my_obj, evt, in_val, out_val);
break;
case MM_STREAM_STATE_CFG:
rc = mm_stream_fsm_cfg(my_obj, evt, in_val, out_val);
break;
case MM_STREAM_STATE_BUFFED:
rc = mm_stream_fsm_buffed(my_obj, evt, in_val, out_val);
break;
case MM_STREAM_STATE_REG:
rc = mm_stream_fsm_reg(my_obj, evt, in_val, out_val);
break;
case MM_STREAM_STATE_ACTIVE:
rc = mm_stream_fsm_active(my_obj, evt, in_val, out_val);
break;
default:
LOGD("Not a valid state (%d)", my_obj->state);
break;
}
LOGD("X rc =%d",rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_fsm_inited
*
* DESCRIPTION: stream finite state machine function to handle event in INITED
* state.
*
* PARAMETERS :
* @my_obj : ptr to a stream object
* @evt : stream event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_fsm_inited(mm_stream_t *my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = 0;
char dev_name[MM_CAMERA_DEV_NAME_LEN];
const char *dev_name_value = NULL;
if (NULL == my_obj) {
LOGE("NULL camera object\n");
return -1;
}
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
switch(evt) {
case MM_STREAM_EVT_ACQUIRE:
if ((NULL == my_obj->ch_obj) || (NULL == my_obj->ch_obj->cam_obj)) {
LOGE("NULL channel or camera obj\n");
rc = -1;
break;
}
dev_name_value = mm_camera_util_get_dev_name(my_obj->ch_obj->cam_obj->my_hdl);
if (NULL == dev_name_value) {
LOGE("NULL device name\n");
rc = -1;
break;
}
snprintf(dev_name, sizeof(dev_name), "/dev/%s",
dev_name_value);
my_obj->fd = open(dev_name, O_RDWR | O_NONBLOCK);
if (my_obj->fd < 0) {
LOGE("open dev returned %d\n", my_obj->fd);
rc = -1;
break;
}
LOGD("open dev fd = %d\n", my_obj->fd);
rc = mm_stream_set_ext_mode(my_obj);
if (0 == rc) {
my_obj->state = MM_STREAM_STATE_ACQUIRED;
} else {
/* failed setting ext_mode
* close fd */
close(my_obj->fd);
my_obj->fd = -1;
break;
}
break;
default:
LOGE("invalid state (%d) for evt (%d), in(%p), out(%p)",
my_obj->state, evt, in_val, out_val);
break;
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_fsm_acquired
*
* DESCRIPTION: stream finite state machine function to handle event in AQUIRED
* state.
*
* PARAMETERS :
* @my_obj : ptr to a stream object
* @evt : stream event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_fsm_acquired(mm_stream_t *my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = 0;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
switch(evt) {
case MM_STREAM_EVT_SET_FMT:
{
mm_camera_stream_config_t *config =
(mm_camera_stream_config_t *)in_val;
rc = mm_stream_config(my_obj, config);
/* change state to configed */
my_obj->state = MM_STREAM_STATE_CFG;
break;
}
case MM_STREAM_EVT_RELEASE:
rc = mm_stream_release(my_obj);
/* change state to not used */
my_obj->state = MM_STREAM_STATE_NOTUSED;
break;
case MM_STREAM_EVT_SET_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_stream_set_parm(my_obj, payload->parms);
}
break;
case MM_STREAM_EVT_GET_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_stream_get_parm(my_obj, payload->parms);
}
break;
default:
LOGE("invalid state (%d) for evt (%d), in(%p), out(%p)",
my_obj->state, evt, in_val, out_val);
}
LOGD("X rc = %d", rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_fsm_cfg
*
* DESCRIPTION: stream finite state machine function to handle event in CONFIGURED
* state.
*
* PARAMETERS :
* @my_obj : ptr to a stream object
* @evt : stream event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_fsm_cfg(mm_stream_t * my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = 0;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
switch(evt) {
case MM_STREAM_EVT_SET_FMT:
{
mm_camera_stream_config_t *config =
(mm_camera_stream_config_t *)in_val;
rc = mm_stream_config(my_obj, config);
/* change state to configed */
my_obj->state = MM_STREAM_STATE_CFG;
break;
}
case MM_STREAM_EVT_RELEASE:
rc = mm_stream_release(my_obj);
my_obj->state = MM_STREAM_STATE_NOTUSED;
break;
case MM_STREAM_EVT_SET_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_stream_set_parm(my_obj, payload->parms);
}
break;
case MM_STREAM_EVT_GET_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_stream_get_parm(my_obj, payload->parms);
}
break;
case MM_STREAM_EVT_GET_BUF:
rc = mm_stream_init_bufs(my_obj);
/* change state to buff allocated */
if(0 == rc) {
my_obj->state = MM_STREAM_STATE_BUFFED;
}
break;
default:
LOGE("invalid state (%d) for evt (%d), in(%p), out(%p)",
my_obj->state, evt, in_val, out_val);
}
LOGD("X rc = %d", rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_fsm_buffed
*
* DESCRIPTION: stream finite state machine function to handle event in BUFFED
* state.
*
* PARAMETERS :
* @my_obj : ptr to a stream object
* @evt : stream event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_fsm_buffed(mm_stream_t * my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = 0;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
switch(evt) {
case MM_STREAM_EVT_PUT_BUF:
rc = mm_stream_deinit_bufs(my_obj);
/* change state to configed */
my_obj->state = MM_STREAM_STATE_CFG;
break;
case MM_STREAM_EVT_REG_BUF:
rc = mm_stream_reg_buf(my_obj);
/* change state to regged */
if(0 == rc) {
my_obj->state = MM_STREAM_STATE_REG;
}
break;
case MM_STREAM_EVT_SET_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_stream_set_parm(my_obj, payload->parms);
}
break;
case MM_STREAM_EVT_GET_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_stream_get_parm(my_obj, payload->parms);
}
break;
default:
LOGW("invalid state (%d) for evt (%d), in(%p), out(%p)",
my_obj->state, evt, in_val, out_val);
}
LOGD("X rc = %d", rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_fsm_reg
*
* DESCRIPTION: stream finite state machine function to handle event in REGGED
* state.
*
* PARAMETERS :
* @my_obj : ptr to a stream object
* @evt : stream event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_fsm_reg(mm_stream_t * my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = 0;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
switch(evt) {
case MM_STREAM_EVT_UNREG_BUF:
rc = mm_stream_unreg_buf(my_obj);
/* change state to buffed */
my_obj->state = MM_STREAM_STATE_BUFFED;
break;
case MM_STREAM_EVT_START:
{
uint8_t has_cb = 0;
uint8_t i;
/* launch cmd thread if CB is not null */
pthread_mutex_lock(&my_obj->cb_lock);
for (i = 0; i < MM_CAMERA_STREAM_BUF_CB_MAX; i++) {
if((NULL != my_obj->buf_cb[i].cb) &&
(my_obj->buf_cb[i].cb_type != MM_CAMERA_STREAM_CB_TYPE_SYNC)) {
has_cb = 1;
break;
}
}
pthread_mutex_unlock(&my_obj->cb_lock);
pthread_mutex_lock(&my_obj->cmd_lock);
if (has_cb) {
snprintf(my_obj->cmd_thread.threadName, THREAD_NAME_SIZE, "CAM_StrmAppData");
mm_camera_cmd_thread_launch(&my_obj->cmd_thread,
mm_stream_dispatch_app_data,
(void *)my_obj);
}
pthread_mutex_unlock(&my_obj->cmd_lock);
my_obj->state = MM_STREAM_STATE_ACTIVE;
rc = mm_stream_streamon(my_obj);
if (0 != rc) {
/* failed stream on, need to release cmd thread if it's launched */
pthread_mutex_lock(&my_obj->cmd_lock);
if (has_cb) {
mm_camera_cmd_thread_release(&my_obj->cmd_thread);
}
pthread_mutex_unlock(&my_obj->cmd_lock);
my_obj->state = MM_STREAM_STATE_REG;
break;
}
}
break;
case MM_STREAM_EVT_SET_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_stream_set_parm(my_obj, payload->parms);
}
break;
case MM_STREAM_EVT_GET_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_stream_get_parm(my_obj, payload->parms);
}
break;
default:
LOGE("invalid state (%d) for evt (%d), in(%p), out(%p)",
my_obj->state, evt, in_val, out_val);
}
LOGD("X rc = %d", rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_fsm_active
*
* DESCRIPTION: stream finite state machine function to handle event in ACTIVE
* state.
*
* PARAMETERS :
* @my_obj : ptr to a stream object
* @evt : stream event to be processed
* @in_val : input event payload. Can be NULL if not needed.
* @out_val : output payload, Can be NULL if not needed.
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_fsm_active(mm_stream_t * my_obj,
mm_stream_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = 0;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
switch(evt) {
case MM_STREAM_EVT_QBUF:
rc = mm_stream_buf_done(my_obj, (mm_camera_buf_def_t *)in_val);
break;
case MM_STREAM_EVT_GET_QUEUED_BUF_COUNT:
rc = mm_stream_get_queued_buf_count(my_obj);
break;
case MM_STREAM_EVT_STOP:
{
uint8_t has_cb = 0;
uint8_t i;
rc = mm_stream_streamoff(my_obj);
pthread_mutex_lock(&my_obj->cb_lock);
for (i = 0; i < MM_CAMERA_STREAM_BUF_CB_MAX; i++) {
if(NULL != my_obj->buf_cb[i].cb
&& my_obj->buf_cb[i].cb_type != MM_CAMERA_STREAM_CB_TYPE_SYNC) {
has_cb = 1;
break;
}
}
pthread_mutex_unlock(&my_obj->cb_lock);
pthread_mutex_lock(&my_obj->cmd_lock);
if (has_cb) {
mm_camera_cmd_thread_release(&my_obj->cmd_thread);
}
pthread_mutex_unlock(&my_obj->cmd_lock);
my_obj->state = MM_STREAM_STATE_REG;
}
break;
case MM_STREAM_EVT_SET_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_stream_set_parm(my_obj, payload->parms);
}
break;
case MM_STREAM_EVT_GET_PARM:
{
mm_evt_paylod_set_get_stream_parms_t *payload =
(mm_evt_paylod_set_get_stream_parms_t *)in_val;
rc = mm_stream_get_parm(my_obj, payload->parms);
}
break;
case MM_STREAM_EVT_DO_ACTION:
rc = mm_stream_do_action(my_obj, in_val);
break;
default:
LOGE("invalid state (%d) for evt (%d), in(%p), out(%p)",
my_obj->state, evt, in_val, out_val);
}
LOGD("X rc = %d", rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_map_buf_ops
*
* DESCRIPTION: ops for mapping stream buffer via domain socket to server.
* This function will be passed to upper layer as part of ops table
* to be used by upper layer when allocating stream buffers and mapping
* buffers to server via domain socket.
*
* PARAMETERS :
* @frame_idx : index of buffer within the stream buffers, only valid if
* buf_type is CAM_MAPPING_BUF_TYPE_STREAM_BUF or
* CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF
* @plane_idx : plane index. If all planes share the same fd,
* plane_idx = -1; otherwise, plean_idx is the
* index to plane (0..num_of_planes)
* @fd : file descriptor of the buffer
* @size : size of the buffer
* @userdata : user data ptr (stream object)
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
static int32_t mm_stream_map_buf_ops(uint32_t frame_idx,
int32_t plane_idx, int fd, size_t size,
void *buffer, cam_mapping_buf_type type,
void *userdata)
{
mm_stream_t *my_obj = (mm_stream_t *)userdata;
return mm_stream_map_buf(my_obj,
type, frame_idx, plane_idx, fd, size, buffer);
}
/*===========================================================================
* FUNCTION : mm_stream_bundled_map_buf_ops
*
* DESCRIPTION: ops for mapping bundled stream buffers via domain socket to server.
* This function will be passed to upper layer as part of ops table
* to be used by upper layer when allocating stream buffers and mapping
* buffers to server via domain socket.
*
* PARAMETERS :
* @buf_map_list : list of buffer mapping information
* @userdata : user data ptr (stream object)
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
static int32_t mm_stream_bundled_map_buf_ops(
const cam_buf_map_type_list *buf_map_list,
void *userdata)
{
mm_stream_t *my_obj = (mm_stream_t *)userdata;
return mm_stream_map_bufs(my_obj,
buf_map_list);
}
/*===========================================================================
* FUNCTION : mm_stream_unmap_buf_ops
*
* DESCRIPTION: ops for unmapping stream buffer via domain socket to server.
* This function will be passed to upper layer as part of ops table
* to be used by upper layer when allocating stream buffers and unmapping
* buffers to server via domain socket.
*
* PARAMETERS :
* @frame_idx : index of buffer within the stream buffers, only valid if
* buf_type is CAM_MAPPING_BUF_TYPE_STREAM_BUF or
* CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF
* @plane_idx : plane index. If all planes share the same fd,
* plane_idx = -1; otherwise, plean_idx is the
* index to plane (0..num_of_planes)
* @userdata : user data ptr (stream object)
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
static int32_t mm_stream_unmap_buf_ops(uint32_t frame_idx,
int32_t plane_idx,
cam_mapping_buf_type type,
void *userdata)
{
mm_stream_t *my_obj = (mm_stream_t *)userdata;
return mm_stream_unmap_buf(my_obj,
type,
frame_idx,
plane_idx);
}
/*===========================================================================
* FUNCTION : mm_stream_config
*
* DESCRIPTION: configure a stream
*
* PARAMETERS :
* @my_obj : stream object
* @config : stream configuration
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_config(mm_stream_t *my_obj,
mm_camera_stream_config_t *config)
{
int32_t rc = 0;
int32_t cb_index = 0;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
my_obj->stream_info = config->stream_info;
my_obj->buf_num = (uint8_t) config->stream_info->num_bufs;
my_obj->mem_vtbl = config->mem_vtbl;
my_obj->padding_info = config->padding_info;
if (config->stream_cb_sync != NULL) {
/* SYNC callback is always placed at index 0*/
my_obj->buf_cb[cb_index].cb = config->stream_cb_sync;
my_obj->buf_cb[cb_index].user_data = config->userdata;
my_obj->buf_cb[cb_index].cb_count = -1; /* infinite by default */
my_obj->buf_cb[cb_index].cb_type = MM_CAMERA_STREAM_CB_TYPE_SYNC;
cb_index++;
}
my_obj->buf_cb[cb_index].cb = config->stream_cb;
my_obj->buf_cb[cb_index].user_data = config->userdata;
my_obj->buf_cb[cb_index].cb_count = -1; /* infinite by default */
my_obj->buf_cb[cb_index].cb_type = MM_CAMERA_STREAM_CB_TYPE_ASYNC;
rc = mm_stream_sync_info(my_obj);
if (rc == 0) {
rc = mm_stream_set_fmt(my_obj);
if (rc < 0) {
LOGE("mm_stream_set_fmt failed %d",
rc);
}
}
my_obj->map_ops.map_ops = mm_stream_map_buf_ops;
my_obj->map_ops.bundled_map_ops = mm_stream_bundled_map_buf_ops;
my_obj->map_ops.unmap_ops = mm_stream_unmap_buf_ops;
my_obj->map_ops.userdata = my_obj;
if(my_obj->mem_vtbl.set_config_ops != NULL) {
my_obj->mem_vtbl.set_config_ops(&my_obj->map_ops,
my_obj->mem_vtbl.user_data);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_release
*
* DESCRIPTION: release a stream resource
*
* PARAMETERS :
* @my_obj : stream object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_release(mm_stream_t *my_obj)
{
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
pthread_mutex_lock(&my_obj->buf_lock);
memset(my_obj->buf_status, 0, sizeof(my_obj->buf_status));
pthread_mutex_unlock(&my_obj->buf_lock);
/* close fd */
if (my_obj->fd >= 0) {
#ifndef DAEMON_PRESENT
int32_t rc = 0;
cam_shim_packet_t *shim_cmd;
cam_shim_cmd_data shim_cmd_data;
mm_camera_obj_t *cam_obj = my_obj->ch_obj->cam_obj;
memset(&shim_cmd_data, 0, sizeof(shim_cmd_data));
shim_cmd_data.command = MSM_CAMERA_PRIV_DEL_STREAM;
shim_cmd_data.stream_id = my_obj->server_stream_id;
shim_cmd_data.value = NULL;
shim_cmd = mm_camera_create_shim_cmd_packet(CAM_SHIM_SET_PARM,
cam_obj->sessionid, &shim_cmd_data);
rc = mm_camera_module_send_cmd(shim_cmd);
if (rc < 0) {
LOGE("failed to DELETE STREAM");
}
mm_camera_destroy_shim_cmd_packet(shim_cmd);
#endif /* DAEMON_PRESENT */
close(my_obj->fd);
}
/* destroy mutex */
pthread_cond_destroy(&my_obj->buf_cond);
pthread_mutex_destroy(&my_obj->buf_lock);
pthread_mutex_destroy(&my_obj->cb_lock);
pthread_mutex_destroy(&my_obj->cmd_lock);
/* reset stream obj */
memset(my_obj, 0, sizeof(mm_stream_t));
my_obj->fd = -1;
return 0;
}
/*===========================================================================
* FUNCTION : mm_stream_streamon
*
* DESCRIPTION: stream on a stream. sending v4l2 request to kernel
*
* PARAMETERS :
* @my_obj : stream object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_streamon(mm_stream_t *my_obj)
{
int32_t rc = 0;
int8_t i;
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
pthread_mutex_lock(&my_obj->buf_lock);
for (i = 0; i < my_obj->buf_num; i++) {
if ((my_obj->buf_status[i].map_status == 0) &&
(my_obj->buf_status[i].in_kernel)) {
LOGD("waiting for mapping to done: strm fd = %d",
my_obj->fd);
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += WAIT_TIMEOUT;
rc = pthread_cond_timedwait(&my_obj->buf_cond, &my_obj->buf_lock, &ts);
if (rc == ETIMEDOUT) {
LOGE("Timed out. Abort stream-on \n");
rc = -1;
}
break;
} else if (my_obj->buf_status[i].map_status < 0) {
LOGD("Buffer mapping failed. Abort Stream On");
rc = -1;
break;
}
}
pthread_mutex_unlock(&my_obj->buf_lock);
if (rc < 0) {
/* remove fd from data poll thread in case of failure */
mm_camera_poll_thread_del_poll_fd(&my_obj->ch_obj->poll_thread[0],
my_obj->my_hdl, mm_camera_sync_call);
return rc;
}
mm_camera_obj_t *cam_obj = my_obj->ch_obj->cam_obj;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d session_id:%d stream_id:%d",
my_obj->my_hdl, my_obj->fd, my_obj->state, cam_obj->sessionid,
my_obj->server_stream_id);
rc = ioctl(my_obj->fd, VIDIOC_STREAMON, &buf_type);
if (rc < 0 && my_obj->stream_info->num_bufs != 0) {
LOGE("ioctl VIDIOC_STREAMON failed: rc=%d, errno %d",
rc, errno);
goto error_case;
}
#ifndef DAEMON_PRESENT
cam_shim_packet_t *shim_cmd;
cam_shim_cmd_data shim_cmd_data;
memset(&shim_cmd_data, 0, sizeof(shim_cmd_data));
shim_cmd_data.command = MSM_CAMERA_PRIV_STREAM_ON;
shim_cmd_data.stream_id = my_obj->server_stream_id;
shim_cmd_data.value = NULL;
shim_cmd = mm_camera_create_shim_cmd_packet(CAM_SHIM_SET_PARM,
cam_obj->sessionid, &shim_cmd_data);
rc = mm_camera_module_send_cmd(shim_cmd);
mm_camera_destroy_shim_cmd_packet(shim_cmd);
if (rc < 0) {
LOGE("Module StreamON failed: rc=%d", rc);
ioctl(my_obj->fd, VIDIOC_STREAMOFF, &buf_type);
goto error_case;
}
#endif
LOGD("X rc = %d",rc);
return rc;
error_case:
/* remove fd from data poll thread in case of failure */
mm_camera_poll_thread_del_poll_fd(&my_obj->ch_obj->poll_thread[0],
my_obj->my_hdl, mm_camera_sync_call);
LOGD("X rc = %d",rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_streamoff
*
* DESCRIPTION: stream off a stream. sending v4l2 request to kernel
*
* PARAMETERS :
* @my_obj : stream object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_streamoff(mm_stream_t *my_obj)
{
int32_t rc = 0;
enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
/* step1: remove fd from data poll thread */
rc = mm_camera_poll_thread_del_poll_fd(&my_obj->ch_obj->poll_thread[0],
my_obj->my_hdl, mm_camera_sync_call);
if (rc < 0) {
/* The error might be due to async update. In this case
* wait for all updates to complete before proceeding. */
rc = mm_camera_poll_thread_commit_updates(&my_obj->ch_obj->poll_thread[0]);
if (rc < 0) {
LOGE("Poll sync failed %d", rc);
rc = 0;
}
}
#ifndef DAEMON_PRESENT
cam_shim_packet_t *shim_cmd;
cam_shim_cmd_data shim_cmd_data;
mm_camera_obj_t *cam_obj = my_obj->ch_obj->cam_obj;
memset(&shim_cmd_data, 0, sizeof(shim_cmd_data));
shim_cmd_data.command = MSM_CAMERA_PRIV_STREAM_OFF;
shim_cmd_data.stream_id = my_obj->server_stream_id;
shim_cmd_data.value = NULL;
shim_cmd = mm_camera_create_shim_cmd_packet(CAM_SHIM_SET_PARM,
cam_obj->sessionid, &shim_cmd_data);
rc |= mm_camera_module_send_cmd(shim_cmd);
mm_camera_destroy_shim_cmd_packet(shim_cmd);
if (rc < 0) {
LOGE("Module StreamOFF failed: rc=%d", rc)
}
#endif
/* step2: stream off */
rc |= ioctl(my_obj->fd, VIDIOC_STREAMOFF, &buf_type);
if (rc < 0) {
LOGE("STREAMOFF ioctl failed: %s", strerror(errno));
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_write_user_buf
*
* DESCRIPTION: dequeue a stream buffer from user buffer queue and fill internal structure
*
* PARAMETERS :
* @my_obj : stream object
* @buf : ptr to a struct storing buffer information
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_write_user_buf(mm_stream_t * my_obj,
mm_camera_buf_def_t *buf)
{
int32_t rc = 0, i;
int32_t index = -1, count = 0;
struct msm_camera_user_buf_cont_t *cont_buf = NULL;
if (buf->buf_type == CAM_STREAM_BUF_TYPE_USERPTR) {
pthread_mutex_lock(&my_obj->buf_lock);
my_obj->buf_status[buf->buf_idx].buf_refcnt--;
if (0 == my_obj->buf_status[buf->buf_idx].buf_refcnt) {
pthread_mutex_unlock(&my_obj->buf_lock);
cont_buf = (struct msm_camera_user_buf_cont_t *)my_obj->buf[buf->buf_idx].buffer;
cont_buf->buf_cnt = my_obj->buf[buf->buf_idx].user_buf.bufs_used;
for (i = 0; i < (int32_t)cont_buf->buf_cnt; i++) {
cont_buf->buf_idx[i] = my_obj->buf[buf->buf_idx].user_buf.buf_idx[i];
}
rc = mm_stream_qbuf(my_obj, buf);
if(rc < 0) {
LOGE("mm_camera_stream_qbuf(idx=%d) err=%d\n",
buf->buf_idx, rc);
} else {
for (i = 0; i < (int32_t)cont_buf->buf_cnt; i++) {
my_obj->buf[buf->buf_idx].user_buf.buf_idx[i] = -1;
}
my_obj->buf_status[buf->buf_idx].in_kernel = 1;
my_obj->buf[buf->buf_idx].user_buf.buf_in_use = 1;
}
} else {
LOGD("<DEBUG> : ref count pending count :%d idx = %d",
my_obj->buf_status[buf->buf_idx].buf_refcnt, buf->buf_idx);
pthread_mutex_unlock(&my_obj->buf_lock);
}
return rc;
}
if ((my_obj->cur_buf_idx < 0)
|| (my_obj->cur_buf_idx >= my_obj->buf_num)) {
for (i = 0; i < my_obj->buf_num; i++) {
if ((my_obj->buf_status[i].in_kernel)
|| (my_obj->buf[i].user_buf.buf_in_use)) {
continue;
}
my_obj->cur_buf_idx = index = i;
break;
}
} else {
index = my_obj->cur_buf_idx;
}
if (index == -1) {
LOGE("No Free batch buffer");
rc = -1;
return rc;
}
//Insert Buffer to Batch structure.
my_obj->buf[index].user_buf.buf_idx[count] = buf->buf_idx;
my_obj->cur_bufs_staged++;
LOGD("index = %d filled = %d used = %d",
index,
my_obj->cur_bufs_staged,
my_obj->buf[index].user_buf.bufs_used);
if (my_obj->cur_bufs_staged
== my_obj->buf[index].user_buf.bufs_used){
pthread_mutex_lock(&my_obj->buf_lock);
my_obj->buf_status[index].buf_refcnt--;
if (0 == my_obj->buf_status[index].buf_refcnt) {
pthread_mutex_unlock(&my_obj->buf_lock);
cont_buf = (struct msm_camera_user_buf_cont_t *)my_obj->buf[index].buffer;
cont_buf->buf_cnt = my_obj->buf[index].user_buf.bufs_used;
for (i = 0; i < (int32_t)cont_buf->buf_cnt; i++) {
cont_buf->buf_idx[i] = my_obj->buf[index].user_buf.buf_idx[i];
}
rc = mm_stream_qbuf(my_obj, &my_obj->buf[index]);
if(rc < 0) {
LOGE("mm_camera_stream_qbuf(idx=%d) err=%d\n",
index, rc);
} else {
for (i = 0; i < (int32_t)cont_buf->buf_cnt; i++) {
my_obj->buf[index].user_buf.buf_idx[i] = -1;
}
my_obj->buf_status[index].in_kernel = 1;
my_obj->buf[index].user_buf.buf_in_use = 1;
my_obj->cur_bufs_staged = 0;
my_obj->cur_buf_idx = -1;
}
}else{
LOGD("<DEBUG> : ref count pending count :%d idx = %d",
my_obj->buf_status[index].buf_refcnt, index);
pthread_mutex_unlock(&my_obj->buf_lock);
}
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_read_user_buf
*
* DESCRIPTION: dequeue a stream buffer from user buffer queue and fill internal structure
*
* PARAMETERS :
* @my_obj : stream object
* @buf_info : ptr to a struct storing buffer information
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_read_user_buf(mm_stream_t * my_obj,
mm_camera_buf_info_t* buf_info)
{
int32_t rc = 0, i;
mm_camera_buf_def_t *stream_buf = NULL;
struct msm_camera_user_buf_cont_t *user_buf = NULL;
nsecs_t interval_nsec = 0, frame_ts = 0, timeStamp = 0;
int ts_delta = 0;
uint32_t frameID = 0;
user_buf = (struct msm_camera_user_buf_cont_t *)buf_info->buf->buffer;
if(user_buf != my_obj->buf[buf_info->buf->buf_idx].buffer) {
LOGD("Buffer modified. ERROR");
rc = -1;
return rc;
}
if (buf_info->buf->frame_idx == 1) {
frameID = buf_info->buf->frame_idx;
}else {
frameID = (buf_info->buf->frame_idx - 1) * user_buf->buf_cnt;
}
timeStamp = (nsecs_t)(buf_info->buf->ts.tv_sec) *
1000000000LL + buf_info->buf->ts.tv_nsec;
if (timeStamp <= my_obj->prev_timestamp) {
LOGE("TimeStamp received less than expected");
mm_stream_qbuf(my_obj, buf_info->buf);
return rc;
} else if (my_obj->prev_timestamp == 0
|| (my_obj->prev_frameID != buf_info->buf->frame_idx + 1)) {
/* For first frame or incase batch is droped */
interval_nsec = ((my_obj->stream_info->user_buf_info.frameInterval) * 1000000);
my_obj->prev_timestamp = (timeStamp - (nsecs_t)(user_buf->buf_cnt * interval_nsec));
} else {
ts_delta = timeStamp - my_obj->prev_timestamp;
interval_nsec = (nsecs_t)(ts_delta / user_buf->buf_cnt);
LOGD("Timestamp delta = %d timestamp = %lld", ts_delta, timeStamp);
}
for (i = 0; i < (int32_t)user_buf->buf_cnt; i++) {
buf_info->buf->user_buf.buf_idx[i] = user_buf->buf_idx[i];
stream_buf = &my_obj->plane_buf[user_buf->buf_idx[i]];
stream_buf->frame_idx = frameID + i;
frame_ts = (i * interval_nsec) + my_obj->prev_timestamp;
stream_buf->ts.tv_sec = (frame_ts / 1000000000LL);
stream_buf->ts.tv_nsec = (frame_ts - (stream_buf->ts.tv_sec * 1000000000LL));
stream_buf->is_uv_subsampled = buf_info->buf->is_uv_subsampled;
LOGD("buf_index %d, frame_idx %d, stream type %d, timestamp = %lld",
stream_buf->buf_idx, stream_buf->frame_idx,
my_obj->stream_info->stream_type, frame_ts);
}
buf_info->buf->ts.tv_sec = (my_obj->prev_timestamp / 1000000000LL);
buf_info->buf->ts.tv_nsec = (my_obj->prev_timestamp -
(buf_info->buf->ts.tv_sec * 1000000000LL));
buf_info->buf->user_buf.bufs_used = user_buf->buf_cnt;
buf_info->buf->user_buf.buf_in_use = 1;
my_obj->prev_timestamp = timeStamp;
my_obj->prev_frameID = buf_info->buf->frame_idx;
LOGD("X rc = %d",rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_read_msm_frame
*
* DESCRIPTION: dequeue a stream buffer from kernel queue
*
* PARAMETERS :
* @my_obj : stream object
* @buf_info : ptr to a struct storing buffer information
* @num_planes : number of planes in the buffer
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_read_msm_frame(mm_stream_t * my_obj,
mm_camera_buf_info_t* buf_info,
uint8_t num_planes)
{
int32_t rc = 0;
struct v4l2_buffer vb;
struct v4l2_plane planes[VIDEO_MAX_PLANES];
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
memset(&vb, 0, sizeof(vb));
vb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
vb.memory = V4L2_MEMORY_USERPTR;
vb.m.planes = &planes[0];
vb.length = num_planes;
rc = ioctl(my_obj->fd, VIDIOC_DQBUF, &vb);
if (0 > rc) {
LOGE("VIDIOC_DQBUF ioctl call failed on stream type %d (rc=%d): %s",
my_obj->stream_info->stream_type, rc, strerror(errno));
} else {
pthread_mutex_lock(&my_obj->buf_lock);
my_obj->queued_buffer_count--;
if (0 == my_obj->queued_buffer_count) {
LOGH("Stoping poll on stream %p type: %d",
my_obj, my_obj->stream_info->stream_type);
mm_camera_poll_thread_del_poll_fd(&my_obj->ch_obj->poll_thread[0],
my_obj->my_hdl, mm_camera_async_call);
LOGH("Stopped poll on stream %p type: %d",
my_obj, my_obj->stream_info->stream_type);
}
pthread_mutex_unlock(&my_obj->buf_lock);
uint32_t idx = vb.index;
buf_info->buf = &my_obj->buf[idx];
buf_info->frame_idx = vb.sequence;
buf_info->stream_id = my_obj->my_hdl;
buf_info->buf->stream_id = my_obj->my_hdl;
buf_info->buf->buf_idx = idx;
buf_info->buf->frame_idx = vb.sequence;
buf_info->buf->ts.tv_sec = vb.timestamp.tv_sec;
buf_info->buf->ts.tv_nsec = vb.timestamp.tv_usec * 1000;
buf_info->buf->flags = vb.flags;
LOGH("VIDIOC_DQBUF buf_index %d, frame_idx %d, stream type %d, rc %d,"
"queued: %d, buf_type = %d flags = %d",
vb.index, buf_info->buf->frame_idx,
my_obj->stream_info->stream_type, rc,
my_obj->queued_buffer_count, buf_info->buf->buf_type,
buf_info->buf->flags);
buf_info->buf->is_uv_subsampled =
(vb.reserved == V4L2_PIX_FMT_NV14 || vb.reserved == V4L2_PIX_FMT_NV41);
if(buf_info->buf->buf_type == CAM_STREAM_BUF_TYPE_USERPTR) {
mm_stream_read_user_buf(my_obj, buf_info);
}
if ( NULL != my_obj->mem_vtbl.clean_invalidate_buf ) {
rc = my_obj->mem_vtbl.clean_invalidate_buf(idx,
my_obj->mem_vtbl.user_data);
if (0 > rc) {
LOGE("Clean invalidate cache failed on buffer index: %d",
idx);
}
} else {
LOGE("Clean invalidate cache op not supported");
}
}
LOGD("X rc = %d",rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_set_parms
*
* DESCRIPTION: set parameters per stream
*
* PARAMETERS :
* @my_obj : stream object
* @in_value : ptr to a param struct to be set to server
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
* NOTE : Assume the parms struct buf is already mapped to server via
* domain socket. Corresponding fields of parameters to be set
* are already filled in by upper layer caller.
*==========================================================================*/
int32_t mm_stream_set_parm(mm_stream_t *my_obj,
cam_stream_parm_buffer_t *in_value)
{
int32_t rc = -1;
int32_t value = 0;
if (in_value != NULL) {
mm_camera_obj_t *cam_obj = my_obj->ch_obj->cam_obj;
int stream_id = my_obj->server_stream_id;
rc = mm_camera_util_s_ctrl(cam_obj, stream_id, my_obj->fd,
CAM_PRIV_STREAM_PARM, &value);
if (rc < 0) {
LOGE("Failed to set stream parameter type = %d", in_value->type);
}
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_get_parms
*
* DESCRIPTION: get parameters per stream
*
* PARAMETERS :
* @my_obj : stream object
* @in_value : ptr to a param struct to be get from server
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
* NOTE : Assume the parms struct buf is already mapped to server via
* domain socket. Corresponding fields of parameters to be get
* are already filled in by upper layer caller.
*==========================================================================*/
int32_t mm_stream_get_parm(mm_stream_t *my_obj,
cam_stream_parm_buffer_t *in_value)
{
int32_t rc = -1;
int32_t value = 0;
if (in_value != NULL) {
mm_camera_obj_t *cam_obj = my_obj->ch_obj->cam_obj;
int stream_id = my_obj->server_stream_id;
rc = mm_camera_util_g_ctrl(cam_obj, stream_id, my_obj->fd,
CAM_PRIV_STREAM_PARM, &value);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_do_actions
*
* DESCRIPTION: request server to perform stream based actions
*
* PARAMETERS :
* @my_obj : stream object
* @in_value : ptr to a struct of actions to be performed by the server
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
* NOTE : Assume the action struct buf is already mapped to server via
* domain socket. Corresponding fields of actions to be performed
* are already filled in by upper layer caller.
*==========================================================================*/
int32_t mm_stream_do_action(mm_stream_t *my_obj,
void *in_value)
{
int32_t rc = -1;
int32_t value = 0;
if (in_value != NULL) {
mm_camera_obj_t *cam_obj = my_obj->ch_obj->cam_obj;
int stream_id = my_obj->server_stream_id;
rc = mm_camera_util_s_ctrl(cam_obj, stream_id, my_obj->fd,
CAM_PRIV_STREAM_PARM, &value);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_set_ext_mode
*
* DESCRIPTION: set stream extended mode to server via v4l2 ioctl
*
* PARAMETERS :
* @my_obj : stream object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
* NOTE : Server will return a server stream id that uniquely identify
* this stream on server side. Later on communication to server
* per stream should use this server stream id.
*==========================================================================*/
int32_t mm_stream_set_ext_mode(mm_stream_t * my_obj)
{
int32_t rc = 0;
struct v4l2_streamparm s_parm;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
memset(&s_parm, 0, sizeof(s_parm));
s_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
rc = ioctl(my_obj->fd, VIDIOC_S_PARM, &s_parm);
LOGD("stream fd=%d, rc=%d, extended_mode=%d",
my_obj->fd, rc, s_parm.parm.capture.extendedmode);
if (rc == 0) {
my_obj->server_stream_id = s_parm.parm.capture.extendedmode;
#ifndef DAEMON_PRESENT
cam_shim_packet_t *shim_cmd;
cam_shim_cmd_data shim_cmd_data;
mm_camera_obj_t *cam_obj = my_obj->ch_obj->cam_obj;
memset(&shim_cmd_data, 0, sizeof(shim_cmd_data));
shim_cmd_data.command = MSM_CAMERA_PRIV_NEW_STREAM;
shim_cmd_data.stream_id = my_obj->server_stream_id;
shim_cmd_data.value = NULL;
shim_cmd = mm_camera_create_shim_cmd_packet(CAM_SHIM_SET_PARM,
cam_obj->sessionid, &shim_cmd_data);
rc = mm_camera_module_send_cmd(shim_cmd);
mm_camera_destroy_shim_cmd_packet(shim_cmd);
#endif /* DAEMON_PRESENT */
} else {
LOGE("VIDIOC_S_PARM extendedmode error");
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_qbuf
*
* DESCRIPTION: enqueue buffer back to kernel queue for furture use
*
* PARAMETERS :
* @my_obj : stream object
* @buf : ptr to a struct storing buffer information
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_qbuf(mm_stream_t *my_obj, mm_camera_buf_def_t *buf)
{
int32_t rc = 0;
uint32_t length = 0;
struct v4l2_buffer buffer;
struct v4l2_plane planes[VIDEO_MAX_PLANES];
LOGD("E, my_handle = 0x%x, fd = %d, state = %d, stream type = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state,
my_obj->stream_info->stream_type);
if (buf->buf_type == CAM_STREAM_BUF_TYPE_USERPTR) {
LOGD("USERPTR num_buf = %d, idx = %d",
buf->user_buf.bufs_used, buf->buf_idx);
memset(&planes, 0, sizeof(planes));
planes[0].length = my_obj->stream_info->user_buf_info.size;
planes[0].m.userptr = buf->fd;
length = 1;
} else {
memcpy(planes, buf->planes_buf.planes, sizeof(planes));
length = buf->planes_buf.num_planes;
}
memset(&buffer, 0, sizeof(buffer));
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buffer.memory = V4L2_MEMORY_USERPTR;
buffer.index = (__u32)buf->buf_idx;
buffer.m.planes = &planes[0];
buffer.length = (__u32)length;
if ( NULL != my_obj->mem_vtbl.invalidate_buf ) {
rc = my_obj->mem_vtbl.invalidate_buf(buffer.index,
my_obj->mem_vtbl.user_data);
if ( 0 > rc ) {
LOGE("Cache invalidate failed on buffer index: %d",
buffer.index);
return rc;
}
} else {
LOGE("Cache invalidate op not added");
}
pthread_mutex_lock(&my_obj->buf_lock);
my_obj->queued_buffer_count++;
if (1 == my_obj->queued_buffer_count) {
/* Add fd to data poll thread */
LOGH("Starting poll on stream %p type: %d",
my_obj,my_obj->stream_info->stream_type);
rc = mm_camera_poll_thread_add_poll_fd(&my_obj->ch_obj->poll_thread[0],
my_obj->my_hdl, my_obj->fd, mm_stream_data_notify, (void*)my_obj,
mm_camera_async_call);
if (0 > rc) {
LOGE("Add poll on stream %p type: %d fd error (rc=%d)",
my_obj, my_obj->stream_info->stream_type, rc);
} else {
LOGH("Started poll on stream %p type: %d",
my_obj, my_obj->stream_info->stream_type);
}
}
pthread_mutex_unlock(&my_obj->buf_lock);
rc = ioctl(my_obj->fd, VIDIOC_QBUF, &buffer);
pthread_mutex_lock(&my_obj->buf_lock);
if (0 > rc) {
LOGE("VIDIOC_QBUF ioctl call failed on stream type %d (rc=%d): %s",
my_obj->stream_info->stream_type, rc, strerror(errno));
my_obj->queued_buffer_count--;
if (0 == my_obj->queued_buffer_count) {
/* Remove fd from data poll in case of failing
* first buffer queuing attempt */
LOGH("Stoping poll on stream %p type: %d",
my_obj, my_obj->stream_info->stream_type);
mm_camera_poll_thread_del_poll_fd(&my_obj->ch_obj->poll_thread[0],
my_obj->my_hdl, mm_camera_async_call);
LOGH("Stopped poll on stream %p type: %d",
my_obj, my_obj->stream_info->stream_type);
}
} else {
LOGH("VIDIOC_QBUF buf_index %d, frame_idx %d stream type %d, rc %d,"
" queued: %d, buf_type = %d",
buffer.index, buf->frame_idx, my_obj->stream_info->stream_type, rc,
my_obj->queued_buffer_count, buf->buf_type);
}
pthread_mutex_unlock(&my_obj->buf_lock);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_request_buf
*
* DESCRIPTION: This function let kernel know the amount of buffers need to
* be registered via v4l2 ioctl.
*
* PARAMETERS :
* @my_obj : stream object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_request_buf(mm_stream_t * my_obj)
{
int32_t rc = 0;
struct v4l2_requestbuffers bufreq;
uint8_t buf_num = my_obj->buf_num;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
LOGD("buf_num = %d, stream type = %d",
buf_num, my_obj->stream_info->stream_type);
if(buf_num > MM_CAMERA_MAX_NUM_FRAMES) {
LOGE("buf num %d > max limit %d\n",
buf_num, MM_CAMERA_MAX_NUM_FRAMES);
return -1;
}
memset(&bufreq, 0, sizeof(bufreq));
bufreq.count = buf_num;
bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
bufreq.memory = V4L2_MEMORY_USERPTR;
rc = ioctl(my_obj->fd, VIDIOC_REQBUFS, &bufreq);
if (rc < 0) {
LOGE("fd=%d, ioctl VIDIOC_REQBUFS failed: rc=%d, errno %d",
my_obj->fd, rc, errno);
}
LOGD("X rc = %d",rc);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_need_wait_for_mapping
*
* DESCRIPTION: Utility function to determine whether to wait for mapping
*
* PARAMETERS :
* @my_obj : stream object
*
* RETURN : int8_t whether wait is necessary
* 0 -- no wait
* 1 -- wait
*==========================================================================*/
int8_t mm_stream_need_wait_for_mapping(mm_stream_t * my_obj)
{
uint32_t i;
int8_t ret = 0;
for (i = 0; i < my_obj->buf_num; i++) {
if ((my_obj->buf_status[i].map_status == 0)
&& (my_obj->buf_status[i].in_kernel)) {
/*do not signal in case if any buffer is not mapped
but queued to kernel.*/
ret = 1;
} else if (my_obj->buf_status[i].map_status < 0) {
return 0;
}
}
return ret;
}
/*===========================================================================
* FUNCTION : mm_stream_map_buf
*
* DESCRIPTION: mapping stream buffer via domain socket to server
*
* PARAMETERS :
* @my_obj : stream object
* @buf_type : type of buffer to be mapped. could be following values:
* CAM_MAPPING_BUF_TYPE_STREAM_BUF
* CAM_MAPPING_BUF_TYPE_STREAM_INFO
* CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF
* @frame_idx : index of buffer within the stream buffers, only valid if
* buf_type is CAM_MAPPING_BUF_TYPE_STREAM_BUF or
* CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF
* @plane_idx : plane index. If all planes share the same fd,
* plane_idx = -1; otherwise, plean_idx is the
* index to plane (0..num_of_planes)
* @fd : file descriptor of the buffer
* @size : size of the buffer
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_map_buf(mm_stream_t * my_obj,
uint8_t buf_type, uint32_t frame_idx,
int32_t plane_idx, int32_t fd,
size_t size, void *buffer)
{
int32_t rc = 0;
if (NULL == my_obj || NULL == my_obj->ch_obj || NULL == my_obj->ch_obj->cam_obj) {
LOGE("NULL obj of stream/channel/camera");
return -1;
}
cam_sock_packet_t packet;
memset(&packet, 0, sizeof(cam_sock_packet_t));
packet.msg_type = CAM_MAPPING_TYPE_FD_MAPPING;
packet.payload.buf_map.type = buf_type;
packet.payload.buf_map.fd = fd;
packet.payload.buf_map.size = size;
packet.payload.buf_map.stream_id = my_obj->server_stream_id;
packet.payload.buf_map.frame_idx = frame_idx;
packet.payload.buf_map.plane_idx = plane_idx;
packet.payload.buf_map.buffer = buffer;
LOGD("mapping buf_type %d, stream_id %d, frame_idx %d, fd %d, size %d",
buf_type, my_obj->server_stream_id, frame_idx, fd, size);
#ifdef DAEMON_PRESENT
rc = mm_camera_util_sendmsg(my_obj->ch_obj->cam_obj,
&packet, sizeof(cam_sock_packet_t), fd);
#else
cam_shim_packet_t *shim_cmd;
shim_cmd = mm_camera_create_shim_cmd_packet(CAM_SHIM_REG_BUF,
my_obj->ch_obj->cam_obj->sessionid, &packet);
rc = mm_camera_module_send_cmd(shim_cmd);
mm_camera_destroy_shim_cmd_packet(shim_cmd);
#endif
if ((buf_type == CAM_MAPPING_BUF_TYPE_STREAM_BUF)
|| ((buf_type
== CAM_MAPPING_BUF_TYPE_STREAM_USER_BUF)
&& (my_obj->stream_info != NULL)
&& (my_obj->stream_info->streaming_mode
== CAM_STREAMING_MODE_BATCH))) {
pthread_mutex_lock(&my_obj->buf_lock);
if (rc < 0) {
my_obj->buf_status[frame_idx].map_status = -1;
LOGE("fail status =%d", my_obj->buf_status[frame_idx].map_status);
} else {
my_obj->buf_status[frame_idx].map_status = 1;
}
if (mm_stream_need_wait_for_mapping(my_obj) == 0) {
LOGD("Buffer mapping Done: Signal strm fd = %d",
my_obj->fd);
pthread_cond_signal(&my_obj->buf_cond);
}
pthread_mutex_unlock(&my_obj->buf_lock);
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_map_bufs
*
* DESCRIPTION: mapping stream buffers via domain socket to server
*
* PARAMETERS :
* @my_obj : stream object
* @buf_map_list : list of buffer objects to map
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_map_bufs(mm_stream_t * my_obj,
const cam_buf_map_type_list *buf_map_list)
{
if (NULL == my_obj || NULL == my_obj->ch_obj || NULL == my_obj->ch_obj->cam_obj) {
LOGE("NULL obj of stream/channel/camera");
return -1;
}
cam_sock_packet_t packet;
memset(&packet, 0, sizeof(cam_sock_packet_t));
packet.msg_type = CAM_MAPPING_TYPE_FD_BUNDLED_MAPPING;
memcpy(&packet.payload.buf_map_list, buf_map_list,
sizeof(packet.payload.buf_map_list));
int sendfds[CAM_MAX_NUM_BUFS_PER_STREAM];
uint32_t numbufs = packet.payload.buf_map_list.length;
if (numbufs < 1) {
LOGD("No buffers, suppressing the mapping command");
return 0;
}
uint32_t i;
for (i = 0; i < numbufs; i++) {
packet.payload.buf_map_list.buf_maps[i].stream_id = my_obj->server_stream_id;
sendfds[i] = packet.payload.buf_map_list.buf_maps[i].fd;
}
for (i = numbufs; i < CAM_MAX_NUM_BUFS_PER_STREAM; i++) {
packet.payload.buf_map_list.buf_maps[i].fd = -1;
sendfds[i] = -1;
}
#ifdef DAEMON_PRESENT
int32_t ret = mm_camera_util_bundled_sendmsg(my_obj->ch_obj->cam_obj,
&packet, sizeof(cam_sock_packet_t), sendfds, numbufs);
#else
cam_shim_packet_t *shim_cmd;
shim_cmd = mm_camera_create_shim_cmd_packet(CAM_SHIM_REG_BUF,
my_obj->ch_obj->cam_obj->sessionid, &packet);
int32_t ret = mm_camera_module_send_cmd(shim_cmd);
mm_camera_destroy_shim_cmd_packet(shim_cmd);
#endif
if ((numbufs > 0) && ((buf_map_list->buf_maps[0].type
== CAM_MAPPING_BUF_TYPE_STREAM_BUF)
|| ((buf_map_list->buf_maps[0].type ==
CAM_MAPPING_BUF_TYPE_STREAM_USER_BUF)
&& (my_obj->stream_info != NULL)
&& (my_obj->stream_info->streaming_mode
== CAM_STREAMING_MODE_BATCH)))) {
pthread_mutex_lock(&my_obj->buf_lock);
for (i = 0; i < numbufs; i++) {
if (ret < 0) {
my_obj->buf_status[i].map_status = -1;
} else {
my_obj->buf_status[i].map_status = 1;
}
}
if (mm_stream_need_wait_for_mapping(my_obj) == 0) {
LOGD("Buffer mapping Done: Signal strm fd = %d",
my_obj->fd);
pthread_cond_signal(&my_obj->buf_cond);
}
pthread_mutex_unlock(&my_obj->buf_lock);
}
return ret;
}
/*===========================================================================
* FUNCTION : mm_stream_unmap_buf
*
* DESCRIPTION: unmapping stream buffer via domain socket to server
*
* PARAMETERS :
* @my_obj : stream object
* @buf_type : type of buffer to be unmapped. could be following values:
* CAM_MAPPING_BUF_TYPE_STREAM_BUF
* CAM_MAPPING_BUF_TYPE_STREAM_INFO
* CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF
* @frame_idx : index of buffer within the stream buffers, only valid if
* buf_type is CAM_MAPPING_BUF_TYPE_STREAM_BUF or
* CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF
* @plane_idx : plane index. If all planes share the same fd,
* plane_idx = -1; otherwise, plean_idx is the
* index to plane (0..num_of_planes)
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_unmap_buf(mm_stream_t * my_obj,
uint8_t buf_type,
uint32_t frame_idx,
int32_t plane_idx)
{
int32_t ret;
if (NULL == my_obj || NULL == my_obj->ch_obj || NULL == my_obj->ch_obj->cam_obj) {
LOGE("NULL obj of stream/channel/camera");
return -1;
}
cam_sock_packet_t packet;
memset(&packet, 0, sizeof(cam_sock_packet_t));
packet.msg_type = CAM_MAPPING_TYPE_FD_UNMAPPING;
packet.payload.buf_unmap.type = buf_type;
packet.payload.buf_unmap.stream_id = my_obj->server_stream_id;
packet.payload.buf_unmap.frame_idx = frame_idx;
packet.payload.buf_unmap.plane_idx = plane_idx;
#ifdef DAEMON_PRESENT
ret = mm_camera_util_sendmsg(my_obj->ch_obj->cam_obj,
&packet, sizeof(cam_sock_packet_t), -1);
#else
cam_shim_packet_t *shim_cmd;
shim_cmd = mm_camera_create_shim_cmd_packet(CAM_SHIM_REG_BUF,
my_obj->ch_obj->cam_obj->sessionid, &packet);
ret = mm_camera_module_send_cmd(shim_cmd);
mm_camera_destroy_shim_cmd_packet(shim_cmd);
#endif
pthread_mutex_lock(&my_obj->buf_lock);
my_obj->buf_status[frame_idx].map_status = 0;
pthread_mutex_unlock(&my_obj->buf_lock);
return ret;
}
/*===========================================================================
* FUNCTION : mm_stream_init_bufs
*
* DESCRIPTION: initialize stream buffers needed. This function will request
* buffers needed from upper layer through the mem ops table passed
* during configuration stage.
*
* PARAMETERS :
* @my_obj : stream object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_init_bufs(mm_stream_t * my_obj)
{
int32_t i, rc = 0;
uint8_t *reg_flags = NULL;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
/* deinit buf if it's not NULL*/
if (NULL != my_obj->buf) {
mm_stream_deinit_bufs(my_obj);
}
rc = my_obj->mem_vtbl.get_bufs(&my_obj->frame_offset,
&my_obj->buf_num,
&reg_flags,
&my_obj->buf,
&my_obj->map_ops,
my_obj->mem_vtbl.user_data);
if (0 != rc) {
LOGE("Error get buf, rc = %d\n", rc);
return rc;
}
for (i = 0; i < my_obj->buf_num; i++) {
my_obj->buf_status[i].initial_reg_flag = reg_flags[i];
my_obj->buf[i].stream_id = my_obj->my_hdl;
my_obj->buf[i].stream_type = my_obj->stream_info->stream_type;
if (my_obj->buf[i].buf_type == CAM_STREAM_BUF_TYPE_USERPTR) {
my_obj->buf[i].user_buf.bufs_used =
(int8_t)my_obj->stream_info->user_buf_info.frame_buf_cnt;
my_obj->buf[i].user_buf.buf_in_use = reg_flags[i];
}
}
if (my_obj->stream_info->streaming_mode == CAM_STREAMING_MODE_BATCH) {
my_obj->plane_buf = my_obj->buf[0].user_buf.plane_buf;
if (my_obj->plane_buf != NULL) {
my_obj->plane_buf_num =
my_obj->buf_num *
my_obj->stream_info->user_buf_info.frame_buf_cnt;
for (i = 0; i < my_obj->plane_buf_num; i++) {
my_obj->plane_buf[i].stream_id = my_obj->my_hdl;
my_obj->plane_buf[i].stream_type = my_obj->stream_info->stream_type;
}
}
my_obj->cur_bufs_staged = 0;
my_obj->cur_buf_idx = -1;
}
free(reg_flags);
reg_flags = NULL;
/* update in stream info about number of stream buffers */
my_obj->stream_info->num_bufs = my_obj->buf_num;
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_deinit_bufs
*
* DESCRIPTION: return stream buffers to upper layer through the mem ops table
* passed during configuration stage.
*
* PARAMETERS :
* @my_obj : stream object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_deinit_bufs(mm_stream_t * my_obj)
{
int32_t rc = 0;
mm_camera_map_unmap_ops_tbl_t ops_tbl;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
if (NULL == my_obj->buf) {
LOGD("Buf is NULL, no need to deinit");
return rc;
}
/* release bufs */
ops_tbl.map_ops = mm_stream_map_buf_ops;
ops_tbl.bundled_map_ops = mm_stream_bundled_map_buf_ops;
ops_tbl.unmap_ops = mm_stream_unmap_buf_ops;
ops_tbl.userdata = my_obj;
rc = my_obj->mem_vtbl.put_bufs(&ops_tbl,
my_obj->mem_vtbl.user_data);
if (my_obj->plane_buf != NULL) {
free(my_obj->plane_buf);
my_obj->plane_buf = NULL;
}
free(my_obj->buf);
my_obj->buf = NULL;
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_reg_buf
*
* DESCRIPTION: register buffers with kernel by calling v4l2 ioctl QBUF for
* each buffer in the stream
*
* PARAMETERS :
* @my_obj : stream object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_reg_buf(mm_stream_t * my_obj)
{
int32_t rc = 0;
uint8_t i;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
rc = mm_stream_request_buf(my_obj);
if (rc != 0) {
return rc;
}
my_obj->queued_buffer_count = 0;
for(i = 0; i < my_obj->buf_num; i++){
/* check if need to qbuf initially */
if (my_obj->buf_status[i].initial_reg_flag) {
rc = mm_stream_qbuf(my_obj, &my_obj->buf[i]);
if (rc != 0) {
LOGE("VIDIOC_QBUF rc = %d\n", rc);
break;
}
my_obj->buf_status[i].buf_refcnt = 0;
my_obj->buf_status[i].in_kernel = 1;
} else {
/* the buf is held by upper layer, will not queue into kernel.
* add buf reference count */
my_obj->buf_status[i].buf_refcnt = 1;
my_obj->buf_status[i].in_kernel = 0;
}
}
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_unreg buf
*
* DESCRIPTION: unregister all stream buffers from kernel
*
* PARAMETERS :
* @my_obj : stream object
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_unreg_buf(mm_stream_t * my_obj)
{
struct v4l2_requestbuffers bufreq;
int32_t i, rc = 0;
LOGD("E, my_handle = 0x%x, fd = %d, state = %d",
my_obj->my_hdl, my_obj->fd, my_obj->state);
/* unreg buf to kernel */
bufreq.count = 0;
bufreq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
bufreq.memory = V4L2_MEMORY_USERPTR;
rc = ioctl(my_obj->fd, VIDIOC_REQBUFS, &bufreq);
if (rc < 0) {
LOGE("fd=%d, VIDIOC_REQBUFS failed, rc=%d, errno %d",
my_obj->fd, rc, errno);
}
/* reset buf reference count */
pthread_mutex_lock(&my_obj->buf_lock);
for(i = 0; i < my_obj->buf_num; i++){
my_obj->buf_status[i].buf_refcnt = 0;
my_obj->buf_status[i].in_kernel = 0;
}
pthread_mutex_unlock(&my_obj->buf_lock);
return rc;
}
/*===========================================================================
* FUNCTION : mm_stream_get_v4l2_fmt
*
* DESCRIPTION: translate camera image format into FOURCC code
*
* PARAMETERS :
* @fmt : camera image format
*
* RETURN : FOURCC code for image format
*==========================================================================*/
uint32_t mm_stream_get_v4l2_fmt(cam_format_t fmt)
{
uint32_t val = 0;
switch(fmt) {
case CAM_FORMAT_YUV_420_NV12:
case CAM_FORMAT_YUV_420_NV12_VENUS:
case CAM_FORMAT_YUV_420_NV12_UBWC:
val = V4L2_PIX_FMT_NV12;
break;
case CAM_FORMAT_YUV_420_NV21:
case CAM_FORMAT_YUV_420_NV21_VENUS:
val = V4L2_PIX_FMT_NV21;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_10BPP_GBRG:
val= V4L2_PIX_FMT_SGBRG10;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_10BPP_GRBG:
val= V4L2_PIX_FMT_SGRBG10;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_10BPP_RGGB:
val= V4L2_PIX_FMT_SRGGB10;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_10BPP_BGGR:
val= V4L2_PIX_FMT_SBGGR10;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_12BPP_GBRG:
val= V4L2_PIX_FMT_SGBRG12;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_12BPP_GRBG:
val= V4L2_PIX_FMT_SGRBG12;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_12BPP_RGGB:
val= V4L2_PIX_FMT_SRGGB12;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_12BPP_BGGR:
val = V4L2_PIX_FMT_SBGGR12;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_14BPP_GBRG:
case CAM_FORMAT_BAYER_IDEAL_RAW_MIPI_14BPP_GBRG:
val= V4L2_PIX_FMT_SGBRG14;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_14BPP_GRBG:
case CAM_FORMAT_BAYER_IDEAL_RAW_MIPI_14BPP_GRBG:
val= V4L2_PIX_FMT_SGRBG14;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_14BPP_RGGB:
case CAM_FORMAT_BAYER_IDEAL_RAW_MIPI_14BPP_RGGB:
val= V4L2_PIX_FMT_SRGGB14;
break;
case CAM_FORMAT_BAYER_QCOM_RAW_14BPP_BGGR:
case CAM_FORMAT_BAYER_IDEAL_RAW_MIPI_14BPP_BGGR:
val = V4L2_PIX_FMT_SBGGR14;
break;
case CAM_FORMAT_YUV_422_NV61:
val= V4L2_PIX_FMT_NV61;
break;
case CAM_FORMAT_YUV_RAW_8BIT_YUYV:
val= V4L2_PIX_FMT_YUYV;
break;
case CAM_FORMAT_YUV_RAW_8BIT_YVYU:
val= V4L2_PIX_FMT_YVYU;
break;
case CAM_FORMAT_YUV_RAW_8BIT_UYVY:
val= V4L2_PIX_FMT_UYVY;
break;
case CAM_FORMAT_YUV_RAW_8BIT_VYUY:
val= V4L2_PIX_FMT_VYUY;
break;
case CAM_FORMAT_YUV_420_YV12:
val= V4L2_PIX_FMT_NV12;
break;
case CAM_FORMAT_YUV_422_NV16:
val= V4L2_PIX_FMT_NV16;
break;
case CAM_FORMAT_Y_ONLY:
val= V4L2_PIX_FMT_GREY;
break;
case CAM_FORMAT_Y_ONLY_10_BPP:
val= V4L2_PIX_FMT_Y10;
break;
case CAM_FORMAT_Y_ONLY_12_BPP:
val= V4L2_PIX_FMT_Y12;
break;
case CAM_FORMAT_Y_ONLY_14_BPP:
/* No v4l2 format is defined yet for CAM_FORMAT_Y_ONLY_14_BPP */
/* val= V4L2_PIX_FMT_Y14; */
val = 0;
LOGE("Unknown fmt=%d", fmt);
break;
case CAM_FORMAT_MAX:
/* CAM_STREAM_TYPE_DEFAULT,
* CAM_STREAM_TYPE_OFFLINE_PROC,
* and CAM_STREAM_TYPE_METADATA
* set fmt to CAM_FORMAT_MAX*/
val = 0;
break;
default:
val = 0;
LOGE("Unknown fmt=%d", fmt);
break;
}
LOGD("fmt=%d, val =%d", fmt, val);
return val;
}
/*===========================================================================
* FUNCTION : mm_stream_calc_offset_preview
*
* DESCRIPTION: calculate preview frame offset based on format and
* padding information
*
* PARAMETERS :
* @fmt : image format
* @dim : image dimension
* @buf_planes : [out] buffer plane information
*
* RETURN : int32_t type of status
* 0 -- success
* -1 -- failure
*==========================================================================*/
int32_t mm_stream_calc_offset_preview(cam_stream_info_t *stream_info,
cam_dimension_t *dim,
cam_padding_info_t *padding,
cam_stream_buf_plane_info_t *buf_planes)
{
int32_t rc = 0;
int stride = 0, scanline = 0;
uint32_t width_padding = 0;
uint32_t height_padding = 0;
switch (stream_info->fmt) {
case CAM_FORMAT_YUV_420_NV12:
case CAM_FORMAT_YUV_420_NV21:
case CAM_FORMAT_Y_ONLY:
case CAM_FORMAT_Y_ONLY_10_BPP:
case CAM_FORMAT_Y_ONLY_12_BPP:
case CAM_FORMAT_Y_ONLY_14_BPP:
/* 2 planes: Y + CbCr */
buf_planes->plane_info.num_planes = 2;
if (stream_info->stream_type != CAM_STREAM_TYPE_OFFLINE_PROC) {
width_padding = padding->width_padding;
height_padding = CAM_PAD_TO_2;
} else {
width_padding = padding->width_padding;
height_padding = padding->height_padding;
}
stride = PAD_TO_SIZE(dim->width, width_padding);
scanline = PAD_TO_SIZE(dim->height, height_padding);
buf_planes->plane_info.mp[0].offset = 0;
buf_planes->plane_info.mp[0].len = (uint32_t)(stride * scanline);
buf_planes->plane_info.mp[0].offset_x = 0;
buf_planes->plane_info.mp[0].offset_y = 0;
buf_planes->plane_info.mp[0].stride = stride;
buf_planes->plane_info.mp[0].scanline = scanline;
buf_planes->plane_info.mp[0].width = dim->width;
buf_planes->plane_info.mp[0].height = dim->height;
stride = PAD_TO_SIZE(dim->width, width_padding);
scanline = PAD_TO_SIZE(dim->height / 2, height_padding);
buf_planes->plane_info.mp[1].offset = 0;
buf_planes->plane_info.mp[1].len =
(uint32_t)(stride * scanline);
buf_planes->plane_info.mp[1].offset_x = 0;
buf_planes->plane_info.mp[1].offset_y = 0;
buf_planes->plane_info.mp[1].stride = stride;
buf_planes->plane_info.mp[1].scanline = scanline;
buf_planes->plane_info.mp[1].width = dim->width;
buf_planes->plane_info.mp[1].height = dim->height / 2;
buf_planes->plane_info.frame_len =
PAD_TO_SIZE(buf_planes->plane_info.mp[0].len +
buf_planes->plane_info.mp[1].len,
CAM_PAD_TO_4K);
break;
case CAM_FORMAT_YUV_420_NV21_ADRENO:
/* 2 planes: Y + CbCr */
buf_planes->plane_info.num_planes = 2;
if (stream_info->stream_type != CAM_STREAM_TYPE_OFFLINE_PROC) {
stride = PAD_TO_SIZE(dim->width, CAM_PAD_TO_32);
scanline = PAD_TO_SIZE(dim->height, CAM_PAD_TO_32);
} else {
stride = PAD_TO_SIZE(dim->width, padding->width_padding);
scanline = PAD_TO_SIZE(dim->height, padding->height_padding);
}
buf_planes->plane_info.mp[0].offset = 0;
buf_planes->plane_info.mp[0].len =
PAD_TO_SIZE((uint32_t)(stride * scanline), CAM_PAD_TO_4K);
buf_planes->plane_info.mp[0].offset_x = 0;
buf_planes->plane_info.mp[0].offset_y = 0;
buf_planes->plane_info.mp[0].stride = stride;
buf_planes->plane_info.mp[0].scanline = scanline;
buf_planes->plane_info.mp[0].width = dim->width;
buf_planes->plane_info.mp[0].height = dim->height;
stride = PAD_TO_SIZE(dim->width / 2, CAM_PAD_TO_32) * 2;
scanline = PAD_TO_SIZE(dim->height / 2, CAM_PAD_TO_32);
buf_planes->plane_info.mp[1].offset = 0;
buf_planes->plane_info.mp[1].len =
PAD_TO_SIZE((uint32_t)(stride * scanline), CAM_PAD_TO_4K);
buf_planes->plane_info.mp[1].offset_x = 0;
buf_planes->plane_info.mp[1].offset_y = 0;
buf_planes->plane_info.mp[1].stride = stride;
buf_planes->plane_info.mp[1].scanline = scanline;
buf_planes->plane_info.mp[1].width = dim->width;
buf_planes->plane_info.mp[1].height = dim->height / 2;
buf_planes->plane_info.frame_len =
PAD_TO_SIZE(buf_planes->plane_info.mp[0].len +
buf_planes->plane_info.mp[1].len,
CAM_PAD_TO_4K);
break;
case CAM_FORMAT_YUV_420_YV12:
/* 3 planes: Y + Cr + Cb */
buf_planes->plane_info.num_planes = 3;
if (stream_info->stream_type != CAM_STREAM_TYPE_OFFLINE_PROC) {
stride = PAD_TO_SIZE(dim->width, CAM_PAD_TO_16);
scanline = PAD_TO_SIZE(dim->height, CAM_PAD_TO_2);
} else {
stride = PAD_TO_SIZE(dim->width, padding->width_padding);
scanline = PAD_TO_SIZE(dim->height, padding->height_padding);
}
buf_planes->plane_info.mp[0].offset = 0;
buf_planes->plane_info.mp[0].len = (uint32_t)(stride * scanline);
buf_planes->plane_info.mp[0].offset_x = 0;
buf_planes->plane_info.mp[0].offset_y = 0;
buf_planes->plane_info.mp[0].stride = stride;
buf_planes->plane_info.mp[0].scanline = scanline;
buf_planes->plane_info.mp[0].width = dim->width;
buf_planes->plane_info.mp[0].height = dim->height;
stride = PAD_TO_SIZE(stride / 2, CAM_PAD_TO_16);
scanline = scanline / 2;
buf_planes->plane_info.mp[1].offset = 0;
buf_planes->plane_info.mp[1].len =
(uint32_t)(stride * scanline);
buf_planes->plane_info.mp[1].offset_x = 0;
buf_planes->plane_info.mp[1].offset_y = 0;
buf_planes->plane_info.mp[1].stride = stride;
buf_planes->plane_info.mp[1].scanline = scanline;
buf_planes->plane_info.mp[1].width = dim->width / 2;
buf_planes->plane_info.mp[1].height = dim->height / 2;
buf_planes->plane_info.mp[2].offset = 0;
buf_planes->plane_info.mp[2].len =
(uint32_t)(stride * scanline);
buf_planes->plane_info.mp[2].offset_x = 0;
buf_planes->plane_info.mp[2].offset_y = 0;
buf_planes->plane_info.mp[2].stride = stride;
buf_planes->plane_info.mp[2].scanline = scanline;
buf_planes->plane_info.mp[2].width = dim->width / 2;
buf_planes->plane_info.mp[2].height = dim->height / 2;
buf_planes->plane_info.frame_len =
PAD_TO_SIZE(buf_planes->plane_info.mp[0].len +
buf_planes->plane_info.mp[1].len +
buf_planes->plane_info.mp[2].len,
CAM_PAD_TO_4K);
break;
case CAM_FORMAT_YUV_422_NV16:
case CAM_FORMAT_YUV_422_NV61:
/* 2 planes: Y + CbCr */
buf_planes->plane_info.num_planes = 2;
if (stream_info->stream_type != CAM_STREAM_TYPE_OFFLINE_PROC) {
stride = PAD_TO_SIZE(dim->width, CAM_PAD_TO_16);
scanline = dim->height;
} else {
stride = PAD_TO_SIZE(dim->width, padding->width_padding);
scanline = PAD_TO_SIZE(dim->height, padding->height_padding);
}
buf_planes->plane_info.mp[0].offset = 0;
buf_planes->plane_info.mp[0].len = (uint32_t)(stride * scanline);
buf_planes->plane_info.mp[0].offset_x = 0;
buf_planes->plane_info.mp[0].offset_y = 0;
buf_planes->plane_info.mp[0].stride = stride;
buf_planes->plane_info.mp[0].scanline = scanline;
buf_planes->plane_info.mp[0].width = dim->width;
buf_planes->plane_info.mp[0].height = dim->height;
buf_planes->plane_info.mp[1].offset = 0;
buf_planes->plane_info.mp[1].len = (uint32_t)(stride * scanline);
buf_planes->plane_info.mp[1].offset_x = 0;
buf_planes->plane_info.mp[1].offset_y = 0;
buf_planes->plane_info.mp[1].stride = stride;
buf_planes->plane_info.mp[1].scanline = scanline;
buf_planes->plane_info.mp[1].width = dim->width;
buf_planes->plane_info.mp[1].height = dim->height;
buf_planes->plane_info.frame_len =
PAD_TO_SIZE(buf_planes->plane_info.mp[0].len +
buf_planes->plane_info.mp[1].len,
CAM_PAD_TO_4K);
break;
case CAM_FORMAT_YUV_420_NV12_VENUS:
#ifdef VENUS_PRESENT
// using Venus
if (stream_info->stream_type != CAM_STREAM_TYPE_OFFLINE_PROC) {
stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, dim->width);
scanline = VENUS_Y_SCANLINES(COLOR_FMT_NV12, dim->height);
} else {
stride = PAD_TO_SIZE(dim->width, padding->width_padding);
scanline = PAD_TO_SIZE(dim->height, padding->height_padding);
}
buf_planes->plane_info.frame_len =
VENUS_BUFFER_SIZE(COLOR_FMT_NV12, stride, scanline);
buf_planes->plane_info.num_planes = 2;
buf_planes->plane_info.mp[0].len = (uint32_t)(stride * scanline);
buf_planes->plane_info.mp[0].offset = 0;
buf_planes->plane_info.mp[0].offset_x =0;
buf_planes->plane_info.mp[0].offset_y = 0;
buf_planes->plane_info.mp[0].stride = stride;
buf_planes->plane_info.mp[0].scanline = scanline;
buf_planes->plane_info.mp[0].width = dim->width;
buf_planes->plane_info.mp[0].height = dim->height;
if (stream_info->stream_type != CAM_STREAM_TYPE_OFFLINE_PROC) {
stride = VENUS_UV_STRIDE(COLOR_FMT_NV12, dim->width);
scanline = VENUS_UV_SCANLINES(COLOR_FMT_NV12, dim->height);
} else {
stride = PAD_TO_SIZE(dim->width, padding->width_padding);
scanline = PAD_TO_SIZE(dim->height, padding->height_padding);
}
buf_planes->plane_info.mp[1].len =
buf_planes->plane_info.frame_len - buf_planes->plane_info.mp[0].len;
buf_planes->plane_info.mp[1].offset = 0;
buf_planes->plane_info.mp[1].offset_x =0;
buf_planes->plane_info.mp[1].offset_y = 0;
buf_planes->plane_info.mp[1].stride = stride;
buf_planes->plane_info.mp[1].scanline = scanline;
buf_planes->plane_info.mp[1].width = dim->width;
buf_planes->plane_info.mp[1].height = dim->height / 2;
#else
LOGE("Venus hardware not avail, cannot use this format");
rc = -1;
#endif
break;
case CAM_FORMAT_YUV_420_NV21_VENUS:
#ifdef VENUS_PRESENT
// using Venus
if (stream_info->stream_type != CAM_STREAM_TYPE_OFFLINE_PROC) {
stride = VENUS_Y_STRIDE(COLOR_FMT_NV21, dim->width);
scanline = VENUS_Y_SCANLINES(COLOR_FMT_NV21, dim->height);
} else {
stride = PAD_TO_SIZE(dim->width, padding->width_padding);