PS流(ISO13818和GB28181)分析
1、理論基礎:
PSM(PS System map)提供了對PS流中的原始流和他們之間的相互關系的描述信息;PSM是作為一個PES分組出現,當stream_id == 0xBC時,說明此PES包是一個PSM;PSM是緊跟在系統頭部后面的;PSM是作為PS包的payload存在的;
PS頭(?pack_header):0x000001BA
系統頭部(?system_header):0x000001BB我們一般只要先首先判斷是否存在系統頭,然后我們讀取系統頭的頭部長度,即PS SYSTEM HEADER LENGTH部分,然后根據頭部的長度,跳過PS系統頭。進入下一個部分,即PS 節目流映射頭
節目流映射(?program_stream_map):0x000001BC的位串,指出節目流映射的開始,暫時不需要處理,讀取Header Length直接跳過即可,如果需要解析流編碼類型,必須詳細解析這個字段。
GB28181 對RTP 傳輸的數據負載類型有規定(參考GB28181 附錄B),負載類型中96-127,RFC2250 建議96 表示PS 封裝,建議97 為MPEG-4,建議98 為H264
即我們接收到的RTP 包首先需要判斷負載類型,若負載類型為96,則采用PS 解復用,將音視頻分開解碼。若負載類型為98,直接按照H264 的解碼類型解碼。注:此方法不一定準確,取決于打包格式是否標準。
PES視頻流:0x000001E0
PES音頻流:0x000001C0
針對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 封裝發送就可以了。
PS碼流文件分析:
mpeg-ps里面是沒有音視頻的編碼信息的,如果是像pcm或pcma、pcmu這類音頻,是不知道聲道、采樣率、采樣位數的,所以就無法播放。實際上mpeg-ps中pcma、pcmu的聲道、采樣率、采樣位數一般是1,8000,16,特別是28181協議中。
注:后面跟著就是自定義的描述內容(海康在這里放入了復合流的私有描述:兩字節復合流描述字(40 0E)+內容(用于放置全局時間,編碼設備型號等相關信息)+兩字節復合流描述字(41 12)(可選)+內容(用于描述設備與通道號),所以長度就不是00 00)
?
接著我們來看看解析步驟:(來自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'){ | ||
| '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 |
| '0001' | ?4 | bslbf |
| DTS[32..30] | ?3 | bslbf |
| marker_bit | ?1 | bslbf |
| DTS[29..15] | 15 | bslbf |
| marker_bit | ?1 | bslbf |
| DTS[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’){ | ||
| previous_PES_packet_CRC | 16 | bslbf |
| } | ||
| if ( PES_extension_flag =='1') { | ||
| PES_private_data_flag | ?1 | bslbf |
| pack_header_field_flag | ?1 | bslbf |
| program_packet_sequence_counter_flag | ?1 | bslbf |
| P-STD_buffer_flag | ?1 | bslbf |
| reserved | ?3 | bslbf |
| PES_extension_flag_2 | ?1 | bslbf |
| if(PES_private_data_flag =='1'){ | ||
| PES_private_data | 128 | bslbf |
| } | ||
| if (pack_header_field_flag == '1'){ | ||
| pack_field_length | ?8 | uimsbf |
| pack_header() | ||
| } | ||
| if (program_packer_sequence_counter_flag == '1'){ | ||
| marker_bit | ?1 | bslbf |
| program_packet_sequence_counter | ?7 | uimsbf |
| marker-bit | ?1 | bslbf |
| MPEG1_MPEG2_indentifier | ?1 | bslbf |
| original_stuff_length | ?6 | uimsbf |
| } | ||
| if (P-STD_buffer_flag = = '1'({ | ||
| '01' | ?2 | bslbf |
| P-STD_buffer_scale | ?1 | bslbf |
| P-STD_buffer_size | 13 | uimsbf |
| } | ||
| if (PES_extension_flag_2 == '1'{ | ||
| marker_bit | ?1 | bslbf |
| PES_extension_field_length | ?7 | uimsbf |
| for(i=0;i<PES_extension_field_length;i++){ | ||
| reserved | ?8 | bslbf |
| } | ||
| } | ||
| } | ||
| for (i=0;i<N1;i++)} | ||
| stuffing_byte | ?8 | bslbf |
| } | ||
| for (i=0;i<N2;i++){ | ||
| PES_packet_data_byte | ?8 | bslbf |
| } | ||
| } | ||
| else if (stream_id = = program_stream_map | ||
| || 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 ){ | ||
| for (i=0;i<PES_packet_length;i++){ | ||
| PES_packet_data_byte | ?8 | bslbf |
| } | ||
| } | ||
| else if (steam_id = = padding_stream){ | ||
| for (i=0;i<PES_packet_length;i++){ | ||
| padding_byte | ?8 | bslbf |
| } | ||
| } | ||
| } |
其中表2-18? Stream_id賦值
| stream_id | 注 | 流 編 碼 |
| 1011 1100 | 1 | program_stream_map(0xBC) |
| 1011 1101 | 2 | private_stream_1(0xBD) |
| 1011 1110 | padding_stream(0xBE) | |
| 1011 1111 | 3 | private_stream-2(0xBF) |
| 110x xxxx | GB/T XXXX.3或GB/T AAAA.3音頻流編號xxxx(0xC0~0xDF) | |
| 1110 xxxx | GB/T XXXX.2或GB/T AAAA.2視頻流編號xxxx(0xE0~0xEF) | |
| 1111 0000 | 3 | ECM_stream(0xF0) |
| 1111 0001 | 3 | EMM_stream(0xF1) |
| 1111 0010 | 5 | GB/T XXXX.1附錄B或GB/T XXXX.6_DSMCC_stream(0xF2) |
| 1111 0011 | 2 | ISO/IEC_13522_stream(0xF3) |
| 1111 0100 | 6 | ITU-T Rec. H.222.1類型A |
| 1111 0101 | 6 | ITU-T Rec. H.222.1類型B |
| 1111 0110 | 6 | ITU-T Rec. H.222.1類型C |
| 1111 0111 | 6 | ITU-T Rec. H.222.1類型D |
| 1111 1000 | 6 | ITU-T Rec. H.222.1類型E |
| 1111 1001 | 7 | ancillary_stream(0xF9) |
| 1111 1010…1111 1110 | 保留數據流 | |
| 1111 1111 | 4 | program_stream_directory(0xFF) |
| 符號x表示值'0'或'1'均被允許且可產生相同的流類型。流號碼由x的取值決定。 注 1? 類型為program_stream_map的PES分組有唯一的語法,在2.5.4.1中作了規定。 2? 類型為private_stream_1和ISO/IEC_13352_stream的PES分組與GB/T XXXX.2及GB/T XXXX.3音頻流服從相同的PES分組語法。 3? 類型為private_stream_2,ECM_stream和EMM_stream的PES分組與private_stream_1相似,除了在PES_packet_length字段后未規定語法。 4? 類型為program_stream_directory的PES分組有唯一的語法,在2.5.5中作了規定。 5? 類型為DSM_CC_stream的PES分組有唯一的語法,在GB/T XXXX.6中作了規定。 6? stream_id與表2-29中的stream_type? 0x09相關聯。 7? stream_id僅用于PES分組。PES分組在傳輸流中攜帶了來源于節目流或GB/T AAAA.1系統流的數據(參見2.4.3.7)。 | ||
總結
以上是生活随笔為你收集整理的PS流(ISO13818和GB28181)分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国十大古典名曲
- 下一篇: ssm基于微信小程序的毕业论文选题管理系