关闭

从SPS帧解析视频分辨率

6500人阅读 评论(1) 收藏 举报
分类:

一 H.264句法

1.1元素分层结构

H.264编码器输出的Bit流中,每个Bit都隶属于某个句法元素。句法元素被组织成有层次的结构,分别描述各个层次的信息。

 

 

图1

H.264分层结构由五层组成,分别是序列参数集、图像参数集、片(Slice)、和宏块和子块。参数集是一个独立的数据单位,不依赖于参数集外的其它句法元素。图2描述了参数集与参数集外的句法元素之间的关系。

 

图2

一个参数集不对应某一个特定的图像或序列,同一序列参数集可以被多个图像参数集引用,同理,同一个图像参数集也可以被多个图像引用。只在编码器认为需要更新参数集的内容时,才会发出新的参数集。

 

在H.264中,图像以序列为单位进行组织。一个序列的第一个图像叫做IDR图像,IDR图像都是I帧,H.264引入IDR图像为了解码的同步,当解码器解码到IDR图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。

 

IDR是I帧,但I帧不一定是IDR。I帧之后的图像有可能会使用I帧之前的图像做运动参考。

 

1.2描述子

描述子描述从Bit流中取出句法元素的方法。

编号

语法

说明

1

ae(e)

CABAC

2

b(8)

读进连续的8个Bit

3

ce(v)

CAVLC

4

f(n)

读进连续的n个Bit

5

i(n)/i(v)

读进连续的若干Bit,并把它们解释为有符号整数

6

me(v)

映射指数Golomb熵编码

7

se(v)

有符号指数Golomb熵编码

8

te(v)

截断指数Golomb熵编码

9

u(n)/u(v)

读进连续的若干Bit,并把它们解释为无符号整数

10

ue(v)

无符号指数Golomb熵编码

表1

1.3句法的表示方法

句法元素的名称由小写字母和一系列下划线组成,变量名称是大小写字母组成,中间没有下划线。

二 句法表

定义了H.264的句法,指明在码流中依次出现的句法元素及它们出现的条件、提取描述子等。句法表是分层嵌套的。

句法表中的C字段表示该句法元素的分类,这是为片区服务,分类的具体含义如下表描述。

nal_unit_type

NAL类型

C

0

未使用

 

1

不分区、非IDR的片

2,3,4

2

片分区A

2

3

片分区B

3

4

版分区C

4

5

IDR图像中的片

2,3

6

补充增强信息单元(SEI)

5

7

序列参数集

0

8

图像参数集

1

9

分界符

6

10

序列结束

7

11

码流结束

8

12

填充

9

13..23

保留

 

24..31

不保留

 

表2

2.1 NAL语法

 

句法

C

Desc

nal_nuit(NumBytesInNALunit){/* NumBytesInNALunit为统计出来的数据长度 */

 

 

    forbidden_zero_bit /* 等于0 */

All

f(1)

    nal_ref_idc/* 当前NAL的优先级,取值范围0-3 */

All

u(2)

    nal_unit_type /* NAL类型,见表2描述 */

All

u(5)

    NumBytesInRBSP=0

 

 

    for(i=1;i<NumBytesInNALunit;i++){

 

 

        if(i+2<NumBytesInNALunit && next_bits(24)==0x000003{

 

 

        /* 0x000003伪起始码,需要删除0x03这个字节 */

 

 

        rbsp_byte[NumBytesInRBSP++]

All

b(8)

        rbsp_byte[NumBytesInRBSP++]

All

b(8)

        i+=2/* 取出前两个0x00后,跳过0x03 */

 

 

        emulation_prevention_three_byte/* equal to 0x03 */

All

f(8)

    }else{

 

 

        rbsp_byte[NumBytesInRBSP++] /* 继续读取后面的字节 */

All

b(8)

    }

 

 

}

 

 

表3

2.2序列参数集(SPS)

句法

C

Desc

seq_parameter_set_rbsp(){

 

 

    profile_idc/* 指明所用的Profile */

0

u(8)

    constraint_set0_flag

0

u(1)

    constraint_set1_flag

0

u(1)

    constraint_set1_flag

0

u(1)

    reserved_zero_5bits /* equal to 0 */

0

u(5)

    level_idc /* 指明所用的Level */

0

u(8)

    seq_parameter_set_id /* 指明本序列参数集的id号,0-31,被图像集引用,编码需要产生新的序列集时,使用新的id,而不是改变原来参数集的内容 */

0

ue(v)

    log2_max_frame_num_minus4/* 为读取元素frame_num服务,frame_num标识图像的解码顺序,frame_num的解码函数是ue(v),其中v=log2_max_frame_num_minus4+4,该元素同时指明frame_num的最大值MaxFrameNum=2( log2_max_frame_num_minus4+4)*/

0

ue(v)

    pic_order_cnt_type /* 指明poc的编码方法,poc标识图像的播放顺序,poc可以由frame_num计算,也可以显示传送。poc共三种计算方式 */

0

ue(v)

    if(pic_order_cnt_type==0)

 

 

        log2_max_pic_order_cnt_lsb_minus4 /* 指明变量MaxPicOrderCntLsb的值, MaxPicOrderCntLsb2(log2_max_pic_order_cnt_lsb_minus4+4) */

0

ue(v)

    else if(pic_order_cnt_type==1){

 

 

        delta_pic_order_always_zero_flag /* 等于1时,元素delta_pic_order_cnt[0]delta_pic_order_cnt[1]不在片头中出现,并且它们的默认值是0,等于0时,上述两元素出现的片头中 */

0

u(1)

        offset_for_non_ref_pic /* 用来计算非参考帧或场的poc[-231,231-1] */

0

se(v)

        offset_for_top_to_bottom_field/* 计算帧的底场的poc */

0

se(v)

        num_ref_frames_inpic_order_cnt_cycle /* 用来解码poc,[0.255] */

0

ue(v)

        for(i=0;i<num_ref_frames_inpic_order_cnt_cycle;i++)

 

 

            offset_for_ref_frame[i]/* 用来解码poc,对于循环中的每个元素指定一个偏移 */

0

se(v)

    }

 

 

    num_ref_frames /* 参考帧队列可达到的最大长度,[0,16] */

0

ue(v)

    gaps_in_frame_num_value_allowed_flag /* 为1,允许slice header中的frame_num不连续 */

0

u(1)

    pic_width_inmbs_minus1 /* 本元素加1,指明以宏块为单位的图像宽度 PicWidthInMbs=pic_width_in_mbs_minus1+1 */

0

ue(v)

    pic_height_in_map_units_minus1 /* 本元素加1,指明以宏块为单位的图像高宽度 PicHeightInMapUnitsMbs=pic_height_in_map_units_minus1+1 */

0

ue(v)

    frame_mbs_only_flag /* 等于0表示本序列中所有图像均为帧编码;等于1,表示可能是帧,也可能场或帧场自适应,具体编码方式由其它元素决定。结合前一元素:FrameHeightInMbs=(2-frame_mbs_only_flag)*PicHeightInMapUnits */

0

ue(v)

    if(frame_mbs_only_flag)

 

 

      mb_adaptiv_frame_field_flag /* 指明本序列是否是帧场自适应模式:

frame_mbs_only_flag=1,全部是帧

frame_mbs_only_flag=0 mb_adaptiv_frame_field_flag=0,帧场共存

frame_mbs_only_flag=0 mb_adaptiv_frame_field_flag=1,帧场自适应和场共存*/

0

u(1)

    direct_8x8_inference_flag /* 用于指明B片的直接和skip模式下的运动矢量的计算方式 */

0

u(1)

    frame_cropping_flag /* 解码器是否要将图像裁剪后输出,如果是,后面为裁剪的左右上下的宽度 */

0

u(1)

    if(frame_cropping_flag){

 

 

        frame_crop_left_offset

0

ue(1)

        frame_crop_right_offset

0

ue(1)

        frame_crop_top_offset

0

ue(1)

        frame_crop_bottom_offset

0

ue(1)

    }

 

 

    vui_parameters_present_flag /* 指明vui子结构是否出现在码流中,vui子结构在附录中指明,用于表征视频格式的信息 */

0

u(1)

    if(vui_parameters_present_flag)

 

 

        vui_parameters()

0

 

    rbsp_trailing_bits()

0

 

}

 

 

表4

//////////////////////////////////////////////////////////////////////////代码//////////////////////////////////////////////////////////////////////////////////

以下是解析宽高的代码:

001 bool UDPReceiver::getResolution(int channel, int &Width, int& Height)
002 {
003     BYTE *buf = new BYTE[1024];
004     int nLen;
005     AVPacket packet;
006     BOOL bSpsComplete = FALSE;
007     // Find SPS
008     while(!bSpsComplete)
009     {
010         int ret = av_read_frame(m_pFormatContext[channel], &packet);
011         if(packet.flags & AV_PKT_FLAG_KEY)
012         {
013             BYTE* p = packet.data;
014             BYTE last_nal_type = 0;
015             int last_nal_pos = 0;
016             for(int i=0; i<packet.size-5; i++)
017             {
018                 p = packet.data + i;
019                 if(p[0]==0x00&&p[1]==0x00&&p[2]==0x00&&p[3]==0x01)
020                 {
021                     if(last_nal_type == 0x67)
022                     {
023                         nLen = i-last_nal_pos;
024                         memcpy(buf, packet.data+last_nal_pos, nLen);
025                         bSpsComplete = TRUE;
026                     }
027                     last_nal_type = p[4];
028                     last_nal_pos = i;
029                     if(bSpsComplete)
030                     {
031                         break;
032                     }
033                 }
034             }
035             if (last_nal_type == 0x67 && bSpsComplete == FALSE)
036             {
037                 nLen = packet.size - last_nal_pos;
038                 memcpy(buf, packet.data+last_nal_pos, nLen);
039                 bSpsComplete = TRUE;
040             }
041         }
042     }
043     // Analyze SPS to find width and height
044     UINT StartBit=0; 
045         buf = buf + 4;
046     int forbidden_zero_bit=u(1,buf,StartBit);
047     int nal_ref_idc=u(2,buf,StartBit);
048     int nal_unit_type=u(5,buf,StartBit);
049     if(nal_unit_type==7)
050     {
051         int profile_idc=u(8,buf,StartBit);
052         int constraint_set0_flag=u(1,buf,StartBit);//(buf[1] & 0x80)>>7;
053         int constraint_set1_flag=u(1,buf,StartBit);//(buf[1] & 0x40)>>6;
054         int constraint_set2_flag=u(1,buf,StartBit);//(buf[1] & 0x20)>>5;
055         int constraint_set3_flag=u(1,buf,StartBit);//(buf[1] & 0x10)>>4;
056         int reserved_zero_4bits=u(4,buf,StartBit);
057         int level_idc=u(8,buf,StartBit);
058   
059         int seq_parameter_set_id=Ue(buf,nLen,StartBit);
060   
061         if( profile_idc == 100 || profile_idc == 110 ||
062             profile_idc == 122 || profile_idc == 144 )
063         {
064             int chroma_format_idc=Ue(buf,nLen,StartBit);
065             if( chroma_format_idc == 3 )
066                 int residual_colour_transform_flag=u(1,buf,StartBit);
067             int bit_depth_luma_minus8=Ue(buf,nLen,StartBit);
068             int bit_depth_chroma_minus8=Ue(buf,nLen,StartBit);
069             int qpprime_y_zero_transform_bypass_flag=u(1,buf,StartBit);
070             int seq_scaling_matrix_present_flag=u(1,buf,StartBit);
071   
072             int seq_scaling_list_present_flag[8];
073             if( seq_scaling_matrix_present_flag )
074             {
075                 for( int i = 0; i < 8; i++ ) {
076                     seq_scaling_list_present_flag[i]=u(1,buf,StartBit);
077                 }
078             }
079         }
080         int log2_max_frame_num_minus4=Ue(buf,nLen,StartBit);
081         int pic_order_cnt_type=Ue(buf,nLen,StartBit);
082         if( pic_order_cnt_type == 0 )
083             int log2_max_pic_order_cnt_lsb_minus4=Ue(buf,nLen,StartBit);
084         else if( pic_order_cnt_type == 1 )
085         {
086             int delta_pic_order_always_zero_flag=u(1,buf,StartBit);
087             int offset_for_non_ref_pic=Se(buf,nLen,StartBit);
088             int offset_for_top_to_bottom_field=Se(buf,nLen,StartBit);
089             int num_ref_frames_in_pic_order_cnt_cycle=Ue(buf,nLen,StartBit);
090   
091             int *offset_for_ref_frame=new int[num_ref_frames_in_pic_order_cnt_cycle];
092             for( int i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
093                 offset_for_ref_frame[i]=Se(buf,nLen,StartBit);
094             delete [] offset_for_ref_frame;
095         }
096         int num_ref_frames=Ue(buf,nLen,StartBit);
097         int gaps_in_frame_num_value_allowed_flag=u(1,buf,StartBit);
098         int pic_width_in_mbs_minus1=Ue(buf,nLen,StartBit);
099         int pic_height_in_map_units_minus1=Ue(buf,nLen,StartBit);
100   
101         Width=(pic_width_in_mbs_minus1+1)*16;
102         Height=(pic_height_in_map_units_minus1+1)*16;
103   
104         return true;
105     }
106     else
107     {
108         return false;
109     }
110 }
111   
112 // Ue find the num of zeros and get (num+1) bits from the first 1, and 
113 // change it to decimal
114 // e.g. 00110 -> return 6(110)
115 UINT UDPReceiver::Ue(BYTE *pBuff, UINT nLen, UINT &nStartBit)
116 {
117     //计算0bit的个数
118     UINT nZeroNum = 0;
119     while (nStartBit < nLen * 8)
120     {
121         if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) //&:按位与,%取余
122         {
123             break;
124         }
125         nZeroNum++;
126         nStartBit++;
127     }
128     nStartBit ++;
129   
130   
131     //计算结果
132     DWORD dwRet = 0;
133     for (UINT i=0; i<nZeroNum; i++)
134     {
135         dwRet <<= 1;
136         if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
137         {
138             dwRet += 1;
139         }
140         nStartBit++;
141     }
142     return (1 << nZeroNum) - 1 + dwRet;
143 }
144   
145 int UDPReceiver::Se(BYTE *pBuff, UINT nLen, UINT &nStartBit)
146 {
147     int UeVal=Ue(pBuff,nLen,nStartBit);
148     double k=UeVal;
149     int nValue=std::ceil(k/2);//ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00
150     if (UeVal % 2==0)
151         nValue=-nValue;
152     return nValue;
153 }
154   
155 // u Just returns the BitCount bits of buf and change it to decimal.
156 // e.g. BitCount = 4, buf = 01011100, then return 5(0101)
157 DWORD UDPReceiver::u(UINT BitCount,BYTE * buf,UINT &nStartBit)
158 {
159     DWORD dwRet = 0;
160     for (UINT i=0; i<BitCount; i++)
161     {
162         dwRet <<= 1;
163         if (buf[nStartBit / 8] & (0x80 >> (nStartBit % 8)))
164         {
165             dwRet += 1;
166         }
167         nStartBit++;
168     }
169     return dwRet;
170 }

 

1
1

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:652688次
    • 积分:7355
    • 等级:
    • 排名:第2968名
    • 原创:53篇
    • 转载:269篇
    • 译文:9篇
    • 评论:164条
    最新评论