// 所有原创文章转载请注明作者及链接
// blackboycpp(AT)gmail.com
// QQ群: 135202158
对TS流的分析, 涉及到对PAT,PMT等等的分析, 具体内容见iso/iec 13838系列文档,
本文只给出自己写的一些和TS分析想关的代码, 简单的分析足够了, 不考虑复杂情况:
////////////////////////////////////////////////////////////////////////// // // TS流结构定义 // ////////////////////////////////////////////////////////////////////////// #ifndef ZZQ_TS_H_ #define ZZQ_TS_H_ #include <vector> using namespace std; typedef unsigned char byte; typedef unsigned int bits; #define TSPKT_LENGTH 188 //----------------------------------------------------------------------------- // 结构体 //----------------------------------------------------------------------------- // TS包构成伪代码 /* transport_packet() { sync_byte transport_error_indicator payload_unit_start_indicator transport_priority PID transport_scrambling_control adaptation_field_control continuity_counter if(adaptation_field_control=='10' || adaptation_field_control=='11') { adaptation_field() } if(adaptation_field_control=='01' || adaptation_field_control=='11') { for (i=0;i<N;i++) { data_byte } } } */ // TS包头部 // WARNING!!! 暂时没有考虑修改区以及修改区内可选字段的处理 struct ts_header { bits sync_byte : 8; bits transport_error_indicator : 1; bits payload_unit_start_indicator : 1; bits transport_priority : 1; bits PID : 13; bits transport_scrambling_control : 2; bits adaptation_field_control : 2; bits continuity_counter : 4; }; // TS包中的修改字段(adaptation field) struct ts_adaptation_field { bits adaptation_field_length : 8; bits discontinuity_idicator : 1; bits random_access_indicator : 1; bits elementary_stream_priority_indicator : 1; bits flags : 5; // 5 flags }; // PAT中的可变段 struct ts_pat_section { bits program_number : 16; bits reserved : 3; bits PID : 13; }; typedef vector<ts_pat_section> vec_pat_section; // PAT表, P138-PAT的结构, 文档P61 struct ts_pat { bits table_id : 8; // 0x00 bits section_syntax_indicator : 1; // 1 bits zero : 1; // 0 bits reserved_1 : 2; // 11 bits section_length : 12; bits transport_stream_id : 16; // 传输数据流识别 bits reserved_2 : 2; // "11" bits version_number : 5; bits current_next_indicator : 1; bits section_number : 8; bits last_section_number : 8; // .... TODO vec_pat_section network_section; vec_pat_section pmt_section; bits crc32 : 32; }; // Stream_type分配表, P85 #define ST_Reserved 0x00 // ITU-T | ISO/IEC Reserved #define ST_VIDEO_1 0x01 // ISO/IEC 11172 Video #define ST_VIDEO_2 0x02 // ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or ISO/IEC 11172-2 constrained parameter video stream #define ST_AUDIO_1 0x03 // ISO/IEC 11172 Audio #define ST_AUDIO_2 0x04 // ISO/IEC 13818-3 Audio #define ST_PRIVATE_SECTIONS 0x05 // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections #define ST_PES_PKT_PRIVATE_DATA 0x06 // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data #define ST_MHEG 0x07 // ISO/IEC 13522 MHEG #define ST_DSMCC 0x08 // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM CC #define ST_H2221 0x09 // ITU-T Rec. H.222.1 #define ST_TYPEA 0x0A // ISO/IEC 13818-6 type A #define ST_TYPEB 0x0B // ISO/IEC 13818-6 type B #define ST_TYPEC 0x0C // ISO/IEC 13818-6 type C #define ST_TYPED 0x0D // ISO/IEC 13818-6 type D #define ST_AUXILIARY 0x0E // ISO/IEC 13818-1 auxiliary // 0x0F-0x7F: ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved // 0x80-0xFF: User Private // PMT表中的ES段 struct ts_pmt_es_section { bits stream_type : 8; bits reserved_1 : 3; bits elementary_PID : 13; bits reserved_2 : 4; bits ES_info_length : 12; }; typedef vector<ts_pmt_es_section> vec_pmt_section; // PMT表, 书P138 - PMT的结构 struct ts_pmt { bits table_id : 8; // 0x02 bits section_syntax_indicator : 1; // 1 bits zero : 1; // 0 bits reserved_1 : 2; // 11 bits section_length : 12; bits program_number : 16; bits reserved_2 : 2; // 11 bits version_number : 5; bits current_next_indicator : 1; bits section_number : 8; bits last_section_number : 8; bits reserved_3 : 3; // 111 bits PCR_PID : 13; bits reserved_4 : 4; // 1111 bits program_info_length : 12; vec_pmt_section es_section; bits crc32 : 32; }; // PES包构成伪代码 P43 /* 太长,略 */ // Steam ID分配表, 文档P47 #define SID_PROGRAM_STREAM_MAP 0xBC #define SID_PRIVATE_STREAM_1 0xBD #define SID_PADDING_STREAM 0xBE #define SID_PRIVATE_STREAM_2 0xBF #define SID_AUDIO_STREAM 0xC0 // 110x xxxx, stream number x xxxx #define SID_VIDEO_STREAM 0xE0 // 1110 xxxx, stream number xxxx #define SID_ECM_STREAM 0xF0 #define SID_EMM_STREAM 0xF1 #define SID_DSMCC_STREAM 0xF2 #define SID_13522_STREAM 0xF3 #define SID_TYPEA 0xF4 #define SID_TYPEB 0xF5 #define SID_TYPEC 0xF6 #define SID_TYPED 0xF7 #define SID_TYPEE 0xF8 #define SID_ANCILLARY_STREAM 0xF9 // 1111 1010 ~ 1111 1110, reserved data stream #define SID_PROGRAM_STREAM_DIRECTORY 0xFF // PES包中的可选包头部 struct optional_pes_header { bits prefix : 2; // "10" bits pes_scrambling_control : 2; bits pes_priority : 1; bits data_alignment_indicator : 1; bits copyright : 1; bits original_or_copy : 1; // 7 flags start bits PTS_DTS_flags : 2; bits ESCR_flag : 1; bits ES_rate_flag : 1; bits DSM_trick_mode_flag : 1; bits additional_copy_info_flag: 1; bits PES_CRC_flag : 1; bits PES_extension_flag : 1; // 7 flags end bits pes_header_data_length : 8; // WARNING!!! 目前只使用 PTS, DTS bits PTS_H : 3; // 32..30 bits PTS_M : 15; // 29..15 bits PTS_L : 15; // 14..0 bits DTS_H : 3; // 32..30 bits DTS_M : 15; // 29..15 bits DTS_L : 15; // 14..0 }; // PES包头部, 文档P43, 书P131 struct pes_header { bits packet_start_code_prefix : 24; bits stream_id : 8; bits pes_packet_length : 16; // 之后是optional PES header, 即任意包头, 它的有无由stream_id决定 bool ophdr_flag; optional_pes_header ophdr; // 如果声明为指针, 会带来一些内存问题 //byte* es_data; // 实际数据指针 int offset; // 实际数据偏移 pes_header() { ophdr_flag = false; offset = -1; } ~pes_header() {} }; //----------------------------------------------------------------------------- // 位段结构调整函数 //----------------------------------------------------------------------------- int adjust_ts_header(ts_header* pkt, byte* buff); int adjust_ts_pat(ts_pat* pkt, byte* buff); int adjust_ts_pmt(ts_pmt* pkt, byte* buff); int adjust_ts_pes_header(pes_header* pkt, byte* buff); __int64 get_pts_from_pes(pes_header& pkt); __int64 get_dts_from_pes(pes_header& pkt); #endif
////////////////////////////////////////////////////////////////////////// // // TS流相关函数 // ////////////////////////////////////////////////////////////////////////// #include <stdio.h> #include "zzq_TS.h" int adjust_ts_header(ts_header* pkt, byte* buff) { if(pkt == NULL || buff == NULL) { return 1; } pkt->sync_byte = buff[0]; pkt->transport_error_indicator = buff[1] >> 7; pkt->payload_unit_start_indicator = buff[1] >> 6 & 0x01; pkt->transport_priority = buff[1] >> 5 & 0x01; pkt->PID = (buff[1] & 0x1f)<<8 | buff[2]; pkt->transport_scrambling_control = buff[3] >> 6; pkt->adaptation_field_control = buff[3] >> 4 & 0x03; pkt->continuity_counter = buff[3] & 0x03; return 0; } int adjust_ts_pat(ts_pat* pkt, byte* buff) { if(pkt == NULL || buff == NULL) { return 1; } pkt->table_id = buff[0]; pkt->section_syntax_indicator = buff[1] >> 7; pkt->zero = buff[1] >> 6 & 0x1; pkt->reserved_1 = buff[1] >> 4 & 0x3; pkt->section_length = (buff[1] & 0x0f) << 8 | buff[2]; pkt->transport_stream_id = buff[3] << 8 | buff[4]; pkt->reserved_2 = buff[5] >> 6; pkt->version_number = buff[5] >> 1 & 0x1f; pkt->current_next_indicator = (buff[5] << 7) >> 7; pkt->section_number = buff[6]; pkt->last_section_number = buff[7]; // get crc32 int len = 3 + pkt->section_length; pkt->crc32 = (buff[len-4] & 0x000000ff) << 24 | (buff[len-3] & 0x000000ff) << 16 | (buff[len-2] & 0x000000ff) << 8 | (buff[len-1] & 0x000000ff); // get variable section for(int i=0; i<pkt->section_length-4-8; i+=4 ) { ts_pat_section sec; sec.program_number = buff[8+i] << 8 | buff[9]; sec.reserved = buff[10+i] >> 5; sec.PID = (buff[10+i] << 3) << 5 | buff[11+i]; if(sec.program_number == 0x0) pkt->network_section.push_back(sec); else pkt->pmt_section.push_back(sec); } return 0; } int adjust_ts_pmt(ts_pmt* pkt, byte* buff) { if(pkt == NULL || buff == NULL) { return 1; } pkt->table_id = buff[0]; pkt->section_syntax_indicator = buff[1] >> 7; pkt->zero = buff[1] >> 6; pkt->reserved_1 = buff[1] >> 4; pkt->section_length = (buff[1] & 0x0f) << 8 | buff[2]; pkt->program_number = buff[3] << 8 | buff[4]; pkt->reserved_2 = buff[5] >> 6; pkt->version_number = buff[5] >> 1 & 0x1f; pkt->current_next_indicator = (buff[5] << 7) >> 7; pkt->section_number = buff[6]; pkt->last_section_number = buff[7]; pkt->reserved_3 = buff[8] >> 5; pkt->PCR_PID = ((buff[8] << 8) | buff[9]) & 0x1fff; pkt->reserved_4 = buff[10] >> 4; pkt->program_info_length = (buff[10] & 0x0f) << 8 | buff[11]; // get crc32 int len = pkt->section_length + 3; pkt->crc32 = (buff[len-4] & 0x000000ff) << 24 | (buff[len-3] & 0x000000ff) << 16 | (buff[len-2] & 0x000000ff) << 8 | (buff[len-1] & 0x000000ff); // skip program description int pos = 12 + pkt->program_info_length; for( ; pos <= (pkt->section_length-4); pos+=5) { ts_pmt_es_section sec; sec.stream_type = buff[pos]; sec.reserved_1 = buff[pos+1] >> 5; sec.elementary_PID = ((buff[pos+1] << 8) | buff[pos+2]) & 0x1fff; sec.ES_info_length = (buff[pos+3] & 0x0f) << 8 | buff[pos+4]; pkt->es_section.push_back(sec); pos += sec.ES_info_length; } return 0; } int adjust_ts_pes_header(pes_header* pkt, byte* buff) { if(pkt == NULL || buff == NULL) { return 1; } // 0000 0000 0000 0000 0000 0001 : 0x000001 pkt->packet_start_code_prefix = (buff[0] & 0x0000ff) << 16 | (buff[1] & 0x0000ff) << 8 | (buff[2] & 0x0000ff); //if(pkt->packet_start_code_prefix != 0x000001) return 2; byte sid = buff[3]; // aux pkt->stream_id = buff[3]; pkt->pes_packet_length = buff[4] << 8 | buff[5]; if(sid != SID_PROGRAM_STREAM_MAP && sid != SID_PADDING_STREAM && sid != SID_PRIVATE_STREAM_2 && sid != SID_ECM_STREAM && sid != SID_EMM_STREAM && sid != SID_PROGRAM_STREAM_DIRECTORY && sid != SID_DSMCC_STREAM && sid != SID_TYPEE ) { pkt->ophdr_flag = true; pkt->ophdr.prefix = buff[6] >> 6; // "10" : 2 //if(pkt->ophdr->prefix != 2) return 2; pkt->ophdr.pes_scrambling_control = buff[6] >> 4 & 0x03; pkt->ophdr.pes_priority = buff[6] >> 3 & 0x01; pkt->ophdr.data_alignment_indicator = buff[6] >> 2 & 0x01; pkt->ophdr.copyright = buff[6] >> 1 & 0x01; pkt->ophdr.original_or_copy = buff[6] & 0x01; pkt->ophdr.PTS_DTS_flags = buff[7] >> 6 & 0x03; pkt->ophdr.ESCR_flag = buff[7] >> 5 & 0x01; pkt->ophdr.ES_rate_flag = buff[7] >> 4 & 0x01; pkt->ophdr.DSM_trick_mode_flag = buff[7] >> 3 & 0x01; pkt->ophdr.additional_copy_info_flag = buff[7] >> 2 & 0x01; pkt->ophdr.PES_CRC_flag = buff[7] >> 1 & 0x01; pkt->ophdr.PES_extension_flag = buff[7] & 0x01; pkt->ophdr.pes_header_data_length = buff[8]; if(pkt->ophdr.PTS_DTS_flags == 0x2) // "10" { // 以下移位操作, 都将各位串靠左对齐 pkt->ophdr.PTS_H = buff[9] << 3 & 0xe0; // 3 bits pkt->ophdr.PTS_M = (buff[10] << 8) | (buff[11] & 0xfe); // 15 bits pkt->ophdr.PTS_L = (buff[12] << 8) | (buff[13] & 0xfe); // 15 bits } else if(pkt->ophdr.PTS_DTS_flags == 0x3) // "11" { // 以下移位操作, 都将各位串靠左对齐 pkt->ophdr.PTS_H = buff[9] << 3 & 0xe0; // 3 bits pkt->ophdr.PTS_M = (buff[10] << 8) | (buff[11] & 0xfe); // 15 bits pkt->ophdr.PTS_L = (buff[12] << 8) | (buff[13] & 0xfe); // 15 bits pkt->ophdr.DTS_H = buff[14] << 3 & 0xe0; pkt->ophdr.DTS_M = (buff[15] << 8) | (buff[16] & 0xfe); // 15 bits pkt->ophdr.DTS_L = (buff[17] << 8) | (buff[18] & 0xfe); // 15 bits } ////////////////////////////////////////////////////////////////////////// // ESCR, ES_rate之类的目前不处理 // 6 + 3: (24+8+16) + (2+2+1+1+1+1+8+8) pkt->offset = 6 + 3 + pkt->ophdr.pes_header_data_length; } else if(sid == SID_PROGRAM_STREAM_MAP || sid == SID_PRIVATE_STREAM_2 || sid == SID_ECM_STREAM || sid == SID_EMM_STREAM || sid == SID_PROGRAM_STREAM_DIRECTORY || sid == SID_DSMCC_STREAM || sid == SID_TYPEE ) { pkt->offset = 6; } else if(sid == SID_PADDING_STREAM) { pkt->offset = -1; } return 0; } __int64 get_pts_from_pes(pes_header& pkt) { if(pkt.ophdr_flag == false) return -1; if(pkt.ophdr.PTS_DTS_flags != 0x2 && pkt.ophdr.PTS_DTS_flags != 0x3) return -1; __int64 H = 0, M = 0, L = 0; L = pkt.ophdr.PTS_L >> 1 | pkt.ophdr.PTS_M << 14; M = pkt.ophdr.PTS_M >> 2 | pkt.ophdr.PTS_H << 13; L = pkt.ophdr.PTS_H >> 3; return (H<<32) | (M<<16) | L; } __int64 get_dts_from_pes(pes_header& pkt) { if(pkt.ophdr_flag == false) return -1; if(pkt.ophdr.PTS_DTS_flags != 0x3) return -1; __int64 H = 0, M = 0, L = 0; L = pkt.ophdr.DTS_L >> 1 | pkt.ophdr.DTS_M << 14; M = pkt.ophdr.DTS_M >> 2 | pkt.ophdr.DTS_H << 13; L = pkt.ophdr.DTS_H >> 3; return (H<<32) | (M<<16) | L; }