blob: 81f10e9c6496bd02b43f9b071af6c531514a7f0c [file] [log] [blame]
/*
Copyright (c) 2011-2012, 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.
*/
#include <pthread.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#include <semaphore.h>
#include <linux/msm_ion.h>
#include "mm_camera_dbg.h"
#include "mm_camera_interface.h"
#include "mm_camera.h"
extern mm_camera_obj_t* mm_camera_util_get_camera_by_handler(uint32_t cam_handler);
extern mm_channel_t * mm_camera_util_get_channel_by_handler(
mm_camera_obj_t * cam_obj,
uint32_t handler);
extern int32_t mm_camera_send_native_ctrl_cmd(mm_camera_obj_t * my_obj,
cam_ctrl_type type,
uint32_t length,
void *value);
extern int32_t mm_camera_send_native_ctrl_timeout_cmd(mm_camera_obj_t * my_obj,
cam_ctrl_type type,
uint32_t length,
void *value,
int timeout);
/* internal function declare goes here */
int32_t mm_channel_qbuf(mm_channel_t *my_obj,
mm_camera_buf_def_t *buf);
int32_t mm_channel_init(mm_channel_t *my_obj);
void mm_channel_release(mm_channel_t *my_obj);
uint32_t mm_channel_add_stream(mm_channel_t *my_obj,
mm_camera_buf_notify_t buf_cb, void *user_data,
uint32_t ext_image_mode, uint32_t sensor_idx);
int32_t mm_channel_del_stream(mm_channel_t *my_obj,
uint32_t stream_id);
int32_t mm_channel_config_stream(mm_channel_t *my_obj,
uint32_t stream_id,
mm_camera_stream_config_t *config);
int32_t mm_channel_bundle_stream(mm_channel_t *my_obj,
mm_camera_buf_notify_t super_frame_notify_cb,
void *user_data,
mm_camera_bundle_attr_t *attr,
uint8_t num_streams,
uint32_t *stream_ids);
int32_t mm_channel_destroy_bundle(mm_channel_t *my_obj);
int32_t mm_channel_start_streams(mm_channel_t *my_obj,
uint8_t num_streams,
uint32_t *stream_ids);
int32_t mm_channel_stop_streams(mm_channel_t *my_obj,
uint8_t num_streams,
uint32_t *stream_ids,
uint8_t tear_down_flag);
int32_t mm_channel_request_super_buf(mm_channel_t *my_obj);
int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj);
int32_t mm_channel_start_focus(mm_channel_t *my_obj,
uint32_t sensor_idx,
uint32_t focus_mode);
int32_t mm_channel_abort_focus(mm_channel_t *my_obj,
uint32_t sensor_idx);
int32_t mm_channel_prepare_snapshot(mm_channel_t *my_obj,
uint32_t sensor_idx);
int32_t mm_channel_set_stream_parm(mm_channel_t *my_obj,
uint32_t s_id,
void *value);
int32_t mm_channel_get_stream_parm(mm_channel_t *my_obj,
uint32_t s_id,
void *value);
uint8_t mm_channel_need_do_pp(mm_channel_t *my_obj,
mm_channel_queue_node_t *super_buf);
int32_t mm_channel_do_post_processing(mm_channel_t *my_obj,
mm_channel_queue_node_t *super_buf);
int32_t mm_channel_cancel_post_processing(mm_channel_t *my_obj);
int32_t mm_channel_superbuf_bufdone_overflow(mm_channel_t* my_obj,
mm_channel_queue_t * queue);
int32_t mm_channel_superbuf_skip(mm_channel_t* my_obj,
mm_channel_queue_t * queue);
/* state machine function declare */
int32_t mm_channel_fsm_fn_notused(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val);
int32_t mm_channel_fsm_fn_stopped(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val);
int32_t mm_channel_fsm_fn_active(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val);
int32_t mm_channel_fsm_fn_paused(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val);
/* channel super queue functions */
int32_t mm_channel_superbuf_queue_init(mm_channel_queue_t * queue);
int32_t mm_channel_superbuf_queue_deinit(mm_channel_queue_t * queue);
int32_t mm_channel_superbuf_comp_and_enqueue(mm_channel_t *ch_obj,
mm_channel_queue_t * queue,
mm_camera_buf_info_t *buf);
mm_channel_queue_node_t* mm_channel_superbuf_dequeue(mm_channel_queue_t * queue);
/* channel utility function */
mm_stream_t * mm_channel_util_get_stream_by_handler(
mm_channel_t * ch_obj,
uint32_t handler)
{
int i;
mm_stream_t *s_obj = NULL;
uint8_t ch_idx = mm_camera_util_get_index_by_handler(handler);
for(i = 0; i < MM_CAMEAR_STRAEM_NUM_MAX; i++) {
if (handler == ch_obj->streams[i].my_hdl) {
s_obj = &ch_obj->streams[i];
break;
}
}
return s_obj;
}
/* CB for handling post processing result from ctrl evt */
static void mm_channel_pp_result_notify(uint32_t camera_handler,
mm_camera_event_t *evt,
void *user_data)
{
uint32_t ch_hdl = (uint32_t)user_data;
mm_camera_obj_t *cam_obj = NULL;
mm_channel_t *ch_obj = NULL;
mm_channel_queue_node_t * node = NULL;
mm_channel_pp_info_t* pp_info = NULL;
cam_obj = mm_camera_util_get_camera_by_handler(camera_handler);
if (NULL == cam_obj) {
CDBG("%s: No matching camera handler", __func__);
return;
}
ch_obj = mm_camera_util_get_channel_by_handler(cam_obj, ch_hdl);
if (NULL == ch_obj) {
CDBG("%s: No matching channel handler", __func__);
return;
}
pthread_mutex_lock(&ch_obj->ch_lock);
if (ch_obj->pending_pp_cnt > 0) {
if (MM_CAMERA_EVT_TYPE_CTRL == evt->event_type) {
/* PP result is sent as CTRL event
* currently we only have WNR */
if (MM_CAMERA_CTRL_EVT_WDN_DONE == evt->e.ctrl.evt) {
/* WNR result */
pp_info = (mm_channel_pp_info_t *)evt->e.ctrl.cookie;
if (NULL != pp_info) {
node = pp_info->super_buf;
}
}
}
if (NULL != node) {
uint8_t pp_done = 1;
if (CAM_CTRL_SUCCESS == evt->e.ctrl.status) {
uint8_t i;
/* 1) update need_pp flag as action done */
for (i=0; i<node->num_of_bufs; i++) {
if (node->super_buf[i].stream_id == pp_info->stream_hdl) {
/* stream pp is done, set the flag to 0*/
node->super_buf[i].need_pp = 0;
break;
}
}
/* 2) check if all bufs done with pp */
for (i=0; i<node->num_of_bufs; i++) {
if (node->super_buf[i].need_pp) {
pp_done = 0;
break;
}
}
}
if (pp_done) {
/* send super buf to CB */
if (NULL != ch_obj->bundle.super_buf_notify_cb) {
mm_camera_super_buf_t super_buf;
uint8_t i;
memset(&super_buf, 0, sizeof(mm_camera_super_buf_t));
super_buf.num_bufs = node->num_of_bufs;
for (i=0; i<node->num_of_bufs; i++) {
super_buf.bufs[i] = node->super_buf[i].buf;
}
super_buf.camera_handle = ch_obj->cam_obj->my_hdl;
super_buf.ch_id = ch_obj->my_hdl;
ch_obj->bundle.super_buf_notify_cb(&super_buf,
ch_obj->bundle.user_data);
ch_obj->pending_pp_cnt--;
} else {
/* buf done with the nonuse super buf */
uint8_t i;
for (i=0; i<node->num_of_bufs; i++) {
mm_channel_qbuf(ch_obj, node->super_buf[i].buf);
}
}
/* done with node, free it */
free(node);
}
}
}
pthread_mutex_unlock(&ch_obj->ch_lock);
}
/* CB for processing stream buffer */
static void mm_channel_process_stream_buf(mm_camera_cmdcb_t * cmd_cb,
void *user_data)
{
mm_camera_super_buf_notify_mode_t notify_mode;
mm_channel_queue_node_t *node = NULL;
mm_channel_t *ch_obj = (mm_channel_t *)user_data;
if (NULL == ch_obj) {
return;
}
if (MM_CAMERA_CMD_TYPE_DATA_CB == cmd_cb->cmd_type) {
/* comp_and_enqueue */
mm_channel_superbuf_comp_and_enqueue(
ch_obj,
&ch_obj->bundle.superbuf_queue,
&cmd_cb->u.buf);
}
notify_mode = ch_obj->bundle.superbuf_queue.attr.notify_mode;
/* bufdone for overflowed bufs */
mm_channel_superbuf_bufdone_overflow(ch_obj, &ch_obj->bundle.superbuf_queue);
/* lock ch_lock */
pthread_mutex_lock(&ch_obj->ch_lock);
/* dispatch frame if pending_cnt>0 or is in continuous streaming mode */
while ( (ch_obj->pending_cnt > 0) ||
(MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS == notify_mode) ) {
/* skip frames if needed */
mm_channel_superbuf_skip(ch_obj, &ch_obj->bundle.superbuf_queue);
/* dequeue */
node = mm_channel_superbuf_dequeue(&ch_obj->bundle.superbuf_queue);
if (NULL != node) {
/* decrease pending_cnt */
CDBG("%s: Super Buffer received, Call client callback",__func__);
if (MM_CAMERA_SUPER_BUF_NOTIFY_BURST == notify_mode) {
ch_obj->pending_cnt--;
}
if (mm_channel_need_do_pp(ch_obj, node)) {
/* do post processing */
ch_obj->pending_pp_cnt++;
mm_channel_do_post_processing(ch_obj, node);
/* no need to free node here
* node will be as cookie sent to backend doing pp */
} else {
/* dispatch superbuf */
if (NULL != ch_obj->bundle.super_buf_notify_cb) {
mm_camera_super_buf_t super_buf;
uint8_t i;
memset(&super_buf, 0, sizeof(mm_camera_super_buf_t));
super_buf.num_bufs = node->num_of_bufs;
for (i=0; i<node->num_of_bufs; i++) {
super_buf.bufs[i] = node->super_buf[i].buf;
}
super_buf.camera_handle = ch_obj->cam_obj->my_hdl;
super_buf.ch_id = ch_obj->my_hdl;
ch_obj->bundle.super_buf_notify_cb(&super_buf,
ch_obj->bundle.user_data);
} else {
/* buf done with the nonuse super buf */
uint8_t i;
for (i=0; i<node->num_of_bufs; i++) {
mm_channel_qbuf(ch_obj, node->super_buf[i].buf);
}
}
free(node);
}
} else {
/* no superbuf avail, break the loop */
CDBG_ERROR("%s : Superbuffer not available",__func__);
break;
}
}
/* unlock ch_lock */
pthread_mutex_unlock(&ch_obj->ch_lock);
}
/* state machine entry */
int32_t mm_channel_fsm_fn(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = -1;
CDBG("%s : E state = %d",__func__,my_obj->state);
switch (my_obj->state) {
case MM_CHANNEL_STATE_NOTUSED:
rc = mm_channel_fsm_fn_notused(my_obj, evt, in_val, out_val);
break;
case MM_CHANNEL_STATE_STOPPED:
rc = mm_channel_fsm_fn_stopped(my_obj, evt, in_val, out_val);
break;
case MM_CHANNEL_STATE_ACTIVE:
rc = mm_channel_fsm_fn_active(my_obj, evt, in_val, out_val);
break;
case MM_CHANNEL_STATE_PAUSED:
rc = mm_channel_fsm_fn_paused(my_obj, evt, in_val, out_val);
break;
default:
CDBG("%s: Not a valid state (%d)", __func__, my_obj->state);
break;
}
/* unlock ch_lock */
pthread_mutex_unlock(&my_obj->ch_lock);
CDBG("%s : X rc = %d",__func__,rc);
return rc;
}
int32_t mm_channel_fsm_fn_notused(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = -1;
switch (evt) {
default:
CDBG_ERROR("%s: invalid state (%d) for evt (%d)",
__func__, my_obj->state, evt);
break;
}
return rc;
}
int32_t mm_channel_fsm_fn_stopped(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = -1;
CDBG("%s : E evt = %d",__func__,evt);
switch (evt) {
case MM_CHANNEL_EVT_ADD_STREAM:
{
uint32_t s_hdl = 0;
mm_evt_paylod_add_stream_t *payload =
(mm_evt_paylod_add_stream_t *)in_val;
s_hdl = mm_channel_add_stream(my_obj,
payload->buf_cb,
payload->user_data,
payload->ext_image_mode,
payload->sensor_idx);
*((uint32_t*)out_val) = s_hdl;
rc = 0;
}
break;
case MM_CHANNEL_EVT_DEL_STREAM:
{
uint32_t s_id = *((uint32_t *)in_val);
rc = mm_channel_del_stream(my_obj, s_id);
}
break;
case MM_CHANNEL_EVT_START_STREAM:
{
mm_evt_payload_start_stream_t *payload =
(mm_evt_payload_start_stream_t *)in_val;
rc = mm_channel_start_streams(my_obj,
payload->num_streams,
payload->stream_ids);
/* first stream started in stopped state
* move to active state */
if (0 == rc) {
my_obj->state = MM_CHANNEL_STATE_ACTIVE;
}
}
break;
case MM_CHANNEL_EVT_CONFIG_STREAM:
{
mm_evt_paylod_config_stream_t *payload =
(mm_evt_paylod_config_stream_t *)in_val;
rc = mm_channel_config_stream(my_obj,
payload->stream_id,
payload->config);
}
break;
case MM_CHANNEL_EVT_INIT_BUNDLE:
{
mm_evt_payload_bundle_stream_t *payload =
(mm_evt_payload_bundle_stream_t *)in_val;
rc = mm_channel_bundle_stream(my_obj,
payload->super_frame_notify_cb,
payload->user_data,
payload->attr,
payload->num_streams,
payload->stream_ids);
}
break;
case MM_CHANNEL_EVT_DESTROY_BUNDLE:
rc = mm_channel_destroy_bundle(my_obj);
break;
case MM_CHANNEL_EVT_PREPARE_SNAPSHOT:
{
uint32_t sensor_idx = (uint32_t)in_val;
rc = mm_channel_prepare_snapshot(my_obj, sensor_idx);
}
break;
case MM_CHANNEL_EVT_DELETE:
mm_channel_release(my_obj);
rc = 0;
break;
case MM_CHANNEL_EVT_SET_STREAM_PARM:
{
uint32_t s_id = (uint32_t)in_val;
rc = mm_channel_set_stream_parm(my_obj, s_id, out_val);
}
break;
case MM_CHANNEL_EVT_GET_STREAM_PARM:
{
uint32_t s_id = (uint32_t)in_val;
rc = mm_channel_get_stream_parm(my_obj, s_id, out_val);
}
break;
default:
CDBG_ERROR("%s: invalid state (%d) for evt (%d)",
__func__, my_obj->state, evt);
break;
}
CDBG("%s : E rc = %d",__func__,rc);
return rc;
}
int32_t mm_channel_fsm_fn_active(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = -1;
CDBG("%s : E evt = %d",__func__,evt);
switch (evt) {
case MM_CHANNEL_EVT_CONFIG_STREAM:
{
mm_evt_paylod_config_stream_t *payload =
(mm_evt_paylod_config_stream_t *)in_val;
rc = mm_channel_config_stream(my_obj,
payload->stream_id,
payload->config);
}
break;
case MM_CHANNEL_EVT_START_STREAM:
{
mm_evt_payload_start_stream_t *payload =
(mm_evt_payload_start_stream_t *)in_val;
rc = mm_channel_start_streams(my_obj,
payload->num_streams,
payload->stream_ids);
}
break;
case MM_CHANNEL_EVT_STOP_STREAM:
case MM_CHANNEL_EVT_TEARDOWN_STREAM:
{
int i;
uint8_t tear_down_flag = (MM_CHANNEL_EVT_TEARDOWN_STREAM == evt)? 1:0;
uint8_t all_stopped = 1;
mm_evt_payload_stop_stream_t *payload =
(mm_evt_payload_stop_stream_t *)in_val;
rc = mm_channel_stop_streams(my_obj,
payload->num_streams,
payload->stream_ids,
tear_down_flag);
/* check if all streams are stopped
* then we move to stopped state */
for (i=0; i<MM_CAMEAR_STRAEM_NUM_MAX; i++) {
if (MM_STREAM_STATE_ACTIVE_STREAM_ON == my_obj->streams[i].state ||
MM_STREAM_STATE_ACTIVE_STREAM_OFF == my_obj->streams[i].state) {
all_stopped = 0;
break;
}
}
if (all_stopped) {
my_obj->state = MM_CHANNEL_STATE_STOPPED;
}
}
break;
case MM_CHANNEL_EVT_INIT_BUNDLE:
{
mm_evt_payload_bundle_stream_t *payload =
(mm_evt_payload_bundle_stream_t *)in_val;
rc = mm_channel_bundle_stream(my_obj,
payload->super_frame_notify_cb,
payload->user_data,
payload->attr,
payload->num_streams,
payload->stream_ids);
}
break;
case MM_CHANNEL_EVT_DESTROY_BUNDLE:
rc = mm_channel_destroy_bundle(my_obj);
break;
case MM_CHANNEL_EVT_REQUEST_SUPER_BUF:
rc = mm_channel_request_super_buf(my_obj);
break;
case MM_CHANNEL_EVT_CANCEL_REQUEST_SUPER_BUF:
rc = mm_channel_cancel_super_buf_request(my_obj);
break;
case MM_CHANNEL_EVT_START_FOCUS:
{
mm_evt_payload_start_focus_t* payload =
(mm_evt_payload_start_focus_t *)in_val;
rc = mm_channel_start_focus(my_obj,
payload->sensor_idx,
payload->focus_mode);
}
break;
case MM_CHANNEL_EVT_ABORT_FOCUS:
{
uint32_t sensor_idx = (uint32_t)in_val;
rc = mm_channel_abort_focus(my_obj, sensor_idx);
}
break;
case MM_CHANNEL_EVT_PREPARE_SNAPSHOT:
{
uint32_t sensor_idx = (uint32_t)in_val;
rc = mm_channel_prepare_snapshot(my_obj, sensor_idx);
}
break;
case MM_CHANNEL_EVT_SET_STREAM_PARM:
{
uint32_t s_id = (uint32_t)in_val;
rc = mm_channel_set_stream_parm(my_obj, s_id, out_val);
}
break;
case MM_CHANNEL_EVT_GET_STREAM_PARM:
{
uint32_t s_id = (uint32_t)in_val;
rc = mm_channel_get_stream_parm(my_obj, s_id, out_val);
}
break;
case MM_CHANNEL_EVT_DEL_STREAM:
{
uint32_t s_id = *((uint32_t *)in_val);
rc = mm_channel_del_stream(my_obj, s_id);
}
break;
default:
CDBG_ERROR("%s: invalid state (%d) for evt (%d)",
__func__, my_obj->state, evt);
break;
}
CDBG("%s : X rc = %d",__func__,rc);
return rc;
}
int32_t mm_channel_fsm_fn_paused(mm_channel_t *my_obj,
mm_channel_evt_type_t evt,
void * in_val,
void * out_val)
{
int32_t rc = -1;
/* currently we are not supporting pause/resume channel */
CDBG_ERROR("%s: evt (%d) not supported in state (%d)",
__func__, evt, my_obj->state);
return rc;
}
int32_t mm_channel_init(mm_channel_t *my_obj)
{
int32_t rc = 0;
CDBG("%s : Launch data poll thread in channel open",__func__);
mm_camera_poll_thread_launch(&my_obj->poll_thread[0],
MM_CAMERA_POLL_TYPE_CH);
/* change state to stopped state */
my_obj->state = MM_CHANNEL_STATE_STOPPED;
return rc;
}
void mm_channel_release(mm_channel_t *my_obj)
{
/* stop data poll thread */
mm_camera_poll_thread_release(&my_obj->poll_thread[0]);
/* change state to notused state */
my_obj->state = MM_CHANNEL_STATE_NOTUSED;
}
uint32_t mm_channel_add_stream(mm_channel_t *my_obj,
mm_camera_buf_notify_t buf_cb, void *user_data,
uint32_t ext_image_mode, uint32_t sensor_idx)
{
int32_t rc = 0;
uint8_t idx = 0;
uint32_t s_hdl = 0;
mm_stream_t *stream_obj = NULL;
CDBG("%s : image mode = %d",__func__,ext_image_mode);
/* check available stream */
for (idx = 0; idx < MM_CAMEAR_STRAEM_NUM_MAX; idx++) {
if (MM_STREAM_STATE_NOTUSED == my_obj->streams[idx].state) {
stream_obj = &my_obj->streams[idx];
break;
}
}
if (NULL == stream_obj) {
CDBG_ERROR("%s: streams reach max, no more stream allowed to add", __func__);
return s_hdl;
}
/* initialize stream object */
memset(stream_obj, 0, sizeof(mm_stream_t));
stream_obj->my_hdl = mm_camera_util_generate_handler(idx);
stream_obj->ch_obj = my_obj;
/* cd through intf always palced at idx 0 of buf_cb */
stream_obj->buf_cb[0].cb = buf_cb;
stream_obj->buf_cb[0].user_data = user_data;
stream_obj->buf_cb[0].cb_count = -1; /* infinite by default */
stream_obj->ext_image_mode = ext_image_mode + 1;
stream_obj->sensor_idx = sensor_idx;
stream_obj->fd = -1;
pthread_mutex_init(&stream_obj->buf_lock, NULL);
pthread_mutex_init(&stream_obj->cb_lock, NULL);
stream_obj->state = MM_STREAM_STATE_INITED;
/* acquire stream */
rc = mm_stream_fsm_fn(stream_obj, MM_STREAM_EVT_ACQUIRE, NULL, NULL);
if (0 == rc) {
s_hdl = stream_obj->my_hdl;
} else {
/* error during acquire, de-init */
pthread_mutex_destroy(&stream_obj->buf_lock);
pthread_mutex_destroy(&stream_obj->cb_lock);
memset(stream_obj, 0, sizeof(mm_stream_t));
}
CDBG("%s : stream handle = %d",__func__,s_hdl);
return s_hdl;
}
int32_t mm_channel_del_stream(mm_channel_t *my_obj,
uint32_t stream_id)
{
int rc = -1;
mm_stream_t * stream_obj = NULL;
stream_obj = mm_channel_util_get_stream_by_handler(my_obj, stream_id);
if (NULL == stream_obj) {
CDBG_ERROR("%s :Invalid Stream Object",__func__);
return rc;
}
rc = mm_stream_fsm_fn(stream_obj,
MM_STREAM_EVT_RELEASE,
NULL,
NULL);
return rc;
}
int32_t mm_channel_config_stream(mm_channel_t *my_obj,
uint32_t stream_id,
mm_camera_stream_config_t *config)
{
int rc = -1;
mm_stream_t * stream_obj = NULL;
CDBG("%s : E stream ID = %d",__func__,stream_id);
stream_obj = mm_channel_util_get_stream_by_handler(my_obj, stream_id);
if (NULL == stream_obj) {
CDBG_ERROR("%s : X rc = %d",__func__,rc);
return rc;
}
/* set stream fmt */
rc = mm_stream_fsm_fn(stream_obj,
MM_STREAM_EVT_SET_FMT,
(void *)config,
NULL);
CDBG("%s : X rc = %d",__func__,rc);
return rc;
}
int32_t mm_channel_bundle_stream(mm_channel_t *my_obj,
mm_camera_buf_notify_t super_frame_notify_cb,
void *user_data,
mm_camera_bundle_attr_t *attr,
uint8_t num_streams,
uint32_t *stream_ids)
{
int32_t rc = 0;
int i;
mm_stream_t* s_objs[MM_CAMEAR_MAX_STRAEM_BUNDLE] = {NULL};
/* first check if all streams to be bundled are valid */
for (i=0; i < num_streams; i++) {
s_objs[i] = mm_channel_util_get_stream_by_handler(my_obj, stream_ids[i]);
if (NULL == s_objs[i]) {
CDBG_ERROR("%s: invalid stream handler %d (idx=%d) to be bundled",
__func__, stream_ids[i], i);
return -1;
}
}
/* init superbuf queue */
mm_channel_superbuf_queue_init(&my_obj->bundle.superbuf_queue);
/* save bundle config */
memcpy(&my_obj->bundle.superbuf_queue.attr, attr, sizeof(mm_camera_bundle_attr_t));
my_obj->bundle.super_buf_notify_cb = super_frame_notify_cb;
my_obj->bundle.user_data = user_data;
my_obj->bundle.superbuf_queue.num_streams = num_streams;
my_obj->bundle.superbuf_queue.expected_frame_id = 0;
for (i=0; i < num_streams; i++) {
/* set bundled flag to streams */
s_objs[i]->is_bundled = 1;
/* init bundled streams to invalid value -1 */
//my_obj->bundle.superbuf_queue.bundled_streams[i] = -1;
my_obj->bundle.superbuf_queue.bundled_streams[i] = stream_ids[i];
}
/* launch cmd thread for super buf dataCB */
mm_camera_cmd_thread_launch(&my_obj->cmd_thread,
mm_channel_process_stream_buf,
(void*)my_obj);
/* check if we need to do post-processing */
if (my_obj->cam_obj->need_pp) {
/* register postProcessingCB at camera evt polling thread
* because pp result is coming from ctrl evt */
mm_camera_register_event_notify_internal(my_obj->cam_obj,
mm_channel_pp_result_notify,
(void *)my_obj->my_hdl,
MM_CAMERA_EVT_TYPE_CTRL);
}
return rc;
}
/* bundled streams must all be stopped before bundle can be destroyed */
int32_t mm_channel_destroy_bundle(mm_channel_t *my_obj)
{
mm_camera_cmd_thread_release(&my_obj->cmd_thread);
/* deinit superbuf queue */
mm_channel_superbuf_queue_deinit(&my_obj->bundle.superbuf_queue);
/* memset bundle info */
memset(&my_obj->bundle, 0, sizeof(mm_channel_bundle_t));
return 0;
}
int32_t mm_channel_start_streams(mm_channel_t *my_obj,
uint8_t num_streams,
uint32_t *stream_ids)
{
int32_t rc = 0;
int i, j;
mm_stream_t* s_objs[MM_CAMEAR_MAX_STRAEM_BUNDLE] = {NULL};
uint8_t num_streams_to_start = num_streams;
uint32_t streams_to_start[MM_CAMEAR_MAX_STRAEM_BUNDLE];
uint8_t bundle_to_start = 0;
/* check if any bundled stream to be start,
* then all bundled stream should be started */
memcpy(streams_to_start, stream_ids, sizeof(uint32_t) * num_streams);
for (i=0; i < num_streams; i++) {
for (j=0; j < my_obj->bundle.superbuf_queue.num_streams; j++) {
if (stream_ids[i] == my_obj->bundle.superbuf_queue.bundled_streams[j]) {
bundle_to_start = 1;
break;
}
}
}
if (bundle_to_start) {
uint8_t need_add;
/* add bundled streams into the start list if not already added*/
for (i=0; i<my_obj->bundle.superbuf_queue.num_streams; i++) {
need_add = 1;
for (j=0; j<num_streams; j++) {
if (stream_ids[j] == my_obj->bundle.superbuf_queue.bundled_streams[i]) {
need_add = 0;
break;
}
}
if (need_add) {
streams_to_start[num_streams_to_start++] =
my_obj->bundle.superbuf_queue.bundled_streams[i];
}
}
}
/* check if all streams to be started are valid */
for (i=0; i<num_streams_to_start; i++) {
s_objs[i] = mm_channel_util_get_stream_by_handler(my_obj, streams_to_start[i]);
if (NULL == s_objs[i]) {
CDBG_ERROR("%s: invalid stream handler %d (idx=%d) to be started",
__func__, streams_to_start[i], i);
return -1;
}
}
for (i=0; i<num_streams_to_start; i++) {
/* allocate buf */
rc = mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_GET_BUF,
NULL,
NULL);
if (0 != rc) {
CDBG_ERROR("%s: get buf failed at idx(%d)", __func__, i);
break;
}
/* reg buf */
rc = mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_REG_BUF,
NULL,
NULL);
if (0 != rc) {
CDBG_ERROR("%s: reg buf failed at idx(%d)", __func__, i);
break;
}
/* TODO */
/* for now, hard-coded to 1 for main image stream */
/* Query if stream need to do pp under current hardware configuration,
* when camera has offline pp capability */
if (my_obj->cam_obj->need_pp) {
if (MSM_V4L2_EXT_CAPTURE_MODE_MAIN == s_objs[i]->ext_image_mode) {
s_objs[i]->is_pp_needed = 1;
} else {
s_objs[i]->is_pp_needed = 0;
}
}
/* start stream */
rc = mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_START,
NULL,
NULL);
if (0 != rc) {
CDBG_ERROR("%s: start stream failed at idx(%d)", __func__, i);
break;
}
}
/* error handling */
if (0 != rc) {
for (j=0; j<=i; j++) {
/* stop streams*/
mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_STOP,
NULL,
NULL);
/* unreg buf */
mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_UNREG_BUF,
NULL,
NULL);
/* put buf back */
mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_PUT_BUF,
NULL,
NULL);
}
}
return rc;
}
/* Required: bundled streams need to be stopped together */
int32_t mm_channel_stop_streams(mm_channel_t *my_obj,
uint8_t num_streams,
uint32_t *stream_ids,
uint8_t tear_down_flag)
{
int32_t rc = 0;
int i, j;
mm_stream_t* s_objs[MM_CAMEAR_MAX_STRAEM_BUNDLE] = {NULL};
uint8_t num_streams_to_stop = num_streams;
uint32_t streams_to_stop[MM_CAMEAR_MAX_STRAEM_BUNDLE];
uint8_t bundle_to_stop = 0;
/* make sure bundled streams are stopped together */
memcpy(streams_to_stop, stream_ids, sizeof(uint32_t) * num_streams);
for (i=0; i<num_streams; i++) {
for (j=0; j<my_obj->bundle.superbuf_queue.num_streams; j++) {
if (stream_ids[i] == my_obj->bundle.superbuf_queue.bundled_streams[j]) {
bundle_to_stop = 1;
break;
}
}
}
if (bundle_to_stop) {
uint8_t need_add;
/* add bundled streams into the start list if not already added*/
for (i=0; i<my_obj->bundle.superbuf_queue.num_streams; i++) {
need_add = 1;
for (j=0; j<num_streams; j++) {
if (stream_ids[j] == my_obj->bundle.superbuf_queue.bundled_streams[i]) {
need_add = 0;
break;
}
}
if (need_add) {
streams_to_stop[num_streams_to_stop++] =
my_obj->bundle.superbuf_queue.bundled_streams[i];
}
}
}
for (i=0; i<num_streams_to_stop; i++) {
s_objs[i] = mm_channel_util_get_stream_by_handler(my_obj, streams_to_stop[i]);
if (NULL != s_objs[i]) {
/* stream off */
mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_STOP,
NULL,
NULL);
/* unreg buf at kernel */
mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_UNREG_BUF,
NULL,
NULL);
}
}
/* since all streams are stopped, we are safe to
* release all buffers allocated in stream */
for (i=0; i<num_streams_to_stop; i++) {
if (NULL != s_objs[i]) {
/* put buf back */
mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_PUT_BUF,
NULL,
NULL);
if (tear_down_flag) {
/* to tear down stream totally, stream needs to be released */
mm_stream_fsm_fn(s_objs[i],
MM_STREAM_EVT_RELEASE,
NULL,
NULL);
}
}
}
return rc;
}
int32_t mm_channel_request_super_buf(mm_channel_t *my_obj)
{
int32_t rc = 0;
mm_camera_cmdcb_t* node = NULL;
/* set pending_cnt
* will trigger dispatching super frames if pending_cnt > 0 */
my_obj->pending_cnt = my_obj->bundle.superbuf_queue.attr.burst_num;
/* send sem_post to wake up cmd thread to dispatch 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_REQ_DATA_CB;
/* enqueue to cmd thread */
mm_camera_queue_enq(&(my_obj->cmd_thread.cmd_queue), node);
/* wake up cmd thread */
sem_post(&(my_obj->cmd_thread.cmd_sem));
} else {
CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__);
rc = -1;
}
return rc;
}
int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj)
{
int32_t rc = 0;
/* reset pending_cnt */
my_obj->pending_cnt = 0;
if (my_obj->pending_pp_cnt > 0) {
rc = mm_channel_cancel_post_processing(my_obj);
}
my_obj->pending_pp_cnt = 0;
return rc;
}
int32_t mm_channel_qbuf(mm_channel_t *my_obj,
mm_camera_buf_def_t *buf)
{
int32_t rc = -1;
struct ion_flush_data cache_inv_data;
int ion_fd;
struct msm_frame *cache_frame;
struct msm_frame *cache_frame1 = NULL;
mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, buf->stream_id);
if (NULL != s_obj) {
rc = mm_stream_fsm_fn(s_obj,
MM_STREAM_EVT_QBUF,
(void *)buf,
NULL);
}
#ifdef USE_ION
cache_inv_data.vaddr = cache_frame->buffer;
cache_inv_data.fd = cache_frame->fd;
cache_inv_data.handle = cache_frame->fd_data.handle;
cache_inv_data.length = cache_frame->ion_alloc.len;
ion_fd = cache_frame->ion_dev_fd;
if(ion_fd > 0) {
if(ioctl(ion_fd, ION_IOC_INV_CACHES, &cache_inv_data) < 0)
CDBG_ERROR("%s: Cache Invalidate failed\n", __func__);
else {
CDBG("%s: Successful cache invalidate\n", __func__);
if(cache_frame1) {
ion_fd = cache_frame1->ion_dev_fd;
cache_inv_data.vaddr = cache_frame1->buffer;
cache_inv_data.fd = cache_frame1->fd;
cache_inv_data.handle = cache_frame1->fd_data.handle;
cache_inv_data.length = cache_frame1->ion_alloc.len;
if(ioctl(ion_fd, ION_IOC_INV_CACHES, &cache_inv_data) < 0)
CDBG_ERROR("%s: Cache Invalidate failed\n", __func__);
else
CDBG("%s: Successful cache invalidate\n", __func__);
}
}
}
#endif
return rc;
}
int32_t mm_channel_start_focus(mm_channel_t *my_obj,
uint32_t sensor_idx,
uint32_t focus_mode)
{
return mm_camera_send_native_ctrl_cmd(my_obj->cam_obj,
CAMERA_SET_PARM_AUTO_FOCUS,
sizeof(uint32_t), (void*)focus_mode);
}
int32_t mm_channel_abort_focus(mm_channel_t *my_obj, uint32_t sensor_idx)
{
return mm_camera_send_native_ctrl_cmd(my_obj->cam_obj,
CAMERA_AUTO_FOCUS_CANCEL,
0, NULL);
}
int32_t mm_channel_prepare_snapshot(mm_channel_t *my_obj, uint32_t sensor_idx)
{
return mm_camera_send_native_ctrl_timeout_cmd(my_obj->cam_obj,
CAMERA_PREPARE_SNAPSHOT,
0, NULL, 2000);
}
int32_t mm_channel_set_stream_parm(mm_channel_t *my_obj,
uint32_t s_id,
void *value)
{
int32_t rc = -1;
mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, s_id);
if (NULL != s_obj) {
rc = mm_stream_fsm_fn(s_obj,
MM_STREAM_EVT_SET_PARM,
value,
NULL);
}
return rc;
}
int32_t mm_channel_get_stream_parm(mm_channel_t *my_obj,
uint32_t s_id,
void *value)
{
int32_t rc = -1;
mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, s_id);
if (NULL != s_obj) {
rc = mm_stream_fsm_fn(s_obj,
MM_STREAM_EVT_GET_PARM,
NULL,
value);
}
return rc;
}
uint8_t mm_channel_need_do_pp(mm_channel_t *my_obj,
mm_channel_queue_node_t *super_buf)
{
uint8_t need_pp = 0;
uint8_t i;
for (i=0; i<super_buf->num_of_bufs; i++) {
if (super_buf->super_buf[i].need_pp) {
need_pp = 1;
break;
}
}
return need_pp;
}
int32_t mm_channel_do_post_processing(mm_channel_t *my_obj,
mm_channel_queue_node_t *super_buf)
{
int32_t rc = 0;
cam_sock_packet_t packet;
uint8_t i;
mm_stream_t* s_obj = NULL;
mm_channel_pp_info_t *cookie = NULL;
/* TODO : currently we only do WNR, may need extended PP */
/* send cmd to backend to start pp */
for (i=0; i<super_buf->num_of_bufs; i++) {
if (super_buf->super_buf[i].need_pp) {
s_obj = mm_channel_util_get_stream_by_handler(my_obj, super_buf->super_buf[i].stream_id);
if (NULL != s_obj) {
cookie = (mm_channel_pp_info_t*)malloc(sizeof(mm_channel_pp_info_t));
if (NULL != cookie) {
memset(&packet, 0, sizeof(cam_sock_packet_t));
memset(cookie, 0, sizeof(mm_channel_pp_info_t));
cookie->cam_hdl = my_obj->cam_obj->my_hdl;
cookie->ch_hdl = my_obj->my_hdl;
cookie->stream_hdl = s_obj->my_hdl;
cookie->super_buf = super_buf;
packet.msg_type = CAM_SOCK_MSG_TYPE_WDN_START;
packet.payload.wdn_start.cookie = (unsigned long)cookie;
packet.payload.wdn_start.num_frames = 1;
packet.payload.wdn_start.ext_mode[0] = s_obj->ext_image_mode;
packet.payload.wdn_start.frame_idx[0] = super_buf->super_buf[i].buf->buf_idx;
rc = mm_camera_util_sendmsg(my_obj->cam_obj, &packet, sizeof(packet), 0);
if (0 != rc) {
CDBG_ERROR("%s: Send DoPP msg failed (rc=%d)", __func__, rc);
free(cookie);
break;
}
} else {
CDBG_ERROR("%s: No memory for mm_channel_pp_info_t", __func__);
break;
}
}
}
}
return rc;
}
int32_t mm_channel_cancel_post_processing(mm_channel_t *my_obj)
{
int32_t rc = 0;
/* TODO */
/* need send cmd to backend to cancel all pp request */
return rc;
}
int32_t mm_channel_reg_stream_cb(mm_channel_t *my_obj,
mm_stream_data_cb_t *cb,
uint32_t ext_image_mode,
uint32_t sensor_idx)
{
uint8_t idx;
mm_stream_t *dest_stream = NULL;
int32_t rc = -1;
/* browse all streams in channel to find the destination */
for (idx=0; idx < MM_CAMEAR_STRAEM_NUM_MAX; idx++) {
if (my_obj->streams[idx].state != MM_STREAM_STATE_NOTUSED &&
my_obj->streams[idx].ext_image_mode == ext_image_mode &&
my_obj->streams[idx].sensor_idx == sensor_idx) {
/* find matching stream as the destination */
dest_stream = &my_obj->streams[idx];
break;
}
}
if (NULL != dest_stream) {
rc = mm_stream_reg_buf_cb(dest_stream, cb);
}
return rc;
}
int32_t mm_channel_superbuf_queue_init(mm_channel_queue_t * queue)
{
return mm_camera_queue_init(&queue->que);
}
int32_t mm_channel_superbuf_queue_deinit(mm_channel_queue_t * queue)
{
return mm_camera_queue_deinit(&queue->que);
}
int8_t mm_channel_util_seq_comp_w_rollover(uint32_t v1,
uint32_t v2)
{
int8_t ret = 0;
/* TODO: need to handle the case if v2 roll over to 0 */
if (v1 > v2) {
ret = 1;
} else if (v1 < v2) {
ret = -1;
}
return ret;
}
int32_t mm_channel_superbuf_comp_and_enqueue(
mm_channel_t* ch_obj,
mm_channel_queue_t * queue,
mm_camera_buf_info_t *buf_info)
{
mm_camera_q_node_t* node = NULL;
struct cam_list *head = NULL;
struct cam_list *pos = NULL;
mm_channel_queue_node_t* super_buf = NULL;
uint8_t buf_s_idx, i;
for (buf_s_idx=0; buf_s_idx < queue->num_streams; buf_s_idx++) {
if (buf_info->stream_id == queue->bundled_streams[buf_s_idx]) {
break;
}
}
if (buf_s_idx == queue->num_streams) {
CDBG_ERROR("%s: buf from stream (%d) not bundled", __func__, buf_info->stream_id);
return -1;
}
if (mm_channel_util_seq_comp_w_rollover(buf_info->frame_idx,
queue->expected_frame_id) < 0) {
/* incoming buf is older than expected buf id, will discard it */
mm_channel_qbuf(ch_obj, buf_info->buf);
return 0;
}
if (MM_CAMERA_SUPER_BUF_PRIORITY_NORMAL != queue->attr.priority) {
/* TODO */
/* need to decide if we want to queue the frame based on focus or exposure
* if frame not to be queued, we need to qbuf it back */
}
/* comp */
pthread_mutex_lock(&queue->que.lock);
head = &queue->que.head.list;
/* get the last one in the queue which is possibly having no matching */
pos = head->next;
while (pos != head) {
node = member_of(pos, mm_camera_q_node_t, list);
super_buf = (mm_channel_queue_node_t*)node->data;
if (NULL != super_buf) {
if (super_buf->matched) {
/* find a matched super buf, move to next one */
pos = pos->next;
continue;
} else {
/* have an unmatched super buf, break the loop */
break;
}
}
}
if (pos == head) {
/* all nodes in queue are mtached, or no node in queue
* create a new node */
mm_channel_queue_node_t *new_buf = NULL;
mm_camera_q_node_t* new_node = NULL;
new_buf = (mm_channel_queue_node_t*)malloc(sizeof(mm_channel_queue_node_t));
new_node = (mm_camera_q_node_t*)malloc(sizeof(mm_camera_q_node_t));
if (NULL != new_buf && NULL != new_node) {
memset(new_buf, 0, sizeof(mm_channel_queue_node_t));
memset(new_node, 0, sizeof(mm_camera_q_node_t));
new_node->data = (void *)new_buf;
new_buf->num_of_bufs = queue->num_streams;
memcpy(&new_buf->super_buf[buf_s_idx], buf_info, sizeof(mm_camera_buf_info_t));
/* enqueue */
//cam_list_add_tail_node(&node->list, &queue->que.head.list);
cam_list_add_tail_node(&new_node->list, &queue->que.head.list);
queue->que.size++;
if(queue->num_streams == 1) {
//TODO : Check. Live snapshot will have one stream in bundle?
new_buf->matched = 1;
if (new_buf->matched) {
queue->expected_frame_id = buf_info->frame_idx + queue->attr.post_frame_skip;
queue->match_cnt++;
}
}
} else {
/* No memory */
if (NULL != new_buf) {
free(new_buf);
}
if (NULL != new_node) {
free(new_node);
}
/* qbuf the new buf since we cannot enqueue */
mm_channel_qbuf(ch_obj, buf_info->buf);
}
} else {
/* find an unmatched super buf */
if (super_buf->super_buf[buf_s_idx].frame_idx == 0) {
/* new frame from the stream_id */
uint8_t is_new = 1;
uint32_t frame_idx;
for (i=0; i < super_buf->num_of_bufs; i++) {
//for (i=0; i < buf_s_idx; i++) {
if(super_buf->super_buf[i].buf == NULL) {
continue;
}
frame_idx = super_buf->super_buf[i].buf->frame_idx;
if (frame_idx == 0) {
continue;
}
if (frame_idx < buf_info->frame_idx) {
/* existing frame is older than the new frame, qbuf it */
mm_channel_qbuf(ch_obj, super_buf->super_buf[i].buf);
memset(&super_buf->super_buf[i], 0, sizeof(mm_camera_buf_info_t));
} else if (frame_idx > buf_info->frame_idx) {
/* new frame is older */
is_new = 0;
break;
}else{
//TODO: reveiw again
break;
}
}
if (is_new) {
memcpy(&super_buf->super_buf[buf_s_idx], buf_info, sizeof(mm_camera_buf_info_t));
/* check if superbuf is all matched */
super_buf->matched = 1;
for (i=0; i < super_buf->num_of_bufs; i++) {
if (super_buf->super_buf[i].frame_idx == 0) {
super_buf->matched = 0;
break;
}
}
if (super_buf->matched) {
queue->expected_frame_id = buf_info->frame_idx + queue->attr.post_frame_skip;
queue->match_cnt++;
}
} else {
mm_channel_qbuf(ch_obj, buf_info->buf);
}
} else {
if (super_buf->super_buf[buf_s_idx].frame_idx < buf_info->frame_idx) {
/* current frames in superbuf are older than the new frame
* qbuf all current frames */
for (i=0; i<super_buf->num_of_bufs; i++) {
if (super_buf->super_buf[i].frame_idx != 0) {
mm_channel_qbuf(ch_obj, super_buf->super_buf[i].buf);
memset(&super_buf->super_buf[i], 0, sizeof(mm_camera_buf_info_t));
}
}
/* add the new frame into the superbuf */
memcpy(&super_buf->super_buf[buf_s_idx], buf_info, sizeof(mm_camera_buf_info_t));
} else {
/* the new frame is older, just ignor */
mm_channel_qbuf(ch_obj, buf_info->buf);
}
}
}
pthread_mutex_unlock(&queue->que.lock);
return 0;
}
mm_channel_queue_node_t* mm_channel_superbuf_dequeue_internal(mm_channel_queue_t * queue)
{
mm_camera_q_node_t* node = NULL;
struct cam_list *head = NULL;
struct cam_list *pos = NULL;
mm_channel_queue_node_t* super_buf = NULL;
head = &queue->que.head.list;
pos = head->next;
if (pos != head) {
/* get the first node */
node = member_of(pos, mm_camera_q_node_t, list);
super_buf = (mm_channel_queue_node_t*)node->data;
if (NULL != super_buf) {
if (super_buf->matched) {
/* we found a mtaching super buf, dequeue it */
cam_list_del_node(&node->list);
queue->que.size--;
queue->match_cnt--;
free(node);
} else {
super_buf = NULL;
}
}
}
return super_buf;
}
mm_channel_queue_node_t* mm_channel_superbuf_dequeue(mm_channel_queue_t * queue)
{
mm_camera_q_node_t* node = NULL;
struct cam_list *head = NULL;
struct cam_list *pos = NULL;
mm_channel_queue_node_t* super_buf = NULL;
pthread_mutex_lock(&queue->que.lock);
super_buf = mm_channel_superbuf_dequeue_internal(queue);
pthread_mutex_unlock(&queue->que.lock);
return super_buf;
}
int32_t mm_channel_superbuf_bufdone_overflow(mm_channel_t* my_obj,
mm_channel_queue_t * queue)
{
int32_t rc = 0, i;
mm_channel_queue_node_t* super_buf = NULL;
if (MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS == queue->attr.notify_mode) {
/* for continuous streaming mode, no overflow is needed */
return 0;
}
/* bufdone overflowed bufs */
pthread_mutex_lock(&queue->que.lock);
while (queue->match_cnt > queue->attr.water_mark) {
super_buf = mm_channel_superbuf_dequeue_internal(queue);
if (NULL != super_buf) {
for (i=0; i<super_buf->num_of_bufs; i++) {
if (NULL != super_buf->super_buf[i].buf) {
mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
}
}
free(super_buf);
}
}
pthread_mutex_unlock(&queue->que.lock);
return rc;
}
int32_t mm_channel_superbuf_skip(mm_channel_t* my_obj,
mm_channel_queue_t * queue)
{
int32_t rc = 0, i, count;
mm_channel_queue_node_t* super_buf = NULL;
if (MM_CAMERA_SUPER_BUF_NOTIFY_CONTINUOUS == queue->attr.notify_mode) {
/* for continuous streaming mode, no skip is needed */
return 0;
}
/* bufdone overflowed bufs */
pthread_mutex_lock(&queue->que.lock);
while (queue->match_cnt > queue->attr.look_back) {
super_buf = mm_channel_superbuf_dequeue_internal(queue);
if (NULL != super_buf) {
for (i=0; i<super_buf->num_of_bufs; i++) {
if (NULL != super_buf->super_buf[i].buf) {
mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf);
}
}
free(super_buf);
}
}
pthread_mutex_unlock(&queue->que.lock);
return rc;
}