时间:2021-07-01 10:21:17 帮助过:18人阅读
首先我们需要知道PS包流格式是怎么样的:
针对H264 做如下PS 封装:每个IDR NALU 前一般都会包含SPS、PPS 等NALU,因此将SPS、PPS、IDR 的NALU 封装为一个PS 包,包括ps 头,然后加上PS system header,PS system map,PES header+h264 raw data。所以一个IDR NALU PS 包由外到内顺序是:PSheader| PS system header | PS system Map | PES header | h264 raw data。对于其它非关键帧的PS 包,就简单多了,直接加上PS头和PES 头就可以了。顺序为:PS header | PES header | h264raw data。以上是对只有视频video 的情况,如果要把音频Audio也打包进PS 封装,也可以。当有音频数据时,将数据加上PES header 放到视频PES 后就可以了。顺序如下:PS 包=PS头|PES(video)|PES(audio),再用RTP 封装发送就可以了。
上面这是对数据流的一个整体封装格式,下面我们来看看每个封装中的每个部分:
首先是PSheader部分:(来自MPEG2标准中文文档)
语法 | 位数 | 助记符 |
pack_header() { |
|
|
pack_start_code | 32 | bslbf |
'01' | 2 | bslbf |
system_clock_reference_base[32..30] | 3 | bslbf |
marker_bit | 1 | bslbf |
system_clock_reference_base[29..15] | 15 | bslbf |
marker_bit | 1 | bslbf |
system_clock_reference_base[14..0] | 15 | bslbf |
marker_bit | 1 | bslbf |
system_clock_reference_extension | 9 | uimsbf |
marker_bit | 1 | bslbf |
program_mux_rate | 22 | uimsbf |
marker_bit | 1 | bslbf |
marker_bit | 1 | bslbf |
reserved | 5 | bslbf |
pack_stuffing_length | 3 | uimsbf |
for (i=0;i<pack_stuffing_length;i++){ |
|
|
stuffing_byte | 8 | bslbf |
} |
|
|
if (nextbits()==system_header_start_code) { |
|
|
system_header() |
|
|
} |
|
|
} |
|
|
节目流包(PS header)中各字段的语义定义:
包起始码字段 pack_start_code
值为'0000 0000 0000 0000 0000 0001 1011 1010' (0x000001BA)的位串,用来标志一个包的开始。
系统时钟参考字段 system_clock_reference_base,system_clock_reference_extenstion
系统时钟参考(SCR)是一个分两部分编码的42位字段。第一部分system_clock_reference_base是一个长度为33位的字段,其值SCR_base(i)由式2-19给出;第二部分system_clock_reference_extenstion是一个长度为9位的字段,其值SCR_ext(i)由式2-20给出。SCR字段指出了基本流中包含ESCR_base最后一位的字节到达节目目标解码器输入端的期望时间。
SCR字段的编码频率要求见2.7.1。
标记位字段 marker_bit
1位字段,取值'1'。
节目复合速率字段 program_mux_rate
一个22位整数,规定P-STD在包含该字段的包期间接收节目流的速率。其值以50字节/秒为单位。不允许取0值。该字段所表示的值用于在2.5.2中定义P-STD输入端的字节到达时间。该字段值在本标准中的节目多路复合流的不同包中取值可能不同。
包填充长度字段 pack_stuffing_length
3位整数,规定该字段后填充字节的个数。
填充字节字段 stuffing_byte
8位字段,取值恒为'1111 1111'。该字段能由编码器插入,例如为了满足通道的要求。它由解码器丢弃。在每个包标题中最多只允许有7个填充字节。
它的定义字节顺序,如下所示:
4B的包起始码:
byte 0 | byte 1 | byte 2 | byte 3 | ||||||||||||||||||||||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
0000 0000 0000 0000 0000 0001 | 1011 1010 |
PACK identifier -- 0xBA
系统时钟基准(SCR-System Clock Reference)的基本部分、SCR的扩展部分:
byte 4 | byte 5 | byte 6 | byte 7 | byte 8 | byte 9 | ||||||||||||||||||||||||||||||||||||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
01 | SCR 32..30 | 1 | SCR 29..15 | 1 | SCR 14..00 | 1 | SCR_ext | 1 |
PS复用速率:
byte 10 | byte 11 | byte 12 | byte 13 | ||||||||||||||||||||||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Program_Mux_Rate | 1 | 1 | reserved | pack_stuffing_length
|
==============================================================
接下来看看PS system header(即PS系统头:节目流系统标题)部分的定义:(来自MPEG-2标准文档)
表2-34 节目流系统标题
语 法 | 位数 | 助记符 |
system_header() { |
|
|
system_header_start_code | 32 | bslbf |
header_length | 16 | uimsbf |
marker_bit | 1 | bslbf |
rate_bound | 22 | uimsbf |
marker_bit | 1 | bslbf |
audio_bound | 6 | uimsbf |
fixed_flag | 1 | bslbf |
CSPS_flag | 1 | bslbf |
system_audio_lock_flag | 1 | bslbf |
system_video_lock_flag | 1 | bslbf |
marker_bit | 1 | bslbf |
vedio_bound | 5 | uimsbf |
packet_rate_restriction_flag | 1 | bslbf |
reserved_bits | 7 | bslbf |
while (nextbits()=='1') { |
|
|
stream_id | 8 | uimsbf |
'11' | 2 | bslbf |
P-STD_buffer_bound_scale | 1 | bslbf |
P-STD_buffer_size_bound | 13 | uimsbf |
} |
|
|
} |
|
|
系统标题中各字段的语义定义:
系统标题起始码字段 system_header_start_code
取值'0000 0000 0000 0000 0000 0001 1011 1011' (0x000001BB)的位串,指出系统标题的开始。
标题长度字段 header_length
16位字段。指出该字段后的系统标题的字节长度。在本规范将来的扩充中可能扩展该字段。
速率界限字段 rate_bound
22位字段,取值不小于编码在节目流的任何包中的program_mux_rate字段的最大值。该字段可被解码器用于估计是否有能力对整个流解码。
音频界限字段 audio_bound
6位字段,取值是在从0到32的闭区间中的整数,且不小于节目流中解码过程同时活动的GB/T XXXX.3和GB/T AAAA.3音频流的最大数目。在本小节中,若STD缓冲区非空或展现单元正在P-STD模型中展现,则GB/T XXXX.3和GB/T AAAA.3音频流的解码过程是活动的。
固定标志字段 fixed_flag
1位标志位。置'1'时表示比特率恒定的操作;置'0'时,表示操作的比特率可变。在恒定比特率的操作期间,复合的GB/T XXXX.1流中的system_clock_reference字段值应遵从下面的线性公式:
SCR_base(i)=((c1×i+c2) p 300) % 233 (2-22)
SCR_ext(i)=((c1×i+c2) p 300) % 300 (2-23)
其中:
c1 对所有i均有效的实型常数;
c2 对所有i均有效的实型常数;
i 在GB/T XXXX.1复合流中包含任何system_clock_reference字段的最后一位的字节索引。
CSPS标志字段 CSPS_flag
1位字段。置'1'时,节目流符合2.7.9中定义的限制。
系统音频锁定标志字段 system_audio_lock_flag
1位字段。表示在系统目标解码器的音频采样率和system_clock_frequency之间存在规定的比率。system_clock_frequency在2.5.2.1中定义而音频采样率由GB/T XXXX.3规定。如果对节目流中所有音频基本流的所有展现单元,system_clock_frequency和实际音频采样率的比例SCASR是恒定的,且对音频流中所指出的标准采样率和下表中数值相等,则该字段只能为'1'。
SCASR=(system_clock_frequency) / audio_sample_rate_in_the_P-STD (2-24)
记号X/Y表示实数除法。
标准音频采样频率(kHz) | 16 | 32 | 22.05 | 44.1 | 24 | 48 |
SCASR | 27 000 000 -------- 16 000 | 27 000 000 ------- 32 000 | 27 000 000 ------ 22 050 | 27 000 000 ------ 44 100 | 27 000 000 ------ 24 000 | 27 000 000 -------- 48 000 |
系统视频锁定标志字段 system_video_lock_flag
1位字段。表示在系统目标解码器的视频帧速率和system_clock_frequency之间存在规定的比率。system_clock_frequency在2.5.2.1中定义而视频帧速率由GB/T XXXX.2规定。如果对GB/T XXXX.1中所有视频基本流的所有展现单元,system_clock_frequency和实际视频帧速率的比例SCFR是恒定的,且对视频流中所指出的标准帧速率和下表中数值相等,则该字段只能为'1'。
SCFR=system_clock_frequency / frame_rate_in_the_P-STD (2-25)
标准帧速率(Hz) | 23.976 | 24 | 25 | 29.97 | 30 | 50 | 59.94 | 60 |
SCFR | 1 126 125 | 1 125 000 | 1 080 000 | 900 900 | 900 000 | 540 000 | 450 450 | 450 000 |
比率SCFR的值是精确的。对于23.976,29.97或59.94帧/秒的标准速率,实际的帧速率与标准速率略有不同。
视频界限字段 video_bound
5位字段,取值是在从0到16的闭区间中的整数且不小于节目流中解码过程同时活动的GB/T XXXX.2和GB/T AAAA.2流的最大数目。在本小节中,若P-STD缓冲区非空或展现单元正在P-STD模型中展现,则GB/T XXXX.2和GB/T AAAA.2视频流的解码过程是活动的。
分组速率限制标志字段 packet_rate_restriction_flag
1位标志位。若CSPS标识为'1',则该字段表示2.7.9中规定的哪个限制适用于分组速率。若CSPS标识为'0',则该字段的含义未定义。
保留位字段 reserved_bits
7位字段。被保留供ISO/IEC将来使用。它的值应为'111 1111',除非ISO/IEC对它作出其它规定。
流标识字段 stream_id
8位字段。指示其后的P-STD_buffer_bound_scale和P-STD_buffer_size_bound字段所涉及的流的编码和基本流号码。
若取值'1011 1000',则其后的P-STD_buffer_bound_scale和P-STD_buffer_size_bound字段指节目流中所有的音频流。
若取值'1011 1001',则其后的P-STD_buffer_bound_scale和P-STD_buffer_size_bound字段指节目流中所有的视频流。
若stream_id取其它值,则应该是大于或等于'1011 1100'的一字节值且应根据表2-18解释为流的编码和基本流号码。
节目流中的每个基本流应在每个系统标题中通过这种机制精确地规定一次它的P-STD_buffer_bound_scale和P-STD_buffer_size_bound。
P-STD缓冲区界限比例字段 P-STD_buffer_bound_scale
1位字段。表示用于解释后续P-STD_buffer_size_bound字段的比例系数。若前面的stream_id表示一个音频流,则该字段值为'0'。若表示一个视频流,则该字段值为'1'。对于所有其它的流类型,该字段值可以为'0'也可以为'1'。
P-STD缓冲区大小界限字段 P-STD_buffer_size_bound
13位无符号整数,取值不小于节目流中流n的所有分组的P-STD缓冲区大小BSn的最大值。若P-STD_buffer_bound_scale的值为'0',则该字段以128字节为单位来度量缓冲区大小的边界。若P-STD_buffer_bound_scale的值为'1',则该字段以1024字节为单位来度量缓冲区大小的边界。因此:
if (P-STD_buffer_bound_scale = = 0)
BSn≤P-STD_buffer_size_bound×128
else
BSn≤P-STD_buffer_size_bound×1024
所以对于系统头部的解析,我们一般只要先首先判断是否存在系统头(根据系统头的起始码0x000001BB),然后我们读取系统头的头部长度,即PS SYSTEM HEADER LENGTH部分,然后根据头部的长度,跳过PS系统头。进入下一个部分,即PS 节目流映射头。
==========================================================
接着看看PS流的节目映射流部分(节目流映射)定义:(来自MPEG-2标准文档)
表2-35 节目流映射
语 法 | 位数 | 助记符 |
program_stream_map() { |
|
|
packet_start_code_prefix | 24 | bslbf |
map_stream_id | 8 | uimsbf |
program_stream_map_length | 16 | uimsbf |
current_next_indicator | 1 | bslbf |
reserved | 2 | bslbf |
program_stream_map_version | 5 | uimsbf |
reserved | 7 | bslbf |
marker_bit | 1 | bslbf |
program_stream_info_length | 16 | uimsbf |
for (i=0;i<N;i++){ |
|
|
descriptor() |
|
|
} |
|
|
elementary_stream_map_length | 16 | uimsbf |
for (i=0;i<N1;i++){ |
|
|
stream_type | 8 | uimsbf |
elementary_stream_id | 8 | uimsbf |
elementary_stream_info_length | 16 | uimsbf |
for (i=0;i<N2;i++) { |
|
|
descriptor() |
|
|
} |
|
|
} |
|
|
CRC_32 | 32 | rpchof |
} |
|
|
节目流映射中各字段的语义定义:
分组起始码前缀字段 packet_start_code_prefix
24位码。它和跟随其后的map_stream_id共同组成一个分组起始码以标志分组的开始。该字段是值为'0000 0000 0000 0000 0000 0001' (0x000001)的位串。
映射流标识字段 map_stream_id
8位字段,值为0xBC。
节目流映射长度字段 program_stream_map_length
16位字段。指示紧跟在该字段后的program_stream_map中的字节数。该字段的最大值为1018(0x3FA)。
当前下一个指示符字段 current_next_indicator
1位字段。置'1'时表示传送的节目流映射当前是可用的。置'0'时表示传送的节目流映射还不可用,但它将是下一个生效的表。
节目流映射版本字段 program_stream_map_version
5位字段,表示整个节目流映射的版本号。一旦节目流映射的定义发生变化,该字段将递增1,并对32取模。在current_next_indicator为'1'时,该字段应该是当前适用的节目流映射的版本号;在current_next_indicator为'0'时,该字段应该是下一个适用的节目流映射的版本号。
节目流信息长度字段 program_stream_info_length
16位字段,指出紧跟在该字段后的描述符的总长度。
标记位字段 marker_bit
1位字段,取值为'1'。
基本流映射长度字段 elementary_stream_map_length
16位字段,指出在该节目流映射中的所有基本流信息的字节长度。它只包括stream_type、elementary_stream_id和elementary_stream_info_length字段。(这里注意一下,这里的基本流映射长度,他只包括他后面的指定的那几个定义字段的总和,即从从这个长度,我们可以知道后面他根了几种类型的流定义,因为一种流的这个定义字段:stream_type(1BYTE)、elementary_stream_id(1byte)和elementary_stream_info_length(2byte)字段总和为4个字节,所以用elementary_stream_map_length/4可以得到后面定义了几个流类型信息。)
流类型字段 stream_type
8位字段,根据表2-29规定了流的类型。该字段只能标志包含在PES分组中的基本流且取值不能为0x05。
(这里我们暂时根据国标GB28181中的定义可以知道
1、MPEG-4 视频流: 0x10;
2、H.264 视频流: 0x1B;
3、SVAC 视频流: 0x80;
4、G.711 音频流: 0x90;
5、G.722.1 音频流: 0x92;
6、G.723.1 音频流: 0x93;
7、G.729 音频流: 0x99;
8、SVAC音频流: 0x9B。
因为节目映射流字段只有在关键帧打包的时候,才会存在,所以如果要判断PS打包的流编码类型,就根据这个字段来判断。)
基本流标识字段 elementary_stream_id
8位字段,指出该基本流所在PES分组的PES分组标题中stream_id字段的值。
(这个字段的定义,其中0x(C0~DF)指音频,0x(E0~EF)为视频)
基本流信息长度字段 elmentary_stream_info_length
16位字段,指出紧跟在该字段后的描述符的字节长度。(即这个类型的流描述长度。这个后面的字段后面的指定长度不在elementary_stream_map_length指定的范围类。)
CRC 32字段 CRC_32
32位字段,它包含CRC值以在处理完整个节目流映射后在附录A中定义的解码器寄存器产生0输出值。
对于这个字段的解析,我们需要取值0x000001BC的位串,指出节目流映射的开始,暂时不需要处理,读取Header Length直接跳过即可,如果需要解析流编码类型,必须详细解析这个字段。
=================PES包=============================
接下来我们来分析下PES包的内容:PES包=PES header+code raw data;
先看下PES header:(来自http://www.gxlcms.com/)
接着我们来看看解析步骤:(来自MPEG-2标准文档)
表2-17 PES分组
语 法 | 位数 | 助记符 |
PES_packet(){ |
|
|
packet_start_code_prefix | 24 | bslbf |
stream_id | 8 | uimsbf |
PES_packet_length | 16 | uimsbf |
if(stream_id != program_stream_map |
|
|
&& stream_id !=padding_stream |
|
|
&& stream_id !=private_stream_2 |
|
|
&& stream_id !=ECM |
|
|
&& stream_id !=EMM |
|
|
&& stream_id !=program_stream_directory |
|
|
&& stream_id !=DSMCC_stream |
|
|
&& stream_id !=ITU-T Rec.H.222.1 type E stream){ |
|
|
'10' | 2 | bslbf |
PES_scrambling_control | 2 | bslbf |
PES_priority | 1 | bslbf |
data_alignment_indicator | 1 | bslbf |
copyright | 1 | bslbf |
original_or_copy | 1 | bslbf |
PTS_DTS_flags | 2 | bslbf |
ESCR_flag | 1 | bslbf |
ES_rate_flag | 1 | bslbf |
DSM_trick_mode_flag | 1 | bslbf |
additional_copy_info_flag | 1 | bslbf |
PES_CRC_flag | 1 | bslbf |
PES_extension_flag | 1 | bslbf |
PES_header_data_length | 8 | uimsbf |
if(PTS_DTS_flags =='10'){ |
|
|
'0010' | 4 | bslbf |
PTS[32..30] | 3 | bslbf |
marker_bit | 1 | bslbf |
PTS[29..15] | 15 | bslbf |
marker_bit | 1 | bslbf |
PTS[14..0] | 15 | bslbf |
marker_bit | 1 | bslbf |
} |
|
|
if(PTS_DTS_flags =='11'){ |
|
|
'0011' | 4 | bslbf |
PTS[32..30] | 3 | bslbf |
marker_bit | 1 | bslbf |
PTS[29..15] | 15 | bslbf |
marker_bit | 1 | bslbf |
PTS[14..0] | 15 | bslbf |
marker_bit | 1 | bslbf |
'0001' | 4 | bslbf |
PTS[32..30] | 3 | bslbf |
marker_bit | 1 | bslbf |
PTS[29..15] | 15 | bslbf |
marker_bit | 1 | bslbf |
PTS[14..0] | 15 | bslbf |
marker_bit | 1 | bslbf |
} |
|
|
if(ESCR_flag =='1'){ |
|
|
reserved | 2 | bslbf |
ESCR_base[32..30] | 3 | bslbf |
marker_bit | 1 | bslbf |
ESCR_base[29..15] | 15 | bslbf |
marker_bit | 1 | bslbf |
ESCR_base[14..0] | 15 | bslbf |
marker_bit | 1 | bslbf |
ESCR_extension | 9 | uimsbf |
marker_bit | 1 | bslbf |
} |
|
|
if(ES_rate_flag =='1'){ |
|
|
marker_bit | 1 | bslbf |
ES_rate | 22 | uimsbf |
marker_bit | 1 | bslbf |
} |
|
|
if (DSM_trick_mode_flag =='1'){ |
|
|
trick_mode_control | 3 | uimsbf |
if ( trick_mode_control = =fast_forward ) { |
|
|
field_id | 2 | bslbf |
intra_slice_refresh | 1 | bslbf |
frequency_truncation | 2 | bslbf |
} |
|
|
else if ( trick_mode_control = = slow_motion ) { |
|
|
rep_cntrl | 5 | uimsbf |
} |
|
|
else if ( trick_mode _control = = freeze_frame ) { |
|
|
field_id | 2 | uimsbf |
reserved | 3 | bslbf |
} |
|
|
else if ( trick_mode _control = = fast_reverse ) { |
|
|
field_id | 2 | bslbf |
intra_slice_refresh | 1 | bslbf |
frequency_truncation | 2 | bslbf |
else if ( trick_mode_control = = slow_reverse ) { |
|
|
rep_cntrl | 5 | uimsbf |
} |
|
|
else |
|
|
reserved | 5 | bslbf |
} |
|
|
if ( additional_copy_info_flag = ='1'){ |
|
|
marker_bit | 1 | bslbf |
additional_copy_info | 7 | bslbf |
} |
|
|
if (PES_CRC_flag==‘1’){ |
|
|
人气教程排行
|