织梦CMS - 轻松建站从此开始!

罗索

h264 poc

落鹤生 发布于 2012-11-27 18:01 点击:次 
POCLsb: POC的低有效位.通过slice header传送到解码端.由于编码端知道传送的序列的顺序,所以在编码端,POC的值由以下方法确定
TAG:

关于参数的注解:

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)    当前图片为IDR图片时, prevPOCMsb= prevPOCLsb=0;

(2)    非IDR,但mmco=5时,而且非底场时prevPOCMsb=0, prevPOCLsb=prevTopFOC;

(3)    非IDR,mmco不等于5,为底场时prevPOCMsb= prevPOCLsb=0;

(4)    除以上情况外Msb和Lsb都等于前一幅图片的Msb和Lsb.

 

算法:

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.


expectedDeltaPerPicOrderCntCycle: 一个POC循环的期望delta值.等于在这个POC循环中的所有delta值之和.

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:                           2
                              循环二
frame_num:              
poc:                      6
                              循环三
frame_num:              
poc:                12       10

此时
对于
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;frameNumInPicOrderCntCycle=(3-1)%1=0;
expectedDeltaPerPicOrderCntCycle = 0
for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
expectedDeltaPerPicOrderCntCycle += offset_for_ref_frame[ i ]
则expectedDeltaPerPicOrderCntCycle =4;
expectedPicOrderCnt = picOrderCntCycleCnt * expectedDeltaPerPicOrderCntCycle
for( i = 0; i <= frameNumInPicOrderCntCycle; i++ )
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:                2 
poc:                            4
                                   循环二
frame_num:               
poc:               12          10
                                     循环三
frame_num:             4 
poc:                18      14    16

此时
对于
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;frameNumInPicOrderCntCycle=(3-1)%1=0;
expectedDeltaPerPicOrderCntCycle =6;
由于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:                              4
poc:                            10        18   12  14  16
  
                                                 循环二
frame_num:                             
poc:              22     20    28    24   26   36   30  32  34
                                                 循环三
frame_num:                     10   10  10
poc:              40     38    46    42   44   54  48   50  52
此时
对于
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;frameNumInPicOrderCntCycle=(9-1)%3=2;
expectedDeltaPerPicOrderCntCycle =18;
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;frameNumInPicOrderCntCycle=(9-1)%3=2;
由于连续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级输出

 POC,和frame_num的概念:
 POC picture order count,是一个顺序计数器,代表显示顺序,假如是场编码,那么分别要对两场都有不同的值,比如对第一帧的两场top,bottom分别为0,1所有的帧都包括在里面,包括B帧也需要计数,比如序列IPBPB,假如是帧编码,那么序号分别为0,4,2,8,6,顶底两场分别为0,0,4,4,2,2,8,8,6,6实际上这个并不输出到码流里面,假如是场变码那么是0,1,4,5,2,3,8,9,6,7
frame_num ,是一个顺序计数器,代表帧的编码顺序,由于代表帧,计数器递增基数为2,所以总是偶数,
比如序列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如果是帧编码
    enc_picture->top_ref_pic_num    [LIST_0][i] = this_ref->top_poc * 2;
    enc_picture->bottom_ref_pic_num [LIST_0][i] = this_ref->bottom_poc * 2 + 1;
那么top_poc将会等于bottom_poc,为了区分着两个值,因此我们做了扩展,但是这可能导致溢出,所以定义成64位的大数
这些变量似乎是在去块滤波里面有用到,用来计算滤波强度。关于去块滤波的问题,留着下次解决,需要先熟息标准,才能
看源代码....H.264的知识面太宽了,越来越感到它的无边了,作为压缩效率最高,图像质量最好,当然当今最复杂的动态图像压缩标准,
JVT工作组从开始着手准备,到现在通过ISO/ITU标准,也不过短短几年时间.
我觉得一天两天,一个月两个月拿下,那是不可能的事情,至今5个月了,我希望自己越来越接近目标,
( 南冠彤)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201211/16396.html]
本文出处:新浪博客 作者: 南冠彤 原文
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容