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; }