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