JM8.5中的多参考帧问题
Outline:
1、 CFG文件中有关多参考帧的相关选项
2、 多参考帧涉及到的数据结构和全局变量
3、 保存重建图像为参考帧
4、 编码一帧前,设置参考帧列表
5、 多参考帧的使用(即参考帧的选择策略问题)
6、 遗留问题
1、CFG文件中有关多参考帧的相关选项
############################################################################### #Encoder Control
###############################################################################
…
NumberReferenceFrames = 10 # Number of previous frames used for inter motion search (1-16)
解释:
a、 首先通过Configure()转换成input->num_reference_frames
b、 input->num_reference_frames再通过parset.c文件中的IdentifyNumRefFrames()返回给同一文件的FillParameterSetStructures()中的sps->num_ref_frames。
c、 FillParameterSetStructures()其实被parset.c文件中的GenerateParameterSets()函数调用,所以sps又被赋给了active_sps,active_sps是全局变量。
d、 active_sps->num_ref_frames又会在lencod.c中的init_img()函数中被赋给img->num_reference_frames。
PList0References = 0 # P slice List 0 reference override (0 disable, N <= NumberReferenceFrames)
解释:
用于限制LIST0中参考帧的数目
…
###############################################################################
# B Frames
###############################################################################
…
BList0References = 0 # B slice List 0 reference override (0 disable, N <= NumberReferenceFrames)
BList1References = 0 # B slice List 1 reference override (0 disable, N <= NumberReferenceFrames)
…
2、 多参考帧涉及到的数据结构和全局变量
a、 概要
多参考帧相关的重要的数据结构都在mbuffer.h文件中。
其中重要的数据结构有:StorblePicture, FrameStore, DecodedPictureBuffer
重要的全局变量有:
extern DecodedPictureBuffer dpb;
extern StorablePicture **listX[6];
extern int listXsize[6];
b、 各数据结构的作用和相互之间的关系
StorblePicture存放的是一帧帧方式或场方式的重建图像
FrameStore嵌套了StorblePicture,同时增加了一些标志信息,如是否已输出到文件等,所以它可以用于通用的表示一帧的数据结构(不分场或帧)
DecodedPictureBuffer又嵌套了FrameStore,它用于保存所有的重建图像(应该保存的),其中设置很多辅助的参数,如used_size用来表示已经保存的重建图像数。
c、 各全局变量的作用
dpb的作用从上面对DecodedPictureBuffer的解释中,已经可以看出是用来存储所有的重建图像。值的提醒的是它可能保存了非参考帧重建图像。
listX[6]:该变量的作用是用来在每次编码一帧图像时,将所要用到的参考帧保存在其中。但真正所要用到的参考帧图像数据是指向到dpb对应的结构元素中。
对于P帧,只要用到listX[0]。
对于B帧,要用到listX[0],listX[1]
对于Mbaff的编码方式,可能还会用到listX[2-5]。
3、 保存重建图像为参考帧
所用到的函数是:void store_picture_in_dpb(StorablePicture* p),mbuffer.c
该函数在image.c的encode_one_frame()的后段被调要到。
其中重要的程序段如下:
// first try to remove unused frames 当缓冲已满时
if (dpb.used_size==dpb.size)
{
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);
return;
}
}
// flush a frame
output_one_frame_from_dpb();//输出一帧到文件
}
…
insert_picture_in_dpb(dpb.fs[dpb.used_size],p); //将当前解码帧插入到dpb尾部
4、 编码一帧前,设置参考帧列表
所用到的函数是:init_lists(), mbuffer.c
该函数在image.c中的code_a_picture()的开始部分被调用到。
其中重要的程序段如下:(只举例分析帧模式的情况)
…
////////////////////////////////
//将dpb中参考帧写入ListX中去
////////////////////////////////
if ((currSliceType == I_SLICE)||(currSliceType == SI_SLICE))
{
listXsize[0] = 0;
listXsize[1] = 0;
return;
}
if ((currSliceType == P_SLICE)||(currSliceType == SP_SLICE))
{
// Calculate FrameNumWrap and PicNum
if (currPicStructure == FRAME)
{
for (i=0; i<dpb.ref_frames_in_buffer; i++)
{
if (dpb.fs_ref[i]->is_used==3)
{
if ((dpb.fs_ref[i]->frame->used_for_reference)&&(!dpb.fs_ref[i]->frame->is_long_term))
{
listX[0][list0idx++] = dpb.fs_ref[i]->frame;
}
}
}
// order list 0 by PicNum
qsort((void *)listX[0], list0idx, sizeof(StorablePicture*), compare_pic_by_pic_num_desc);
listXsize[0] = list0idx;
…
}
else//B_SLICE
{
…
}
5、 多参考帧的使用(即参考帧的选择策略问题)
所用到的函数是:PartitionMotionSearch(), mv_search.c 该函数的作用是对各种尺寸的宏块或亚宏块寻找匹配块。
其中涉及到多参考帧的程序段如下:
…
//===== LOOP OVER REFERENCE FRAMES =====
for (list=0; list<numlists;list++)
{
for (ref=0; ref < listXsize[list+list_offset]; ref++)//list_offset和场模式有关
{
…
NOTE:从上面的程序可以看出,JM8.5对多参考帧的选择,是采用的是一种完全遍历的方式,所以其计算复杂度会很高。
6、 遗留问题
a、 在init_lists()对于ListX[0]和ListX[1]中参考帧数相同时,会采用一种交换机制,不知其目的如何?
b、 dpb的参考帧有short_term或long_term这样的属性,这属性会影响多参考帧机制的整个过程,但不知其具体作用和原理?
<script type="text/javascript">google_ad_client = "pub-7168982058404735";google_ad_width = 728;google_ad_height = 90;google_ad_format = "728x90_as";google_ad_type = "text_image";google_ad_channel = "";google_color_border = "C3D9FF";google_color_bg = "FFFFFF";google_color_link = "3D81EE";google_color_text = "000000";google_color_url = "008000";google_ui_features = "rc:0";google_language = 'zh-CN'; //--></script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>