int mm_camera_zsl_check_burst_dispatching(mm_camera_obj_t * my_obj,
                               mm_camera_frame_queue_t *main_q,
                               mm_camera_frame_queue_t *thumb_q,
                               mm_camera_stream_t *main_stream,
                               mm_camera_stream_t *thumb_stream, int *deliver_done)
{
    mm_camera_ch_data_buf_t data;
    int i;
    mm_camera_frame_t *main_frame = NULL;
    mm_camera_frame_t *thumb_frame = NULL;
    mm_camera_ch_t *ch = &my_obj->ch[MM_CAMERA_CH_SNAPSHOT];
    *deliver_done = 0;
    if(ch->snapshot.pending_cnt > 0) {
        if(!main_q->match_cnt || !thumb_q->match_cnt)
            return 0;
        /* dequeue one by one and then pass to HAL */
        main_frame = mm_camera_stream_frame_deq_no_lock(main_q);
        thumb_frame = mm_camera_stream_frame_deq_no_lock(thumb_q);
        main_q->match_cnt--;
        thumb_q->match_cnt--;
        CDBG("%s: Dequeued frame: main frame idx: %d thumbnail "
             "frame idx: %d", __func__, main_frame->idx, thumb_frame->idx);
        /* dispatch this pair of frames */
        memset(&data, 0, sizeof(data));
        data.type = MM_CAMERA_CH_SNAPSHOT;
        data.snapshot.main.frame = &main_frame->frame;
        data.snapshot.main.idx = main_frame->idx;
        data.snapshot.thumbnail.frame = &thumb_frame->frame;
        data.snapshot.thumbnail.idx = thumb_frame->idx;
        ch->snapshot.pending_cnt--;
        for( i=0;i<MM_CAMERA_BUF_CB_MAX;i++) {
            if (ch->buf_cb[i].cb)
              ch->buf_cb[i].cb(&data, ch->buf_cb[i].user_data);
        }
        if(ch->snapshot.pending_cnt == 0)
            *deliver_done = 1;
    }
    return 0;
}
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;
}