/****************************************************************************** * * 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); } } }