int task_get_references(davs2_t *h, int64_t pts, int64_t dts)
{
    davs2_mgr_t    *mgr   = h->task_info.taskmgr;
    davs2_frame_t **dpb   = mgr->dpb;
    davs2_frame_t  *frame = NULL;
    int i, j;

#define IS_VALID_FRAME(frame) ((frame)->i_coi != INVALID_FRAME && (frame)->i_poc != INVALID_FRAME)

    davs2_thread_mutex_lock(&mgr->mutex_mgr);

    h->fdec = NULL;
    h->num_of_references = 0;
    for (i = 0; i < AVS2_MAX_REFS; i++) {
        h->fref[i] = NULL;
    }

    for (i = 0; i < mgr->num_frames_to_remove; i++) {
        int coi_frame_to_remove = mgr->coi_remove_frame[i];

        for (j = 0; j < mgr->dpbsize; j++) {
            frame = dpb[j];

            if (!IS_VALID_FRAME(frame)) {
                continue;
            }

            if (frame->i_coi == coi_frame_to_remove) {
                break;
            }
        }

        if (j < mgr->dpbsize) {
            davs2_thread_mutex_lock(&frame->mutex_frm);
            // assert(frame->i_disposable == 0);

            if (frame->i_ref_count == 0) {
                clean_one_frame(frame);
            } else {
                frame->i_disposable = 1;
            }

            davs2_thread_mutex_unlock(&frame->mutex_frm);
        }
    }


    if (h->i_frame_type == AVS2_GB_SLICE) {
        h->fdec = h->f_background_cur;
    } else {
        for (i = 0; i < h->rps.num_of_ref; i++) {
            int ref_frame_coi = h->i_coi - h->rps.ref_pic[i];
            for (j = 0; j < mgr->dpbsize; j++) {
                frame = dpb[j];

                if (!IS_VALID_FRAME(frame)) {
                    continue;
                }

                davs2_thread_mutex_lock(&frame->mutex_frm);

                if (frame->i_coi >= 0 && ref_frame_coi == frame->i_coi) {
                    assert(frame->i_disposable == 0);
                    assert(frame->b_refered_by_others != 0);

                    if (frame->i_disposable == 0 && frame->b_refered_by_others != 0) {
                        frame->i_ref_count++;
                        davs2_thread_mutex_unlock(&frame->mutex_frm);

                        h->fref[i] = frame;
                        h->num_of_references++;

                        break;
                    }
                }

                davs2_thread_mutex_unlock(&frame->mutex_frm);
            }

            if (j == mgr->dpbsize) {
                davs2_log(h, DAVS2_LOG_ERROR, "reference frame of [coi: %d, poc: %d]: <COI: %d> not found.",
                    h->i_coi, h->i_poc, ref_frame_coi);
                goto fail;
            }
        }

        if (h->i_frame_type == AVS2_B_SLICE &&
            (h->num_of_references != 2 || h->fref[0]->i_poc <= h->i_poc || h->fref[1]->i_poc >= h->i_poc)) {
            davs2_log(h, DAVS2_LOG_ERROR, "reference frames for B frame [coi: %d, poc: %d] are wrong: %d frames found",
                h->i_coi, h->i_poc, h->num_of_references);
            goto fail;
        }

        /* delete the frame that will never be used */
        mgr->num_frames_to_remove = h->rps.num_to_remove;

        for (i = 0; i < h->rps.num_to_remove; i++) {
            mgr->coi_remove_frame[i] = h->i_coi - h->rps.remove_pic[i];
        }

        /* clean old frames */
        for (i = 0; i < mgr->dpbsize; i++) {
            frame = dpb[i];

            if (!IS_VALID_FRAME(frame)) {
                continue;
            }

            davs2_thread_mutex_lock(&frame->mutex_frm);

            if (DAVS2_ABS(frame->i_poc - h->i_poc) >= MAX_POC_DISTANCE) {
                if (frame->i_ref_count == 0) {
                    davs2_log(h, DAVS2_LOG_WARNING, "force to remove obsolete frame <poc: %d>.", frame->i_poc);
                    /* no one is holding reference to this frame: clean it ! */
                    clean_one_frame(frame);
                } else {
                    /* weird ? */
                    /* some task has forgot to release it ? */
                    if (frame->i_disposable == 0) {
                        frame->i_disposable = 1;
                        davs2_log(h, DAVS2_LOG_WARNING, "force to mark obsolete frame <poc: %d> as to be removed.", frame->i_poc);
                    }
                }
            }

            davs2_thread_mutex_unlock(&frame->mutex_frm);
        }

        /* find fdec */
        for (;;) {
            for (i = 0; i < mgr->dpbsize; i++) {
                frame = dpb[i];

                davs2_thread_mutex_lock(&frame->mutex_frm);

                if (frame->i_ref_count == 0 && frame->b_refered_by_others == 0) {
                    assert(frame->i_disposable == 0);

                    frame->i_ref_count++;   /* for the decoding thread */
                    frame->i_ref_count++;   /* for the output thread */

                    frame->i_disposable = h->rps.refered_by_others == 0 ? 1 : 0;

                    h->fdec = frame;

                    davs2_thread_mutex_unlock(&frame->mutex_frm);

                    break;
                }

                davs2_thread_mutex_unlock(&frame->mutex_frm);
            }

            if (h->fdec != NULL) {
                /* got it */
                break;
            }

            /* DPB full ? */
            if (open_dbp_buffer_warning) {
                davs2_log(h, DAVS2_LOG_WARNING, "running out of DPB buffers, performance may suffer.");
                open_dbp_buffer_warning = 0;      /* avoid too many warnings */
            }

            /* detect possible blocks */
            if (has_blocking(mgr) != 0) {
                if (mgr->outpics.pics == NULL) {
                    /*!!! try to use an earliest frame ??? */
                    /* find the frame with the least POC value */
                    for (i = 0; i < mgr->dpbsize; i++) {
                        frame = dpb[i];
                        davs2_thread_mutex_lock(&frame->mutex_frm);

                        if (frame->i_ref_count == 0 && (h->fdec == NULL || h->fdec->i_poc > frame->i_poc)) {
                            if (h->fdec) {
                                davs2_thread_mutex_lock(&h->fdec->mutex_frm);
                                h->fdec->i_ref_count--;
                                h->fdec->i_ref_count--;
                                davs2_thread_mutex_unlock(&h->fdec->mutex_frm);
                            }

                            frame->i_ref_count++;   /* for the decoding thread */
                            frame->i_ref_count++;   /* for the output thread */

                            h->fdec = frame;
                        }

                        davs2_thread_mutex_unlock(&frame->mutex_frm);
                    }

                    if (NULL == h->fdec) {
                        davs2_log(h, DAVS2_LOG_ERROR, "no frame for new task, DPB size (%d) too small(reorder delay: %d) ?", mgr->dpbsize, mgr->seq_info.picture_reorder_delay);
                        goto fail;
                    }

                    h->fdec->i_disposable = h->rps.refered_by_others == 0 ? 1 : 0;

                    davs2_log(h, DAVS2_LOG_WARNING, "force one frame as the reconstruction frame.");

                    break;
                } else {
                    /* next frame will not be available, skip it */
                    assert(mgr->outpics.output < mgr->outpics.pics->frame->i_poc);
                    /* emit an error */
                    davs2_log(h, DAVS2_LOG_ERROR, "the expected frame %d unavailable, proceed to frame %d.", mgr->outpics.output, mgr->outpics.pics->frame->i_poc);
                    /* output the next available frame */
                    mgr->outpics.output = mgr->outpics.pics->frame->i_poc;
                }
            }

            davs2_thread_mutex_unlock(&mgr->mutex_mgr);

            /* wait for the output thread to release some frames */
            davs2_sleep_ms(1);

            /* check it again */
            davs2_thread_mutex_lock(&mgr->mutex_mgr);
        }

        init_fdec(h, pts, dts);

        if (h->i_frame_type == AVS2_S_SLICE) {
            int num_in_spu = h->i_width_in_spu * h->i_height_in_spu;

            for (i = 0; i < mgr->dpbsize; i++) {
                memset(dpb[i]->mvbuf, 0, num_in_spu * sizeof(mv_t));
                memset(dpb[i]->refbuf, 0, num_in_spu * sizeof(int8_t));
            }
        }
    }

    davs2_thread_mutex_unlock(&mgr->mutex_mgr);

    return 0;

fail:

    davs2_log(NULL, DAVS2_LOG_ERROR, "Failed to decode frame <COI: %d, POC: %d>\n", h->i_coi, h->i_poc);
    davs2_thread_mutex_unlock(&mgr->mutex_mgr);

    task_release_frames(h);

    return -1;
}
int task_get_references(davs2_t *h, int64_t pts, int64_t dts)
{
    davs2_mgr_t    *mgr   = h->task_info.taskmgr;
    davs2_frame_t **dpb   = mgr->dpb;
    davs2_frame_t  *frame = NULL;
    int i, j;

#define IS_VALID_FRAME(frame) ((frame)->i_coi != INVALID_FRAME && (frame)->i_poc != INVALID_FRAME)

    davs2_thread_mutex_lock(&mgr->mutex_mgr);

    h->fdec = NULL;
    h->num_of_references = 0;
    for (i = 0; i < AVS2_MAX_REFS; i++) {
        h->fref[i] = NULL;
    }

    for (i = 0; i < mgr->num_frames_to_remove; i++) {
        int coi_frame_to_remove = mgr->coi_remove_frame[i];

        for (j = 0; j < mgr->dpbsize; j++) {
            frame = dpb[j];

            if (!IS_VALID_FRAME(frame)) {
                continue;
            }

            if (frame->i_coi == coi_frame_to_remove) {
                break;
            }
        }

        if (j < mgr->dpbsize) {
            davs2_thread_mutex_lock(&frame->mutex_frm);
             

            if (frame->i_ref_count == 0) {
                clean_one_frame(frame);
            } else {
                frame->i_disposable = 1;
            }

            davs2_thread_mutex_unlock(&frame->mutex_frm);
        }
    }


    if (h->i_frame_type == AVS2_GB_SLICE) {
        h->fdec = h->f_background_cur;
    } else {
        for (i = 0; i < h->rps.num_of_ref; i++) {
            int ref_frame_coi = h->i_coi - h->rps.ref_pic[i];
            for (j = 0; j < mgr->dpbsize; j++) {
                frame = dpb[j];

                if (!IS_VALID_FRAME(frame)) {
                    continue;
                }

                davs2_thread_mutex_lock(&frame->mutex_frm);

                if (frame->i_coi >= 0 && ref_frame_coi == frame->i_coi) {
                    assert(frame->i_disposable == 0);
                    assert(frame->b_refered_by_others != 0);

                    if (frame->i_disposable == 0 && frame->b_refered_by_others != 0) {
                        frame->i_ref_count++;
                        davs2_thread_mutex_unlock(&frame->mutex_frm);

                        h->fref[i] = frame;
                        h->num_of_references++;

                        break;
                    }
                }

                davs2_thread_mutex_unlock(&frame->mutex_frm);
            }

            if (j == mgr->dpbsize) {
                davs2_log(h, DAVS2_LOG_ERROR, "reference frame of [coi: %d, poc: %d]: <COI: %d> not found.",
                    h->i_coi, h->i_poc, ref_frame_coi);
                goto fail;
            }
        }

        if (h->i_frame_type == AVS2_B_SLICE &&
            (h->num_of_references != 2 || h->fref[0]->i_poc <= h->i_poc || h->fref[1]->i_poc >= h->i_poc)) {
            davs2_log(h, DAVS2_LOG_ERROR, "reference frames for B frame [coi: %d, poc: %d] are wrong: %d frames found",
                h->i_coi, h->i_poc, h->num_of_references);
            goto fail;
        }

         
        mgr->num_frames_to_remove = h->rps.num_to_remove;

        for (i = 0; i < h->rps.num_to_remove; i++) {
            mgr->coi_remove_frame[i] = h->i_coi - h->rps.remove_pic[i];
        }

         
        for (i = 0; i < mgr->dpbsize; i++) {
            frame = dpb[i];

            if (!IS_VALID_FRAME(frame)) {
                continue;
            }

            davs2_thread_mutex_lock(&frame->mutex_frm);

            if (DAVS2_ABS(frame->i_poc - h->i_poc) >= MAX_POC_DISTANCE) {
                if (frame->i_ref_count == 0) {
                    davs2_log(h, DAVS2_LOG_WARNING, "force to remove obsolete frame <poc: %d>.", frame->i_poc);
                     
                    clean_one_frame(frame);
                } else {
                     
                     
                    if (frame->i_disposable == 0) {
                        frame->i_disposable = 1;
                        davs2_log(h, DAVS2_LOG_WARNING, "force to mark obsolete frame <poc: %d> as to be removed.", frame->i_poc);
                    }
                }
            }

            davs2_thread_mutex_unlock(&frame->mutex_frm);
        }

         
        for (;;) {
            for (i = 0; i < mgr->dpbsize; i++) {
                frame = dpb[i];

                davs2_thread_mutex_lock(&frame->mutex_frm);

                if (frame->i_ref_count == 0 && frame->b_refered_by_others == 0) {
                    assert(frame->i_disposable == 0);

                    frame->i_ref_count++;    
                    frame->i_ref_count++;    

                    frame->i_disposable = h->rps.refered_by_others == 0 ? 1 : 0;

                    h->fdec = frame;

                    davs2_thread_mutex_unlock(&frame->mutex_frm);

                    break;
                }

                davs2_thread_mutex_unlock(&frame->mutex_frm);
            }

            if (h->fdec != NULL) {
                 
                break;
            }

             
            if (open_dbp_buffer_warning) {
                davs2_log(h, DAVS2_LOG_WARNING, "running out of DPB buffers, performance may suffer.");
                open_dbp_buffer_warning = 0;       
            }

             
            if (has_blocking(mgr) != 0) {
                if (mgr->outpics.pics == NULL) {
                     
                     
                    for (i = 0; i < mgr->dpbsize; i++) {
                        frame = dpb[i];
                        davs2_thread_mutex_lock(&frame->mutex_frm);

                        if (frame->i_ref_count == 0 && (h->fdec == NULL || h->fdec->i_poc > frame->i_poc)) {
                            if (h->fdec) {
                                davs2_thread_mutex_lock(&h->fdec->mutex_frm);
                                h->fdec->i_ref_count--;
                                h->fdec->i_ref_count--;
                                davs2_thread_mutex_unlock(&h->fdec->mutex_frm);
                            }

                            frame->i_ref_count++;    
                            frame->i_ref_count++;    

                            h->fdec = frame;
                        }

                        davs2_thread_mutex_unlock(&frame->mutex_frm);
                    }

                    if (NULL == h->fdec) {
                        davs2_log(h, DAVS2_LOG_ERROR, "no frame for new task, DPB size (%d) too small(reorder delay: %d) ?", mgr->dpbsize, mgr->seq_info.picture_reorder_delay);
                        goto fail;
                    }

                    h->fdec->i_disposable = h->rps.refered_by_others == 0 ? 1 : 0;

                    davs2_log(h, DAVS2_LOG_WARNING, "force one frame as the reconstruction frame.");

                    break;
                } else {
                     
                    assert(mgr->outpics.output < mgr->outpics.pics->frame->i_poc);
                     
                    davs2_log(h, DAVS2_LOG_ERROR, "the expected frame %d unavailable, proceed to frame %d.", mgr->outpics.output, mgr->outpics.pics->frame->i_poc);
                     
                    mgr->outpics.output = mgr->outpics.pics->frame->i_poc;
                }
            }

            davs2_thread_mutex_unlock(&mgr->mutex_mgr);

             
            davs2_sleep_ms(1);

             
            davs2_thread_mutex_lock(&mgr->mutex_mgr);
        }

        init_fdec(h, pts, dts);

        if (h->i_frame_type == AVS2_S_SLICE) {
            int num_in_spu = h->i_width_in_spu * h->i_height_in_spu;

            for (i = 0; i < mgr->dpbsize; i++) {
                memset(dpb[i]->mvbuf, 0, num_in_spu * sizeof(mv_t));
                memset(dpb[i]->refbuf, 0, num_in_spu * sizeof(int8_t));
            }
        }
    }

    davs2_thread_mutex_unlock(&mgr->mutex_mgr);

    return 0;

fail:

    davs2_log(NULL, DAVS2_LOG_ERROR, "Failed to decode frame <COI: %d, POC: %d>\n", h->i_coi, h->i_poc);
    davs2_thread_mutex_unlock(&mgr->mutex_mgr);

    task_release_frames(h);

    return -1;
}