C++程序  |  507行  |  12.1 KB

/******************************************************************************
*
* Copyright (C) 2012 Ittiam Systems Pvt Ltd, Bangalore
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/**
 *******************************************************************************
 * @file
 *  ihevc_dpb_mgr.c
 *
 * @brief
 *  Function definitions used for decoded picture buffer management
 *
 * @author
 *  Srinivas T
 *
 * @par List of Functions:
 *   - ihevc_dpb_mgr_init()
 *   - ihevc_dpb_mgr_del_lt()
 *   - ihevc_dpb_mgr_insert_lt()
 *   - ihevc_dpb_mgr_del_st_or_make_lt()
 *   - ihevc_dpb_mgr_insert_st()
 *   - ihevc_dpb_mgr_reset()
 *   - ihevc_dpb_mgr_release_pics()
 *
 * @remarks
 *  None
 *
 *******************************************************************************
 */

#include <stdio.h>
#include <stdlib.h>

#include "ihevc_typedefs.h"
#include "ihevc_defs.h"
#include "ihevc_macros.h"
#include "ihevc_func_selector.h"
#include "ihevc_structs.h"
#include "ihevc_buf_mgr.h"
#include "ihevc_dpb_mgr.h"

/**
 *******************************************************************************
 *
 * @brief
 *  DPB manager initializer
 *
 * @par Description:
 *  Initialises the DPB manager structure
 *
 * @param[in] ps_dpb_mgr
 *  Pointer to the DPB manager structure
 *
 * @returns
 *
 * @remarks
 *
 *
 *******************************************************************************
 */

void ihevc_dpb_mgr_init(dpb_mgr_t *ps_dpb_mgr)
{
    UWORD32 i;
    dpb_info_t *ps_dpb_info = ps_dpb_mgr->as_dpb_info;
    for(i = 0; i < MAX_DPB_BUFS; i++)
    {
        ps_dpb_info[i].ps_prev_dpb = NULL;
        ps_dpb_info[i].ps_pic_buf = NULL;

    }

    ps_dpb_mgr->u1_num_ref_bufs = 0;
    ps_dpb_mgr->ps_dpb_head = NULL;

}


/**
 *******************************************************************************
 *
 * @brief
 *  Adds a reference picture into the linked  list
 *
 * @par Description:
 *  Adds the reference buffer with the given buffer id into the DPB manager
 *
 *
 * @param[in] ps_dpb_mgr
 *  Pointer to the DPB manager structure
 *
 * @param[in] ps_picBuf
 *  Pointer to the picture buffer
 *
 * @param[in] buf_id
 *  buffer id of the picture buffer
 *
 * @returns  0 if successful, -1 otherwise
 *
 * @remarks
 *
 *
 *******************************************************************************
 */

WORD32 ihevc_dpb_mgr_insert_ref(dpb_mgr_t *ps_dpb_mgr,
                                pic_buf_t *ps_pic_buf,
                                WORD32 buf_id)
{
    int i;
    dpb_info_t *ps_dpb_info;

    ps_dpb_info = ps_dpb_mgr->as_dpb_info;

    /* Return error if buffer is already present in the DPB */
    for(i = 0; i < MAX_DPB_BUFS; i++)
    {
        if((ps_dpb_info[i].ps_pic_buf == ps_pic_buf)
                        && (ps_dpb_info[i].ps_pic_buf->u1_used_as_ref))
        {
            return (-1);
        }


    }

    /* Find an unused DPB location */
    for(i = 0; i < MAX_DPB_BUFS; i++)
    {
        if(NULL == ps_dpb_info[i].ps_pic_buf)
        {
            break;
        }
    }
    if(i == MAX_DPB_BUFS)
    {
        return (-1);
    }

    /* Create DPB info */
    ps_dpb_info[i].ps_pic_buf = ps_pic_buf;
    ps_dpb_info[i].ps_prev_dpb = ps_dpb_mgr->ps_dpb_head;
    ps_dpb_info[i].ps_pic_buf->u1_buf_id = buf_id;
    ps_dpb_info[i].ps_pic_buf->u1_used_as_ref = SHORT_TERM_REF;

    /* update the head node of linked list to point to the current picture */
    ps_dpb_mgr->ps_dpb_head = ps_dpb_info + i;

    /* Increment Short term buffer count */
    ps_dpb_mgr->u1_num_ref_bufs++;

    return 0;
}

/**
 *******************************************************************************
 *
 * @brief
 *  Deletes a reference buffer from the dpb manager
 *
 * @par Description:
 *  Delete short term reference with a given POC from the linked
 *  list
 *
 * @param[in] ps_dpb_mgr
 *  Pointer to DPB Manager structure
 *
 * @param[in] ps_buf_mgr
 *  Pointer to buffer manager structure
 *
 * @param[in] u4_abs_poc
 *  Node's absolute poc
 *
 *
 * @returns  0 if successful, -1 otherwise
 *
 * @remarks
 *
 *
 *******************************************************************************
 */

void ihevc_dpb_mgr_del_ref(dpb_mgr_t *ps_dpb_mgr,
                           buf_mgr_t *ps_buf_mgr,
                           WORD32 i4_abs_poc)
{
    int i;
    dpb_info_t *ps_next_dpb;

    dpb_info_t *ps_unmark_node;
    UWORD8 u1_del_node;
    UNUSED(u1_del_node);
    u1_del_node = 0;

    /* Find the node with matching absolute POC */
    ps_next_dpb = ps_dpb_mgr->ps_dpb_head;
    if(ps_next_dpb->ps_pic_buf->i4_abs_poc == i4_abs_poc)
    {
        ps_unmark_node = ps_next_dpb;
    }
    else
    {
        for(i = 1; i < ps_dpb_mgr->u1_num_ref_bufs; i++)
        {
            if(ps_next_dpb->ps_prev_dpb->ps_pic_buf->i4_abs_poc == i4_abs_poc)
                break;
            ps_next_dpb = ps_next_dpb->ps_prev_dpb;
        }

        if(i == ps_dpb_mgr->u1_num_ref_bufs)
        {
            return;
        }
        else
            ps_unmark_node = ps_next_dpb->ps_prev_dpb;
    }

    if(ps_unmark_node == ps_dpb_mgr->ps_dpb_head)
    {
        ps_dpb_mgr->ps_dpb_head = ps_unmark_node->ps_prev_dpb;
    }
    else
    {
        ps_next_dpb->ps_prev_dpb = ps_unmark_node->ps_prev_dpb; //update link
        ps_unmark_node->ps_prev_dpb = NULL;
    }
    ps_dpb_mgr->u1_num_ref_bufs--; //decrement buffer count

    /* Release the physical buffer */
    ihevc_buf_mgr_release((buf_mgr_t *)ps_buf_mgr, ps_unmark_node->ps_pic_buf->u1_buf_id,
                          BUF_MGR_REF);
    ps_unmark_node->ps_prev_dpb = NULL;
    ps_unmark_node->ps_pic_buf = NULL;
}


/**
 *******************************************************************************
 *
 * @brief
 *  Gets a buffer with abs_poc closest to the current poc
 *
 * @par Description:
 *  Returns the pointer to the picture buffer whose poc is equal to abs_poc
 *
 * @param[in] ps_dpb_mgr
 *  Pointer to DPB Manager structure
 *
 * @param[out] ps_pic_buf
 *  Pointer to picture buffer

 * @param[in] abs_poc
 *  poc of the buffer to be returned
 *
 * @returns
 *  0 if successful, pic_buf otherwise
 * @remarks
 *
 *
 *******************************************************************************
 */
pic_buf_t* ihevc_dpb_mgr_get_ref_by_nearest_poc(dpb_mgr_t *ps_dpb_mgr, WORD32 cur_abs_poc)
{
    WORD32 i;
    WORD32 min_diff = 0x7FFFFFFF;
    pic_buf_t *ps_pic_buf = NULL;

    for(i = 0; i < MAX_DPB_BUFS; i++)
    {
        if((ps_dpb_mgr->as_dpb_info[i].ps_pic_buf) &&
                        (ps_dpb_mgr->as_dpb_info[i].ps_pic_buf->u1_used_as_ref != UNUSED_FOR_REF))
        {
            WORD32 poc_diff = cur_abs_poc - ps_dpb_mgr->as_dpb_info[i].ps_pic_buf->i4_abs_poc;
            if((poc_diff > 0) && (poc_diff < min_diff))
            {
                min_diff = poc_diff;
                ps_pic_buf = ps_dpb_mgr->as_dpb_info[i].ps_pic_buf;
            }
        }
    }

    if(NULL == ps_pic_buf)
    {
        min_diff = 0x7FFFFFFF;
        for(i = 0; i < MAX_DPB_BUFS; i++)
        {
            if((ps_dpb_mgr->as_dpb_info[i].ps_pic_buf) &&
                            (ps_dpb_mgr->as_dpb_info[i].ps_pic_buf->u1_used_as_ref != UNUSED_FOR_REF))
            {
                WORD32 poc_diff = cur_abs_poc - ps_dpb_mgr->as_dpb_info[i].ps_pic_buf->i4_abs_poc;
                if(ABS(poc_diff) < min_diff)
                {
                    min_diff = ABS(poc_diff);
                    ps_pic_buf = ps_dpb_mgr->as_dpb_info[i].ps_pic_buf;
                }
            }
        }
    }

    return ps_pic_buf;
}


/**
 *******************************************************************************
 *
 * @brief
 *  Gets a buffer with abs_poc
 *
 * @par Description:
 *  Returns the pointer to the picture buffer whose poc is equal to abs_poc
 *
 * @param[in] ps_dpb_mgr
 *  Pointer to DPB Manager structure
 *
 * @param[out] ps_pic_buf
 *  Pointer to picture buffer

 * @param[in] abs_poc
 *  poc of the buffer to be returned
 *
 * @returns
 *  0 if successful, pic_buf otherwise
 * @remarks
 *
 *
 *******************************************************************************
 */
pic_buf_t* ihevc_dpb_mgr_get_ref_by_poc(dpb_mgr_t *ps_dpb_mgr, WORD32 abs_poc)
{
    UWORD32 i;
    dpb_info_t *ps_next_ref;
    pic_buf_t *ps_pic_buf = NULL;


    ps_next_ref = ps_dpb_mgr->ps_dpb_head;
    for(i = 0; i < ps_dpb_mgr->u1_num_ref_bufs; i++)
    {
        if(ps_next_ref->ps_pic_buf->i4_abs_poc == abs_poc)
        {
            ps_pic_buf = ps_next_ref->ps_pic_buf;
            break;
        }

        ps_next_ref = ps_next_ref->ps_prev_dpb;
    }

    if(i == ps_dpb_mgr->u1_num_ref_bufs)
    {
        ps_pic_buf = NULL;
    }

    return ps_pic_buf;
}

/**
 *******************************************************************************
 *
 * @brief
 *  Gets a buffer with poc_lsb
 *
 * @par Description:
 *  Returns the pointer to the picture buffer whose poc is equal to poc_lsb
 *
 * @param[in] ps_dpb_mgr
 *  Pointer to DPB Manager structure
 *
 * @param[out] ps_pic_buf
 *  Pointer to picture buffer

 * @param[in] poc_lsb
 *  poc_lsb of the buffer to be returned
 *
 * @returns
 *  0 if successful, pic_buf otherwise
 * @remarks
 *
 *
 *******************************************************************************
 */

pic_buf_t* ihevc_dpb_mgr_get_ref_by_poc_lsb(dpb_mgr_t *ps_dpb_mgr, WORD32 poc_lsb)
{
    pic_buf_t *ps_pic_buf = NULL;
    UWORD32 i;
    dpb_info_t *ps_next_ref;

    ps_next_ref = ps_dpb_mgr->ps_dpb_head;
    for(i = 0; i < ps_dpb_mgr->u1_num_ref_bufs; i++)
    {
        if(ps_next_ref->ps_pic_buf->i4_poc_lsb == poc_lsb)
        {
            ps_pic_buf = ps_next_ref->ps_pic_buf;
            break;
        }

        ps_next_ref = ps_next_ref->ps_prev_dpb;
    }

    if(i == ps_dpb_mgr->u1_num_ref_bufs)
    {
        ps_pic_buf = NULL;
    }

    return ps_pic_buf;
}


/**
 *******************************************************************************
 *
 * @brief
 *  Resets the DPB manager
 *
 * @par Description:
 *  Re-initialises the DPB manager structure
 *
 * @param[in] ps_dpb_mgr
 *  Pointer to DPB Manager structure
 *
 * @param[in] ps_buf_mgr
 *  Pointer to buffer manager structure
 *
 * @returns
 *
 * @remarks
 *
 *
 *******************************************************************************
 */

void ihevc_dpb_mgr_reset(dpb_mgr_t *ps_dpb_mgr, buf_mgr_t *ps_buf_mgr)
{
    int i;
    dpb_info_t *ps_dpb_info;

    ps_dpb_info = ps_dpb_mgr->as_dpb_info;

    for(i = 0; i < MAX_DPB_BUFS; i++)
    {
        if(ps_dpb_info[i].ps_pic_buf->u1_used_as_ref)
        {
            ps_dpb_info[i].ps_pic_buf->u1_used_as_ref = UNUSED_FOR_REF;
            ps_dpb_info[i].ps_prev_dpb = NULL;
            //Release physical buffer
            ihevc_buf_mgr_release(ps_buf_mgr, ps_dpb_info[i].ps_pic_buf->u1_buf_id,
                                  BUF_MGR_REF);

            ps_dpb_info[i].ps_pic_buf = NULL;
        }
    }
    ps_dpb_mgr->u1_num_ref_bufs = 0;
    ps_dpb_mgr->ps_dpb_head = NULL;

}

/**
 *******************************************************************************
 *
 * @brief
 *  deletes all pictures from DPB
 *
 * @par Description:
 *  Deletes all pictures present in the DPB manager
 *
 * @param[in] ps_buf_mgr
 *  Pointer to buffer manager structure
 *
 * @param[in] u1_disp_bufs
 *  Number of buffers to be deleted
 *
 * @returns
 *
 * @remarks
 *
 *
 *******************************************************************************
 */

void ihevc_dpb_mgr_release_pics(buf_mgr_t *ps_buf_mgr, UWORD8 u1_disp_bufs)
{
    WORD8 i;
    UWORD32 buf_status;

    for(i = 0; i < u1_disp_bufs; i++)
    {
        buf_status = ihevc_buf_mgr_get_status(ps_buf_mgr, i);
        if(0 != buf_status)
        {
            ihevc_buf_mgr_release((buf_mgr_t *)ps_buf_mgr, i, BUF_MGR_REF);
        }
    }
}