关于参数的注解: FrameNumOffset: 帧数的偏置.定义为当前帧为IDR时,FNO的值为0;当prevFrameNum > frame_num时,说明了有溢出,故FrameNumOffset = prevFrameNumOffset + MaxFrameNum.当prevFrameNum <=frame_num时FrameNumOffset = prevFrameNumOffset. POCLsb: POC的低有效位.通过slice header传送到解码端.由于编码端知道传送的序列的顺序,所以在编码端,POC的值由以下方法确定: (1)对于帧或者场 img->toppoc = IMG_NUMBER*img->offset_for_ref_frame[0]; (2)对于B帧 img->toppoc = (IMG_NUMBER-1)*img->offset_for_ref_frame[0] + 2* img->b_frame_to_code. 而编码端只需要传送POCLsb到解码端,解码端就可以解出POC的值. 解码端通过IDR帧进行分段(编码端并没有分段),每次分段将POCLsb置0.然后计算出POC的值. POCMsb: POC的高有效位.POCMsb的计算方法如下: if( ( pic_order_cnt_lsb < prevPicOrderCntLsb ) &&
( ( prevPicOrderCntLsb – pic_order_cnt_lsb ) >= ( MaxPicOrderCntLsb / 2 ) ) ) PicOrderCntMsb = prevPicOrderCntMsb + MaxPicOrderCntLsb else if( ( pic_order_cnt_lsb > prevPicOrderCntLsb ) && ( ( pic_order_cnt_lsb – prevPicOrderCntLsb ) > ( MaxPicOrderCntLsb / 2 ) ) ) PicOrderCntMsb = prevPicOrderCntMsb – MaxPicOrderCntLsb else PicOrderCntMsb = prevPicOrderCntMsb
这段程序的解释:例:log2_max_poc_lsb_minus4=0,prevPOCMsb=16,prevPOCLsb=1,POCLsb=14. 此时MaxPOCLsb=16,所以POCMsb=0
prevPOCMsb和prevPOCLsb的确定:
(1)
(2)
(3)
(4)
算法: 0模式: 当为帧时 TopFieldOrderCount = POCMsb + POCLsb POCLsb被送到每个slice header.POCMsb在POCLsb达到最大值时增加. BottomFieldOrderCnt = TopFieldOrderCnt + delta_pic_order_cnt_bottom 因为帧时POC=min(TopFOC,BottomFOC) 故只需要计算TopFieldOrderCount = POCMsb + POCLsb 为场时 TopFieldOrderCount = POCMsb + POCLsb BottomFieldOrderCnt= POCMsb + POCLsb
1模式: TopFieldOrderCount = expected POC + delta_pic_order_cnt[0] BottomFieldOrderCount = expected POC + delta[1] (场) = expected POC + offset to bottom field + delta[0] (帧)
2模式: TopFieldOrderCnt = BottomFieldOrderCount =tempPicOrderCnt 没有用作参考时 tempPicOrderCnt = 2 * ( FrameNumOffset + frame_num ) – 1 用作参考时 tempPicOrderCnt = 2 * ( FrameNumOffset + frame_num ) 输出: 当为帧或场对时,输出TopFieldOrderCount和 BottomFieldOrderCnt中的小值; 当为顶场时,输出TopFieldOrderCount; 当为底场时输出BottomFieldOrderCnt.
expectedDeltaPerPicOrder deltaPOC[0]表示一个帧中顶场与expectPOC的差值.[1]表示底场与expectPOC的差值. Offset_for_ref_pic用来计算参考图片间的POC的差值. Offset_for_non_ref_pic用来计算非参考图片间的POC的差值. Num_ref_frame_in_pic_order_cnt_cycle表示在一个POC循环中的参考图片的个数,可以取值0-255,但是在jm75中,设为1.
pic_order_cnt_type=1的时候:
考虑如下序列情况 SPS中设置对于帧编码,offset_for_top_to_bottom_field=0;对于场编码offset_for_top_to_bottom_field=1; 序列1: frame_num: poc: frame_num: poc: frame_num: poc: 此时 对于 num_ref_frames_in_pic_order_cnt_cycle=1,num_ref_frames_in_pic_order_cnt_cycle 表示IDR后一个循环内参考帧的总数.offset_for_ref_frame[0]=4,offset_for_ref_frame表示IDR后参考 帧之间的偏移。 如果要计算poc=12的P帧的POC,如何得到呢?
首先已经知道frame_num=3,num_ref_frames_in_pic_order_cnt_cycle=1,offset_for_ref_frame[0]=4,
则可以得到
absFrameNum=3,picOrderCntCycleCnt =(3-1)/1=2;frameNumInPicOrderCntCyc expectedDeltaPerPicOrder for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ ) expectedDeltaPerPicOrder 则expectedDeltaPerPicOrder expectedPicOrderCnt = picOrderCntCycleCnt * expectedDeltaPerPicOrder for( i = 0; i <= frameNumInPicOrderCntCyc expectedPicOrderCnt = expectedPicOrderCnt + offset_for_ref_frame[ i ] 则expectedPicOrderCnt =12;可以得到 由于是P-slice,此时slice header中 delta_pic_order_cnt[ 0 ]=0;delta_pic_order_cnt[ 1 ]=0; TopFieldOrderCnt = 12;BottomFieldOrderCnt = 12; 序列2: frame_num: poc: frame_num: poc: frame_num: poc: 此时 对于 num_ref_frames_in_pic_order_cnt_cycle=1, offset_for_ref_frame[0]=6。 如果要计算poc=16的B帧的POC,如何得到呢?
首先已经知道frame_num=4,num_ref_frames_in_pic_order_cnt_cycle=1,offset_for_ref_frame[0]=6,
则可以得到
absFrameNum=4-1(因为是B帧不用于参考),picOrderCntCycleCnt =(3-1)/1=2;frameNumInPicOrderCntCyc expectedDeltaPerPicOrder 由于offset_for_non_ref_pic=-2*(连续B帧的数量);这里应该是-4 expectedPicOrderCnt =14;可以得到, 此时slice_header中delta_pic_order_cnt[ 0 ]=2,delta_pic_order_cnt[ 1 ]=0; TopFieldOrderCnt = 16;BottomFieldOrderCnt = 16; 序列2: frame_num: poc: frame_num: poc: frame_num: poc: 此时 对于 num_ref_frames_in_pic_order_cnt_cycle=3, offset_for_ref_frame[3]={4,6,8}。 如果要计算poc=54的P帧的POC,如何得到呢?
首先已经知道frame_num=9,num_ref_frames_in_pic_order_cnt_cycle=3,offset_for_ref_frame[3]={4,6,8},
则可以得到absFrameNum=9,picOrderCntCycleCnt =(9-1)/3=2;frameNumInPicOrderCntCyc expectedDeltaPerPicOrder expectedPicOrderCnt =18*2+4+6+8=54;可以得到, 此时slice_header中delta_pic_order_cnt[ 0 ]=0,delta_pic_order_cnt[ 1 ]=0; TopFieldOrderCnt = 54;BottomFieldOrderCnt = 54; 如果要计算poc=50的B帧的POC,如何得到呢?由于是B帧 absFrameNum=10-1=9,picOrderCntCycleCnt =(9-1)/3=2;frameNumInPicOrderCntCyc 由于连续B帧数目是变化的取平均值为2,此时offset_for_non_ref_pic=-4, expectedPicOrderCnt =18*2+4+6+8-4=50;此时slice_header中delta_pic_order_cnt[ 0 ]=0,delta_pic_order_cnt[ 1 ]=0; pic_order_cnt_type=2的时候: poc是由frame_num推导出来的,这个比较简单,但是应该注意,在这种情况下不存在连续的非参考图象(注释),且解码输出的顺序和显示输出顺序一 致(注释),意思就是说不出现B帧,但可以出现非参考的P场,这也是为什么当nal_ref_idc=0的时候tempPicOrderCnt = 2 * ( FrameNumOffset + frame_num ) – 1的情况。这里保证了参考场的POC始终为偶数,并且大于同帧的另外一个场。 综合三种poc的,类型2应该是最省bit的,因为直接从frame_num获得,但是序列方式限制最大; 类型1,只需要一定的bit量在sps标志出一些信息还在slice header中表示poc的变化,但是比类型0要节省bit,但是其序列并不是随意的,要周期变化;对于类型0因为要对poc的 lsb进行编码所以用到的bit最多,优点是序列可以随意。
注意,H264码流的输出顺序是编码顺序,所以在编码B帧的时候,由于B是双 向预测,需要先编码后面编码帧P/I,这时候先输出I/P,后面才有B帧,我们在解码段拿到相应的I/P帧后,不能马上丢到buffer list里面,还需要等待后面的B帧,解码B帧后再reorder.所以相应产生了两个参数。poc,frame_num,这两个元素在slice级输出frame_num 比如序列IPBPB如果是帧编码,那么0,2,4,6,如果是场编码,那么是0,0,2,2,4,4,4,4,6,6 第一帧I不管top,bottom,都是0,第二帧P,top,bottom都是2,第3帧B,4,第四P也是4,第五B是6 注意B帧不能算编码帧,所以B slice中的frame_num只能等于后向参考帧的frame_num,注意当frame_num达到设定的最大值的时候, frame_num,将重新归0,POC一般是分为两部分,一部分为高位,一部分为低位,上面说的都是低位pic_order_cnt_lsb, 当pic_order_cnt_lsb达到最大值的时候,将向高位Pic_Order_Cnt_Msb进位,高位加上低位才是该场的POC. 在JM中由几个变量类型是int64,为什么可能会有如此的大数,看函数set_ref_pic_num,由于POC是一个一直递增的数值。 有时候list缓冲里面this_ref如果是帧编码 那么top_poc将会等于bottom_poc,为了区分着两个值,因此我们做了扩展,但是这可能导致溢出,所以定义成64位的大数 这些变量似乎是在去块滤波里面有用到,用来计算滤波强度。关于去块滤波的问题,留着下次解决,需要先熟息标准,才能 看源代码....H.264的知识面太宽了,越来越感到它的无边了,作为压缩效率最高,图像质量最好,当然当今最复杂的动态图像压缩标准, JVT工作组从开始着手准备,到现在通过ISO/ITU标准,也不过短短几年时间. 我觉得一天两天,一个月两个月拿下,那是不可能的事情,至今5个月了,我希望自己越来越接近目标, |