TS格式解析
1.TS格式介紹
?? TS:全稱為MPEG2-TS。TS即"Transport Stream"的縮寫。它是分包發送的,每一個包長為188字節(還有192和204個字節的包)。包的結構為,包頭為4個字節(第一個字節為0x47),負載為184個字節。在TS流里可以填入很多類型的數據,如視頻、音頻、自定義信息等。MPEG2-TS主要應用于實時傳送的節目,比如實時廣播的電視節目。MPEG2-TS格式的特點就是要求從視頻流的任一片段開始都是可以獨立解碼的。簡單地說,將DVD上的VOB文件的前面一截cut掉(或者是數據損壞數據)就會導致整個文件無法解碼,而電視節目是任何時候打開電視機都能解碼(收看)的。
?? TS解析需要參考:ISO/IEC 13818-1的2.4 Transport Stream bitstream requirements
2.TS流包含的內容
? ??一段TS流,必須包含PAT包、PMT包、多個音頻包、多個視頻包、多個PCR包、以及其他信息包。
? ??解析TS流數據的流程:查找PID為0x0的包,解析PAT,PAT包中的program_map_PID表示PMT的PID;查找PMT,PMT包中的elementary_PID表示音視頻包的PID,PMT包中的PCR_PID表示PCR的PID,有的時候PCR的PID跟音頻或者視頻的PID相同,說明PCR會融進音視頻的包,注意解析,有的時候PCR是自己單獨的包;CAT、NIT、SDT、EIT的PID分別為: 0x01、0x10、0x11、0x12。
3.TS包頭解析
??? TS包頭有4個字節
| //Transport Stream header typedef?struct?TS_header { ?????????unsigned sync_byte??????????????????? :8;????? //同步字節,固定為0x47 ,表示后面的是一個TS分組,當然,后面包中的數據是不會出現0x47的 ?????????unsigned transport_error_indicator?????? :1;????? //傳輸錯誤標志位,一般傳輸錯誤的話就不會處理這個包了 ?????????unsigned payload_unit_start_indicator??? :1;????? //有效負載的開始標志,根據后面有效負載的內容不同功能也不同 ?????????// payload_unit_start_indicator為1時,在前4個字節之后會有一個調整字節,它的數值決定了負載內容的具體開始位置。 ?????????unsigned transport_priority????????????? :1;????? //傳輸優先級位,1表示高優先級 ?????????unsigned PID????????????????????????? :13;???? //有效負載數據的類型 ?????????unsigned transport_scrambling_control???? :2;????? //加密標志位,00表示未加密 ?????????unsigned adaption_field_control????????? :2;????? //調整字段控制,。01僅含有效負載,10僅含調整字段,11含有調整字段和有效負載。為00的話解碼器不進行處理。 ?????????unsigned continuity_counter????????????? :4;????? //一個4bit的計數器,范圍0-15 } TS_header; ????//特殊參數說明: ???//sync_byte:0x47 ???//payload_unit_start_indicator:0x01表示含有PSI或者PES頭 ???//PID:0x0表示后面負載內容為PAT,不同的PID表示不同的負載 ???//adaption_field_control: ????????// 0x0: // reserved for future use by ISO/IEC ????????// 0x1: // 無調整字段,僅含有效負載?? ????????// 0x2: // 僅含調整字段,無有效負載 ????????// 0x3: // 調整字段后含有效負載 // Parse TS header int?Parse_TS_header(unsignedchar?*pTSBuf, TS_header *pheader) { ????pheader->sync_byte???????????????????????????????????? = pTSBuf[0]; ????if?(pheader->sync_byte != 0x47) ????????return?-1; ????pheader->transport_error_indicator?????? = pTSBuf[1] >> 7; ????pheader->payload_unit_start_indicator??? = pTSBuf[1] >> 6 & 0x01; ????pheader->transport_priority???????????? = pTSBuf[1] >> 5 & 0x01; ????pheader->PID???????????????????????? = (pTSBuf[1] & 0x1F) << 8 | pTSBuf[2]; ????pheader->transport_scrambling_control?? = pTSBuf[3] >> 6; ????pheader->adaption_field_control???????? = pTSBuf[3] >> 4 & 0x03; ????pheader->continuity_counter??????????? = pTSBuf[3] & 0x0F; ????return?0; } |
????? TS包頭解析需要參考:ISO/IEC 13818-1的2.4.3.2 Transport Stream packet layer
4.TS負載格式解析
4.1 PAT解析
?? TS_header包頭中的PID值為0x0,表示當前負載為PAT(Program Association Table)。PAT數據的信息可以理解為整個TS流包含的節目信息。
| // Program Association Table typedef?struct?PAT_Packet_tag { ????unsigned table_id??????????????????????? : 8; //固定為0x00 ,標志是該表是PAT ????unsigned section_syntax_indicator??????? : 1; //段語法標志位,固定為1 ????unsigned zero??????????????????????????? : 1; //0 ????unsigned reserved_1????????????????????? : 2; // 保留位 ????unsigned section_length????????????????? : 12;//表示這個字節后面有用的字節數,包括CRC32 ????unsigned transport_stream_id???????????? : 16;//該傳輸流的ID,區別于一個網絡中其它多路復用的流 ????unsigned reserved_2????????????????????? : 2; // 保留位 ????unsigned version_number????????????????? : 5; //范圍0-31,表示PAT的版本號 ????unsigned current_next_indicator????????? : 1; //發送的PAT是當前有效還是下一個PAT有效 ????unsigned section_number????????????????? : 8; //分段的號碼。PAT可能分為多段傳輸,第一段為00,以后每個分段加1,最多可能有256個分段 ????unsigned last_section_number???????????? : 8; //最后一個分段的號碼 ????// for(i=0; i<N; i++) ????// { ????unsigned program_number????????????????? : 16; ????unsigned reserved_3????????????????????? : 3; ????unsigned network_PID???????????????????? : 16;? // 或者program_map_PID // } ????unsigned CRC_32????????????????????????? : 32; } PAT_Packet; // Parse PAT int?Parse_PAT(unsignedchar?*pTSBuf, PAT_Packet *packet) { ????TS_header TSheader; ????if?(Parse_TS_packet_header(pTSBuf, &TSheader) != 0) ????????return?-1; ????if?(TSheader.payload_unit_start_indicator == 0x01) // 表示含有PSI或者PES頭 ????{ ????????if?(TSheader.PID == 0x0)? // 表示PAT ????????{ ?????????????int?iBeginlen = 4; ?????????????int?adaptation_field_length = pTSBuf[4]; ?????????????switch(TSheader.adaption_field_control) ?????????????{ ?????????????case?0x0:???????????????????????????????????// reserved for future use by ISO/IEC ??????????????????return?-1; ?????????????case?0x1:???????????????????????????????????// 無調整字段,僅含有效負載?????? ??????????????????iBeginlen += pTSBuf[iBeginlen] + 1;? // + pointer_field ??????????????????break; ?????????????case?0x2:????????????????????????????????????// 僅含調整字段,無有效負載 ??????????????????return?-1; ?????????????case?0x3:// 調整字段后含有效負載 ?????????????????if?(adaptation_field_length > 0) ?????????????????{ ??????????????????????iBeginlen += 1;?????????????????? // adaptation_field_length占8位 ??????????????????????iBeginlen += adaptation_field_length; // + adaptation_field_length ?????????????????} ?????????????????else ?????????????????{ ??????????????????????iBeginlen += 1;?????????????????????? // adaptation_field_length占8位 ?????????????????} ?????????????????iBeginlen += pTSBuf[iBeginlen] + 1;?????????? // + pointer_field ?????????????????break; ????????????default: ?????????????????break; ????????????} ????????????unsignedchar?*pPAT = pTSBuf + iBeginlen; ????????????packet->table_id??????????????????? = pPAT[0]; ????????????packet->section_syntax_indicator??? = pPAT[1] >> 7; ????????????packet->zero??????????????????????? = pPAT[1] >> 6 & 0x1; ????????????packet->reserved_1????????????????? = pPAT[1] >> 4 & 0x3; ????????????packet->section_length????????????? = (pPAT[1] & 0x0F) << 8 |pPAT[2]; ????????????packet->transport_stream_id???????? = pPAT[3] << 8 | pPAT[4]; ????????????packet->reserved_2????????????????? = pPAT[5] >> 6; ????????????packet->version_number????????????? = pPAT[5] >> 1 &? 0x1F; ????????????packet->current_next_indicator????? = (pPAT[5] << 7) >> 7; ????????????packet->section_number????????????? = pPAT[6]; ????????????packet->last_section_number???????? = pPAT[7]; ????????????int?len = 0; ????????????len = 3 + packet->section_length; ????????????packet->CRC_32????????????????????? = (pPAT[len-4] & 0x000000FF) << 24 ????????????????????????????????????????????????| (pPAT[len-3] & 0x000000FF) << 16 ????????????????????????????????????????????????| (pPAT[len-2] & 0x000000FF) << 8 ????????????????????????????????????????????????| (pPAT[len-1] & 0x000000FF); ????????????int?n = 0; ????????????for?( n = 0; n < (packet->section_length - 12); n += 4 ) ????????????{ ?????????????????packet->program_number = pPAT[8 + n ] << 8 | pPAT[9 + n ]; ?????????????????packet->reserved_3??????????????? = pPAT[10 + n ] >> 5; ?????????????????if?( packet->program_number == 0x00) ?????????????????{ ?????????????????????packet->network_PID = (pPAT[10 + n ] & 0x1F) << 8 |pPAT[11 + n ]; ?????????????????} ?????????????????else ?????????????????{ ?????????????????????// 有效的PMT的PID,然后通過這個PID值去查找PMT包 ?????????????????????program_map_PID = (pPAT[10 + n] & 0x1F) << 8 |pPAT[11 + n]; ?????????????????} ????????????} ????????????return?0; ?????????} ????} ????return?-1; } |
PAT數據解析需要參考:ISO/IEC 13818-1的2.4.4.3 Program Association Table
4.2 PMT解析
??? 由PAT包中的program_map_PID可以確定PMT(Program Map Table)的PID。PMT數據的信息可以理解為這個節目包含的音頻和視頻信息。?
???
| // Program Map Table typedef?struct?PMT_Packet_tag { ?????unsigned table_id??????????????????????? : 8; ?????unsigned section_syntax_indicator??????? : 1; ?????unsigned zero??????????????????????????? : 1; ?????unsigned reserved_1????????????????????? : 2; ?????unsigned section_length????????????????? : 12; ?????unsigned program_number????????????????? : 16; ?????unsigned reserved_2????????????????????? : 2; ?????unsigned version_number????????????????? : 5; ?????unsigned current_next_indicator????????? : 1; ?????unsigned section_number????????????????? : 8; ?????unsigned last_section_number???????????? : 8; ?????unsigned reserved_3????????????????????? : 3; ?????unsigned PCR_PID???????????????????????? : 13; ?????unsigned reserved_4????????????????????? : 4; ?????unsigned program_info_length???????????? : 12; ?????// for(i=0; i<N; i++) ?????// { ?????unsigned stream_type???????????????????? : 8; ?????unsigned reserved_5????????????????????? : 3; ?????unsigned elementary_PID????????????????? : 13; ?????unsigned reserved_6????????????????????? : 4; ?????unsigned ES_info_length????????????????? : 12; ?????// } ?????unsigned CRC_32????????????????????????? : 32; } PMT_Packet; ???// Parse PMT int?Parse_PMT(unsignedchar?*pTSBuf, PMT_Packet *packet) { ????// 參考Parse_PAT()來做就行了 ????// ... ????? ????return?0; } |
PMT數據解析需要參考:ISO/IEC 13818-1的2.4.4.8 Program Map Table
4.3 PES解析
??? 根據文檔參考PAT、PMT的解析流程就能完成PES的解析了。
??? 需要注意的是PES中PTS的解析,一般來說在90 kHz 中,PTS/9000的值為秒單位。
????
| unsignedlong?long?Parse_PTS(unsigned *pBuf) { ?????unsignedlong?long?llpts = (((unsigned long?long)(pBuf[0] & 0x0E)) << 29) ?????????| (unsigned long?long)(pBuf[1] << 22) ?????????| (((unsigned long?long)(pBuf[2] & 0xFE)) << 14) ?????????| (unsigned long?long)(pBuf[3] << 7) ?????????| (unsigned long?long)(pBuf[4] >> 1); ?????return?llpts; } PES結構詳解 2013年08月05日???編程?? 共 1100字???評論數 2?? 被圍觀 3,562+ PES是Packetized Elementary Stream的簡稱,是將原始ES流打包后形成的,再將PES經過不同的打包方式可以組成MPEG program stream 和 MPEG transport stream,即PS流和TS流。 PES的組成結構如圖,包括6個字節的包頭字段,加上3個字節基本流信息字段,根據信息字段的設置可在之后附加其他字段。 <a href="http://www.yunlipiao.com/wp-content/uploads/2013/08/pes.jpg" class="cboxElement" rel="example4" 208"="" style="text-decoration: none; color: rgb(1, 150, 227);">PES結構 前三字節是包頭起始標識字段,內容為0x000001 第四個字節是流ID字段,不同的流ID有不用的意義,如圖,音頻流ID范圍從0xC0到0xDF,視頻流ID范圍從0xE0到0xEF。 PES流ID字段 第五六個字節是PES包長度,表示PES包頭部在該字段之后的長度,單位是字節 接下來的第七八九字節是PES的擴展頭部字段,用于設置流的基本信息,結構如圖 PES可選擴展 第六字節的高兩位是標識位,值為10b 第七字節的高兩位是PTS和DTS指示位,00表示無PTS無DTS,01禁止使用,10表示PES頭部字段會附加PTS結構 pts結構 11表示PES頭部字段會附加PTS和DTS結構 pts和dts結構 其中PTS和DTS使用的是90KHZ時鐘單位,即1PTS表示1/90000秒,PTS和DTS雖然是33位,但占用了5個字節 ESCR FLAG字段設為1,會在頭部附加6個字節的ESCR結構,ES RATE FLAG字段設置為1,會在頭部附加3個字節ES rate結構,其他標識位如果設置為1也會相應的在頭部附加對應字段。 ES rate結構 ESCR結構 ? 本文地址:http://www.yunlipiao.com/208.html,出自云里飄博客,轉載請保留鏈接 |
轉載于:https://www.cnblogs.com/jukan/p/5290239.html
總結
- 上一篇: linkit-smart-7688-fe
- 下一篇: xcode 7.2 怎么在Playgro