RTP PS PES ES H264协议学习

参考:https://www.cnblogs.com/wainiwann/p/7477794.html

https://blog.csdn.net/chenhande1990chenhan/article/details/78744344

https://blog.csdn.net/H514434485/article/details/52064945

https://blog.csdn.net/appledurian/article/details/73134558

https://blog.csdn.net/leopard21/article/details/24818715 

https://blog.csdn.net/appledurian/article/details/70851428 

https://blog.csdn.net/zjf535214685/article/details/60321345

https://blog.csdn.net/twoconk/article/details/52217493

https://blog.csdn.net/linolzhang/article/details/60885130

一些概念

ES流(Elementary Stream原始流),是音、视频信号经过编码器之后或数据信号的基本码流。只包含一种内容。每个ES都由若  干个存取单元(AU)组成,每个视频或音频AU都是由头部和编码数据两部分组成,1个AU相当于编码的1幅视频图像或1个  音频帧  也可以说,每个AU实际上是编码数据流的显示单元,即相当于解码的1幅视频图像或1个音频帧的取样。
PES(Paketized Elementary Stream)是ES经过打包后的码流,长度可变。视频一般一帧一个包,音频一般不超过64KB. 
PTS--(presentation time stamp)显示时间戳,表示显示单元出现在系统目标解码器(H.264、MJPEG等)的时间。
DTS--(Decoding Time Stamp)解码时间戳,表示将存取单元全部字节从解码缓存器移走的时间。
PTS和DTS打在PES包头内,是解决音视频同步,防止解码器输入缓存上溢或下溢的关键。每一个pes header都包含pts和dts,是相对SCR(系统参考)的时间戳,以90000为单位,系统时钟频率(H264采样频率?)为90Khz;所以转换到秒为PTS/90000;如果是以ms为单位的播放器,ms=pts/90;如果是以时钟频率为单位,直接将PTS/DTS送进去解码即可;如果没有B帧,PTS和DTS的顺序应该是一致的,如果有B帧,则需要先解码P帧,才能解出来B帧,所以需要PTS和DTS来控制解码时间和显示时间;
在解码时,pes-->es,音视频的同步,除了使用pts和dts以外,还会用到SCR(system clock reference),
在编码时,都是由STC(system time clock)生成.
   I(关键帧)、P(预测帧)、B(双向预测帧)的包头都有一个PTS和DTS。
   I帧和P帧显示前一定要存储于视频解码器的重新排序缓存器中,经过延迟(重新排序)后再显示,所以一定要分别标明PTS和DTS。无需标出B帧的DTS。

PES包头说明

(一)Packet start code prefix:包头起始码,固定为0x000001,24bit;
(二)Stream id: PES包中的负载流类型,一般视频为0xe0,音频为0xc0,8bit;
(三)PES packet length: PES包长度,包括此字节后的可选包头和负载的长度,16bit;
(四)Optional PES Header,顺序依次为:
 1,’10’字段:2bit;
 2,PES scrambling control:加密模式,2bit;00未加密,01或10或11由用户定义;
 3,PES priority:有效负载的优先级,1bit;1比0的负载优先级高;
 4,Data alignment indicator:数据定位指示器,1bit;
 5,Copyright:版权信息,1为有版权,0无版权,1bit;
 6,Original or copy:原始或备份,1为原始,0为备份,1bit;
 7,7个flags:7bit;一般1表示有指定的可选定段,0表示没有,依次为:
  PTS_flags:DTS_flags:ESCR_flag: ES_rate_flag:
  DSM_trick_mode_flag: Additional_copy_info_flag: PES_CRC_flag: PES_extension_flag: 
 8,PES header data length:PES首部中可选字段和填充字段的长度;8bit;
 9,Optional fields:可选字段的描述信息区域,其内容由上面的7个flag来控制;
  PTS/DTS字段: 40bit,时间占33bit,PTS和DTS的内容是在这40bit中取33位,方式相同,如下:
   start_code:4bit;起始码 依PTS_DTS_flags变化:

     ‘10’,只有PTS,起始码为0010;‘11’, PTS的起始码为0011,DTS的起始码为0001;

   PTS[32..30];1bit;PTS[29..15];1bit;PTS[14..0];1bit;
   计算方法:PTS/DTS  = (PTS1 & 0x0e) << 29 + (PTS2 & 0xfffe) << 14 + (PTS3 & 0xfffe ) >> 1;
  ESCR字段:48bit,由33bit的ESCR_base和9bit的ESCR_extension组成,顺序:
   Reserved: 2bit;ESCR_1[32..30];1bit;ESCR_2[29..15];1bit;ESCR_3[14..0];1bit;
   ESCR_extension:9bit;周期数,取值范围0~299;循环一次,base+1;1bit;
  ES rate字段:目标解码器接收PES分组字节速率,禁止为0,占位24bit;
   1bit;ES_rate:22bit;1bit;
  Trick mode control:表示哪种trick mode被应用于相应的视频流,8bit,
   trick_mode_control占前3bit,后面5bit内容可变;
        ‘000’ ‘011’:field_id:2bit;intra_slice_refresh:1bit;frequency_truncation:2bit;
     ‘001’ ‘100’: rep_cntrl:5bit;

    ‘010’:field_id:2bit;Reserved:3bit;
  Additional copy info字段:8bit,表示和版权相关的私有数据; 
   1bit;copy info字段:7bit;
  Previous PES CRC:16bit,包含CRC值, 
  PES extension:PES扩展字段是否包含的标志,8bit,1表示有此字段,0无。 
   PES_private_data_flag;Pack_header_field_flag;
   Program_packet_sequence_counter_flag;P-STD_buffer_flag;
   Reserved:3bit;PES_extension_flag_2;
      Optional fields :PES扩展字段依上述标志存在的内容顺序为:
        PES_private_data:私有数据128bit;
        Pack_header_field:
         Pack_field_length:指定后面的field的长度,8bit;
         pack_header_field();
       Program_packet_sequence_counter:计数器,16bit; 
        1bit;packet_sequence_counter:7bit;1bit;

                    MPEG1_MPEG2_identifier:1bit,PES包负载来源(1 MPEG1流,0 PS流);

                     original_stuff_length:6bit,(PES头部填充字节长度);
      P-STD_buffer: 16bit; 
         ’01’字段:2bit;
         P-STD_buffer_scale:1bit,表示用来解释后面P-STD_buffer_size字段的比例因子;
           若stream_id为音频流,为0;视频流,为1,其他类型,均可;
         P-STD_buffer_size:13bit;大于或等于所有P-STD输入缓冲区大小BSn的最大值;
           若P-STD_buffer_scale为0,以128字节为单位;为1,以1024字节为单位;
      PES_extension2:扩展字段的扩展字段;N*8bit, 
      1bit;PES_extension_field_length:7bit,表示扩展区域的长度;
             Reserved字段:8*PES_extension_field_length个bit;
 10,Stuffing bytes:填充字段,固定为0xFF;不能超过32个字节;
(五)PES_packet_data_byte:PES包负载中的数据,即ES原始流数据;

RTP包头说明:RTP包最大为1400字节,包头固定为12字节,百度百科上说明如下:

V

P

X

CC

M

PT

序列号

时戳

同步信源(SSRC)标识符

特约信源(CSRC)标识符

···

RTP报文由两部分组成:报头和有效载荷。RTP报头格式如图所示,其中:

V:RTP协议的版本号,占2位,当前协议版本号为2。

P:填充标志,占1位,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。

X:扩展标志,占1位,如果X=1,则在RTP报头后跟有一个扩展报头。

CC:CSRC计数器,占4位,指示CSRC 标识符的个数。

M: 标记,占1位,不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始。

同步信源(SSRC)标识符:占32位,用于标识同步信源。该标识符是随机选择的,参加同一视频会议的两个同步信源不能有相同的SSRC。

 特约信源(CSRC)标识符:每个CSRC标识符占32位,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源。

PT: 有效载荷类型,占7位,用于说明RTP报文中有效载荷的类型,如GSM音频、JPEM图像等。

序列号:占16位,用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1。接收者通过序列号来检测报文丢失情况,重新排序报文,恢复数据。

时戳(Timestamp):占32位,时戳反映了该RTP报文的第一个八位组的采样时刻。接收者使用时戳来计算延迟和延迟抖动,并进行同步控制。

负载大于1400时,需要分片处理,具体的分片方法,以H264I帧数据为例:

   当获取到一帧h264的I帧数据时,先进行PS封装,在视频数据前加

                  PS header + PS system header + PS system Map header 

            加PES头时,由于PES头的负载长度类型是short,最大65536,所以每65536字节的数据后都得加一个PES头,如下: 
                 | PS header | PS system header | PS system Map |PES | data | PES头 | data | PES头 | data| 
            这样PS封装就完成了剩下的就是把封装好的数据分包打RTP包,每1300字节的数据前加一个RTP包头,然后发送出去
 

PS包头说明

PS封装的几个头: 
(1)PS header:14字节 
pack_start_code : (32b) 起始码字段 默认0x000001BA 标志一个包的开始 。marker_bit :(2b) 标记位字段,取值’01’。 
system_clock_reference_base[32..30] :(3b)系统时钟参考字段 。marker_bit : (1b) 标记位字段取值’1’ 
system_clock_reference_base[29..15] : (15b) 系统时钟参考字段 。marker_bit : (1b) 标记位字段取值’1’ 
system_clock_reference_base[14..0] : (15b) 系统时钟参考字段 。marker_bit : (1b) 标记位字段取值’1’ 
system_clock_reference_extension : (9b) 系统时钟参考字段 。marker_bit : (1b) 标记位字段取值’1’

program_mux_rate : (22b) 节目复合速率字段。 marker_bit : (2b) 标记位字段取值’11’ 。reserved : (5b) 填充字段 
pack_stuffing_length : (3b) 包填充长度字段

节目复合速率字段 program_mux_rate 
一个22位整数,规定P-STD在包含该字段的包期间接收节目流的速率。其值以50字节/秒为单位。不允许取0。用于定义P-STD输入端的字节到达时间。在节目多路复合流的不同包中取值可能不同。

如下例:
80 60 00 00 00 00 00 00 0d 25 5a a5    /12字节RTP头/ 
00 00 01 ba 44 00 05 5f 94 01 00 60 1b f8  /PS 头/  红色部分为开始码

蓝色部分为 系统时钟参考字段,二进制:01 000 1 000000000000000 1 010101111110010 1 000000000 1

SCR = 90000/8 = 00000000 00000000 00101011 11110010 (SRC值是累加的,这个是第一帧数据的SRC值) 
000 这三个位段的值是由SCR值的第30-32位填充,参考上述SRC值,故填充3位0 
000000000000000 这15位字段是由SRC值的第15-29位填充,故填充000000000000000

010101111110010 这15位字段是由SRC值的第0-14位填充,故填充 0101011 11110010

橙色部分为节目复合速率, 二进制: 00000000001100000000110 11 11111 000 没看懂用途,尝试随便取值不影响视频和音频,不能取0。

(2) PS system header:18字节,当切仅当第一个数据包时存在。

system_header_start_code : (32b) 开始码 0x000001BB 
header_length : (16) 该字段后的系统标题的字节长度 。 
marker_bit : (1b) 标记位字段取值’1’,rate_bound : (22b) 速率界限字段 。marker_bit : (1b) 标记位字段取值’1’ 
audio_bound : (6b) 音频界限字段 ,fixed_flag : (1b) 固定标志字段 ,CSPS_flag : (1b) CSPS标志字段 
system_audio_lock_flag : (1b) 系统音频锁定标志字段 
system_video_lock_flag : (1b) 系统视频锁定标志字段 。marker_bit : (1b) 标记位字段取值’1’ 
vedio_bound : (5b) 视频界限字段 
packet_rate_restriction_flag: (1b) 分组速率限制标志字段 。reserved_bits : (7b) 保留位字段, 值’111 1111’
stream_id : (8b) 流标识字段 。marker_bit : (2b) 取值’11’ ,
P-STD_buffer_bound_scale : (1b) P-STD缓冲区界限比例,P-STD_buffer_size_bound : (13) P-STD缓冲区大小界限
00 00 01 bb 00 0c 80 1e ff fe e1 7f e0 e0 d8 c0 c0 20 红色为系统头开始码 ,绿色头长度00 0c : 当前字段后该头的长度 12 
粉色速率界限80 1e ff 转成二进制: 1 0000000000111101111111 1 ,可被解码器用于估计是否有能力对整个流解码
fe e1 7f转成二进制: 111111 1 0 1 1 1 00001 0 1111111 
111111: 音频界限字段 audio_bound 6位字段,取值0-32,且不小于节目流中解码过程同时活动的音频流的最大数目。本小节中,若STD缓冲区非空或展现单元正在P-STD模型中展现,则音频流的解码过程是活动的。 
1 : 固定标志字段 fixed_flag 1位标志位。置’1’时表示比特率恒定的操作;置’0’时,表示操作的比特率可变。 
0 : CSPS标志字段 CSPS_flag 1位字段; 1: 音频锁定;1: 视频锁定;00001: 视频界限video_bound 
0: 分组速率限制, packet_rate_restriction_flag 1位标志位。若CSPS标识为’1’,则该字段表示哪个限制适用于分组速率。
1111111 : 7位,保留。

e0 e0 d8 c0 c0 20转成二进制: 11100000 11 1 0000011011000 11000000 11 0 0000000100000 
11100000 : 流标识字段 stream_id ,E0是视频,C0是音频 ;11: 固定值 
1: 用于解释P-STD_buffer_size_bound的比例系数。若stream_id表示音频,值为’0’,则以128字节为单位来度量缓冲区大小的边界。视频流,为’1’,则以1024字节为单位来度量缓冲区大小的边界。其它类型未定义。

(3) PS Map Header:30字节 
packet_start_code_prefix : (24b) 开始码 0x000001 ;map_stream_id : (8) 映射流标识字段 值为0xBC 
program_stream_map_length: (16) 节目流映射长度字段 
current_next_indicator : (1) 当前下一个指示符字段; reserved : (2);program_stream_map_version: (5) 节目流映射版本 
reserved : (7) ;marker_bit : (1) ;program_stream_info_length : (16) 节目流信息长度字段 
elementary_stream_map_length: (16) 基本流映射长度字段 ;stream_type : (8) 流类型字段 
elementary_stream_id : (8) 基本流标识字段 ;elementary_stream_info_length : (16) 基本流信息长度字段 
CRC_32 : (32) CRC 32字段

00 00 01 bc 00 18 e1 ff 00 00 00 08 1b e0 00 00 90 c0 00 00 23 b9 0f 3d;00 00 01 bc 开始码加固定id ;00 18 头的长度 
e1 ff 00 00 00 08二进制: 111 00001 1111111 1 0000000000000000 0000000000001000 
1: current_next_indicator 。置’1’传送的节目流映射当前是可用的。’0’传送的节目流映射不可用,将是下一个生效的表。 
11: 填充;00001: 节目流映射版本,表示整个节目流映射的版本号。一旦节目流映射的定义变化,将递增1,并对32取模。current_next_indicator为’1’时,是当前适用的节目流映射的版本号;为’0’时,是下一个适用的节目流映射的版本号。

1111111: 填充;1填充;0000000000000000: 节目流信息长度 ,指出紧跟在该字段后的描述符总长度 ;
0000000000001000: 基本流映射长度,指出在该节目流映射中的所有基本流信息(只包括stream_type(1B)、elementary_stream_id(1B)和elementary_stream_info_length(2B))的字节长度。(elementary_stream_map_length/4可得到后面定义了几个流类型信息。) 
1b e0 00 00: 流类型,1b是H264视频流;基本流标识,e0 :指视频 ;00 00基本流信息长度,0字节的视频描述字节 
90 c0 00 00: 90是G.711 音频流:0x90;c0指音频 ;00 00:0个字节描述符 
23 b9 0f 3d : 32位字段,它包含CRC值以在处理完整个节目流映射后在附录A中定义的解码器寄存器产生0输出值。

(4) PS PES Header:(变长),详见上面的PES头说明

packet_start_code_prefix : (24b) 分组起始码前缀字段 packet_start_code_prefix 0x000001 
stream_id : (8) 流标识字段 stream_id 这个字段的定义,其中0x(C0~DF)指音频,0x(E0~EF)为视频 
PES_packet_length : (16) PES分组长度字段 PES_packet_length 
‘10’ : (2) ;PES_scrambling_control : (2) PES加扰控制字段 PES_scrambling_control 
PES_priority : (1) PES优先级字段 PES_priority ;data_alignment_indicator : (1) 数据对齐指示符字段 data_alignment_indicator 
copyright: (1) 版权字段 copyright ;original_or_copy : (1) 原始或拷贝字段 original_or_copy 
PTS_DTS_flags : (2) PTS DTS标志 ;ESCR_flag : (1) ESCR标志 ;ES_rate_flag : (1) ES速率标志;
DSM_trick_mode_flag : (1) DSM特技方式标志;additional_copy_info_flag : (1) 附加版权信息标志;
PES_CRC_flag : (1) PES CRC标志;PES_extension_flag: (1) PES扩展标志;
PES_header_data_length: (8) PES标题数据长度字段 PES_header_data_length 
‘0011’ : (4) ;PTS[32..30] : (3) 展现时间戳字段 PTS ;marker_bit: (1) ;PTS[29..15] : (15) ;
marker_bit : (1) ;PTS[14..0] : (15) ;marker_bit : (1);
00 00 01 e0 49 e6 88 80 05 31 00 01 57 e5 00 00 01: 开始码  e0 : 视频  49 e6: 视频数据长度 
88 80 05 :二进制数据10 00 1 0 0 0 10 0 0 0 0 0 0 00000101 
10 : 固定值 ,00: PES加扰控制 ,1: PES优先级  ‘1’表示PES分组中有效负载的优先级高于为’0’的PES分组有效负载 
0: 数据对齐指示符   当值为’0’时,没有定义。 0: 版权  0: 原始或拷贝  置’1’负载是原始的;’0’负载是一份拷贝

10: PTS DTS标志 只有’10’时,PTS;当值为’11’时,PTS和DTS都有;’00’时,PTS和DTS都无。值’01’是不允许的。 
0 0 0 0 0 0 六个扩展标志位 置0 
00000101 : 数据长度 5 标明后续有五个字节 
31 00 01 57 e5:二进制如下 11 000 1 000000000000000 1 010101111110010 1 
0011: 只有PTS ;PTS = 90000/8 = 11250 二进制: 10101111110010 
000: PTS第30 -32位填充  000000000000000:  PTS第15 -29位填充  010101111110010:  PTS第0 -14位填充
 

RTP荷载PS流
 一、针对H264视频video 做如下PS 封装:
1,每个IDR NALU 前一般都会包含SPS、PPS 等NALU,因此将SPS、PPS、IDR 的NALU 封装为一个PS 包,包括ps 头,然后加上PS system 头,PS system map,PES 头+h264 raw data。
2,一个IDR NALU PS 包由外到内顺序是:PS头| PS system 头| PS system Map | PES 头| h264 raw data。对于其它非关键帧的PS 包,直接加上PS头和PES 头就可以了。
顺序:PS 头| PES 头| h264raw data。
二、当有音频数据时,将数据加上PES header 放到视频PES 后就可以了。
顺序:PS头|PES(video)|PES(audio),再用RTP 封装发送就可以了。
GB28181 对RTP 传输的数据负载类型范围:96-127 。RFC2250 建议:96 ,PS; 97 ,MPEG-4;98 ,H264。
收到的RTP 包首先需要判断负载类型,若为96,则采用PS 解复用,将音视频分开解码。98,直接按照H264 类型解码

H264格式说明:

1、    H264的功能分为两层:视频编码层(VLC,Video Coding Layer)和网络抽象层(NAL, Network Abstraction Layer)。VLC数据即编码处理的输出,表示被压缩编码后的视频数据序列。VCL数据传输或存储之前,这些数据先被映射或封装进NAL单元。每个NAL单元包括一个原始字节序列负荷(RBSP, Raw Byte Sequence Payload)、一组对应于视频编码的NAL头信息。

起始码startcode:如果NALU对应的Slice为一帧的开始,则4字节,即0x00000001;否则3字节,即0x000001。起始码之后即为NAL单元。NAL_Size的长度不包括起始码。
SODB:(String of Data Bits)最原始的编码数据,无任何附加数据。
RBSP:在SODB的基础上增加了rbsp_stop_ont_bit(bit值为1)并用0按字节补位对齐。基本结构是在原始编码数据的后面添加了结尾比特。一个bit"1",若干比特"0",以便字节对齐。
每个NAL单元包括NAL头+RBSP。NAL单元序列如下:
 
典型的RBSP单元如下: 
NAL头结构为:|0|1|2|3|4|5|6|7|   |F|NRI|  Type   |
NAL头说明:
 

EBSP:(Encapsulation Byte Sequence Packets)在RBSP的基础上增加了防止伪起始码字节(0x03)。为了使NALU的主体不包括起始码,在编码的时候每遇到两个字节(连续)的0,就插入一个字节0x03,以便和起始码相区别,解码时,则将相应的0x03删除掉。所以有时候NAL单元有可能是NAL头+EBSP组成。
NALU主体 编码时插入0x03如:0x000000  >>>  0x00000300  0x000001  >>>  0x00000301
接下来对应刚刚的H264,其文件数据表示如下:
 
前面两个0x00000001对应PPS和SPS,第三个0x000001对应SEI。
2、    SPS、PPS和SEI。
1、SPS即Sequence Paramater Set序列参数集。SPS中保存了一组编码视频序列(Coded video sequence)的全局参数。所谓的 编码视频序列即原始视频的一帧一帧的像素数据经过编码之后的结构组成的序列。一般情况SPS和PPS的NAL Unit通常位于 整个码流的起始位置。特殊情况下,码流中间也可能出现这两种结构,可能为:
      1)解码器需要在码流中间开始解码;
      2)编码器在编码的过程中改变了码流的参数(如图像分辨率等);
      在做视频播放器时,为了让后续的解码过程可以使用SPS中包含的参数,必须对其中的数据进行解析。
2、PPS即Picture Paramater Set(PPS) 图像参数集。每一帧编码后数据所依赖的参数保存于图像参数集PPS中。PPS类似于  SPS,在H.264的裸码流中单独保存在一个NAL Unit中,PPS NAL Unit的nal_unit_type值为8;在封装格式中,PPS通常与   SPS一起,保存在视频文件的文件头中。
   有的文件每个IDR帧前面都有PPS和SPS,有的只是开头才有。一般来说:
      1)、直播每个IDR帧前面都应加SPS和PPS,因为观众会中途进来观看。
      2)、本地文件可在开头加SPS和PPS,或都加。

3、SEI(Supplemental Enhancement Information):辅助增强信息。可存放简介,版权或私有信息。有的H264文件有SEI,有的没 有,对播放并无影响。

PPS说明:


  (1) pic_parameter_set_id当前PPS的id。某个PPS在码流中会被相应的slice引用,引用方式就是在Slice header中保存PPS的id值。取值[0,255]。
(2) seq_parameter_set_id当前PPS引用的激活的SPS的id。这样PPS中可取到对应SPS中的参数。取值[0,31]。
(3) entropy_coding_mode_flag熵编码模式标识,表示码流中熵编码/解码选择的算法。对于部分语法元素,在不同的编码配置下,选择的熵编码方式不同。例如在一个宏块语法元素中,宏块类型mb_type的语法元素描述符为“ue(v) | ae(v)”,在baseline profile等设置下采用指数哥伦布编码,在main profile等设置下采用CABAC编码。该值为0时,选择左边的算法,通常为指数哥伦布编码或CAVLC;为1时,选择右边的算法,通常为CABAC。
(4) bottom_field_pic_order_in_frame_present_flag标识位,表示delta_pic_order_cnt_bottom和delta_pic_order_cn是否存在。这两个语法元素表示了某一帧的底场的POC的计算方法。
(5) num_slice_groups_minus1表示某一帧中slice group的个数。为0时,一帧中所有的slice都属于一个slice group。slice group是一帧中宏块的组合方式,定义在协议文档的3.141部分。
(6) num_ref_idx_10_default_active_minus1、num_ref_idx_11_default_active_minus1表示当Slice Header中的num_ref_idx_active_override_flag标识位为0时,P/SP/B slice的语法元素num_ref_idx_10_active_minus1和num_ref_idx_11_active_minus1的默认值。
(7) weighted_pred_flag标识位,表示在P/SP slice中是否开启加权预测。
(8) weighted_bipred_idc表示在B Slice中加权预测方法。0默认,1显式,2隐式。
(9) pic_init_qp_minus26和pic_init_qs_minus26表示初始的量化参数。实际的量化参数由该参数与slice header中的slice_qp_delta/slice_qs_delta计算得到。
(10) chroma_qp_index_offset计算色度分量的量化参数,取值[-12,12]。
(11) deblocking_filter_control_present_flag表示Slice header中是否存在用于去块滤波器控制的信息。
(12) constrained_intra_pred_flag为1,表示I宏块在进行帧内预测时只能使用来自I和SI类型宏块的信息; 0,表示I宏块可使用来自Inter类型宏块的信息。
(13) redundant_pic_cnt_present_flag表示Slice header中是否存在redundant_pic_cnt语法元素。
3 解析SDP中包含的H.264的SPS和PPS串。SDP中的SPS和PPS都是BASE64编码形式的,需要解析。
RTP传输H264的时候,需要用到sdp协议描述,其中需要从H264码流中获取到PPS,SPS。H264码流中,以"0x00 00 01"或"0x00 00 00 0x01"为开始码,其后的第一个字节的低5位判断是否为7(sps)或8(pps),然后对获取的nal去掉开始码之后进行base64编码,得到的信息就可以用于sdp。sps和pps需要用逗号分隔开来.

SPS说明:


 (1) SPS中,第一个字节表示profile_idc:标识当前H.264码流的profile。H.264中定义了三种常用的档次profile:
基准档次:baseline=66;主要档次:main=77;扩展档次:extended=88;
新版标准中,还包括了High、High 10、High 4:2:2、High 4:4:4、High 10 Intra、High 4:2:2 Intra、High 4:4:4 Intra、CAVLC 4:4:4 Intra等,每一种都由不同的profile_idc表示。
constraint_set0_flag ~ constraint_set5_flag是在编码的档次方面对码流增加的限制条件。
(2) level_idc标识当前码流的Level。定义了某种条件下的最大视频分辨率、最大视频帧率等参数。
(3) seq_parameter_set_id当前的序列参数集的id。通过该id值,图像参数集pps可以引用其代表的sps中的参数。
(4) log2_max_frame_num_minus4用于计算MaxFrameNum= 2^(log2_max_frame_num_minus4 + 4)。MaxFrameNum是frame_num(图像序号的一种表示方法,在帧间编码中常用作一种参考帧标记的手段)的上限值。
(5) pic_order_cnt_type表示解码picture order count(POC)的方法。POC是另一种计量图像序号的方式,与frame_num有着不同的计算方法。该语法元素的取值为0、1或2。
(6) log2_max_pic_order_cnt_lsb_minus4用于计算MaxPicOrderCntLsb = 2^(log2_max_pic_order_cnt_lsb_minus4 + 4),该值表示POC的上限。
 (7) max_num_ref_frames表示参考帧的最大数目。
(8) gaps_in_frame_num_value_allowed_flag标识位,说明frame_num中是否允许不连续的值。
(9) pic_width_in_mbs_minus1用于计算图像的宽度。单位为宏块个数。
frame_width = 16 × (pic\_width\_in\_mbs_minus1 + 1);
(10) pic_height_in_map_units_minus1用来度量视频中一帧图像的高度。图高并非图像明确的以像素或宏块为单位的高度,需要考虑该宏块是帧或场编码。PicHeightInMapUnits = pic\_height\_in\_map\_units\_minus1 + 1;
(11) frame_mbs_only_flag标识位,说明宏块的编码方式。为0时,宏块可能为帧编码或场编码 表示一场数据;为1时,所有宏块都采用帧编码,表示一帧数据。
按照宏块计算的图像实际高度:FrameHeightInMbs = ( 2 − frame_mbs_only_flag ) * PicHeightInMapUnits
(12) mb_adaptive_frame_field_flag标识位,说明是否采用了宏块级的帧场自适应编码。
为0时,不存在帧、场编码之间的切换;为1时,宏块可能在帧、场编码模式之间选择。
(13) direct_8x8_inference_flag标识位,用于B_Skip、B_Direct模式运动矢量的推导计算。
(14) frame_cropping_flag标识位,说明是否需要对输出的图像帧进行裁剪。
(15) vui_parameters_present_flag标识位,说明SPS中是否存在VUI信息。
 

RTP封装PS的H264流及音频流

H264由NALU单元组成,视频帧起始码I帧是  00 00 00 01 65  非I帧 00 00 00 01 41

                                            SPS起始码 00 00 00 01 67     PPS起始码 00 00 00 01 68           

I帧前面需要增加PS头+System 头+ System Map 头+ PES 头

非I帧前面增加PS 头 + PES 头

当有音频数据时,将数据加上PES header 放到视频PES 后就可以了。

猜你喜欢

转载自blog.csdn.net/DANFBAORE/article/details/84027396