从SPS帧解析视频分辨率

转载 2013年12月05日 13:53:14

一 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 }

 

相关文章推荐

h.264码流解析_一个SPS的nalu及获取视频的分辨率

00 00 00 01 67 42 00 28 E9 00  A0 0B 77 FE 00 02 00 03 C4 80  00 00 03 00 80 00 00 1A 4D 88  1...

h265 sps 数据解析

typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned long uint32; typedef un...

解析h264 sps中获取帧率和分辨率记录

从live555中提取代码出来,可以成功获取分辨率和帧率,帧率主要是获取num_units_in_tick和time_scale两个参数; 其中遇到了以下问题: 与网友类似的问题,这里截取了他的问...
  • tuyooc
  • tuyooc
  • 2015年03月12日 23:13
  • 4897

h264 sps pps详解

1、学习路线 step1、初步了解h264,了解h264数据帧分类和识别 step2、h264专业名词解析 step3、sps、pps帧语法定义 2、h264简介   3、h264名词解析   4、s...

H264 SPS分析

SPS: sequence parameter sets01. Profile_idc它指的是码流对应的profile.1.1 基线profile(Baseline profile)遵循基线profi...

H.264码流解析 一个SPS的nalu及获取视频的分辨率

00 00 00 01 67 42 00 28 E9 00   A0 0B 77 FE 00 02 00 03 C4 80   00 00 03 00 80 00 00 1A 4D 88   10 9...

通过sps和pps得到视频的width和height

You must run a complex function to extract video dimensions from Sequence Parameter Sets. How to do ...

H.264码流解析 一个SPS的nalu及获取视频的分辨率

00 00 00 01 67 42 00 28 E9 00   A0 0B 77 FE 00 02 00 03 C4 80   00 00 03 00 80 00 00 1A 4D 88   10 9...

H264中的SPS、PPS提取与作用

牛逼的视频会议网站:http://wmnmtm.blog.163.com/blog/#m=0 ++++++++++++++++++++++++++++++++++++++++++++++++++...
  • sunnylgz
  • sunnylgz
  • 2012年06月20日 16:37
  • 71331

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:从SPS帧解析视频分辨率
举报原因:
原因补充:

(最多只允许输入30个字)