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);
    }
}
Пример #5
0
/*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,
                                                   &notify_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,
                                                   &notify_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, &notify_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, &notify_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, &notify_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, &notify_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,
                                                   &notify_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,
                                                   &notify_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,
                                                   &notify_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,
                                                   &notify_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,
                                                   &notify_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,
                                                   &notify_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, &notify_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, &notify_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, &notify_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, &notify_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,
                                                   &notify_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,
                                                   &notify_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,
                                                   &notify_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,
                                                   &notify_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;
}