| /* 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 <pthread.h> |
| #include <fcntl.h> |
| |
| // Camera dependencies |
| #include "cam_semaphore.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); |
| /* Static frame sync info used between different camera channels*/ |
| static mm_channel_frame_sync_info_t fs = { .num_cam =0, .pos = 0}; |
| /* Frame sync info access lock */ |
| static pthread_mutex_t fs_lock = PTHREAD_MUTEX_INITIALIZER; |
| |
| /* 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_cancel_buf(mm_channel_t *my_obj, |
| uint32_t stream_id, uint32_t buf_idx); |
| int32_t mm_channel_init(mm_channel_t *my_obj, |
| mm_camera_channel_attr_t *attr, |
| mm_camera_buf_notify_t channel_cb, |
| void *userdata); |
| void mm_channel_release(mm_channel_t *my_obj); |
| uint32_t mm_channel_add_stream(mm_channel_t *my_obj); |
| int32_t mm_channel_del_stream(mm_channel_t *my_obj, |
| uint32_t stream_id); |
| uint32_t mm_channel_link_stream(mm_channel_t *my_obj, |
| mm_camera_stream_link_t *stream_link); |
| 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_get_bundle_info(mm_channel_t *my_obj, |
| cam_bundle_config_t *bundle_info); |
| int32_t mm_channel_start(mm_channel_t *my_obj); |
| int32_t mm_channel_stop(mm_channel_t *my_obj); |
| int32_t mm_channel_request_super_buf(mm_channel_t *my_obj, |
| mm_camera_req_buf_t *buf); |
| int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj); |
| int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj, |
| uint32_t frame_idx, |
| cam_stream_type_t stream_type); |
| int32_t mm_channel_config_notify_mode(mm_channel_t *my_obj, |
| mm_camera_super_buf_notify_mode_t notify_mode); |
| int32_t mm_channel_start_zsl_snapshot(mm_channel_t *my_obj); |
| int32_t mm_channel_stop_zsl_snapshot(mm_channel_t *my_obj); |
| int32_t mm_channel_superbuf_flush(mm_channel_t* my_obj, |
| mm_channel_queue_t * queue, cam_stream_type_t cam_type); |
| int32_t mm_channel_set_stream_parm(mm_channel_t *my_obj, |
| mm_evt_paylod_set_get_stream_parms_t *payload); |
| int32_t mm_channel_get_queued_buf_count(mm_channel_t *my_obj, |
| uint32_t stream_id); |
| |
| int32_t mm_channel_get_stream_parm(mm_channel_t *my_obj, |
| mm_evt_paylod_set_get_stream_parms_t *payload); |
| int32_t mm_channel_do_stream_action(mm_channel_t *my_obj, |
| mm_evt_paylod_do_stream_action_t *payload); |
| int32_t mm_channel_map_stream_buf(mm_channel_t *my_obj, |
| cam_buf_map_type *payload); |
| int32_t mm_channel_map_stream_bufs(mm_channel_t *my_obj, |
| cam_buf_map_type_list *payload); |
| int32_t mm_channel_unmap_stream_buf(mm_channel_t *my_obj, |
| cam_buf_unmap_type *payload); |
| |
| /* 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, mm_channel_t *ch_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); |
| |
| static int32_t mm_channel_proc_general_cmd(mm_channel_t *my_obj, |
| mm_camera_generic_cmd_t *p_gen_cmd); |
| int32_t mm_channel_superbuf_flush_matched(mm_channel_t* my_obj, |
| mm_channel_queue_t * queue); |
| |
| /* Start of Frame Sync util methods */ |
| void mm_frame_sync_reset(); |
| int32_t mm_frame_sync_register_channel(mm_channel_t *ch_obj); |
| int32_t mm_frame_sync_unregister_channel(mm_channel_t *ch_obj); |
| int32_t mm_frame_sync_add(uint32_t frame_id, mm_channel_t *ch_obj); |
| int32_t mm_frame_sync_remove(uint32_t frame_id); |
| uint32_t mm_frame_sync_find_matched(uint8_t oldest); |
| int8_t mm_frame_sync_find_frame_index(uint32_t frame_id); |
| void mm_frame_sync_lock_queues(); |
| void mm_frame_sync_unlock_queues(); |
| void mm_channel_node_qbuf(mm_channel_t *ch_obj, mm_channel_queue_node_t *node); |
| /* End of Frame Sync Util methods */ |
| void mm_channel_send_super_buf(mm_channel_node_info_t *info); |
| mm_channel_queue_node_t* mm_channel_superbuf_dequeue_frame_internal( |
| mm_channel_queue_t * queue, uint32_t frame_idx); |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_util_get_stream_by_handler |
| * |
| * DESCRIPTION: utility function to get a stream object from its handle |
| * |
| * PARAMETERS : |
| * @cam_obj: ptr to a channel object |
| * @handler: stream handle |
| * |
| * RETURN : ptr to a stream object. |
| * NULL if failed. |
| *==========================================================================*/ |
| 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; |
| for(i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) { |
| if ((MM_STREAM_STATE_NOTUSED != ch_obj->streams[i].state) && |
| (handler == ch_obj->streams[i].my_hdl)) { |
| s_obj = &ch_obj->streams[i]; |
| break; |
| } |
| } |
| return s_obj; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_dispatch_super_buf |
| * |
| * DESCRIPTION: dispatch super buffer of bundle to registered user |
| * |
| * PARAMETERS : |
| * @cmd_cb : ptr storing matched super buf information |
| * @userdata: user data ptr |
| * |
| * RETURN : none |
| *==========================================================================*/ |
| static void mm_channel_dispatch_super_buf(mm_camera_cmdcb_t *cmd_cb, |
| void* user_data) |
| { |
| mm_channel_t * my_obj = (mm_channel_t *)user_data; |
| |
| if (NULL == my_obj) { |
| return; |
| } |
| |
| if (MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB != cmd_cb->cmd_type) { |
| LOGE("Wrong cmd_type (%d) for super buf dataCB", |
| cmd_cb->cmd_type); |
| return; |
| } |
| |
| if (my_obj->bundle.super_buf_notify_cb) { |
| my_obj->bundle.super_buf_notify_cb(&cmd_cb->u.superbuf, my_obj->bundle.user_data); |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_process_stream_buf |
| * |
| * DESCRIPTION: handle incoming buffer from stream in a bundle. In this function, |
| * matching logic will be performed on incoming stream frames. |
| * Will depends on the bundle attribute, either storing matched frames |
| * in the superbuf queue, or sending matched superbuf frames to upper |
| * layer through registered callback. |
| * |
| * PARAMETERS : |
| * @cmd_cb : ptr storing matched super buf information |
| * @userdata: user data ptr |
| * |
| * RETURN : none |
| *==========================================================================*/ |
| 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; |
| uint32_t i = 0; |
| /* Set expected frame id to a future frame idx, large enough to wait |
| * for good_frame_idx_range, and small enough to still capture an image */ |
| uint8_t needStartZSL = FALSE; |
| |
| 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); |
| } else if (MM_CAMERA_CMD_TYPE_REQ_DATA_CB == cmd_cb->cmd_type) { |
| /* skip frames if needed */ |
| ch_obj->pending_cnt = cmd_cb->u.req_buf.num_buf_requested; |
| ch_obj->pending_retro_cnt = cmd_cb->u.req_buf.num_retro_buf_requested; |
| ch_obj->req_type = cmd_cb->u.req_buf.type; |
| ch_obj->bWaitForPrepSnapshotDone = 0; |
| |
| LOGH("pending cnt (%d), retro count (%d)" |
| "req_type (%d) is_primary (%d)", |
| ch_obj->pending_cnt, ch_obj->pending_retro_cnt, |
| ch_obj->req_type, cmd_cb->u.req_buf.primary_only); |
| if (!ch_obj->pending_cnt || (ch_obj->pending_retro_cnt > ch_obj->pending_cnt)) { |
| ch_obj->pending_retro_cnt = ch_obj->pending_cnt; |
| } |
| if (ch_obj->pending_retro_cnt > 0) { |
| LOGL("Resetting need Led Flash!!!"); |
| ch_obj->needLEDFlash = 0; |
| } |
| ch_obj->stopZslSnapshot = 0; |
| ch_obj->unLockAEC = 0; |
| |
| mm_channel_superbuf_skip(ch_obj, &ch_obj->bundle.superbuf_queue); |
| |
| } else if (MM_CAMERA_CMD_TYPE_START_ZSL == cmd_cb->cmd_type) { |
| ch_obj->manualZSLSnapshot = TRUE; |
| mm_camera_start_zsl_snapshot(ch_obj->cam_obj); |
| } else if (MM_CAMERA_CMD_TYPE_STOP_ZSL == cmd_cb->cmd_type) { |
| ch_obj->manualZSLSnapshot = FALSE; |
| mm_camera_stop_zsl_snapshot(ch_obj->cam_obj); |
| } else if (MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY == cmd_cb->cmd_type) { |
| ch_obj->bundle.superbuf_queue.attr.notify_mode = cmd_cb->u.notify_mode; |
| } else if (MM_CAMERA_CMD_TYPE_FLUSH_QUEUE == cmd_cb->cmd_type) { |
| ch_obj->bundle.superbuf_queue.expected_frame_id = cmd_cb->u.flush_cmd.frame_idx; |
| mm_channel_superbuf_flush(ch_obj, |
| &ch_obj->bundle.superbuf_queue, cmd_cb->u.flush_cmd.stream_type); |
| cam_sem_post(&(ch_obj->cmd_thread.sync_sem)); |
| return; |
| } else if (MM_CAMERA_CMD_TYPE_GENERAL == cmd_cb->cmd_type) { |
| LOGH("MM_CAMERA_CMD_TYPE_GENERAL"); |
| switch (cmd_cb->u.gen_cmd.type) { |
| case MM_CAMERA_GENERIC_CMD_TYPE_AE_BRACKETING: |
| case MM_CAMERA_GENERIC_CMD_TYPE_AF_BRACKETING: { |
| uint32_t start = cmd_cb->u.gen_cmd.payload[0]; |
| LOGI("MM_CAMERA_GENERIC_CMDTYPE_AF_BRACKETING %u", |
| start); |
| mm_channel_superbuf_flush(ch_obj, |
| &ch_obj->bundle.superbuf_queue, CAM_STREAM_TYPE_DEFAULT); |
| |
| if (start) { |
| LOGH("need AE bracketing, start zsl snapshot"); |
| ch_obj->bracketingState = MM_CHANNEL_BRACKETING_STATE_WAIT_GOOD_FRAME_IDX; |
| } else { |
| ch_obj->bracketingState = MM_CHANNEL_BRACKETING_STATE_OFF; |
| } |
| } |
| break; |
| case MM_CAMERA_GENERIC_CMD_TYPE_FLASH_BRACKETING: { |
| uint32_t start = cmd_cb->u.gen_cmd.payload[0]; |
| LOGI("MM_CAMERA_GENERIC_CMDTYPE_FLASH_BRACKETING %u", |
| start); |
| mm_channel_superbuf_flush(ch_obj, |
| &ch_obj->bundle.superbuf_queue, CAM_STREAM_TYPE_DEFAULT); |
| |
| if (start) { |
| LOGH("need flash bracketing"); |
| ch_obj->isFlashBracketingEnabled = TRUE; |
| } else { |
| ch_obj->isFlashBracketingEnabled = FALSE; |
| } |
| } |
| break; |
| case MM_CAMERA_GENERIC_CMD_TYPE_ZOOM_1X: { |
| uint32_t start = cmd_cb->u.gen_cmd.payload[0]; |
| LOGI("MM_CAMERA_GENERIC_CMD_TYPE_ZOOM_1X %u", |
| start); |
| mm_channel_superbuf_flush(ch_obj, |
| &ch_obj->bundle.superbuf_queue, CAM_STREAM_TYPE_DEFAULT); |
| |
| if (start) { |
| LOGH("need zoom 1x frame"); |
| ch_obj->isZoom1xFrameRequested = TRUE; |
| } else { |
| ch_obj->isZoom1xFrameRequested = FALSE; |
| } |
| } |
| break; |
| case MM_CAMERA_GENERIC_CMD_TYPE_CAPTURE_SETTING: { |
| uint32_t start = cmd_cb->u.gen_cmd.payload[0]; |
| LOGI("MM_CAMERA_GENERIC_CMD_TYPE_CAPTURE_SETTING %u num_batch = %d", |
| start, cmd_cb->u.gen_cmd.frame_config.num_batch); |
| |
| if (start) { |
| memset(&ch_obj->frameConfig, 0, sizeof(cam_capture_frame_config_t)); |
| for (i = 0; i < cmd_cb->u.gen_cmd.frame_config.num_batch; i++) { |
| if (cmd_cb->u.gen_cmd.frame_config.configs[i].type |
| != CAM_CAPTURE_RESET) { |
| ch_obj->frameConfig.configs[ |
| ch_obj->frameConfig.num_batch] = |
| cmd_cb->u.gen_cmd.frame_config.configs[i]; |
| ch_obj->frameConfig.num_batch++; |
| LOGH("capture setting frame = %d type = %d", |
| i,ch_obj->frameConfig.configs[ |
| ch_obj->frameConfig.num_batch].type); |
| } |
| } |
| LOGD("Capture setting Batch Count %d", |
| ch_obj->frameConfig.num_batch); |
| ch_obj->isConfigCapture = TRUE; |
| } else { |
| ch_obj->isConfigCapture = FALSE; |
| memset(&ch_obj->frameConfig, 0, sizeof(cam_capture_frame_config_t)); |
| } |
| ch_obj->cur_capture_idx = 0; |
| memset(ch_obj->capture_frame_id, 0, sizeof(uint8_t) * MAX_CAPTURE_BATCH_NUM); |
| break; |
| } |
| default: |
| LOGE("Error: Invalid command"); |
| break; |
| } |
| } |
| notify_mode = ch_obj->bundle.superbuf_queue.attr.notify_mode; |
| |
| /*Handle use case which does not need start ZSL even in unified case*/ |
| if ((ch_obj->pending_cnt > 0) |
| && (ch_obj->isConfigCapture) |
| && (ch_obj->manualZSLSnapshot == FALSE) |
| && (ch_obj->startZSlSnapshotCalled == FALSE)) { |
| needStartZSL = TRUE; |
| for (i = ch_obj->cur_capture_idx; |
| i < ch_obj->frameConfig.num_batch; |
| i++) { |
| cam_capture_type type = ch_obj->frameConfig.configs[i].type; |
| if (((type == CAM_CAPTURE_FLASH) && (!ch_obj->needLEDFlash)) |
| || ((type == CAM_CAPTURE_LOW_LIGHT) && (!ch_obj->needLowLightZSL))) { |
| /*For flash and low light capture, start ZSL is triggered only if needed*/ |
| needStartZSL = FALSE; |
| break; |
| } |
| } |
| } |
| |
| if ((ch_obj->isConfigCapture) |
| && (needStartZSL)) { |
| for (i = ch_obj->cur_capture_idx; |
| i < ch_obj->frameConfig.num_batch; |
| i++) { |
| ch_obj->capture_frame_id[i] = |
| ch_obj->bundle.superbuf_queue.expected_frame_id |
| + MM_CAMERA_MAX_FUTURE_FRAME_WAIT; |
| } |
| |
| /* Need to Flush the queue and trigger frame config */ |
| mm_channel_superbuf_flush(ch_obj, |
| &ch_obj->bundle.superbuf_queue, CAM_STREAM_TYPE_DEFAULT); |
| LOGI("TRIGGER Start ZSL"); |
| mm_camera_start_zsl_snapshot(ch_obj->cam_obj); |
| ch_obj->startZSlSnapshotCalled = TRUE; |
| ch_obj->burstSnapNum = ch_obj->pending_cnt; |
| ch_obj->bWaitForPrepSnapshotDone = 0; |
| } else if ((ch_obj->pending_cnt > 0) |
| && ((ch_obj->needLEDFlash == TRUE) || |
| (MM_CHANNEL_BRACKETING_STATE_OFF != ch_obj->bracketingState)) |
| && (ch_obj->manualZSLSnapshot == FALSE) |
| && ch_obj->startZSlSnapshotCalled == FALSE) { |
| |
| LOGI("TRIGGER Start ZSL for Flash"); |
| mm_camera_start_zsl_snapshot(ch_obj->cam_obj); |
| ch_obj->startZSlSnapshotCalled = TRUE; |
| ch_obj->burstSnapNum = ch_obj->pending_cnt; |
| ch_obj->bWaitForPrepSnapshotDone = 0; |
| } else if (((ch_obj->pending_cnt == 0) || (ch_obj->stopZslSnapshot == 1)) |
| && (ch_obj->manualZSLSnapshot == FALSE) |
| && (ch_obj->startZSlSnapshotCalled == TRUE)) { |
| LOGI("TRIGGER Stop ZSL for cancel picture"); |
| mm_camera_stop_zsl_snapshot(ch_obj->cam_obj); |
| // Unlock AEC |
| ch_obj->startZSlSnapshotCalled = FALSE; |
| ch_obj->needLEDFlash = FALSE; |
| ch_obj->burstSnapNum = 0; |
| ch_obj->stopZslSnapshot = 0; |
| ch_obj->bWaitForPrepSnapshotDone = 0; |
| ch_obj->unLockAEC = 1; |
| ch_obj->bracketingState = MM_CHANNEL_BRACKETING_STATE_OFF; |
| ch_obj->isConfigCapture = FALSE; |
| } |
| /* bufdone for overflowed bufs */ |
| mm_channel_superbuf_bufdone_overflow(ch_obj, &ch_obj->bundle.superbuf_queue); |
| |
| LOGD("Super Buffer received, pending_cnt=%d queue cnt = %d expected = %d", |
| ch_obj->pending_cnt, ch_obj->bundle.superbuf_queue.match_cnt, |
| ch_obj->bundle.superbuf_queue.expected_frame_id); |
| |
| /* 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)) && |
| (!ch_obj->bWaitForPrepSnapshotDone)) { |
| |
| /* dequeue */ |
| mm_channel_node_info_t info; |
| memset(&info, 0x0, sizeof(info)); |
| |
| if (ch_obj->req_type == MM_CAMERA_REQ_FRAME_SYNC_BUF) { |
| // Lock the Queues |
| mm_frame_sync_lock_queues(); |
| uint32_t match_frame = mm_frame_sync_find_matched(FALSE); |
| if (match_frame) { |
| uint8_t j = 0; |
| for (j = 0; j < MAX_NUM_CAMERA_PER_BUNDLE; j++) { |
| if (fs.ch_obj[j]) { |
| mm_channel_queue_t *ch_queue = |
| &fs.ch_obj[j]->bundle.superbuf_queue; |
| if (ch_queue == NULL) { |
| LOGW("Channel queue is NULL"); |
| break; |
| } |
| node = mm_channel_superbuf_dequeue_frame_internal( |
| ch_queue, match_frame); |
| if (node != NULL) { |
| info.ch_obj[info.num_nodes] = fs.ch_obj[j]; |
| info.node[info.num_nodes] = node; |
| info.num_nodes++; |
| LOGH("Added ch(%p) to node ,num nodes %d", |
| fs.ch_obj[j], info.num_nodes); |
| } |
| } |
| } |
| mm_frame_sync_remove(match_frame); |
| LOGI("match frame %d", match_frame); |
| if (info.num_nodes != fs.num_cam) { |
| LOGI("num node %d != num cam (%d) Debug this", |
| info.num_nodes, fs.num_cam); |
| uint8_t j = 0; |
| // free super buffers from various nodes |
| for (j = 0; j < info.num_nodes; j++) { |
| if (info.node[j]) { |
| mm_channel_node_qbuf(info.ch_obj[j], info.node[j]); |
| free(info.node[j]); |
| } |
| } |
| // we should not use it as matched dual camera frames |
| info.num_nodes = 0; |
| } |
| } |
| mm_frame_sync_unlock_queues(); |
| } else { |
| node = mm_channel_superbuf_dequeue(&ch_obj->bundle.superbuf_queue, ch_obj); |
| if (node != NULL) { |
| if (ch_obj->isConfigCapture && |
| ((node->frame_idx < |
| ch_obj->capture_frame_id[ch_obj->cur_capture_idx]))) { |
| uint8_t i; |
| LOGD("Not expected super buffer. frameID = %d expected = %d", |
| node->frame_idx, ch_obj->capture_frame_id[ch_obj->cur_capture_idx]); |
| for (i = 0; i < node->num_of_bufs; i++) { |
| mm_channel_qbuf(ch_obj, node->super_buf[i].buf); |
| } |
| free(node); |
| } else { |
| info.num_nodes = 1; |
| info.ch_obj[0] = ch_obj; |
| info.node[0] = node; |
| } |
| } |
| } |
| if (info.num_nodes > 0) { |
| /* decrease pending_cnt */ |
| if (MM_CAMERA_SUPER_BUF_NOTIFY_BURST == notify_mode) { |
| ch_obj->pending_cnt--; |
| if (ch_obj->pending_retro_cnt > 0) { |
| if (ch_obj->pending_retro_cnt == 1) { |
| ch_obj->bWaitForPrepSnapshotDone = 1; |
| } |
| ch_obj->pending_retro_cnt--; |
| } |
| |
| if (((ch_obj->pending_cnt == 0) || |
| (ch_obj->stopZslSnapshot == 1)) && |
| (ch_obj->manualZSLSnapshot == FALSE) && |
| ch_obj->startZSlSnapshotCalled == TRUE) { |
| LOGI("TRIGGER Stop ZSL. All frame received"); |
| mm_camera_stop_zsl_snapshot(ch_obj->cam_obj); |
| ch_obj->startZSlSnapshotCalled = FALSE; |
| ch_obj->burstSnapNum = 0; |
| ch_obj->stopZslSnapshot = 0; |
| ch_obj->unLockAEC = 1; |
| ch_obj->needLEDFlash = FALSE; |
| ch_obj->bracketingState = MM_CHANNEL_BRACKETING_STATE_OFF; |
| ch_obj->isConfigCapture = FALSE; |
| } |
| |
| if (ch_obj->isConfigCapture) { |
| if (ch_obj->frameConfig.configs[ch_obj->cur_capture_idx].num_frames != 0) { |
| ch_obj->frameConfig.configs[ch_obj->cur_capture_idx].num_frames--; |
| } else { |
| LOGW("Invalid frame config batch index %d max batch = %d", |
| ch_obj->cur_capture_idx, ch_obj->frameConfig.num_batch); |
| } |
| |
| if (ch_obj->frameConfig.configs[ch_obj->cur_capture_idx].num_frames == 0) { |
| //Received all frames for current batch |
| ch_obj->cur_capture_idx++; |
| ch_obj->bundle.superbuf_queue.expected_frame_id = |
| ch_obj->capture_frame_id[ch_obj->cur_capture_idx]; |
| ch_obj->bundle.superbuf_queue.good_frame_id = |
| ch_obj->capture_frame_id[ch_obj->cur_capture_idx]; |
| } else { |
| LOGH("Need %d frames more for batch %d", |
| ch_obj->frameConfig.configs[ch_obj->cur_capture_idx].num_frames, |
| ch_obj->cur_capture_idx); |
| } |
| } |
| } |
| /* dispatch superbuf */ |
| mm_channel_send_super_buf(&info); |
| } else { |
| /* no superbuf avail, break the loop */ |
| break; |
| } |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_send_super_buf |
| * |
| * DESCRIPTION: Send super buffers to HAL |
| * |
| * PARAMETERS : |
| * @info : Info of super buffers to be sent in callback |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void mm_channel_send_super_buf(mm_channel_node_info_t *info) |
| { |
| if (!info || !info->num_nodes){ |
| LOGE("X Error!! Info invalid"); |
| return; |
| } |
| mm_channel_queue_node_t *node = NULL; |
| |
| LOGH("num nodes %d to send", info->num_nodes); |
| uint32_t idx = 0; |
| mm_channel_t *ch_obj = NULL; |
| for (idx = 0; idx < info->num_nodes; idx++) { |
| node = info->node[idx]; |
| ch_obj = info->ch_obj[idx]; |
| if ((ch_obj) && (NULL != ch_obj->bundle.super_buf_notify_cb) && node) { |
| mm_camera_cmdcb_t* cb_node = NULL; |
| LOGD("Send superbuf to HAL, pending_cnt=%d", |
| ch_obj->pending_cnt); |
| /* send cam_sem_post to wake up cb thread to dispatch super buffer */ |
| cb_node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t)); |
| if (NULL != cb_node) { |
| memset(cb_node, 0, sizeof(mm_camera_cmdcb_t)); |
| cb_node->cmd_type = MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB; |
| cb_node->u.superbuf.num_bufs = node->num_of_bufs; |
| uint8_t i = 0; |
| for (i = 0; i < node->num_of_bufs; i++) { |
| cb_node->u.superbuf.bufs[i] = node->super_buf[i].buf; |
| } |
| cb_node->u.superbuf.camera_handle = ch_obj->cam_obj->my_hdl; |
| cb_node->u.superbuf.ch_id = ch_obj->my_hdl; |
| cb_node->u.superbuf.bReadyForPrepareSnapshot = |
| ch_obj->bWaitForPrepSnapshotDone; |
| if (ch_obj->unLockAEC == 1) { |
| cb_node->u.superbuf.bUnlockAEC = 1; |
| LOGH("Unlocking AEC"); |
| ch_obj->unLockAEC = 0; |
| } |
| /* enqueue to cb thread */ |
| cam_queue_enq(&(ch_obj->cb_thread.cmd_queue), cb_node); |
| /* wake up cb thread */ |
| cam_sem_post(&(ch_obj->cb_thread.cmd_sem)); |
| LOGH("Sent super buf for node[%d] ", idx); |
| |
| } else { |
| LOGE("No memory for mm_camera_node_t"); |
| /* buf done with the unused super buf */ |
| uint8_t i = 0; |
| for (i = 0; i < node->num_of_bufs; i++) { |
| mm_channel_qbuf(ch_obj, node->super_buf[i].buf); |
| } |
| } |
| free(node); |
| } else if ((ch_obj != NULL) && (node != NULL)) { |
| /* buf done with the unused 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 { |
| LOGE("node is NULL, debug this"); |
| } |
| } |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_reg_stream_buf_cb |
| * |
| * DESCRIPTION: Register callback for stream buffer |
| * |
| * PARAMETERS : |
| * @my_obj : Channel object |
| * @stream_id : stream that will be linked |
| * @buf_cb : special callback needs to be registered for stream buffer |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_reg_stream_buf_cb (mm_channel_t* my_obj, |
| uint32_t stream_id, mm_stream_data_cb_t buf_cb) |
| { |
| int32_t rc = -1; |
| mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, |
| stream_id); |
| |
| if (NULL != s_obj) { |
| if (s_obj->ch_obj != my_obj) { |
| /* No op. on linked streams */ |
| return 0; |
| } |
| rc = mm_stream_reg_buf_cb(s_obj, buf_cb); |
| } |
| |
| return rc; |
| |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_fsm_fn |
| * |
| * DESCRIPTION: channel finite state machine entry function. Depends on channel |
| * state, incoming event will be handled differently. |
| * |
| * PARAMETERS : |
| * @my_obj : ptr to a channel object |
| * @evt : channel 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_channel_fsm_fn(mm_channel_t *my_obj, |
| mm_channel_evt_type_t evt, |
| void * in_val, |
| void * out_val) |
| { |
| int32_t rc = -1; |
| |
| LOGD("E state = %d", 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: |
| LOGD("Not a valid state (%d)", my_obj->state); |
| break; |
| } |
| |
| /* unlock ch_lock */ |
| pthread_mutex_unlock(&my_obj->ch_lock); |
| LOGD("X rc = %d", rc); |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_fsm_fn_notused |
| * |
| * DESCRIPTION: channel finite state machine function to handle event |
| * in NOT_USED state. |
| * |
| * PARAMETERS : |
| * @my_obj : ptr to a channel object |
| * @evt : channel 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_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: |
| LOGE("invalid state (%d) for evt (%d), in(%p), out(%p)", |
| my_obj->state, evt, in_val, out_val); |
| break; |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_fsm_fn_stopped |
| * |
| * DESCRIPTION: channel finite state machine function to handle event |
| * in STOPPED state. |
| * |
| * PARAMETERS : |
| * @my_obj : ptr to a channel object |
| * @evt : channel 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_channel_fsm_fn_stopped(mm_channel_t *my_obj, |
| mm_channel_evt_type_t evt, |
| void * in_val, |
| void * out_val) |
| { |
| int32_t rc = 0; |
| LOGD("E evt = %d", evt); |
| switch (evt) { |
| case MM_CHANNEL_EVT_ADD_STREAM: |
| { |
| uint32_t s_hdl = 0; |
| s_hdl = mm_channel_add_stream(my_obj); |
| *((uint32_t*)out_val) = s_hdl; |
| rc = 0; |
| } |
| break; |
| case MM_CHANNEL_EVT_LINK_STREAM: |
| { |
| mm_camera_stream_link_t *stream_link = NULL; |
| uint32_t s_hdl = 0; |
| stream_link = (mm_camera_stream_link_t *) in_val; |
| s_hdl = mm_channel_link_stream(my_obj, stream_link); |
| *((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: |
| { |
| rc = mm_channel_start(my_obj); |
| /* 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_GET_BUNDLE_INFO: |
| { |
| cam_bundle_config_t *payload = |
| (cam_bundle_config_t *)in_val; |
| rc = mm_channel_get_bundle_info(my_obj, payload); |
| } |
| break; |
| case MM_CHANNEL_EVT_DELETE: |
| { |
| mm_channel_release(my_obj); |
| rc = 0; |
| } |
| break; |
| case MM_CHANNEL_EVT_SET_STREAM_PARM: |
| { |
| mm_evt_paylod_set_get_stream_parms_t *payload = |
| (mm_evt_paylod_set_get_stream_parms_t *)in_val; |
| rc = mm_channel_set_stream_parm(my_obj, payload); |
| } |
| break; |
| case MM_CHANNEL_EVT_GET_STREAM_QUEUED_BUF_COUNT: |
| { |
| uint32_t stream_id = *((uint32_t *)in_val); |
| rc = mm_channel_get_queued_buf_count(my_obj, stream_id); |
| } |
| break; |
| case MM_CHANNEL_EVT_GET_STREAM_PARM: |
| { |
| mm_evt_paylod_set_get_stream_parms_t *payload = |
| (mm_evt_paylod_set_get_stream_parms_t *)in_val; |
| rc = mm_channel_get_stream_parm(my_obj, payload); |
| } |
| break; |
| case MM_CHANNEL_EVT_DO_STREAM_ACTION: |
| { |
| mm_evt_paylod_do_stream_action_t *payload = |
| (mm_evt_paylod_do_stream_action_t *)in_val; |
| rc = mm_channel_do_stream_action(my_obj, payload); |
| } |
| break; |
| case MM_CHANNEL_EVT_MAP_STREAM_BUF: |
| { |
| cam_buf_map_type *payload = |
| (cam_buf_map_type *)in_val; |
| rc = mm_channel_map_stream_buf(my_obj, payload); |
| } |
| break; |
| case MM_CHANNEL_EVT_MAP_STREAM_BUFS: |
| { |
| cam_buf_map_type_list *payload = |
| (cam_buf_map_type_list *)in_val; |
| rc = mm_channel_map_stream_bufs(my_obj, payload); |
| } |
| break; |
| case MM_CHANNEL_EVT_UNMAP_STREAM_BUF: |
| { |
| cam_buf_unmap_type *payload = |
| (cam_buf_unmap_type *)in_val; |
| rc = mm_channel_unmap_stream_buf(my_obj, payload); |
| } |
| break; |
| case MM_CHANNEL_EVT_REG_STREAM_BUF_CB: |
| { |
| mm_evt_paylod_reg_stream_buf_cb *payload = |
| (mm_evt_paylod_reg_stream_buf_cb *)in_val; |
| rc = mm_channel_reg_stream_buf_cb (my_obj, |
| payload->stream_id, payload->buf_cb); |
| } |
| break; |
| default: |
| LOGW("invalid state (%d) for evt (%d)", |
| my_obj->state, evt); |
| break; |
| } |
| LOGD("E rc = %d", rc); |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_fsm_fn_active |
| * |
| * DESCRIPTION: channel finite state machine function to handle event |
| * in ACTIVE state. |
| * |
| * PARAMETERS : |
| * @my_obj : ptr to a channel object |
| * @evt : channel 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_channel_fsm_fn_active(mm_channel_t *my_obj, |
| mm_channel_evt_type_t evt, |
| void * in_val, |
| void * out_val) |
| { |
| int32_t rc = 0; |
| |
| LOGD("E evt = %d", evt); |
| switch (evt) { |
| case MM_CHANNEL_EVT_STOP: |
| { |
| rc = mm_channel_stop(my_obj); |
| my_obj->state = MM_CHANNEL_STATE_STOPPED; |
| } |
| break; |
| case MM_CHANNEL_EVT_REQUEST_SUPER_BUF: |
| { |
| mm_camera_req_buf_t *payload = |
| (mm_camera_req_buf_t *)in_val; |
| rc = mm_channel_request_super_buf(my_obj, payload); |
| } |
| break; |
| case MM_CHANNEL_EVT_CANCEL_REQUEST_SUPER_BUF: |
| { |
| rc = mm_channel_cancel_super_buf_request(my_obj); |
| } |
| break; |
| case MM_CHANNEL_EVT_FLUSH_SUPER_BUF_QUEUE: |
| { |
| uint32_t frame_idx = *((uint32_t *)in_val); |
| rc = mm_channel_flush_super_buf_queue(my_obj, frame_idx, CAM_STREAM_TYPE_DEFAULT); |
| } |
| break; |
| case MM_CHANNEL_EVT_START_ZSL_SNAPSHOT: |
| { |
| rc = mm_channel_start_zsl_snapshot(my_obj); |
| } |
| break; |
| case MM_CHANNEL_EVT_STOP_ZSL_SNAPSHOT: |
| { |
| rc = mm_channel_stop_zsl_snapshot(my_obj); |
| } |
| break; |
| case MM_CHANNEL_EVT_CONFIG_NOTIFY_MODE: |
| { |
| mm_camera_super_buf_notify_mode_t notify_mode = |
| *((mm_camera_super_buf_notify_mode_t *)in_val); |
| rc = mm_channel_config_notify_mode(my_obj, notify_mode); |
| } |
| break; |
| case MM_CHANNEL_EVT_SET_STREAM_PARM: |
| { |
| mm_evt_paylod_set_get_stream_parms_t *payload = |
| (mm_evt_paylod_set_get_stream_parms_t *)in_val; |
| rc = mm_channel_set_stream_parm(my_obj, payload); |
| } |
| break; |
| case MM_CHANNEL_EVT_GET_STREAM_QUEUED_BUF_COUNT: |
| { |
| uint32_t stream_id = *((uint32_t *)in_val); |
| rc = mm_channel_get_queued_buf_count(my_obj, stream_id); |
| } |
| break; |
| case MM_CHANNEL_EVT_GET_STREAM_PARM: |
| { |
| mm_evt_paylod_set_get_stream_parms_t *payload = |
| (mm_evt_paylod_set_get_stream_parms_t *)in_val; |
| rc = mm_channel_get_stream_parm(my_obj, payload); |
| } |
| break; |
| case MM_CHANNEL_EVT_DO_STREAM_ACTION: |
| { |
| mm_evt_paylod_do_stream_action_t *payload = |
| (mm_evt_paylod_do_stream_action_t *)in_val; |
| rc = mm_channel_do_stream_action(my_obj, payload); |
| } |
| break; |
| case MM_CHANNEL_EVT_MAP_STREAM_BUF: |
| { |
| cam_buf_map_type *payload = |
| (cam_buf_map_type *)in_val; |
| if (payload != NULL) { |
| uint8_t type = payload->type; |
| if ((type == CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF) || |
| (type == CAM_MAPPING_BUF_TYPE_OFFLINE_META_BUF)) { |
| rc = mm_channel_map_stream_buf(my_obj, payload); |
| } |
| } else { |
| LOGE("cannot map regualr stream buf in active state"); |
| } |
| } |
| break; |
| case MM_CHANNEL_EVT_MAP_STREAM_BUFS: |
| { |
| cam_buf_map_type_list *payload = |
| (cam_buf_map_type_list *)in_val; |
| if ((payload != NULL) && (payload->length > 0)) { |
| uint8_t type = payload->buf_maps[0].type; |
| if ((type == CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF) || |
| (type == CAM_MAPPING_BUF_TYPE_OFFLINE_META_BUF)) { |
| rc = mm_channel_map_stream_bufs(my_obj, payload); |
| } |
| } else { |
| LOGE("cannot map regualr stream buf in active state"); |
| } |
| } |
| break; |
| case MM_CHANNEL_EVT_UNMAP_STREAM_BUF: |
| { |
| cam_buf_unmap_type *payload = |
| (cam_buf_unmap_type *)in_val; |
| if (payload != NULL) { |
| uint8_t type = payload->type; |
| if ((type == CAM_MAPPING_BUF_TYPE_OFFLINE_INPUT_BUF) || |
| (type == CAM_MAPPING_BUF_TYPE_OFFLINE_META_BUF)) { |
| rc = mm_channel_unmap_stream_buf(my_obj, payload); |
| } |
| } else { |
| LOGE("cannot unmap regualr stream buf in active state"); |
| } |
| } |
| break; |
| case MM_CHANNEL_EVT_AF_BRACKETING: |
| { |
| LOGH("MM_CHANNEL_EVT_AF_BRACKETING"); |
| uint32_t start_flag = *((uint32_t *)in_val); |
| mm_camera_generic_cmd_t gen_cmd; |
| gen_cmd.type = MM_CAMERA_GENERIC_CMD_TYPE_AF_BRACKETING; |
| gen_cmd.payload[0] = start_flag; |
| rc = mm_channel_proc_general_cmd(my_obj, &gen_cmd); |
| } |
| break; |
| case MM_CHANNEL_EVT_AE_BRACKETING: |
| { |
| LOGH("MM_CHANNEL_EVT_AE_BRACKETING"); |
| uint32_t start_flag = *((uint32_t *)in_val); |
| mm_camera_generic_cmd_t gen_cmd; |
| gen_cmd.type = MM_CAMERA_GENERIC_CMD_TYPE_AE_BRACKETING; |
| gen_cmd.payload[0] = start_flag; |
| rc = mm_channel_proc_general_cmd(my_obj, &gen_cmd); |
| } |
| break; |
| case MM_CHANNEL_EVT_FLASH_BRACKETING: |
| { |
| LOGH("MM_CHANNEL_EVT_FLASH_BRACKETING"); |
| uint32_t start_flag = *((uint32_t *)in_val); |
| mm_camera_generic_cmd_t gen_cmd; |
| gen_cmd.type = MM_CAMERA_GENERIC_CMD_TYPE_FLASH_BRACKETING; |
| gen_cmd.payload[0] = start_flag; |
| rc = mm_channel_proc_general_cmd(my_obj, &gen_cmd); |
| } |
| break; |
| case MM_CHANNEL_EVT_ZOOM_1X: |
| { |
| LOGH("MM_CHANNEL_EVT_ZOOM_1X"); |
| uint32_t start_flag = *((uint32_t *)in_val); |
| mm_camera_generic_cmd_t gen_cmd; |
| gen_cmd.type = MM_CAMERA_GENERIC_CMD_TYPE_ZOOM_1X; |
| gen_cmd.payload[0] = start_flag; |
| rc = mm_channel_proc_general_cmd(my_obj, &gen_cmd); |
| } |
| break; |
| case MM_CAMERA_EVT_CAPTURE_SETTING: |
| { |
| mm_camera_generic_cmd_t gen_cmd; |
| cam_capture_frame_config_t *input; |
| gen_cmd.type = MM_CAMERA_GENERIC_CMD_TYPE_CAPTURE_SETTING; |
| LOGH("MM_CAMERA_EVT_CAPTURE_SETTING"); |
| if (in_val == NULL) { |
| gen_cmd.payload[0] = 0; |
| memset(&gen_cmd.frame_config, 0, sizeof(cam_capture_frame_config_t)); |
| } else { |
| gen_cmd.payload[0] = 1; |
| input = (cam_capture_frame_config_t *)in_val; |
| gen_cmd.frame_config = *input; |
| } |
| rc = mm_channel_proc_general_cmd(my_obj, &gen_cmd); |
| } |
| break; |
| case MM_CHANNEL_EVT_REG_STREAM_BUF_CB: |
| { |
| mm_evt_paylod_reg_stream_buf_cb *payload = |
| (mm_evt_paylod_reg_stream_buf_cb *)in_val; |
| rc = mm_channel_reg_stream_buf_cb (my_obj, |
| payload->stream_id, payload->buf_cb); |
| } |
| break; |
| default: |
| LOGE("invalid state (%d) for evt (%d), in(%p), out(%p)", |
| my_obj->state, evt, in_val, out_val); |
| break; |
| } |
| LOGD("X rc = %d", rc); |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_fsm_fn_paused |
| * |
| * DESCRIPTION: channel finite state machine function to handle event |
| * in PAUSED state. |
| * |
| * PARAMETERS : |
| * @my_obj : ptr to a channel object |
| * @evt : channel 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_channel_fsm_fn_paused(mm_channel_t *my_obj, |
| mm_channel_evt_type_t evt, |
| void * in_val, |
| void * out_val) |
| { |
| int32_t rc = 0; |
| |
| /* currently we are not supporting pause/resume channel */ |
| LOGE("invalid state (%d) for evt (%d), in(%p), out(%p)", |
| my_obj->state, evt, in_val, out_val); |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_init |
| * |
| * DESCRIPTION: initialize a channel |
| * |
| * PARAMETERS : |
| * @my_obj : channel object be to initialized |
| * @attr : bundle attribute of the channel if needed |
| * @channel_cb : callback function for bundle data notify |
| * @userdata : user data ptr |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| * NOTE : if no bundle data notify is needed, meaning each stream in the |
| * channel will have its own stream data notify callback, then |
| * attr, channel_cb, and userdata can be NULL. In this case, |
| * no matching logic will be performed in channel for the bundling. |
| *==========================================================================*/ |
| int32_t mm_channel_init(mm_channel_t *my_obj, |
| mm_camera_channel_attr_t *attr, |
| mm_camera_buf_notify_t channel_cb, |
| void *userdata) |
| { |
| int32_t rc = 0; |
| |
| my_obj->bundle.super_buf_notify_cb = channel_cb; |
| my_obj->bundle.user_data = userdata; |
| if (NULL != attr) { |
| my_obj->bundle.superbuf_queue.attr = *attr; |
| } |
| |
| LOGD("Launch data poll thread in channel open"); |
| snprintf(my_obj->poll_thread[0].threadName, THREAD_NAME_SIZE, "CAM_dataPoll"); |
| mm_camera_poll_thread_launch(&my_obj->poll_thread[0], |
| MM_CAMERA_POLL_TYPE_DATA); |
| |
| /* change state to stopped state */ |
| my_obj->state = MM_CHANNEL_STATE_STOPPED; |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_release |
| * |
| * DESCRIPTION: release a channel resource. Channel state will move to UNUSED |
| * state after this call. |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * |
| * RETURN : none |
| *==========================================================================*/ |
| void mm_channel_release(mm_channel_t *my_obj) |
| { |
| /* stop data poll thread */ |
| mm_camera_poll_thread_release(&my_obj->poll_thread[0]); |
| |
| /* memset bundle info */ |
| memset(&my_obj->bundle, 0, sizeof(mm_channel_bundle_t)); |
| |
| /* change state to notused state */ |
| my_obj->state = MM_CHANNEL_STATE_NOTUSED; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_link_stream |
| * |
| * DESCRIPTION: link a stream from external channel into this channel |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @stream_link : channel and stream to be linked |
| * |
| * RETURN : uint32_t type of stream handle |
| * 0 -- invalid stream handle, meaning the op failed |
| * >0 -- successfully added a stream with a valid handle |
| *==========================================================================*/ |
| uint32_t mm_channel_link_stream(mm_channel_t *my_obj, |
| mm_camera_stream_link_t *stream_link) |
| { |
| uint8_t idx = 0; |
| uint32_t s_hdl = 0; |
| mm_stream_t *stream_obj = NULL; |
| mm_stream_t *stream = NULL; |
| |
| if (NULL == stream_link) { |
| LOGE("Invalid stream link"); |
| return 0; |
| } |
| |
| stream = mm_channel_util_get_stream_by_handler(stream_link->ch, |
| stream_link->stream_id); |
| if (NULL == stream) { |
| return 0; |
| } |
| |
| /* check available stream */ |
| for (idx = 0; idx < MAX_STREAM_NUM_IN_BUNDLE; idx++) { |
| if (MM_STREAM_STATE_NOTUSED == my_obj->streams[idx].state) { |
| stream_obj = &my_obj->streams[idx]; |
| break; |
| } |
| } |
| if (NULL == stream_obj) { |
| LOGE("streams reach max, no more stream allowed to add"); |
| return s_hdl; |
| } |
| |
| /* initialize stream object */ |
| *stream_obj = *stream; |
| stream_obj->linked_stream = stream; |
| s_hdl = stream->my_hdl; |
| |
| LOGD("stream handle = %d", s_hdl); |
| return s_hdl; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_add_stream |
| * |
| * DESCRIPTION: add a stream into the channel |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * |
| * RETURN : uint32_t type of stream handle |
| * 0 -- invalid stream handle, meaning the op failed |
| * >0 -- successfully added a stream with a valid handle |
| *==========================================================================*/ |
| uint32_t mm_channel_add_stream(mm_channel_t *my_obj) |
| { |
| int32_t rc = 0; |
| uint8_t idx = 0; |
| uint32_t s_hdl = 0; |
| mm_stream_t *stream_obj = NULL; |
| |
| LOGD("E"); |
| /* check available stream */ |
| for (idx = 0; idx < MAX_STREAM_NUM_IN_BUNDLE; idx++) { |
| if (MM_STREAM_STATE_NOTUSED == my_obj->streams[idx].state) { |
| stream_obj = &my_obj->streams[idx]; |
| break; |
| } |
| } |
| if (NULL == stream_obj) { |
| LOGE("streams reach max, no more stream allowed to add"); |
| return s_hdl; |
| } |
| |
| /* initialize stream object */ |
| memset(stream_obj, 0, sizeof(mm_stream_t)); |
| stream_obj->fd = -1; |
| stream_obj->my_hdl = mm_camera_util_generate_handler(idx); |
| stream_obj->ch_obj = my_obj; |
| pthread_mutex_init(&stream_obj->buf_lock, NULL); |
| pthread_mutex_init(&stream_obj->cb_lock, NULL); |
| pthread_mutex_init(&stream_obj->cmd_lock, NULL); |
| pthread_cond_init(&stream_obj->buf_cond, NULL); |
| memset(stream_obj->buf_status, 0, |
| sizeof(stream_obj->buf_status)); |
| 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_cond_destroy(&stream_obj->buf_cond); |
| pthread_mutex_destroy(&stream_obj->buf_lock); |
| pthread_mutex_destroy(&stream_obj->cb_lock); |
| pthread_mutex_destroy(&stream_obj->cmd_lock); |
| memset(stream_obj, 0, sizeof(mm_stream_t)); |
| } |
| LOGD("stream handle = %d", s_hdl); |
| return s_hdl; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_del_stream |
| * |
| * DESCRIPTION: delete a stream from the channel bu its handle |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @stream_id : stream handle |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| * NOTE : assume steam is stooped before it can be deleted |
| *==========================================================================*/ |
| 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) { |
| LOGE("Invalid Stream Object for stream_id = %d", stream_id); |
| return rc; |
| } |
| |
| if (stream_obj->ch_obj != my_obj) { |
| /* Only unlink stream */ |
| pthread_mutex_lock(&stream_obj->linked_stream->buf_lock); |
| stream_obj->linked_stream->is_linked = 0; |
| stream_obj->linked_stream->linked_obj = NULL; |
| pthread_mutex_unlock(&stream_obj->linked_stream->buf_lock); |
| memset(stream_obj, 0, sizeof(mm_stream_t)); |
| |
| return 0; |
| } |
| |
| rc = mm_stream_fsm_fn(stream_obj, |
| MM_STREAM_EVT_RELEASE, |
| NULL, |
| NULL); |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_config_stream |
| * |
| * DESCRIPTION: configure a stream |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @stream_id : stream handle |
| * @config : stream configuration |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| 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; |
| LOGD("E stream ID = %d", stream_id); |
| stream_obj = mm_channel_util_get_stream_by_handler(my_obj, stream_id); |
| |
| if (NULL == stream_obj) { |
| LOGE("Invalid Stream Object for stream_id = %d", stream_id); |
| return rc; |
| } |
| |
| if (stream_obj->ch_obj != my_obj) { |
| /* No op. on linked streams */ |
| return 0; |
| } |
| |
| /* set stream fmt */ |
| rc = mm_stream_fsm_fn(stream_obj, |
| MM_STREAM_EVT_SET_FMT, |
| (void *)config, |
| NULL); |
| LOGD("X rc = %d",rc); |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_get_bundle_info |
| * |
| * DESCRIPTION: query bundle info of the channel, which should include all |
| * streams within this channel |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @bundle_info : bundle info to be filled in |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_get_bundle_info(mm_channel_t *my_obj, |
| cam_bundle_config_t *bundle_info) |
| { |
| int i; |
| mm_stream_t *s_obj = NULL; |
| cam_stream_type_t stream_type = CAM_STREAM_TYPE_DEFAULT; |
| int32_t rc = 0; |
| |
| memset(bundle_info, 0, sizeof(cam_bundle_config_t)); |
| bundle_info->bundle_id = my_obj->my_hdl; |
| bundle_info->num_of_streams = 0; |
| for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) { |
| if (my_obj->streams[i].my_hdl > 0) { |
| s_obj = mm_channel_util_get_stream_by_handler(my_obj, |
| my_obj->streams[i].my_hdl); |
| if (NULL != s_obj) { |
| stream_type = s_obj->stream_info->stream_type; |
| if ((CAM_STREAM_TYPE_METADATA != stream_type) && |
| (s_obj->ch_obj == my_obj)) { |
| bundle_info->stream_ids[bundle_info->num_of_streams++] = |
| s_obj->server_stream_id; |
| } |
| } else { |
| LOGE("cannot find stream obj (%d) by handler (%d)", |
| i, my_obj->streams[i].my_hdl); |
| rc = -1; |
| break; |
| } |
| } |
| } |
| if (rc != 0) { |
| /* error, reset to 0 */ |
| memset(bundle_info, 0, sizeof(cam_bundle_config_t)); |
| } |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_start |
| * |
| * DESCRIPTION: start a channel, which will start all streams in the channel |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_start(mm_channel_t *my_obj) |
| { |
| int32_t rc = 0; |
| int i = 0, j = 0; |
| mm_stream_t *s_objs[MAX_STREAM_NUM_IN_BUNDLE] = {NULL}; |
| uint8_t num_streams_to_start = 0; |
| uint8_t num_streams_in_bundle_queue = 0; |
| mm_stream_t *s_obj = NULL; |
| int meta_stream_idx = 0; |
| cam_stream_type_t stream_type = CAM_STREAM_TYPE_DEFAULT; |
| |
| for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) { |
| if (my_obj->streams[i].my_hdl > 0) { |
| s_obj = mm_channel_util_get_stream_by_handler(my_obj, |
| my_obj->streams[i].my_hdl); |
| if (NULL != s_obj) { |
| stream_type = s_obj->stream_info->stream_type; |
| /* remember meta data stream index */ |
| if ((stream_type == CAM_STREAM_TYPE_METADATA) && |
| (s_obj->ch_obj == my_obj)) { |
| meta_stream_idx = num_streams_to_start; |
| } |
| s_objs[num_streams_to_start++] = s_obj; |
| |
| if (!s_obj->stream_info->noFrameExpected) { |
| num_streams_in_bundle_queue++; |
| } |
| } |
| } |
| } |
| |
| if (meta_stream_idx > 0 ) { |
| /* always start meta data stream first, so switch the stream object with the first one */ |
| s_obj = s_objs[0]; |
| s_objs[0] = s_objs[meta_stream_idx]; |
| s_objs[meta_stream_idx] = s_obj; |
| } |
| |
| if (NULL != my_obj->bundle.super_buf_notify_cb) { |
| /* need to send up cb, therefore launch thread */ |
| /* init superbuf queue */ |
| mm_channel_superbuf_queue_init(&my_obj->bundle.superbuf_queue); |
| my_obj->bundle.superbuf_queue.num_streams = num_streams_in_bundle_queue; |
| my_obj->bundle.superbuf_queue.expected_frame_id = |
| my_obj->bundle.superbuf_queue.attr.user_expected_frame_id; |
| my_obj->bundle.superbuf_queue.expected_frame_id_without_led = 0; |
| my_obj->bundle.superbuf_queue.led_off_start_frame_id = 0; |
| my_obj->bundle.superbuf_queue.led_on_start_frame_id = 0; |
| my_obj->bundle.superbuf_queue.led_on_num_frames = 0; |
| my_obj->bundle.superbuf_queue.good_frame_id = 0; |
| |
| for (i = 0; i < num_streams_to_start; i++) { |
| /* Only bundle streams that belong to the channel */ |
| if(!(s_objs[i]->stream_info->noFrameExpected)) { |
| if (s_objs[i]->ch_obj == my_obj) { |
| /* set bundled flag to streams */ |
| s_objs[i]->is_bundled = 1; |
| } |
| my_obj->bundle.superbuf_queue.bundled_streams[j++] = s_objs[i]->my_hdl; |
| } |
| } |
| |
| /* launch cb thread for dispatching super buf through cb */ |
| snprintf(my_obj->cb_thread.threadName, THREAD_NAME_SIZE, "CAM_SuperBuf"); |
| mm_camera_cmd_thread_launch(&my_obj->cb_thread, |
| mm_channel_dispatch_super_buf, |
| (void*)my_obj); |
| |
| /* launch cmd thread for super buf dataCB */ |
| snprintf(my_obj->cmd_thread.threadName, THREAD_NAME_SIZE, "CAM_SuperBufCB"); |
| mm_camera_cmd_thread_launch(&my_obj->cmd_thread, |
| mm_channel_process_stream_buf, |
| (void*)my_obj); |
| |
| /* set flag to TRUE */ |
| my_obj->bundle.is_active = TRUE; |
| } |
| |
| /* link any streams first before starting the rest of the streams */ |
| for (i = 0; i < num_streams_to_start; i++) { |
| if (s_objs[i]->ch_obj != my_obj) { |
| pthread_mutex_lock(&s_objs[i]->linked_stream->buf_lock); |
| s_objs[i]->linked_stream->linked_obj = my_obj; |
| s_objs[i]->linked_stream->is_linked = 1; |
| pthread_mutex_unlock(&s_objs[i]->linked_stream->buf_lock); |
| continue; |
| } |
| } |
| |
| for (i = 0; i < num_streams_to_start; i++) { |
| if (s_objs[i]->ch_obj != my_obj) { |
| continue; |
| } |
| /* all streams within a channel should be started at the same time */ |
| if (s_objs[i]->state == MM_STREAM_STATE_ACTIVE) { |
| LOGE("stream already started idx(%d)", i); |
| rc = -1; |
| break; |
| } |
| |
| /* allocate buf */ |
| rc = mm_stream_fsm_fn(s_objs[i], |
| MM_STREAM_EVT_GET_BUF, |
| NULL, |
| NULL); |
| if (0 != rc) { |
| LOGE("get buf failed at idx(%d)", i); |
| break; |
| } |
| |
| /* reg buf */ |
| rc = mm_stream_fsm_fn(s_objs[i], |
| MM_STREAM_EVT_REG_BUF, |
| NULL, |
| NULL); |
| if (0 != rc) { |
| LOGE("reg buf failed at idx(%d)", i); |
| break; |
| } |
| |
| /* start stream */ |
| rc = mm_stream_fsm_fn(s_objs[i], |
| MM_STREAM_EVT_START, |
| NULL, |
| NULL); |
| if (0 != rc) { |
| LOGE("start stream failed at idx(%d)", i); |
| break; |
| } |
| } |
| |
| /* error handling */ |
| if (0 != rc) { |
| /* unlink the streams first */ |
| for (j = 0; j < num_streams_to_start; j++) { |
| if (s_objs[j]->ch_obj != my_obj) { |
| pthread_mutex_lock(&s_objs[j]->linked_stream->buf_lock); |
| s_objs[j]->linked_stream->is_linked = 0; |
| s_objs[j]->linked_stream->linked_obj = NULL; |
| pthread_mutex_unlock(&s_objs[j]->linked_stream->buf_lock); |
| |
| if (TRUE == my_obj->bundle.is_active) { |
| mm_channel_flush_super_buf_queue(my_obj, 0, |
| s_objs[i]->stream_info->stream_type); |
| } |
| memset(s_objs[j], 0, sizeof(mm_stream_t)); |
| continue; |
| } |
| } |
| |
| for (j = 0; j <= i; j++) { |
| if ((NULL == s_objs[j]) || (s_objs[j]->ch_obj != my_obj)) { |
| continue; |
| } |
| /* stop streams*/ |
| mm_stream_fsm_fn(s_objs[j], |
| MM_STREAM_EVT_STOP, |
| NULL, |
| NULL); |
| |
| /* unreg buf */ |
| mm_stream_fsm_fn(s_objs[j], |
| MM_STREAM_EVT_UNREG_BUF, |
| NULL, |
| NULL); |
| |
| /* put buf back */ |
| mm_stream_fsm_fn(s_objs[j], |
| MM_STREAM_EVT_PUT_BUF, |
| NULL, |
| NULL); |
| } |
| |
| /* destroy super buf cmd thread */ |
| if (TRUE == my_obj->bundle.is_active) { |
| /* first stop bundle thread */ |
| mm_camera_cmd_thread_release(&my_obj->cmd_thread); |
| mm_camera_cmd_thread_release(&my_obj->cb_thread); |
| |
| /* deinit superbuf queue */ |
| mm_channel_superbuf_queue_deinit(&my_obj->bundle.superbuf_queue); |
| |
| /* memset super buffer queue info */ |
| my_obj->bundle.is_active = 0; |
| memset(&my_obj->bundle.superbuf_queue, 0, sizeof(mm_channel_queue_t)); |
| } |
| } |
| my_obj->bWaitForPrepSnapshotDone = 0; |
| if (my_obj->bundle.superbuf_queue.attr.enable_frame_sync) { |
| LOGH("registering Channel obj %p", my_obj); |
| mm_frame_sync_register_channel(my_obj); |
| } |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_stop |
| * |
| * DESCRIPTION: stop a channel, which will stop all streams in the channel |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_stop(mm_channel_t *my_obj) |
| { |
| int32_t rc = 0; |
| int i; |
| mm_stream_t *s_objs[MAX_STREAM_NUM_IN_BUNDLE] = {NULL}; |
| uint8_t num_streams_to_stop = 0; |
| mm_stream_t *s_obj = NULL; |
| int meta_stream_idx = 0; |
| cam_stream_type_t stream_type = CAM_STREAM_TYPE_DEFAULT; |
| |
| if (my_obj->bundle.superbuf_queue.attr.enable_frame_sync) { |
| mm_frame_sync_unregister_channel(my_obj); |
| } |
| |
| for (i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) { |
| if (my_obj->streams[i].my_hdl > 0) { |
| s_obj = mm_channel_util_get_stream_by_handler(my_obj, |
| my_obj->streams[i].my_hdl); |
| if (NULL != s_obj) { |
| if (s_obj->ch_obj == my_obj) { |
| stream_type = s_obj->stream_info->stream_type; |
| /* remember meta data stream index */ |
| if (stream_type == CAM_STREAM_TYPE_METADATA) { |
| meta_stream_idx = num_streams_to_stop; |
| } |
| } |
| s_objs[num_streams_to_stop++] = s_obj; |
| } |
| } |
| } |
| |
| if (meta_stream_idx < num_streams_to_stop - 1 ) { |
| /* always stop meta data stream last, so switch the stream object with the last one */ |
| s_obj = s_objs[num_streams_to_stop - 1]; |
| s_objs[num_streams_to_stop - 1] = s_objs[meta_stream_idx]; |
| s_objs[meta_stream_idx] = s_obj; |
| } |
| |
| for (i = 0; i < num_streams_to_stop; i++) { |
| /* stream that are linked to this channel should not be stopped */ |
| if (s_objs[i]->ch_obj != my_obj) { |
| continue; |
| } |
| |
| /* 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); |
| } |
| |
| for (i = 0; i < num_streams_to_stop; i++) { |
| if (s_objs[i]->ch_obj != my_obj) { |
| /* Only unlink stream */ |
| pthread_mutex_lock(&s_objs[i]->linked_stream->buf_lock); |
| s_objs[i]->linked_stream->is_linked = 0; |
| s_objs[i]->linked_stream->linked_obj = NULL; |
| pthread_mutex_unlock(&s_objs[i]->linked_stream->buf_lock); |
| } |
| } |
| |
| /* destroy super buf cmd thread */ |
| if (TRUE == my_obj->bundle.is_active) { |
| mm_channel_flush_super_buf_queue(my_obj, 0, CAM_STREAM_TYPE_DEFAULT); |
| /* first stop bundle thread */ |
| mm_camera_cmd_thread_release(&my_obj->cmd_thread); |
| mm_camera_cmd_thread_release(&my_obj->cb_thread); |
| |
| /* deinit superbuf queue */ |
| mm_channel_superbuf_queue_deinit(&my_obj->bundle.superbuf_queue); |
| |
| /* reset few fields in the bundle info */ |
| my_obj->bundle.is_active = 0; |
| my_obj->bundle.superbuf_queue.expected_frame_id = 0; |
| my_obj->bundle.superbuf_queue.good_frame_id = 0; |
| my_obj->bundle.superbuf_queue.match_cnt = 0; |
| } |
| |
| /* 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 (s_objs[i]->ch_obj != my_obj) { |
| continue; |
| } |
| /* put buf back */ |
| mm_stream_fsm_fn(s_objs[i], |
| MM_STREAM_EVT_PUT_BUF, |
| NULL, |
| NULL); |
| } |
| |
| for (i = 0; i < num_streams_to_stop; i++) { |
| if (s_objs[i]->ch_obj != my_obj) { |
| memset(s_objs[i], 0, sizeof(mm_stream_t)); |
| } else { |
| continue; |
| } |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_request_super_buf |
| * |
| * DESCRIPTION: for burst mode in bundle, reuqest certain amount of matched |
| * frames from superbuf queue |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @num_buf_requested : number of matched frames needed |
| * @num_retro_buf_requested : number of retro frames needed |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_request_super_buf(mm_channel_t *my_obj, |
| mm_camera_req_buf_t *buf) |
| { |
| int32_t rc = 0; |
| mm_camera_cmdcb_t* node = NULL; |
| |
| if(!buf) { |
| LOGE("Request info buf is NULL"); |
| return -1; |
| } |
| |
| /* set pending_cnt |
| * will trigger dispatching super frames if pending_cnt > 0 */ |
| /* send cam_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; |
| node->u.req_buf = *buf; |
| |
| /* 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"); |
| rc = -1; |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_cancel_super_buf_request |
| * |
| * DESCRIPTION: for burst mode in bundle, cancel the reuqest for certain amount |
| * of matched frames from superbuf queue |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_cancel_super_buf_request(mm_channel_t *my_obj) |
| { |
| int32_t rc = 0; |
| /* reset pending_cnt */ |
| mm_camera_req_buf_t buf; |
| memset(&buf, 0x0, sizeof(buf)); |
| buf.type = MM_CAMERA_REQ_SUPER_BUF; |
| buf.num_buf_requested = 0; |
| rc = mm_channel_request_super_buf(my_obj, &buf); |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_flush_super_buf_queue |
| * |
| * DESCRIPTION: flush superbuf queue |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @frame_idx : frame idx until which to flush all superbufs |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_flush_super_buf_queue(mm_channel_t *my_obj, uint32_t frame_idx, |
| cam_stream_type_t stream_type) |
| { |
| int32_t rc = 0; |
| mm_camera_cmdcb_t* node = NULL; |
| |
| 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_FLUSH_QUEUE; |
| node->u.flush_cmd.frame_idx = frame_idx; |
| node->u.flush_cmd.stream_type = stream_type; |
| |
| /* 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)); |
| |
| /* wait for ack from cmd thread */ |
| cam_sem_wait(&(my_obj->cmd_thread.sync_sem)); |
| } else { |
| LOGE("No memory for mm_camera_node_t"); |
| rc = -1; |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_config_notify_mode |
| * |
| * DESCRIPTION: configure notification mode |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @notify_mode : notification mode |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_config_notify_mode(mm_channel_t *my_obj, |
| mm_camera_super_buf_notify_mode_t notify_mode) |
| { |
| int32_t rc = 0; |
| mm_camera_cmdcb_t* node = NULL; |
| |
| node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t)); |
| if (NULL != node) { |
| memset(node, 0, sizeof(mm_camera_cmdcb_t)); |
| node->u.notify_mode = notify_mode; |
| node->cmd_type = MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY; |
| |
| /* 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"); |
| rc = -1; |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_start_zsl_snapshot |
| * |
| * DESCRIPTION: start zsl snapshot |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_start_zsl_snapshot(mm_channel_t *my_obj) |
| { |
| int32_t rc = 0; |
| mm_camera_cmdcb_t* node = NULL; |
| |
| 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_START_ZSL; |
| |
| /* 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"); |
| rc = -1; |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_stop_zsl_snapshot |
| * |
| * DESCRIPTION: stop zsl snapshot |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_stop_zsl_snapshot(mm_channel_t *my_obj) |
| { |
| int32_t rc = 0; |
| mm_camera_cmdcb_t* node = NULL; |
| |
| 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_STOP_ZSL; |
| |
| /* 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"); |
| rc = -1; |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_qbuf |
| * |
| * DESCRIPTION: enqueue buffer back to kernel |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @buf : buf ptr to be enqueued |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_qbuf(mm_channel_t *my_obj, |
| mm_camera_buf_def_t *buf) |
| { |
| int32_t rc = -1; |
| mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, buf->stream_id); |
| |
| if (NULL != s_obj) { |
| if (s_obj->ch_obj != my_obj) { |
| /* Redirect to linked stream */ |
| rc = mm_stream_fsm_fn(s_obj->linked_stream, |
| MM_STREAM_EVT_QBUF, |
| (void *)buf, |
| NULL); |
| } else { |
| rc = mm_stream_fsm_fn(s_obj, |
| MM_STREAM_EVT_QBUF, |
| (void *)buf, |
| NULL); |
| } |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_cancel_buf |
| * |
| * DESCRIPTION: Get back buffer already sent to kernel |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @buf : buf ptr to be enqueued |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_cancel_buf(mm_channel_t *my_obj, |
| uint32_t stream_id, uint32_t buf_idx) |
| { |
| int32_t rc = -1; |
| mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, stream_id); |
| |
| if (NULL != s_obj) { |
| if (s_obj->ch_obj != my_obj) { |
| /* Redirect to linked stream */ |
| rc = mm_stream_fsm_fn(s_obj->linked_stream, |
| MM_STREAM_EVT_CANCEL_BUF, |
| (void *)&buf_idx, |
| NULL); |
| } else { |
| rc = mm_stream_fsm_fn(s_obj, |
| MM_STREAM_EVT_CANCEL_BUF, |
| (void *)&buf_idx, |
| NULL); |
| } |
| } |
| |
| return rc; |
| } |
| |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_get_queued_buf_count |
| * |
| * DESCRIPTION: return queued buffer count |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @stream_id : steam_id |
| * |
| * RETURN : queued buffer count |
| *==========================================================================*/ |
| int32_t mm_channel_get_queued_buf_count(mm_channel_t *my_obj, uint32_t stream_id) |
| { |
| int32_t rc = -1; |
| mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, stream_id); |
| |
| if (NULL != s_obj) { |
| if (s_obj->ch_obj != my_obj) { |
| /* Redirect to linked stream */ |
| rc = mm_stream_fsm_fn(s_obj->linked_stream, |
| MM_STREAM_EVT_GET_QUEUED_BUF_COUNT, |
| NULL, |
| NULL); |
| } else { |
| rc = mm_stream_fsm_fn(s_obj, |
| MM_STREAM_EVT_GET_QUEUED_BUF_COUNT, |
| NULL, |
| NULL); |
| } |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_set_stream_parms |
| * |
| * DESCRIPTION: set parameters per stream |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @s_id : stream handle |
| * @parms : 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_channel_set_stream_parm(mm_channel_t *my_obj, |
| mm_evt_paylod_set_get_stream_parms_t *payload) |
| { |
| int32_t rc = -1; |
| mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, |
| payload->stream_id); |
| if (NULL != s_obj) { |
| if (s_obj->ch_obj != my_obj) { |
| /* No op. on linked streams */ |
| return 0; |
| } |
| |
| rc = mm_stream_fsm_fn(s_obj, |
| MM_STREAM_EVT_SET_PARM, |
| (void *)payload, |
| NULL); |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_get_stream_parms |
| * |
| * DESCRIPTION: get parameters per stream |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @s_id : stream handle |
| * @parms : 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. Parameters to be get from server are already |
| * filled in by upper layer caller. After this call, corresponding |
| * fields of requested parameters will be filled in by server with |
| * detailed information. |
| *==========================================================================*/ |
| int32_t mm_channel_get_stream_parm(mm_channel_t *my_obj, |
| mm_evt_paylod_set_get_stream_parms_t *payload) |
| { |
| int32_t rc = -1; |
| mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, |
| payload->stream_id); |
| if (NULL != s_obj) { |
| if (s_obj->ch_obj != my_obj) { |
| /* No op. on linked streams */ |
| return 0; |
| } |
| |
| rc = mm_stream_fsm_fn(s_obj, |
| MM_STREAM_EVT_GET_PARM, |
| (void *)payload, |
| NULL); |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_do_stream_action |
| * |
| * DESCRIPTION: request server to perform stream based action. Maybe removed later |
| * if the functionality is included in mm_camera_set_parms |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @s_id : stream handle |
| * @actions : ptr to an action struct buf to be performed by 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. Actions to be performed by server are already |
| * filled in by upper layer caller. |
| *==========================================================================*/ |
| int32_t mm_channel_do_stream_action(mm_channel_t *my_obj, |
| mm_evt_paylod_do_stream_action_t *payload) |
| { |
| int32_t rc = -1; |
| mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, |
| payload->stream_id); |
| if (NULL != s_obj) { |
| if (s_obj->ch_obj != my_obj) { |
| /* No op. on linked streams */ |
| return 0; |
| } |
| |
| rc = mm_stream_fsm_fn(s_obj, |
| MM_STREAM_EVT_DO_ACTION, |
| (void *)payload, |
| NULL); |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_map_stream_buf |
| * |
| * DESCRIPTION: mapping stream buffer via domain socket to server |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @payload : ptr to payload for mapping |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_map_stream_buf(mm_channel_t *my_obj, |
| cam_buf_map_type *payload) |
| { |
| int32_t rc = -1; |
| mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, |
| payload->stream_id); |
| if (NULL != s_obj) { |
| if (s_obj->ch_obj != my_obj) { |
| /* No op. on linked streams */ |
| return 0; |
| } |
| rc = mm_stream_map_buf(s_obj, |
| payload->type, payload->frame_idx, |
| payload->plane_idx, payload->fd, |
| payload->size, payload->buffer); |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_map_stream_bufs |
| * |
| * DESCRIPTION: mapping stream buffers via domain socket to server |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @payload : ptr to payload for mapping |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_map_stream_bufs(mm_channel_t *my_obj, |
| cam_buf_map_type_list *payload) |
| { |
| int32_t rc = -1; |
| if ((payload == NULL) || (payload->length == 0)) { |
| return rc; |
| } |
| |
| mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, |
| payload->buf_maps[0].stream_id); |
| if (NULL != s_obj) { |
| if (s_obj->ch_obj != my_obj) { |
| /* No op. on linked streams */ |
| return 0; |
| } |
| |
| rc = mm_stream_map_bufs(s_obj, payload); |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_unmap_stream_buf |
| * |
| * DESCRIPTION: unmapping stream buffer via domain socket to server |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @payload : ptr to unmap payload |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_unmap_stream_buf(mm_channel_t *my_obj, |
| cam_buf_unmap_type *payload) |
| { |
| int32_t rc = -1; |
| mm_stream_t* s_obj = mm_channel_util_get_stream_by_handler(my_obj, |
| payload->stream_id); |
| if (NULL != s_obj) { |
| if (s_obj->ch_obj != my_obj) { |
| /* No op. on linked streams */ |
| return 0; |
| } |
| |
| rc = mm_stream_unmap_buf(s_obj, payload->type, |
| payload->frame_idx, payload->plane_idx); |
| } |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_superbuf_queue_init |
| * |
| * DESCRIPTION: initialize superbuf queue in the channel |
| * |
| * PARAMETERS : |
| * @queue : ptr to superbuf queue to be initialized |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_superbuf_queue_init(mm_channel_queue_t * queue) |
| { |
| return cam_queue_init(&queue->que); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_superbuf_queue_deinit |
| * |
| * DESCRIPTION: deinitialize superbuf queue in the channel |
| * |
| * PARAMETERS : |
| * @queue : ptr to superbuf queue to be deinitialized |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_superbuf_queue_deinit(mm_channel_queue_t * queue) |
| { |
| return cam_queue_deinit(&queue->que); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_util_seq_comp_w_rollover |
| * |
| * DESCRIPTION: utility function to handle sequence number comparison with rollover |
| * |
| * PARAMETERS : |
| * @v1 : first value to be compared |
| * @v2 : second value to be compared |
| * |
| * RETURN : int8_t type of comparison result |
| * >0 -- v1 larger than v2 |
| * =0 -- vi equal to v2 |
| * <0 -- v1 smaller than v2 |
| *==========================================================================*/ |
| 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; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_validate_super_buf. |
| * |
| * DESCRIPTION: Validate incoming buffer with existing super buffer. |
| * |
| * PARAMETERS : |
| * @ch_obj : channel object |
| * @queue : superbuf queue |
| * @buf_info: new buffer from stream |
| * |
| * RETURN : int8_t type of validation result |
| * >0 -- Valid frame |
| * =0 -- Cannot validate |
| * <0 -- Invalid frame. Can be freed |
| *==========================================================================*/ |
| int8_t mm_channel_validate_super_buf(__unused mm_channel_t* ch_obj, |
| mm_channel_queue_t *queue, mm_camera_buf_info_t *buf_info) |
| { |
| int8_t ret = 0; |
| cam_node_t* node = NULL; |
| struct cam_list *head = NULL; |
| struct cam_list *pos = NULL; |
| mm_channel_queue_node_t* super_buf = NULL; |
| |
| (void)ch_obj; |
| |
| /* 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, cam_node_t, list); |
| super_buf = (mm_channel_queue_node_t*)node->data; |
| if (NULL != super_buf) { |
| if ((super_buf->expected_frame) && |
| (buf_info->frame_idx == super_buf->frame_idx)) { |
| //This is good frame. Expecting more frames. Keeping this frame. |
| ret = 1; |
| break; |
| } else { |
| pos = pos->next; |
| continue; |
| } |
| } |
| } |
| pthread_mutex_unlock(&queue->que.lock); |
| return ret; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_handle_metadata |
| * |
| * DESCRIPTION: Handle frame matching logic change due to metadata |
| * |
| * PARAMETERS : |
| * @ch_obj : channel object |
| * @queue : superbuf queue |
| * @buf_info: new buffer from stream |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_handle_metadata( |
| mm_channel_t* ch_obj, |
| mm_channel_queue_t * queue, |
| mm_camera_buf_info_t *buf_info) |
| { |
| |
| int rc = 0 ; |
| mm_stream_t* stream_obj = NULL; |
| stream_obj = mm_channel_util_get_stream_by_handler(ch_obj, |
| buf_info->stream_id); |
| uint8_t is_prep_snapshot_done_valid = 0; |
| uint8_t is_good_frame_idx_range_valid = 0; |
| int32_t prep_snapshot_done_state = 0; |
| cam_frame_idx_range_t good_frame_idx_range; |
| uint8_t is_crop_1x_found = 0; |
| uint32_t snapshot_stream_id = 0; |
| uint32_t i; |
| /* Set expected frame id to a future frame idx, large enough to wait |
| * for good_frame_idx_range, and small enough to still capture an image */ |
| const uint32_t max_future_frame_offset = MM_CAMERA_MAX_FUTURE_FRAME_WAIT; |
| |
| memset(&good_frame_idx_range, 0, sizeof(good_frame_idx_range)); |
| |
| if (NULL == stream_obj) { |
| LOGE("Invalid Stream Object for stream_id = %d", |
| buf_info->stream_id); |
| rc = -1; |
| goto end; |
| } |
| if (NULL == stream_obj->stream_info) { |
| LOGE("NULL stream info for stream_id = %d", |
| buf_info->stream_id); |
| rc = -1; |
| goto end; |
| } |
| |
| if ((CAM_STREAM_TYPE_METADATA == stream_obj->stream_info->stream_type) && |
| ((stream_obj->ch_obj == ch_obj) || |
| ((stream_obj->linked_stream != NULL) && |
| (stream_obj->linked_stream->linked_obj == ch_obj)))) { |
| const metadata_buffer_t *metadata; |
| metadata = (const metadata_buffer_t *)buf_info->buf->buffer; |
| |
| if (NULL == metadata) { |
| LOGE("NULL metadata buffer for metadata stream"); |
| rc = -1; |
| goto end; |
| } |
| LOGL("E , expected frame id: %d", queue->expected_frame_id); |
| |
| IF_META_AVAILABLE(const int32_t, p_prep_snapshot_done_state, |
| CAM_INTF_META_PREP_SNAPSHOT_DONE, metadata) { |
| prep_snapshot_done_state = *p_prep_snapshot_done_state; |
| is_prep_snapshot_done_valid = 1; |
| LOGH("prepare snapshot done valid "); |
| } |
| IF_META_AVAILABLE(const cam_frame_idx_range_t, p_good_frame_idx_range, |
| CAM_INTF_META_GOOD_FRAME_IDX_RANGE, metadata) { |
| good_frame_idx_range = *p_good_frame_idx_range; |
| is_good_frame_idx_range_valid = 1; |
| LOGH("good_frame_idx_range : min: %d, max: %d , num frames = %d", |
| good_frame_idx_range.min_frame_idx, |
| good_frame_idx_range.max_frame_idx, good_frame_idx_range.num_led_on_frames); |
| } |
| IF_META_AVAILABLE(const cam_crop_data_t, p_crop_data, |
| CAM_INTF_META_CROP_DATA, metadata) { |
| cam_crop_data_t crop_data = *p_crop_data; |
| |
| for (i = 0; i < ARRAY_SIZE(ch_obj->streams); i++) { |
| if (MM_STREAM_STATE_NOTUSED == ch_obj->streams[i].state) { |
| continue; |
| } |
| if (CAM_STREAM_TYPE_SNAPSHOT == |
| ch_obj->streams[i].stream_info->stream_type) { |
| snapshot_stream_id = ch_obj->streams[i].server_stream_id; |
| break; |
| } |
| } |
| |
| for (i=0; i<crop_data.num_of_streams; i++) { |
| if (snapshot_stream_id == crop_data.crop_info[i].stream_id) { |
| if (!crop_data.crop_info[i].crop.left && |
| !crop_data.crop_info[i].crop.top) { |
| is_crop_1x_found = 1; |
| break; |
| } |
| } |
| } |
| } |
| |
| IF_META_AVAILABLE(const cam_buf_divert_info_t, p_divert_info, |
| CAM_INTF_BUF_DIVERT_INFO, metadata) { |
| cam_buf_divert_info_t divert_info = *p_divert_info; |
| if (divert_info.frame_id >= buf_info->frame_idx) { |
| ch_obj->diverted_frame_id = divert_info.frame_id; |
| } else { |
| ch_obj->diverted_frame_id = 0; |
| } |
| } |
| |
| if (ch_obj->isZoom1xFrameRequested) { |
| if (is_crop_1x_found) { |
| ch_obj->isZoom1xFrameRequested = 0; |
| queue->expected_frame_id = buf_info->frame_idx + 1; |
| } else { |
| queue->expected_frame_id += max_future_frame_offset; |
| /* Flush unwanted frames */ |
| mm_channel_superbuf_flush_matched(ch_obj, queue); |
| } |
| goto end; |
| } |
| |
| if (ch_obj->startZSlSnapshotCalled && is_good_frame_idx_range_valid) { |
| LOGI("frameID = %d, expected = %d good_frame_idx = %d", |
| buf_info->frame_idx, queue->expected_frame_id, |
| good_frame_idx_range.min_frame_idx); |
| } |
| |
| if (is_prep_snapshot_done_valid) { |
| ch_obj->bWaitForPrepSnapshotDone = 0; |
| if (prep_snapshot_done_state == NEED_FUTURE_FRAME) { |
| queue->expected_frame_id += max_future_frame_offset; |
| LOGI("PreFlash Done. Need Main Flash"); |
| |
| mm_channel_superbuf_flush(ch_obj, |
| queue, CAM_STREAM_TYPE_DEFAULT); |
| |
| ch_obj->needLEDFlash = TRUE; |
| } else { |
| ch_obj->needLEDFlash = FALSE; |
| } |
| } |
| if (is_good_frame_idx_range_valid) { |
| queue->expected_frame_id = |
| good_frame_idx_range.min_frame_idx; |
| queue->good_frame_id = good_frame_idx_range.min_frame_idx; |
| if((ch_obj->needLEDFlash == TRUE) && (ch_obj->burstSnapNum > 1)) { |
| queue->led_on_start_frame_id = |
| good_frame_idx_range.min_frame_idx; |
| queue->led_off_start_frame_id = |
| good_frame_idx_range.max_frame_idx; |
| queue->once = 0; |
| queue->led_on_num_frames = |
| good_frame_idx_range.num_led_on_frames; |
| queue->frame_skip_count = good_frame_idx_range.frame_skip_count; |
| LOGD("Need Flash, expected frame id = %d," |
| " led_on start = %d, led off start = %d, led on frames = %d ", |
| queue->expected_frame_id, queue->led_on_start_frame_id, |
| queue->led_off_start_frame_id, queue->led_on_num_frames); |
| } else { |
| LOGD("No flash, expected frame id = %d ", |
| queue->expected_frame_id); |
| } |
| } else if ((MM_CHANNEL_BRACKETING_STATE_WAIT_GOOD_FRAME_IDX == ch_obj->bracketingState) && |
| !is_prep_snapshot_done_valid) { |
| /* Flush unwanted frames */ |
| mm_channel_superbuf_flush_matched(ch_obj, queue); |
| queue->expected_frame_id += max_future_frame_offset; |
| } |
| if (ch_obj->isFlashBracketingEnabled && |
| is_good_frame_idx_range_valid) { |
| /* Flash bracketing needs two frames, with & without led flash. |
| * in valid range min frame is with led flash and max frame is |
| * without led flash */ |
| queue->expected_frame_id = |
| good_frame_idx_range.min_frame_idx; |
| /* max frame is without led flash */ |
| queue->expected_frame_id_without_led = |
| good_frame_idx_range.max_frame_idx; |
| queue->good_frame_id = |
| good_frame_idx_range.min_frame_idx; |
| } else if (is_good_frame_idx_range_valid) { |
| queue->expected_frame_id = |
| good_frame_idx_range.min_frame_idx; |
| ch_obj->bracketingState = MM_CHANNEL_BRACKETING_STATE_ACTIVE; |
| queue->good_frame_id = |
| good_frame_idx_range.min_frame_idx; |
| } |
| |
| if (ch_obj->isConfigCapture && is_good_frame_idx_range_valid |
| && (good_frame_idx_range.config_batch_idx < ch_obj->frameConfig.num_batch)) { |
| |
| LOGI("Frame Config: Expcted ID = %d batch index = %d", |
| good_frame_idx_range.min_frame_idx, good_frame_idx_range.config_batch_idx); |
| ch_obj->capture_frame_id[good_frame_idx_range.config_batch_idx] = |
| good_frame_idx_range.min_frame_idx; |
| |
| if (ch_obj->cur_capture_idx == good_frame_idx_range.config_batch_idx) { |
| queue->expected_frame_id = |
| good_frame_idx_range.min_frame_idx; |
| } else { |
| queue->expected_frame_id = |
| ch_obj->capture_frame_id[ch_obj->cur_capture_idx]; |
| } |
| queue->good_frame_id = queue->expected_frame_id; |
| } |
| |
| if ((ch_obj->burstSnapNum > 1) && (ch_obj->needLEDFlash == TRUE) |
| && !ch_obj->isFlashBracketingEnabled |
| && (MM_CHANNEL_BRACKETING_STATE_OFF == ch_obj->bracketingState) |
| && !ch_obj->isConfigCapture) { |
| if((buf_info->frame_idx >= queue->led_off_start_frame_id) |
| && !queue->once) { |
| LOGD("Burst snap num = %d ", |
| ch_obj->burstSnapNum); |
| // Skip frames from LED OFF frame to get a good frame |
| queue->expected_frame_id = queue->led_off_start_frame_id + |
| queue->frame_skip_count; |
| queue->once = 1; |
| ch_obj->stopZslSnapshot = 1; |
| ch_obj->needLEDFlash = FALSE; |
| LOGD("Reached max led on frames = %d , expected id = %d", |
| buf_info->frame_idx, queue->expected_frame_id); |
| } |
| } |
| |
| IF_META_AVAILABLE(const cam_low_light_mode_t, low_light_level, |
| CAM_INTF_META_LOW_LIGHT, metadata) { |
| ch_obj->needLowLightZSL = *low_light_level; |
| } |
| |
| // For the instant capture case, if AEC settles before expected frame ID from user, |
| // reset the expected frame ID to current frame index. |
| if (queue->attr.user_expected_frame_id > 0) { |
| if (queue->attr.user_expected_frame_id > buf_info->frame_idx) { |
| IF_META_AVAILABLE(const cam_3a_params_t, ae_params, |
| CAM_INTF_META_AEC_INFO, metadata) { |
| if (ae_params->settled) { |
| queue->expected_frame_id = buf_info->frame_idx; |
| // Reset the expected frame ID from HAL to 0 |
| queue->attr.user_expected_frame_id = 0; |
| LOGD("AEC settled, reset expected frame ID from user"); |
| } |
| } |
| } else { |
| // Reset the expected frame ID from HAL to 0 after |
| // current frame index is greater than expected id. |
| queue->attr.user_expected_frame_id = 0; |
| LOGD("reset expected frame ID from user as it reached the bound"); |
| } |
| } |
| } |
| end: |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_superbuf_comp_and_enqueue |
| * |
| * DESCRIPTION: implementation for matching logic for superbuf |
| * |
| * PARAMETERS : |
| * @ch_obj : channel object |
| * @queue : superbuf queue |
| * @buf_info: new buffer from stream |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| 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) |
| { |
| cam_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, found_super_buf, unmatched_bundles; |
| struct cam_list *last_buf, *insert_before_buf, *last_buf_ptr; |
| |
| LOGD("E"); |
| |
| 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) { |
| LOGE("buf from stream (%d) not bundled", buf_info->stream_id); |
| return -1; |
| } |
| |
| if(buf_info->frame_idx == 0) { |
| mm_channel_qbuf(ch_obj, buf_info->buf); |
| return 0; |
| } |
| |
| if (mm_channel_handle_metadata(ch_obj, queue, buf_info) < 0) { |
| mm_channel_qbuf(ch_obj, buf_info->buf); |
| return -1; |
| } |
| |
| if ((mm_channel_util_seq_comp_w_rollover(buf_info->frame_idx, |
| queue->expected_frame_id) < 0) && |
| (mm_channel_validate_super_buf(ch_obj, queue, buf_info) <= 0)) { |
| LOGH("incoming buf id(%d) is older than expected buf id(%d), will discard it", |
| buf_info->frame_idx, queue->expected_frame_id); |
| mm_channel_qbuf(ch_obj, buf_info->buf); |
| return 0; |
| } |
| |
| /* 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; |
| |
| found_super_buf = 0; |
| unmatched_bundles = 0; |
| last_buf = NULL; |
| insert_before_buf = NULL; |
| last_buf_ptr = NULL; |
| |
| while (pos != head) { |
| node = member_of(pos, cam_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 if (( buf_info->frame_idx == super_buf->frame_idx ) |
| /*Pick metadata greater than available frameID*/ |
| || ((queue->attr.priority == MM_CAMERA_SUPER_BUF_PRIORITY_LOW) |
| && (super_buf->super_buf[buf_s_idx].frame_idx == 0) |
| && (buf_info->buf->stream_type == CAM_STREAM_TYPE_METADATA) |
| && (super_buf->frame_idx < buf_info->frame_idx)) |
| /*Pick available metadata closest to frameID*/ |
| || ((queue->attr.priority == MM_CAMERA_SUPER_BUF_PRIORITY_LOW) |
| && (buf_info->buf->stream_type != CAM_STREAM_TYPE_METADATA) |
| && (super_buf->super_buf[buf_s_idx].frame_idx == 0) |
| && (super_buf->unmatched_meta_idx > buf_info->frame_idx))){ |
| /*super buffer frame IDs matching OR In low priority bundling |
| metadata frameID greater than avialbale super buffer frameID OR |
| metadata frame closest to incoming frameID will be bundled*/ |
| found_super_buf = 1; |
| /* If we are filling into a 'meta only' superbuf, make sure to reset |
| the super_buf frame_idx so that missing streams in this superbuf |
| are filled as per matching frame id logic. Note that, in low priority |
| queue, only meta frame id need not match (closest suffices) but |
| the other streams in this superbuf should have same frame id. */ |
| if (super_buf->unmatched_meta_idx > 0) { |
| super_buf->unmatched_meta_idx = 0; |
| super_buf->frame_idx = buf_info->frame_idx; |
| } |
| break; |
| } else { |
| unmatched_bundles++; |
| if ( NULL == last_buf ) { |
| if ( super_buf->frame_idx < buf_info->frame_idx ) { |
| last_buf = pos; |
| } |
| } |
| if ( NULL == insert_before_buf ) { |
| if ( super_buf->frame_idx > buf_info->frame_idx ) { |
| insert_before_buf = pos; |
| } |
| } |
| pos = pos->next; |
| } |
| } |
| } |
| |
| if ( found_super_buf ) { |
| if(super_buf->super_buf[buf_s_idx].frame_idx != 0) { |
| //This can cause frame drop. We are overwriting same memory. |
| pthread_mutex_unlock(&queue->que.lock); |
| LOGW("Warning: frame is already in camera ZSL queue"); |
| mm_channel_qbuf(ch_obj, buf_info->buf); |
| return 0; |
| } |
| |
| /*Insert incoming buffer to super buffer*/ |
| super_buf->super_buf[buf_s_idx] = *buf_info; |
| |
| /* 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) { |
| if(ch_obj->isFlashBracketingEnabled) { |
| queue->expected_frame_id = |
| queue->expected_frame_id_without_led; |
| if (buf_info->frame_idx >= |
| queue->expected_frame_id_without_led) { |
| ch_obj->isFlashBracketingEnabled = FALSE; |
| } |
| } else { |
| queue->expected_frame_id = buf_info->frame_idx |
| + queue->attr.post_frame_skip; |
| } |
| |
| super_buf->expected_frame = FALSE; |
| |
| LOGD("curr = %d, skip = %d , Expected Frame ID: %d", |
| buf_info->frame_idx, |
| queue->attr.post_frame_skip, queue->expected_frame_id); |
| |
| queue->match_cnt++; |
| if (ch_obj->bundle.superbuf_queue.attr.enable_frame_sync) { |
| pthread_mutex_lock(&fs_lock); |
| mm_frame_sync_add(buf_info->frame_idx, ch_obj); |
| pthread_mutex_unlock(&fs_lock); |
| } |
| /* Any older unmatched buffer need to be released */ |
| if ( last_buf ) { |
| while ( last_buf != pos ) { |
| node = member_of(last_buf, cam_node_t, list); |
| super_buf = (mm_channel_queue_node_t*)node->data; |
| if (NULL != super_buf) { |
| 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); |
| } |
| } |
| queue->que.size--; |
| last_buf = last_buf->next; |
| cam_list_del_node(&node->list); |
| free(node); |
| free(super_buf); |
| } else { |
| LOGE("Invalid superbuf in queue!"); |
| break; |
| } |
| } |
| } |
| }else { |
| if (ch_obj->diverted_frame_id == buf_info->frame_idx) { |
| super_buf->expected_frame = TRUE; |
| ch_obj->diverted_frame_id = 0; |
| } |
| } |
| } else { |
| if ((queue->attr.max_unmatched_frames < unmatched_bundles) |
| && ( NULL == last_buf )) { |
| /* incoming frame is older than the last bundled one */ |
| mm_channel_qbuf(ch_obj, buf_info->buf); |
| } else { |
| last_buf_ptr = last_buf; |
| |
| /* Loop to remove unmatched frames */ |
| while ((queue->attr.max_unmatched_frames < unmatched_bundles) |
| && (last_buf_ptr != NULL && last_buf_ptr != pos)) { |
| node = member_of(last_buf_ptr, cam_node_t, list); |
| super_buf = (mm_channel_queue_node_t*)node->data; |
| if (NULL != super_buf && super_buf->expected_frame == FALSE |
| && (&node->list != insert_before_buf)) { |
| 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); |
| } |
| } |
| queue->que.size--; |
| cam_list_del_node(&node->list); |
| free(node); |
| free(super_buf); |
| unmatched_bundles--; |
| } |
| last_buf_ptr = last_buf_ptr->next; |
| } |
| |
| if (queue->attr.max_unmatched_frames < unmatched_bundles) { |
| node = member_of(last_buf, cam_node_t, list); |
| super_buf = (mm_channel_queue_node_t*)node->data; |
| 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); |
| } |
| } |
| queue->que.size--; |
| cam_list_del_node(&node->list); |
| free(node); |
| free(super_buf); |
| } |
| |
| /* insert the new frame at the appropriate position. */ |
| |
| mm_channel_queue_node_t *new_buf = NULL; |
| cam_node_t* new_node = NULL; |
| |
| new_buf = (mm_channel_queue_node_t*)malloc(sizeof(mm_channel_queue_node_t)); |
| new_node = (cam_node_t*)malloc(sizeof(cam_node_t)); |
| if (NULL != new_buf && NULL != new_node) { |
| memset(new_buf, 0, sizeof(mm_channel_queue_node_t)); |
| memset(new_node, 0, sizeof(cam_node_t)); |
| new_node->data = (void *)new_buf; |
| new_buf->num_of_bufs = queue->num_streams; |
| new_buf->super_buf[buf_s_idx] = *buf_info; |
| new_buf->frame_idx = buf_info->frame_idx; |
| |
| if ((ch_obj->diverted_frame_id == buf_info->frame_idx) |
| || (buf_info->frame_idx == queue->good_frame_id)) { |
| new_buf->expected_frame = TRUE; |
| ch_obj->diverted_frame_id = 0; |
| } |
| |
| /* enqueue */ |
| if ( insert_before_buf ) { |
| cam_list_insert_before_node(&new_node->list, insert_before_buf); |
| } else { |
| cam_list_add_tail_node(&new_node->list, &queue->que.head.list); |
| } |
| queue->que.size++; |
| |
| if(queue->num_streams == 1) { |
| new_buf->matched = 1; |
| new_buf->expected_frame = FALSE; |
| queue->expected_frame_id = buf_info->frame_idx + queue->attr.post_frame_skip; |
| queue->match_cnt++; |
| if (ch_obj->bundle.superbuf_queue.attr.enable_frame_sync) { |
| pthread_mutex_lock(&fs_lock); |
| mm_frame_sync_add(buf_info->frame_idx, ch_obj); |
| pthread_mutex_unlock(&fs_lock); |
| } |
| } |
| /* In low priority queue, this will become a 'meta only' superbuf. Set the |
| unmatched_frame_idx so that the upcoming stream buffers (other than meta) |
| can be filled into this which are nearest to this idx. */ |
| if ((queue->attr.priority == MM_CAMERA_SUPER_BUF_PRIORITY_LOW) |
| && (buf_info->buf->stream_type == CAM_STREAM_TYPE_METADATA)) { |
| new_buf->unmatched_meta_idx = buf_info->frame_idx; |
| } |
| } 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); |
| } |
| } |
| } |
| |
| pthread_mutex_unlock(&queue->que.lock); |
| LOGD("X"); |
| return 0; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_superbuf_dequeue_internal |
| * |
| * DESCRIPTION: internal implementation for dequeue from the superbuf queue |
| * |
| * PARAMETERS : |
| * @queue : superbuf queue |
| * @matched_only : if dequeued buf should be matched |
| * @ch_obj : channel object |
| * |
| * RETURN : ptr to a node from superbuf queue |
| *==========================================================================*/ |
| mm_channel_queue_node_t* mm_channel_superbuf_dequeue_internal( |
| mm_channel_queue_t * queue, |
| uint8_t matched_only, mm_channel_t *ch_obj) |
| { |
| cam_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, cam_node_t, list); |
| super_buf = (mm_channel_queue_node_t*)node->data; |
| if ( (NULL != super_buf) && |
| (matched_only == TRUE) && |
| (super_buf->matched == FALSE) ) { |
| /* require to dequeue matched frame only, but this superbuf is not matched, |
| simply set return ptr to NULL */ |
| super_buf = NULL; |
| } |
| if (NULL != super_buf) { |
| /* remove from the queue */ |
| cam_list_del_node(&node->list); |
| queue->que.size--; |
| if (super_buf->matched == TRUE) { |
| queue->match_cnt--; |
| if (ch_obj->bundle.superbuf_queue.attr.enable_frame_sync) { |
| pthread_mutex_lock(&fs_lock); |
| mm_frame_sync_remove(super_buf->frame_idx); |
| pthread_mutex_unlock(&fs_lock); |
| } |
| } |
| free(node); |
| } |
| } |
| |
| return super_buf; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_superbuf_dequeue_frame_internal |
| * |
| * DESCRIPTION: internal implementation for dequeue based on frame index |
| * from the superbuf queue |
| * |
| * PARAMETERS : |
| * @queue : superbuf queue |
| * @frame_idx : frame index to be dequeued |
| * |
| * RETURN : ptr to a node from superbuf queue with matched frame index |
| * : NULL if not found |
| *==========================================================================*/ |
| mm_channel_queue_node_t* mm_channel_superbuf_dequeue_frame_internal( |
| mm_channel_queue_t * queue, uint32_t frame_idx) |
| { |
| cam_node_t* node = NULL; |
| struct cam_list *head = NULL; |
| struct cam_list *pos = NULL; |
| mm_channel_queue_node_t* super_buf = NULL; |
| |
| if (!queue) { |
| LOGE("queue is NULL"); |
| return NULL; |
| } |
| |
| head = &queue->que.head.list; |
| pos = head->next; |
| LOGL("Searching for match frame %d", frame_idx); |
| while ((pos != head) && (pos != NULL)) { |
| /* get the first node */ |
| node = member_of(pos, cam_node_t, list); |
| super_buf = (mm_channel_queue_node_t*)node->data; |
| if (super_buf && super_buf->matched && |
| (super_buf->frame_idx == frame_idx)) { |
| /* remove from the queue */ |
| cam_list_del_node(&node->list); |
| queue->que.size--; |
| queue->match_cnt--; |
| LOGH("Found match frame %d", frame_idx); |
| free(node); |
| break; |
| } |
| else { |
| LOGH("match frame not found %d", frame_idx); |
| super_buf = NULL; |
| } |
| pos = pos->next; |
| } |
| return super_buf; |
| } |
| |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_superbuf_dequeue |
| * |
| * DESCRIPTION: dequeue from the superbuf queue |
| * |
| * PARAMETERS : |
| * @queue : superbuf queue |
| * @ch_obj : channel object |
| * |
| * RETURN : ptr to a node from superbuf queue |
| *==========================================================================*/ |
| mm_channel_queue_node_t* mm_channel_superbuf_dequeue( |
| mm_channel_queue_t * queue, mm_channel_t *ch_obj) |
| { |
| mm_channel_queue_node_t* super_buf = NULL; |
| |
| pthread_mutex_lock(&queue->que.lock); |
| super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE, ch_obj); |
| pthread_mutex_unlock(&queue->que.lock); |
| |
| return super_buf; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_superbuf_bufdone_overflow |
| * |
| * DESCRIPTION: keep superbuf queue no larger than watermark set by upper layer |
| * via channel attribute |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @queue : superbuf queue |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| 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; |
| } |
| |
| LOGD("before match_cnt=%d, water_mark=%d", |
| queue->match_cnt, queue->attr.water_mark); |
| /* 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, TRUE, my_obj); |
| 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); |
| LOGD("after match_cnt=%d, water_mark=%d", |
| queue->match_cnt, queue->attr.water_mark); |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_superbuf_skip |
| * |
| * DESCRIPTION: depends on the lookback configuration of the channel attribute, |
| * unwanted superbufs will be removed from the superbuf queue. |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @queue : superbuf queue |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_superbuf_skip(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 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, TRUE, my_obj); |
| 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; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_superbuf_flush |
| * |
| * DESCRIPTION: flush the superbuf queue. |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @queue : superbuf queue |
| * @cam_type: flush only particular type (default flushes all) |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_superbuf_flush(mm_channel_t* my_obj, |
| mm_channel_queue_t * queue, cam_stream_type_t cam_type) |
| { |
| int32_t rc = 0, i; |
| mm_channel_queue_node_t* super_buf = NULL; |
| cam_stream_type_t stream_type = CAM_STREAM_TYPE_DEFAULT; |
| |
| /* bufdone bufs */ |
| pthread_mutex_lock(&queue->que.lock); |
| super_buf = mm_channel_superbuf_dequeue_internal(queue, FALSE, my_obj); |
| while (super_buf != NULL) { |
| for (i=0; i<super_buf->num_of_bufs; i++) { |
| if (NULL != super_buf->super_buf[i].buf) { |
| stream_type = super_buf->super_buf[i].buf->stream_type; |
| if ((CAM_STREAM_TYPE_DEFAULT == cam_type) || |
| (cam_type == stream_type)) { |
| mm_channel_qbuf(my_obj, super_buf->super_buf[i].buf); |
| } |
| } |
| } |
| free(super_buf); |
| super_buf = mm_channel_superbuf_dequeue_internal(queue, FALSE, my_obj); |
| } |
| pthread_mutex_unlock(&queue->que.lock); |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_proc_general_cmd |
| * |
| * DESCRIPTION: process general command |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @notify_mode : notification mode |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_proc_general_cmd(mm_channel_t *my_obj, |
| mm_camera_generic_cmd_t *p_gen_cmd) |
| { |
| LOGD("E"); |
| int32_t rc = 0; |
| mm_camera_cmdcb_t* node = NULL; |
| |
| node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t)); |
| if (NULL != node) { |
| memset(node, 0, sizeof(mm_camera_cmdcb_t)); |
| node->u.gen_cmd = *p_gen_cmd; |
| node->cmd_type = MM_CAMERA_CMD_TYPE_GENERAL; |
| |
| /* 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"); |
| rc = -1; |
| } |
| LOGD("X"); |
| |
| return rc; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_superbuf_flush_matched |
| * |
| * DESCRIPTION: flush matched buffers from the superbuf queue. |
| * |
| * PARAMETERS : |
| * @my_obj : channel object |
| * @queue : superbuf queue |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_channel_superbuf_flush_matched(mm_channel_t* my_obj, |
| mm_channel_queue_t * queue) |
| { |
| int32_t rc = 0, i; |
| mm_channel_queue_node_t* super_buf = NULL; |
| |
| /* bufdone bufs */ |
| pthread_mutex_lock(&queue->que.lock); |
| super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE, my_obj); |
| while (super_buf != NULL) { |
| 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); |
| super_buf = mm_channel_superbuf_dequeue_internal(queue, TRUE, my_obj); |
| } |
| pthread_mutex_unlock(&queue->que.lock); |
| |
| return rc; |
| } |
| |
| |
| /*=========================================================================== |
| * FUNCTION : mm_frame_sync_reset |
| * |
| * DESCRIPTION: Reset Frame sync info |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void mm_frame_sync_reset() { |
| memset(&fs, 0x0, sizeof(fs)); |
| LOGD("Reset Done"); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_frame_sync_register_channel |
| * |
| * DESCRIPTION: Register Channel for frame sync |
| * |
| * PARAMETERS : |
| * @ch_obj : channel object |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_frame_sync_register_channel(mm_channel_t *ch_obj) { |
| // Lock frame sync info |
| pthread_mutex_lock(&fs_lock); |
| if ((fs.num_cam >= MAX_NUM_CAMERA_PER_BUNDLE) || (!ch_obj)) { |
| LOGE("Error!! num cam(%d) is out of range ", |
| fs.num_cam); |
| pthread_mutex_unlock(&fs_lock); |
| return -1; |
| } |
| if (fs.num_cam == 0) { |
| LOGH("First channel registering!!"); |
| mm_frame_sync_reset(); |
| } |
| uint8_t i = 0; |
| for (i = 0; i < MAX_NUM_CAMERA_PER_BUNDLE; i++) { |
| if (fs.ch_obj[i] == NULL) { |
| fs.ch_obj[i] = ch_obj; |
| fs.cb[i] = ch_obj->bundle.super_buf_notify_cb; |
| fs.num_cam++; |
| LOGD("DBG_FS index %d", i); |
| break; |
| } |
| } |
| if (i >= MAX_NUM_CAMERA_PER_BUNDLE) { |
| LOGH("X, DBG_FS Cannot register channel!!"); |
| pthread_mutex_unlock(&fs_lock); |
| return -1; |
| } |
| LOGH("num_cam %d ", fs.num_cam); |
| pthread_mutex_unlock(&fs_lock); |
| return 0; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_frame_sync_unregister_channel |
| * |
| * DESCRIPTION: un-register Channel for frame sync |
| * |
| * PARAMETERS : |
| * @ch_obj : channel object |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_frame_sync_unregister_channel(mm_channel_t *ch_obj) { |
| uint8_t i = 0; |
| // Lock frame sync info |
| pthread_mutex_lock(&fs_lock); |
| if (!fs.num_cam || !ch_obj) { |
| LOGH("X, DBG_FS: channel not found !!"); |
| // Lock frame sync info |
| pthread_mutex_unlock(&fs_lock); |
| return -1; |
| } |
| for (i = 0; i < MAX_NUM_CAMERA_PER_BUNDLE; i++) { |
| if (fs.ch_obj[i] == ch_obj) { |
| LOGD("found ch_obj at i (%d) ", i); |
| break; |
| } |
| } |
| if (i < MAX_NUM_CAMERA_PER_BUNDLE) { |
| LOGD("remove channel info "); |
| fs.ch_obj[i] = NULL; |
| fs.cb[i] = NULL; |
| fs.num_cam--; |
| } else { |
| LOGD("DBG_FS Channel not found "); |
| } |
| if (fs.num_cam == 0) { |
| mm_frame_sync_reset(); |
| } |
| LOGH("X, fs.num_cam %d", fs.num_cam); |
| pthread_mutex_unlock(&fs_lock); |
| return 0; |
| } |
| |
| |
| /*=========================================================================== |
| * FUNCTION : mm_frame_sync_add |
| * |
| * DESCRIPTION: Add frame info into frame sync nodes |
| * |
| * PARAMETERS : |
| * @frame_id : frame id to be added |
| * @ch_obj : channel object |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_frame_sync_add(uint32_t frame_id, mm_channel_t *ch_obj) { |
| |
| LOGD("E, frame id %d ch_obj %p", frame_id, ch_obj); |
| if (!frame_id || !ch_obj) { |
| LOGH("X : Error, cannot add sync frame !!"); |
| return -1; |
| } |
| |
| int8_t ch_idx = -1; |
| uint8_t i = 0; |
| for (i = 0; i < MAX_NUM_CAMERA_PER_BUNDLE; i++) { |
| if (fs.ch_obj[i] == ch_obj) { |
| ch_idx = i; |
| LOGD("ch id %d ", ch_idx); |
| break; |
| } |
| } |
| if (ch_idx < 0) { |
| LOGH("X : DBG_FS ch not found!!"); |
| return -1; |
| } |
| int8_t index = mm_frame_sync_find_frame_index(frame_id); |
| if ((index >= 0) && (index < MM_CAMERA_FRAME_SYNC_NODES)) { |
| fs.node[index].frame_valid[ch_idx] = 1; |
| } else if (index < 0) { |
| if (fs.pos >= MM_CAMERA_FRAME_SYNC_NODES) { |
| fs.pos = 0; |
| } |
| index = fs.pos; |
| memset(&fs.node[index], 0x00, sizeof(mm_channel_sync_node_t)); |
| fs.pos++; |
| fs.node[index].frame_idx = frame_id; |
| fs.node[index].frame_valid[ch_idx] = 1; |
| if (fs.num_cam == 1) { |
| LOGD("Single camera frame %d , matched ", frame_id); |
| fs.node[index].matched = 1; |
| } |
| } |
| uint8_t frames_valid = 0; |
| if (!fs.node[index].matched) { |
| for (i = 0; i < MAX_NUM_CAMERA_PER_BUNDLE; i++) { |
| if (fs.node[index].frame_valid[i]) { |
| frames_valid++; |
| } |
| } |
| if (frames_valid == fs.num_cam) { |
| fs.node[index].matched = 1; |
| LOGD("dual camera frame %d , matched ", |
| frame_id); |
| } |
| } |
| return 0; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_frame_sync_remove |
| * |
| * DESCRIPTION: Remove frame info from frame sync nodes |
| * |
| * PARAMETERS : |
| * @frame_id : frame id to be removed |
| * |
| * RETURN : int32_t type of status |
| * 0 -- success |
| * -1 -- failure |
| *==========================================================================*/ |
| int32_t mm_frame_sync_remove(uint32_t frame_id) { |
| int8_t index = -1; |
| |
| LOGD("E, frame_id %d", frame_id); |
| if (!frame_id) { |
| LOGE("X, DBG_FS frame id invalid"); |
| return -1; |
| } |
| |
| index = mm_frame_sync_find_frame_index(frame_id); |
| if ((index >= 0) && (index < MM_CAMERA_FRAME_SYNC_NODES)) { |
| LOGD("Removing sync frame %d", frame_id); |
| memset(&fs.node[index], 0x00, sizeof(mm_channel_sync_node_t)); |
| } |
| LOGD("X "); |
| return 0; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_frame_sync_find_matched |
| * |
| * DESCRIPTION: Find a matched sync frame from the node array |
| * |
| * PARAMETERS : |
| * @oldest : If enabled, find oldest matched frame., |
| * If not enabled, get the first matched frame found |
| * |
| * RETURN : unt32_t type of status |
| * 0 -- If no matched frames found |
| * frame index: inf matched frame found |
| *==========================================================================*/ |
| uint32_t mm_frame_sync_find_matched(uint8_t oldest) { |
| LOGH("E, oldest %d ", oldest); |
| uint8_t i = 0; |
| uint32_t frame_idx = 0; |
| uint32_t curr_frame_idx = 0; |
| for (i = 0; i < MM_CAMERA_FRAME_SYNC_NODES; i++) { |
| if (fs.node[i].matched) { |
| curr_frame_idx = fs.node[i].frame_idx; |
| if (!frame_idx) { |
| frame_idx = curr_frame_idx; |
| } |
| if (!oldest) { |
| break; |
| } else if (frame_idx > curr_frame_idx) { |
| frame_idx = curr_frame_idx; |
| } |
| } |
| } |
| LOGH("X, oldest %d frame idx %d", oldest, frame_idx); |
| return frame_idx; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_frame_sync_find_frame_index |
| * |
| * DESCRIPTION: Find sync frame index if present |
| * |
| * PARAMETERS : |
| * @frame_id : frame id to be searched |
| * |
| * RETURN : int8_t type of status |
| * -1 -- If desired frame not found |
| * index: node array index if frame is found |
| *==========================================================================*/ |
| int8_t mm_frame_sync_find_frame_index(uint32_t frame_id) { |
| |
| LOGD("E, frame_id %d", frame_id); |
| int8_t index = -1, i = 0; |
| for (i = 0; i < MM_CAMERA_FRAME_SYNC_NODES; i++) { |
| if (fs.node[i].frame_idx == frame_id) { |
| index = i; |
| break; |
| } |
| } |
| LOGD("X index :%d", index); |
| return index; |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_frame_sync_lock_queues |
| * |
| * DESCRIPTION: Lock all channel queues present in node info |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void mm_frame_sync_lock_queues() { |
| uint8_t j = 0; |
| LOGD("E "); |
| for (j = 0; j < MAX_NUM_CAMERA_PER_BUNDLE; j++) { |
| if (fs.ch_obj[j]) { |
| mm_channel_queue_t *ch_queue = |
| &fs.ch_obj[j]->bundle.superbuf_queue; |
| if (ch_queue) { |
| pthread_mutex_lock(&ch_queue->que.lock); |
| LOGL("Done locking fs.ch_obj[%d] ", j); |
| } |
| } |
| } |
| pthread_mutex_lock(&fs_lock); |
| LOGD("X "); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_frame_sync_unlock_queues |
| * |
| * DESCRIPTION: Unlock all channel queues |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void mm_frame_sync_unlock_queues() { |
| // Unlock all queues |
| uint8_t j = 0; |
| LOGD("E "); |
| pthread_mutex_unlock(&fs_lock); |
| LOGL("Done unlocking fs "); |
| for (j = 0; j < MAX_NUM_CAMERA_PER_BUNDLE; j++) { |
| if (fs.ch_obj[j]) { |
| mm_channel_queue_t *ch_queue = |
| &fs.ch_obj[j]->bundle.superbuf_queue; |
| if (ch_queue) { |
| pthread_mutex_unlock(&ch_queue->que.lock); |
| LOGL("Done unlocking fs.ch_obj[%d] ", j); |
| } |
| } |
| } |
| LOGD("X "); |
| } |
| |
| /*=========================================================================== |
| * FUNCTION : mm_channel_node_qbuf |
| * |
| * DESCRIPTION: qbuf all buffers in a node |
| * |
| * PARAMETERS : |
| * @ch_obj : Channel info |
| * @node : node to qbuf |
| * |
| * RETURN : None |
| *==========================================================================*/ |
| void mm_channel_node_qbuf(mm_channel_t *ch_obj, mm_channel_queue_node_t *node) { |
| uint8_t i; |
| if (!ch_obj || !node) { |
| return; |
| } |
| for (i = 0; i < node->num_of_bufs; i++) { |
| mm_channel_qbuf(ch_obj, node->super_buf[i].buf); |
| } |
| return; |
| } |