static void mm_camera_snapshot_send_snapshot_notify(mm_camera_obj_t * my_obj) { int delivered = 0; int i; mm_camera_frame_queue_t *s_q, *t_q; mm_camera_ch_data_buf_t data; mm_camera_frame_t *frame; mm_camera_buf_cb_t buf_cb; memset(&buf_cb, 0, sizeof(buf_cb)); s_q = &my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.main.frame.readyq; t_q = &my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.thumbnail.frame.readyq; pthread_mutex_lock(&my_obj->ch[MM_CAMERA_CH_SNAPSHOT].mutex); for( i=0;i<MM_CAMERA_BUF_CB_MAX;i++) { CDBG("%s Got notify: s_q->cnt = %d, t_q->cnt = %d, buf_cb = %x, " "data.used = %d ", __func__, s_q->cnt, t_q->cnt, (uint32_t)my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buf_cb[i].cb, my_obj->poll_threads[MM_CAMERA_CH_SNAPSHOT].data.used); if((s_q->cnt && t_q->cnt && my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buf_cb[i].cb) && (my_obj->poll_threads[MM_CAMERA_CH_SNAPSHOT].data.used == 1)) { data.type = MM_CAMERA_CH_SNAPSHOT; frame = mm_camera_stream_frame_deq(s_q); data.snapshot.main.frame = &frame->frame; data.snapshot.main.idx = frame->idx; frame = mm_camera_stream_frame_deq(t_q); data.snapshot.thumbnail.frame = &frame->frame; data.snapshot.thumbnail.idx = frame->idx; my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.main.frame.ref_count[data.snapshot.main.idx]++; my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.thumbnail.frame.ref_count[data.snapshot.thumbnail.idx]++; if(my_obj->poll_threads[MM_CAMERA_CH_SNAPSHOT].data.used == 1){ buf_cb = my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buf_cb[i]; buf_cb.cb(&data,buf_cb.user_data); my_obj->snap_burst_num_by_user -= 1; CDBG("%s: burst number =%d", __func__, my_obj->snap_burst_num_by_user); delivered = 1; } } } pthread_mutex_unlock(&my_obj->ch[MM_CAMERA_CH_SNAPSHOT].mutex); CDBG("%s Delivered = %d ", __func__, delivered ); if(delivered) { mm_camera_event_t edata; /*for( i=0;i<MM_CAMERA_BUF_CB_MAX;i++){ buf_cb = &my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buf_cb[i]; if((buf_cb) && (my_obj->poll_threads[MM_CAMERA_CH_SNAPSHOT].data.used == 1)) { buf_cb->cb(&data,buf_cb->user_data); } }*/ edata.event_type = MM_CAMERA_EVT_TYPE_CH; edata.e.ch.evt = MM_CAMERA_CH_EVT_DATA_DELIVERY_DONE; edata.e.ch.ch = MM_CAMERA_CH_SNAPSHOT; mm_camera_poll_send_ch_event(my_obj, &edata); } }
static int32_t mm_camera_send_af_failed_event(mm_camera_obj_t *my_obj) { int rc = 0; mm_camera_event_t event; event.event_type = MM_CAMERA_EVT_TYPE_CTRL; event.e.ctrl.evt= MM_CAMERA_CTRL_EVT_AUTO_FOCUS_DONE; event.e.ctrl.status=CAM_CTRL_FAILED; CDBG_HIGH("%s: Issuing call",__func__); rc = mm_camera_poll_send_ch_event(my_obj, &event); return rc; }
static int32_t mm_camera_send_ch_on_off_event(mm_camera_obj_t *my_obj, mm_camera_channel_type_t ch_type, mm_camera_ch_event_type_t evt) { int rc = 0; mm_camera_event_t event; event.event_type = MM_CAMERA_EVT_TYPE_CH; event.e.ch.evt = evt; event.e.ch.ch = ch_type; CDBG("%s: stream on event, type=0x%x, ch=%d, evt=%d", __func__, event.event_type, event.e.ch.ch, event.e.ch.evt); rc = mm_camera_poll_send_ch_event(my_obj, &event); return rc; }
static void mm_camera_snapshot_send_liveshot_notify(mm_camera_obj_t * my_obj) { int delivered = 0; mm_camera_frame_queue_t *s_q; int i; int cnt = 0; // mm_camera_frame_queue_t *s_q, *t_q; mm_camera_buf_cb_t buf_cb[MM_CAMERA_BUF_CB_MAX]; mm_camera_ch_data_buf_t data[MM_CAMERA_BUF_CB_MAX]; mm_camera_frame_t *frame; s_q = &my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.main.frame.readyq; pthread_mutex_lock(&my_obj->ch[MM_CAMERA_CH_SNAPSHOT].mutex); for( i=0;i<MM_CAMERA_BUF_CB_MAX;i++) { if(s_q->cnt && my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buf_cb[i].cb) { data[cnt].type = MM_CAMERA_CH_SNAPSHOT; frame = mm_camera_stream_frame_deq(s_q); data[cnt].snapshot.main.frame = &frame->frame; data[cnt].snapshot.main.idx = frame->idx; data[cnt].snapshot.thumbnail.frame = NULL; my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.main.frame.ref_count[data[cnt].snapshot.main.idx]++; /*my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buf_cb[i].cb(&data, my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buf_cb[i].user_data);*/ memcpy(&buf_cb[cnt], &my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buf_cb[i], sizeof(mm_camera_buf_cb_t)); cnt++; my_obj->snap_burst_num_by_user -= 1; CDBG("%s: burst number =%d", __func__, my_obj->snap_burst_num_by_user); delivered = 1; } } pthread_mutex_unlock(&my_obj->ch[MM_CAMERA_CH_SNAPSHOT].mutex); for( i=0;i<cnt;i++) { if(buf_cb[i].cb != NULL && my_obj->poll_threads[MM_CAMERA_CH_SNAPSHOT].data.used == 1) { buf_cb[i].cb(&data[i],buf_cb[i].user_data); } } if(delivered) { mm_camera_event_t data; data.event_type = MM_CAMERA_EVT_TYPE_CH; data.e.ch.evt = MM_CAMERA_CH_EVT_DATA_DELIVERY_DONE; data.e.ch.ch = MM_CAMERA_CH_SNAPSHOT; mm_camera_poll_send_ch_event(my_obj, &data); } }
/*for ZSL mode to send the image pair to client*/ void mm_camera_dispatch_buffered_frames(mm_camera_obj_t *my_obj, mm_camera_channel_type_t ch_type) { int mcnt, i, rc = MM_CAMERA_E_GENERAL, scnt; int num_of_req_frame = 0; int j; mm_camera_ch_data_buf_t data; mm_camera_frame_t *mframe = NULL, *sframe = NULL; mm_camera_frame_t *qmframe = NULL, *qsframe = NULL; mm_camera_ch_t *ch = &my_obj->ch[ch_type]; mm_camera_frame_queue_t *mq = NULL; mm_camera_frame_queue_t *sq = NULL; mm_camera_stream_t *stream1 = NULL; mm_camera_stream_t *stream2 = NULL; ALOGE("%s: mzhu, E", __func__); mm_camera_ch_util_get_stream_objs(my_obj, ch_type, &stream1, &stream2); stream2 = &my_obj->ch[MM_CAMERA_CH_PREVIEW].preview.stream; if(stream1) { mq = &stream1->frame.readyq; } if(stream2) { sq = &stream2->frame.readyq; } pthread_mutex_lock(&ch->mutex); if (mq && sq && stream1 && stream2) { rc = mm_camera_channel_skip_frames(my_obj, mq, sq, stream1, stream2, &ch->buffering_frame); if(rc != MM_CAMERA_OK) { CDBG_ERROR("%s: Error getting right frame!", __func__); goto end; } num_of_req_frame = my_obj->snap_burst_num_by_user; ch->snapshot.pending_cnt = num_of_req_frame; for(i = 0; i < num_of_req_frame; i++) { mframe = mm_camera_stream_frame_deq(mq); sframe = mm_camera_stream_frame_deq(sq); if(mframe && sframe) { CDBG("%s: frame_id = 0x%x|0x%x, main idx = %d, thumbnail idx = %d", __func__, mframe->frame.frame_id, sframe->frame.frame_id, mframe->idx, sframe->idx); if(mframe->frame.frame_id != sframe->frame.frame_id) { CDBG_ERROR("%s: ZSL algorithm error, main and thumbnail " "frame_ids not same. Need bug fix", __func__); } memset(&data, 0, sizeof(data)); data.type = ch_type; data.snapshot.main.frame = &mframe->frame; data.snapshot.main.idx = mframe->idx; data.snapshot.thumbnail.frame = &sframe->frame; data.snapshot.thumbnail.idx = sframe->idx; ch->snapshot.pending_cnt--; mq->match_cnt--; sq->match_cnt--; for(j=0;j<MM_CAMERA_BUF_CB_MAX;j++) { if( ch->buf_cb[j].cb!=NULL ) ch->buf_cb[j].cb(&data, ch->buf_cb[j].user_data); } } else { CDBG_ERROR("%s: mframe %p, sframe = %p", __func__, mframe, sframe); qmframe = mframe; qsframe = sframe; rc = -1; break; } } if(qmframe) { mm_camera_stream_frame_enq(mq, &stream1->frame.frame[qmframe->idx]); qmframe = NULL; } if(qsframe) { mm_camera_stream_frame_enq(sq, &stream2->frame.frame[qsframe->idx]); qsframe = NULL; } } else { CDBG_ERROR(" mq =%p sq =%p stream1 =%p stream2 =%p", mq, sq , stream1 , stream2); } CDBG("%s: burst number: %d, pending_count: %d", __func__, my_obj->snap_burst_num_by_user, ch->snapshot.pending_cnt); end: pthread_mutex_unlock(&ch->mutex); /* If we are done sending callbacks for all the requested number of snapshots send data delivery done event*/ if((rc == MM_CAMERA_OK) && (!ch->snapshot.pending_cnt)) { mm_camera_event_t data; data.event_type = MM_CAMERA_EVT_TYPE_CH; data.e.ch.evt = MM_CAMERA_CH_EVT_DATA_DELIVERY_DONE; data.e.ch.ch = ch_type; mm_camera_poll_send_ch_event(my_obj, &data); } }
int mm_camera_zsl_frame_cmp_and_enq(mm_camera_obj_t * my_obj, mm_camera_frame_t *node, mm_camera_stream_t *mystream) { int watermark, interval; mm_camera_frame_queue_t *myq; mm_camera_frame_queue_t *peerq; mm_camera_stream_t *peerstream; int rc = 0; int deliver_done = 0; mm_camera_frame_t *peer_frame; mm_camera_frame_t *peer_frame_prev; mm_camera_frame_t *peer_frame_tmp; mm_camera_notify_frame_t notify_frame; uint32_t expected_id; mm_camera_ch_data_buf_t data; mm_camera_frame_t *my_frame = NULL; int i; mm_camera_buf_cb_t buf_cb[MM_CAMERA_BUF_CB_MAX]; pthread_mutex_lock(&my_obj->ch[MM_CAMERA_CH_PREVIEW].mutex); pthread_mutex_lock(&my_obj->ch[MM_CAMERA_CH_SNAPSHOT].mutex); if(mystream->stream_type == MM_CAMERA_STREAM_PREVIEW) { peerstream = &my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.main; } else peerstream = &my_obj->ch[MM_CAMERA_CH_PREVIEW].preview.stream; myq = &mystream->frame.readyq; peerq = &peerstream->frame.readyq; watermark = my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buffering_frame.water_mark; interval = my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buffering_frame.interval; expected_id = my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.expected_matching_id; peer_frame = peerq->tail; /* for 30-120 fps streaming no need to consider the wrapping back of frame_id expected_matching_id is used when requires skipping bwtween frames */ if(!peer_frame || (node->frame.frame_id > peer_frame->frame.frame_id && node->frame.frame_id >= expected_id)) { /* new frame is newer than all stored peer frames. simply keep the node */ /* in case the frame_id wraps back, the peer frame's frame_id will be larger than the new frame's frame id */ CDBG("%s New frame. Just enqueue it into the queue ", __func__); mm_camera_stream_frame_enq_no_lock(myq, node); node->valid_entry = 1; } CDBG("%s Need to find match for the frame id %d ,exped_id =%d, strm type =%d", __func__, node->frame.frame_id, expected_id, mystream->stream_type); /* the node is older than the peer, we will either find a match or drop it */ peer_frame = peerq->head; peer_frame_prev = NULL; peer_frame_tmp = NULL; while(peer_frame) { CDBG("%s peer frame_id = %d node frame_id = %d, expected_id =%d, interval=%d", __func__, peer_frame->frame.frame_id, node->frame.frame_id, expected_id, interval); if(peer_frame->match) { CDBG("%s Peer frame already matched, keep looking in the list ", __func__); /* matched frame., skip */ peer_frame_prev = peer_frame; peer_frame = peer_frame->next; continue; } if(peer_frame->frame.frame_id == node->frame.frame_id && node->frame.frame_id >= my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.expected_matching_id) { /* find a match keep the frame */ node->match = 1; peer_frame->match = 1; CDBG("%s Found match, add to myq, frame_id=%d ", __func__, node->frame.frame_id); mm_camera_stream_frame_enq_no_lock(myq, node); myq->match_cnt++; peerq->match_cnt++; /*set next min matching id*/ my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.expected_matching_id = node->frame.frame_id + interval; goto water_mark; } else { /* no match */ if(node->frame.frame_id > peer_frame->frame.frame_id) { /* the incoming frame is newer than the peer's unmatched frame. drop the peer frame */ CDBG("%s node frame is newer, release old peer frame ", __func__); if(!peer_frame_prev) { /* this is the head */ peer_frame_tmp = mm_camera_stream_frame_deq_no_lock(peerq); notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; mm_camera_stream_util_buf_done(my_obj, peerstream, ¬ify_frame); peer_frame = peerq->head; peer_frame_prev = NULL; continue; } else { /* this is not the head. */ peer_frame_tmp = peer_frame; peer_frame_prev->next = peer_frame->next; if(peer_frame == peerq->tail) { /* peer_frame is the tail */ peerq->tail = peer_frame_prev; } notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; mm_camera_stream_util_buf_done(my_obj, peerstream, ¬ify_frame); peer_frame = peer_frame_prev->next; peerq->cnt--; continue; } } else { /* Current frame is older than peer's unmatched frame, dont add * it into the queue. just drop it */ CDBG("%s node frame is older than peer's unmatched frame. " "Drop the current frame.", __func__); notify_frame.frame = &node->frame; notify_frame.idx = node->idx; mm_camera_stream_util_buf_done(my_obj, mystream, ¬ify_frame); goto end; } } } if(!node->match && !node->valid_entry) { /* if no match and not a valid entry. * the node is not added into the queue. it's dirty node */ CDBG_ERROR("%s: stream type = %d and fd = %d, frame 0x%x is dirty" " and queue back kernel", __func__, mystream->stream_type, mystream->fd, node->frame.frame_id); notify_frame.frame = &node->frame; notify_frame.idx = node->idx; mm_camera_stream_util_buf_done(my_obj, mystream, ¬ify_frame); } water_mark: while((myq->match_cnt > watermark) && (peerq->match_cnt > watermark)) { peer_frame_tmp = mm_camera_stream_frame_deq_no_lock(peerq); if (NULL == peer_frame_tmp) { break; } notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; CDBG("%s match_cnt %d > watermark %d, buf_done on " "peer frame idx %d id = %d", __func__, myq->match_cnt, watermark, notify_frame.idx, notify_frame.frame->frame_id); mm_camera_stream_util_buf_done(my_obj, peerstream, ¬ify_frame); peerq->match_cnt--; peer_frame_tmp = mm_camera_stream_frame_deq_no_lock(myq); notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; mm_camera_stream_util_buf_done(my_obj, mystream, ¬ify_frame); myq->match_cnt--; } end: CDBG("%s myQ->cnt = %d myQ->match_cnt = %d ", __func__, myq->cnt, myq->match_cnt); if(myq->cnt > myq->match_cnt + 1) { /* drop the first unmatched frame */ mm_camera_frame_t *peer_frame = myq->head;; mm_camera_frame_t *peer_frame_prev = NULL; while(peer_frame) { CDBG("%s myQ->cnt = %d myQ->match_cnt = %d ", __func__, myq->cnt, myq->match_cnt); if(peer_frame->match == 0) { /* first unmatched frame */ if(!peer_frame_prev) { /* this is the head */ peer_frame_tmp = mm_camera_stream_frame_deq_no_lock(myq); notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; CDBG("%s Head Issuing buf_done on my frame idx %d id %d", __func__, notify_frame.idx, notify_frame.frame->frame_id); mm_camera_stream_util_buf_done(my_obj, mystream, ¬ify_frame); } else { /* this is not the head. */ peer_frame_tmp = peer_frame; peer_frame_prev->next = peer_frame->next; if(peer_frame == peerq->tail) { /* peer_frame is the tail */ myq->tail = peer_frame_prev; } notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; CDBG("%s Issuing buf_done on my frame idx %d id = %d", __func__, notify_frame.idx, notify_frame.frame->frame_id); mm_camera_stream_util_buf_done(my_obj, mystream, ¬ify_frame); myq->cnt--; } break; } else { peer_frame_prev= peer_frame; peer_frame = peer_frame_prev->next; } } } CDBG("%s peerQ->cnt = %d peerQ->match_cnt = %d ", __func__, peerq->cnt, peerq->match_cnt); if(peerq->cnt > peerq->match_cnt + 1) { /* drop the first unmatched frame */ mm_camera_frame_t *peer_frame = peerq->head; mm_camera_frame_t *peer_frame_prev = NULL; while(peer_frame) { CDBG("%s Traverse peerq list frame idx %d frame_id = %d match %d ", __func__, peer_frame->idx, peer_frame->frame.frame_id, peer_frame->match); if(peer_frame->match == 0) { /* first unmatched frame */ if(!peer_frame_prev) { /* this is the head */ peer_frame_tmp = mm_camera_stream_frame_deq_no_lock(peerq); notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; CDBG("%s Head Issuing buf_done on peer frame idx %d " "id = %d", __func__, notify_frame.idx, notify_frame.frame->frame_id); mm_camera_stream_util_buf_done(my_obj, peerstream, ¬ify_frame); } else { /* this is not the head. */ peer_frame_tmp = peer_frame; peer_frame_prev->next = peer_frame->next; if(peer_frame == peerq->tail) { /* peer_frame is the tail */ peerq->tail = peer_frame_prev; } notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; CDBG("%s Issuing buf_done on peer frame idx %d id = %d", __func__, notify_frame.idx, notify_frame.frame->frame_id); mm_camera_stream_util_buf_done(my_obj, peerstream, ¬ify_frame); peerq->cnt--; } break; } else { peer_frame_prev= peer_frame; peer_frame = peer_frame_prev->next; } } } CDBG("%s Dispatching ZSL frame ", __func__); if(my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.pending_cnt > 0) { if(!myq->match_cnt || !peerq->match_cnt) { pthread_mutex_unlock(&my_obj->ch[MM_CAMERA_CH_SNAPSHOT].mutex); pthread_mutex_unlock(&my_obj->ch[MM_CAMERA_CH_PREVIEW].mutex); return 0; } /* dequeue one by one and then pass to HAL */ my_frame = mm_camera_stream_frame_deq_no_lock(&my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.main.frame.readyq); peer_frame = mm_camera_stream_frame_deq_no_lock(&my_obj->ch[MM_CAMERA_CH_PREVIEW].preview.stream.frame.readyq); if (!my_frame || !peer_frame) { pthread_mutex_unlock(&my_obj->ch[MM_CAMERA_CH_SNAPSHOT].mutex); pthread_mutex_unlock(&my_obj->ch[MM_CAMERA_CH_PREVIEW].mutex); return 0; } myq->match_cnt--; peerq->match_cnt--; CDBG("%s: Dequeued frame: main frame idx: %d thumbnail " "frame idx: %d", __func__, my_frame->idx, peer_frame->idx); /* dispatch this pair of frames */ memset(&data, 0, sizeof(data)); data.type = MM_CAMERA_CH_SNAPSHOT; data.snapshot.main.frame = &my_frame->frame; data.snapshot.main.idx = my_frame->idx; data.snapshot.thumbnail.frame = &peer_frame->frame; data.snapshot.thumbnail.idx = peer_frame->idx; my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.pending_cnt--; memcpy(&buf_cb[0], &my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buf_cb[0], sizeof(mm_camera_buf_cb_t)* MM_CAMERA_BUF_CB_MAX); if(my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.pending_cnt == 0) deliver_done = 1; pthread_mutex_unlock(&my_obj->ch[MM_CAMERA_CH_SNAPSHOT].mutex); pthread_mutex_unlock(&my_obj->ch[MM_CAMERA_CH_PREVIEW].mutex); goto send_to_hal; } pthread_mutex_unlock(&my_obj->ch[MM_CAMERA_CH_SNAPSHOT].mutex); pthread_mutex_unlock(&my_obj->ch[MM_CAMERA_CH_PREVIEW].mutex); return rc; send_to_hal: for( i=0;i < MM_CAMERA_BUF_CB_MAX;i++) { if (buf_cb[i].cb && my_obj->poll_threads[MM_CAMERA_CH_SNAPSHOT].data.used == 1) buf_cb[i].cb(&data,buf_cb[i].user_data); } if(deliver_done > 0) { mm_camera_event_t data_evt; CDBG("%s: ZSL delivered", __func__); data_evt.event_type = MM_CAMERA_EVT_TYPE_CH; data_evt.e.ch.evt = MM_CAMERA_CH_EVT_DATA_DELIVERY_DONE; data_evt.e.ch.ch = MM_CAMERA_CH_SNAPSHOT; mm_camera_poll_send_ch_event(my_obj, &data_evt); } return rc; }
int mm_camera_zsl_frame_cmp_and_enq(mm_camera_obj_t * my_obj, mm_camera_frame_t *node, mm_camera_stream_t *mystream) { int watermark; mm_camera_frame_queue_t *myq; mm_camera_frame_queue_t *peerq; mm_camera_stream_t *peerstream; int rc = 0; int deliver_done = 0; mm_camera_frame_t *peer_frame; mm_camera_frame_t *peer_frame_prev; mm_camera_frame_t *peer_frame_tmp; mm_camera_notify_frame_t notify_frame; pthread_mutex_t *pSnapshotMutex = &(my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.main.frame.readyq.mutex); pthread_mutex_t *pPreviewMutex = &(my_obj->ch[MM_CAMERA_CH_PREVIEW].preview.stream.frame.readyq.mutex); if(mystream->stream_type == MM_CAMERA_STREAM_PREVIEW) { peerstream = &my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.main; } else peerstream = &my_obj->ch[MM_CAMERA_CH_PREVIEW].preview.stream; myq = &mystream->frame.readyq; peerq = &peerstream->frame.readyq; watermark = my_obj->ch[MM_CAMERA_CH_SNAPSHOT].buffering_frame.water_mark; /* lock both queues */ pthread_mutex_lock(pSnapshotMutex); pthread_mutex_lock(pPreviewMutex); peer_frame = peerq->tail; /* for 30-120 fps streaming no need to consider the wrapping back of frame_id */ if(!peer_frame || node->frame.frame_id > peer_frame->frame.frame_id) { /* new frame is newer than all stored peer frames. simply keep the node */ /* in case the frame_id wraps back, the peer frame's frame_id will be larger than the new frame's frame id */ CDBG("%s New frame. Just enqueue it into the queue ", __func__); mm_camera_stream_frame_enq_no_lock(myq, node); node->valid_entry = 1; } CDBG("%s Need to find match for the frame id %d ", __func__, node->frame.frame_id); /* the node is older than the peer, we will either find a match or drop it */ peer_frame = peerq->head; peer_frame_prev = NULL; peer_frame_tmp = NULL; while(peer_frame) { CDBG("%s peer frame_id = %d node frame_id = %d", __func__, peer_frame->frame.frame_id, node->frame.frame_id); if(peer_frame->match) { CDBG("%s Peer frame already matched, keep looking in the list ", __func__); /* matched frame., skip */ peer_frame_prev = peer_frame; peer_frame = peer_frame->next; continue; } if(peer_frame->frame.frame_id == node->frame.frame_id) { /* find a match keep the frame */ node->match = 1; peer_frame->match = 1; CDBG("%s Found match, add to myq ", __func__); mm_camera_stream_frame_enq_no_lock(myq, node); myq->match_cnt++; peerq->match_cnt++; goto water_mark; } else { /* no match */ if(node->frame.frame_id > peer_frame->frame.frame_id) { /* the incoming frame is newer than the peer's unmatched frame. drop the peer frame */ CDBG("%s node frame is newer, release old peer frame ", __func__); if(!peer_frame_prev) { /* this is the head */ peer_frame_tmp = mm_camera_stream_frame_deq_no_lock(peerq); notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; mm_camera_stream_util_buf_done(my_obj, peerstream, ¬ify_frame); peer_frame = peerq->head; peer_frame_prev = NULL; continue; } else { /* this is not the head. */ peer_frame_tmp = peer_frame; peer_frame_prev->next = peer_frame->next; if(peer_frame == peerq->tail) { /* peer_frame is the tail */ peerq->tail = peer_frame_prev; } notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; mm_camera_stream_util_buf_done(my_obj, peerstream, ¬ify_frame); peer_frame = peer_frame_prev->next; peerq->cnt--; continue; } } else { /* Current frame is older than peer's unmatched frame, dont add * it into the queue. just drop it */ CDBG("%s node frame is older than peer's unmatched frame. " "Drop the current frame.", __func__); notify_frame.frame = &node->frame; notify_frame.idx = node->idx; mm_camera_stream_util_buf_done(my_obj, mystream, ¬ify_frame); goto end; } } } if(!node->match && !node->valid_entry) { /* if no match and not a valid entry. * the node is not added into the queue. it's dirty node */ CDBG_ERROR("%s: stream type = %d and fd = %d, frame 0x%x is dirty" " and queue back kernel", __func__, mystream->stream_type, mystream->fd, node->frame.frame_id); notify_frame.frame = &node->frame; notify_frame.idx = node->idx; mm_camera_stream_util_buf_done(my_obj, mystream, ¬ify_frame); } water_mark: while(myq->match_cnt > watermark) { peer_frame_tmp = mm_camera_stream_frame_deq_no_lock(peerq); notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; CDBG("%s match_cnt %d > watermark %d, buf_done on " "peer frame idx %d id = %d", __func__, myq->match_cnt, watermark, notify_frame.idx, notify_frame.frame->frame_id); mm_camera_stream_util_buf_done(my_obj, peerstream, ¬ify_frame); peerq->match_cnt--; peer_frame_tmp = mm_camera_stream_frame_deq_no_lock(myq); notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; mm_camera_stream_util_buf_done(my_obj, mystream, ¬ify_frame); myq->match_cnt--; } end: CDBG("%s myQ->cnt = %d myQ->match_cnt = %d ", __func__, myq->cnt, myq->match_cnt); if(myq->cnt > myq->match_cnt + 1) { /* drop the first unmatched frame */ mm_camera_frame_t *peer_frame = myq->head;; mm_camera_frame_t *peer_frame_prev = NULL; while(peer_frame) { CDBG("%s myQ->cnt = %d myQ->match_cnt = %d ", __func__, myq->cnt, myq->match_cnt); if(peer_frame->match == 0) { /* first unmatched frame */ if(!peer_frame_prev) { /* this is the head */ peer_frame_tmp = mm_camera_stream_frame_deq_no_lock(myq); notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; CDBG("%s Head Issuing buf_done on my frame idx %d id %d", __func__, notify_frame.idx, notify_frame.frame->frame_id); mm_camera_stream_util_buf_done(my_obj, mystream, ¬ify_frame); } else { /* this is not the head. */ peer_frame_tmp = peer_frame; peer_frame_prev->next = peer_frame->next; if(peer_frame == peerq->tail) { /* peer_frame is the tail */ myq->tail = peer_frame_prev; } notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; CDBG("%s Issuing buf_done on my frame idx %d id = %d", __func__, notify_frame.idx, notify_frame.frame->frame_id); mm_camera_stream_util_buf_done(my_obj, mystream, ¬ify_frame); myq->cnt--; } break; } else { peer_frame_prev= peer_frame; peer_frame = peer_frame_prev->next; } } } CDBG("%s peerQ->cnt = %d peerQ->match_cnt = %d ", __func__, peerq->cnt, peerq->match_cnt); if(peerq->cnt > peerq->match_cnt + 1) { /* drop the first unmatched frame */ mm_camera_frame_t *peer_frame = peerq->head; mm_camera_frame_t *peer_frame_prev = NULL; while(peer_frame) { CDBG("%s Traverse peerq list frame idx %d frame_id = %d match %d ", __func__, peer_frame->idx, peer_frame->frame.frame_id, peer_frame->match); if(peer_frame->match == 0) { /* first unmatched frame */ if(!peer_frame_prev) { /* this is the head */ peer_frame_tmp = mm_camera_stream_frame_deq_no_lock(peerq); notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; CDBG("%s Head Issuing buf_done on peer frame idx %d " "id = %d", __func__, notify_frame.idx, notify_frame.frame->frame_id); mm_camera_stream_util_buf_done(my_obj, peerstream, ¬ify_frame); } else { /* this is not the head. */ peer_frame_tmp = peer_frame; peer_frame_prev->next = peer_frame->next; if(peer_frame == peerq->tail) { /* peer_frame is the tail */ peerq->tail = peer_frame_prev; } notify_frame.frame = &peer_frame_tmp->frame; notify_frame.idx = peer_frame_tmp->idx; CDBG("%s Issuing buf_done on peer frame idx %d id = %d", __func__, notify_frame.idx, notify_frame.frame->frame_id); mm_camera_stream_util_buf_done(my_obj, peerstream, ¬ify_frame); peerq->cnt--; } break; } else { peer_frame_prev= peer_frame; peer_frame = peer_frame_prev->next; } } } CDBG("%s Dispatching ZSL frame ", __func__); mm_camera_zsl_check_burst_dispatching(my_obj, &my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.main.frame.readyq, &my_obj->ch[MM_CAMERA_CH_PREVIEW].preview.stream.frame.readyq, &my_obj->ch[MM_CAMERA_CH_SNAPSHOT].snapshot.main, &my_obj->ch[MM_CAMERA_CH_PREVIEW].preview.stream, &deliver_done); pthread_mutex_unlock(pPreviewMutex); pthread_mutex_unlock(pSnapshotMutex); if(deliver_done > 0) { mm_camera_event_t data; CDBG("%s: ZSL delivered", __func__); data.event_type = MM_CAMERA_EVT_TYPE_CH; data.e.ch.evt = MM_CAMERA_CH_EVT_DATA_DELIVERY_DONE; data.e.ch.ch = MM_CAMERA_CH_SNAPSHOT; mm_camera_poll_send_ch_event(my_obj, &data); } return rc; }