H264的PS封裝
一個完整的ps包封裝:
PSheader + PS system header + PS system Map + PES header + h264 data
因為一般視頻數據都是采用rtp打包發送,所以這里我就把ps封裝和rtp封裝放在一起講
視頻關鍵幀的封裝
RTP + PSheader + PS system header + PS system Map + PES header +h264 data視頻非關鍵幀的封裝
RTP +PS header + PES header + h264 data音頻幀的封裝:
RTP + PES header + G711
基于RTP的PS封裝首先按照ISO/IEC 13818-1將視音頻流封裝成PS包再將PS包以負載的方式封裝成RTP包
由于rtp包最大的負載長度是1400,所以大于1400的視頻數據都是需要分包處理的,這里我們就拿 I 幀數據來分析。
具體的分片方法:
當我們獲取到一幀h264的關鍵幀數據時,先進行PS封裝,在視頻數據前加上 PS header + PS system header + PS system Map header ,當前面的頭添加完畢后還需要再加一個 PES header,但是由于PES頭的負載長度類型是short,最大為65536,所以每65536字節的視頻數據后都得加一個PES頭,如下:
| PS header | PS system header | PS system Map |PES | data | PES | data | PES | data|
這樣一個關鍵幀的PS封裝就完成了剩下的就是把封裝好的數據分包打RTP包了,每1300字節的數據前加一個RTP包頭,然后發送出去
PS封裝的幾個頭:
(1) PS header:14字節
pack_start_code : (32b) 起始碼字段 默認0x000001BA 標志一個包的開始
marker_bit :(2b) 標記位字段2位字段,取值’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 : (1b) 標記位字段取值’1’
marker_bit : (1b) 標記位字段取值’1’
reserved : (5b) 填充字段
pack_stuffing_length : (3b) 包填充長度字段
節目復合速率字段 program_mux_rate (沒查到相關資料)
一個22位整數,規定P-STD在包含該字段的包期間接收節目流的速率。其值以50字節/秒為單位。不允許取0值。該字段所表示的值用于在2.5.2中定義P-STD輸入端的字節到達時間。該字段值在本標準中的節目多路復合流的不同包中取值可能不同。
/12字節RTP頭/
80 60 00 00 00 00 00 00 0d 25 5a a5
/PS 頭/
00 00 01 ba 44 00 05 5f 94 01 00 60 1b f8
00 00 01 ba 開始碼
44 00 44 f5 84 01 系統時鐘參考字段,二進制如下
01 000 1 000000000000000 1 010101111110010 1 000000000 1
SCR = 90000/8 = 00000000 00000000 00101011 11110010 (SRC值是累加的,這個是第一幀數據的SRC值)
上面紅色的1都是marker_bit 標記位
000 這三個位段的值是由SCR值的第30-32位填充,參考上述SRC值,故填充3位0
000000000000000 這15位字段是由SRC值的第15-29位填充,故填充000000000000000
010101111110010 這15位字段是由SRC值的第0-14位填充,故填充 0101011 11110010
00 60 1b f8 二進制如下:
00000000001100000000110 11 11111 000
00000000001100000000110 沒看懂用途,嘗試隨便取值不影響視頻和音頻,不能取0,我這里用的是6150(1100000000110)
11111 5位填充字段 全部填1
00 3位擴展長度填充字段 填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) 保留位字段
stream_id : (8b) 流標識字段
marker_bit : (2b) 取值’11’
P-STD_buffer_bound_scale : (1b) P-STD緩沖區界限比例字段
P-STD_buffer_size_bound : (13) P-STD緩沖區大小界限字段
System Header
00 00 01 bb 00 0c 80 1e ff fe e1 7f e0 e0 d8 c0 c0 20
00 00 01 bb : 四字節開始碼
00 0c : 當前字段后該頭的長度 12
80 1e ff 轉成二進制如下:
1 0000000000111101111111 1
111101111111 :rate_bound 該字段可被解碼器用于估計是否有能力對整個流解碼(沒查到如何填值)
fe e1 7f轉成二進制如下:
111111 1 0 1 1 1 00001 0 1111111
111111: 音頻界限字段 audio_bound 6位字段,取值是在從0到32的閉區間中的整數,且不小于節目流中解碼過程同時活動的GB/T XXXX.3和GB/T AAAA.3音頻流的最大數目。在本小節中,若STD緩沖區非空或展現單元正在P-STD模型中展現,則GB/T XXXX.3和GB/T AAAA.3音頻流的解碼過程是活動的。
1 : 固定標志字段 fixed_flag 1位標志位。置’1’時表示比特率恒定的操作;置’0’時,表示操作的比特率可變。
0 : CSPS標志字段 CSPS_flag 1位字段。
1: 系統音頻鎖定標志字段 system_audio_lock_flag 置 ‘1’
1: 系統視頻鎖定標志字段 system_video_lock_flag 置 ‘1’
00001: 視頻界限字段 video_bound
0: 分組速率限制標志字段 packet_rate_restriction_flag 1位標志位。若CSPS標識為’1’,則該字段表示2.7.9中規定的哪個限制適用于分組速率。若CSPS標識為’0’,則該字段的含義未定義。
1111111 : 7位字段。被保留供ISO/IEC將來使用。它的值應為’111 1111’,除非ISO/IEC對它作出其它規定。
e0 e0 d8 c0 c0 20轉成二進制如下:
11100000 11 1 0000011011000 11000000 11 0 0000000100000
11100000 : 流標識字段 stream_id E0在gb28181中定義是視頻
11: 固定值
1: 1位字段。表示用于解釋后續P-STD_buffer_size_bound字段的比例系數。若前面的stream_id表示一個音頻流,則該字段值為’0’。若表示一個視頻流,則該字段值為’1’。對于所有其它的流類型,該字段值可以為’0’也可以為’1’。
0000011011000 : 音頻緩存區大小 216 單位是1024字節
11000000: 流標識字段 stream_id C0在gb28181中定義是音頻
11: 固定值
0:
0000000100000: 視頻緩存區大小 32 單位 128字節
(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二進制如下:
11 00001 1111111 1 0000000000000000 0000000000001000
1: 當前下一個指示符字段 current_next_indicator 1位字段。置’1’時表示傳送的節目流映射當前是可用的。置’0’時表示傳送的節目流映射還不可用,但它將是下一個生效的表。
11: 填充字段 ‘11’
00001: 節目流映射版本字段 program_stream_map_version 5位字段,表示整個節目流映射的版本號。一旦節目流映射的定義發生變化,該字段將遞增1,并對32取模。在current_next_indicator為’1’時,該字段應該是當前適用的節目流映射的版本號;在current_next_indicator為’0’時,該字段應該是下一個適用的節目流映射的版本號。
1111111: 填充字段
0000000000000000: 節目流信息長度字段 program_stream_info_length 16位字段,指出緊跟在該字段后的描述符的總長度
0000000000001000: 基本流映射長度字段 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可以得到后面定義了幾個流類型信息。)
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輸出值。/crc (23 b9 0f 3d)/
(4) PS PES Header:14字節
packet_start_code_prefix : (24b) 分組起始碼前綴字段 packet_start_code_prefix 0x000001
stream_id : (8) 流標識字段 stream_id 這個字段的定義,其中0x(C0DF)指音頻,0x(E0EF)為視頻
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標志字段 PTS_DTS_flags
ESCR_flag : (1) ESCR標志字段 ESCR_flag
ES_rate_flag : (1) ES速率標志字段 ES_rate_flag
DSM_trick_mode_flag : (1) DSM特技方式標志字段 DSM_trick_mode_flag
additional_copy_info_flag : (1) 附加版權信息標志字段 additional_copy_info_flag
PES_CRC_flag : (1) PES CRC標志字段 PES_CRC_flag
PES_extension_flag: (1) PES擴展標志字段 PES_extension_flag
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)
/PES header/
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加擾控制字段 PES_scrambling_control
1: PES優先級字段 PES_priority ‘1’表示PES分組中有效負載的優先級高于該字段為’0’的PES分組有效負載
0: 數據對齊指示符字段 data_alignment_indicator 當值為’0’時,沒有定義是否有任何此種的對齊。
0: 版權字段 copyright當值為’0’時,沒有定義該材料是否受到版權保護
0: 原始或拷貝字段 original_or_copy 1位字段。置’1’時表示相關PES分組有效負載的內容是原始的;值為’0’表示相關PES分組有效負載的內容是一份拷貝
10: PTS DTS標志字段 PTS_DTS_flags
2位字段。當值為’10’時,PTS字段應出現在PES分組標題中;當值為’11’時,PTS字段和DTS字段都應出現在PES分組標題中;當值為’00’時,PTS字段和DTS字段都不出現在PES分組標題中。值’01’是不允許的。
0 0 0 0 0 0 六個擴展標志位 置0
00000101 : PES標題數據長度字段 5 標明后續還有五個字節
31 00 01 57 e5:二進制如下
11 000 1 000000000000000 1 010101111110010 1
0011: 固定值
PTS = 90000/8 = 11250 二進制:
10101111110010
000: PTS第30 -32位填充
000000000000000: PTS第15 -29位填充
010101111110010: PTS第0 -14位填充