H.264参考帧列表管理分析 ―― JM中相关函数解析(上)(三)

2014-11-24 08:53:03 · 作者: · 浏览: 2
ive_memory_management(StorablePicture* p)调用。在编码端,encode_one_frame()的末尾会调用store_picture_in_dpb(StorablePicture* p),从而调用开头的这两个函数进行参考图像的标记;在解码端,主要由exit_picture()通过调用store_picture_in_dpb(StorablePicture* p)来完成这项工作。

[cpp]
/*!
************************************************************************
* \brief
* Store a picture in DPB. This includes cheking for space in DPB and
* flushing frames.
* If we received a frame, we need to check for a new store, if we
* got a field, check if it's the second field of an already allocated
* store.
*
* \param p
* Picture to be stored
*
************************************************************************
*/
void store_picture_in_dpb(StorablePicture* p)
{
unsigned i;
int poc, pos;
// diagnostics
//printf ("Storing (%s) non-ref pic with frame_num #%d\n", (p->type == FRAME) "FRAME":(p->type == TOP_FIELD) "TOP_FIELD":"BOTTOM_FIELD", p->pic_num);
// if frame, check for new store,
assert (p!=NULL);

p->used_for_reference = (img->nal_reference_idc != 0);

img->last_has_mmco_5=0;
img->last_pic_bottom_field = (img->structure == BOTTOM_FIELD);

if (img->currentPicture->idr_flag)
idr_memory_management(p); //!< IDR图像的标记过程
else
{
// adaptive memory management
if (p->used_for_reference && (img->adaptive_ref_pic_buffering_flag))
adaptive_memory_management(p); //!< 自适应标记过程
}

if ((p->structure==TOP_FIELD)||(p->structure==BOTTOM_FIELD)) //!< 场模式(略过)
{
... ...
}

// this is a frame or a field which has no stored complementary field

// sliding window, if necessary
if ((!img->currentPicture->idr_flag)&&(p->used_for_reference && (!img->adaptive_ref_pic_buffering_flag)))
{
sliding_window_memory_management(p); //!< 滑窗标记过程
}

// first try to remove unused frames
if (dpb.used_size==dpb.size) //!< 当缓冲已满时,删除掉dpb中已经输出到文件且不被参考的帧
{

remove_unused_frame_from_dpb();
}

// then output frames until one can be removed
while (dpb.used_size==dpb.size)
{
// non-reference frames may be output directly
if (!p->used_for_reference) //!< 如果当前帧不作为参考帧,可以直接输出到重建文件序列中
{
get_smallest_poc(&poc, &pos);
if ((-1==pos) || (p->poc < poc))
{
direct_output(p, p_dec); //!< 直接输出当前帧而不保存到dpb中
return;
}
}
// flush a frame
output_one_frame_from_dpb(); //!< 输出一帧到文件
}

// check for duplicate frame number in short term reference buffer
if ((p->used_for_reference)&&(!p->is_long_term))
{
for (i=0; i {
if (dpb.fs_ref[i]->frame_num == p->frame_num)
{
error("duplicate frame_num im short-term reference picture buffer", 500);
}
}

}
// store at end of buffer
// printf ("store frame/field at pos %d\n",dpb.used_size);
insert_picture_in_dpb(dpb.fs[dpb.used_size],p); //!< 将当前解码帧插入到dpb尾部

if (p->structure != FRAME)
{
dpb.last_picture = dpb.fs[dpb.used_size];
}
else
{
dpb.last_picture = NULL;
}

dpb.used_size++; //!< 更新dpb中参考帧的计数

update_ref_list(); //!< 更新短期参考帧列表
update_ltref_list(); //!< 更新长期参考帧列表

check_num_ref();

dump_dpb();
}