文章目录
一、ts包头
ts包头以0x47开头,占4个字节32位。
//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;
二、Parse PAT
①通过0x47找到包头。
②解析包头,通过判断包头的PID确定packet带的内容是什么。(PAT 0x000,PMT 0x002,SDT 0x042等等)
③通过transport_error_indicator 判断是否需要处理该包。
④通过payload_unit_start_indicator 判断有效数据的位置,当取值为1时,packet有效数据往后偏移一位。
⑤确定是PAT包解析PAT。
例:
#include <stdio.h>
#include <vector>
#include <cstring>
#include <string.h>
#define PAT 0x000
#define CAT 0x001
#define PMT 0x002
#define SDT 0x042
#define GET_PID(p) ((p[1] & 0x1F) << 8 | p[2])
#define ERROR_INDICATOR(p) ((p[1] & 0x80)) // 0 是 表示当前包没有发生传输错误
#define PAYLOAD_UNIT_START_INDICATOR(p) (p[1] >> 6 & 0x01)
using namespace std;
//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(unsigned char *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;
}
//PAT
typedef struct TS_PAT_Program {
unsigned program_number ;// 16; //节目号
unsigned program_map_PID ;// 13; // 节目映射表的PID,节目号大于0时对应的PID,每个节目对应一个
} TS_PAT_Program;
typedef struct TS_PAT {
unsigned int table_id ;// 8; //固定为0x00 ,标志是该表是PAT表
unsigned int section_syntax_indicator ;// 1; //段语法标志位,固定为1
unsigned int zero ;// 1; //0
unsigned int reserved_1 ;// 2; // 保留位
unsigned int section_length ;// 12; //表示从下一个字段开始到CRC32(含)之间有用的字节数
unsigned int transport_stream_id ;// 16; //该传输流的ID,区别于一个网络中其它多路复用的流
unsigned int reserved_2 ;// 2;// 保留位
unsigned int version_number ;// 5; //范围0-31,表示PAT的版本号
unsigned int current_next_indicator ;// 1; //发送的PAT是当前有效还是下一个PAT有效
unsigned int section_number ;// 8; //分段的号码。PAT可能分为多段传输,第一段为00,以后每个分段加1,最多可能有256个分段
unsigned int last_section_number ;// 8; //最后一个分段的号码
std::vector<TS_PAT_Program> program;
unsigned int reserved_3 ;//3; // 保留位
unsigned long network_PID ;// 13; //网络信息表(NIT)的PID,节目号为0时对应的PID为network_PID
unsigned long CRC_32 ;// 32; //CRC32校验码
} TS_PAT;
int TS_network_Pid ;
std::vector<TS_PAT_Program> TS_program;
bool pushPAt(TS_PAT_Program pat) {
int i=0;
for(i=0; i< TS_program.size(); i++) {
if(TS_program[i].program_map_PID== pat.program_map_PID) {
return false;
}
}
TS_program.push_back(pat);
return true;
}
int adjust_PAT_table( TS_PAT *packet, unsigned char * buffer) {
packet->table_id = buffer[0];
packet->section_syntax_indicator = buffer[1] >> 7;
packet->zero = buffer[1] >> 6 & 0x1;
packet->reserved_1 = buffer[1] >> 4 & 0x3;
packet->section_length = (buffer[1] & 0x0F) << 8 | buffer[2];
packet->transport_stream_id = buffer[3] << 8 | buffer[4];
packet->reserved_2 = buffer[5] >> 6;
packet->version_number = buffer[5] >> 1 & 0x1F;
packet->current_next_indicator = buffer[5] & 0x1;
packet->section_number = buffer[6];
packet->last_section_number = buffer[7];
if( packet->current_next_indicator != 1) {
printf(" the section not available \n");
return -1;
}
printf("packet->table_id =%d packet->section_lengt =%d \n",packet->table_id ,packet->section_length);
int len = 0;
len = 3 + packet->section_length;
packet->CRC_32 = (buffer[len-4] & 0x000000FF) << 24
| (buffer[len-3] & 0x000000FF) << 16
| (buffer[len-2] & 0x000000FF) << 8
| (buffer[len-1] & 0x000000FF);
printf(" version_number =%d , section_number %d last seciton number %d \n",packet->version_number ,packet->section_number , packet->last_section_number);
int n = 0;
for ( n = 8; n < packet->section_length - 4; n += 4 ) {
unsigned int program_num = buffer[n] << 8 | buffer[1+ n ];
packet->reserved_3 = buffer[2 + n ] >> 5;
packet->network_PID = 0x00;
if ( program_num == 0x00) {
packet->network_PID = (buffer[2 + n ] & 0x1F) << 8 | buffer[3 + n ];
TS_network_Pid = packet->network_PID; //记录该TS流的网络PID
// printf(" packet->network_PID %0x \n", packet->network_PID );
} else {
TS_PAT_Program PAT_program;
PAT_program.program_map_PID = (buffer[2 + n] & 0x1F) << 8 | buffer[3 + n];
PAT_program.program_number = program_num;
if(pushPAt(PAT_program) ) {
packet->program.push_back( PAT_program );
//TS_program.push_back( PAT_program );//向全局PAT节目数组中添加PAT节目信息
}
}
}
return 0;
}
int main() {
printf("hello \n");
int res = 0;
FILE *file=NULL;
char mSourcePath[100]= "beijing.ts";
unsigned char buffer[188]= {0};
unsigned char *prt;
int pmt_array[30] = {0};
file = fopen(mSourcePath, "rb");
if(file == NULL) {
printf("open input file error, filePath=%s!!!\n", mSourcePath);
} else {
printf("open input file success, filePath=%s!!!\n", mSourcePath);
}
int pid = -1;
TS_PAT patData;
memset(&patData,0x0,sizeof(TS_PAT));
while(1) {
res = fread(buffer,1,1,file);
if(res<=0) {
break;
}
if(buffer[0] == 0x47) { //find ts heard pakage
res = fread(buffer+1,187,1,file);
prt = buffer;
pid = GET_PID(prt);
if(pid == PAT) { //find pat parse pmt pid
if(ERROR_INDICATOR(prt) == 0) {
if(PAYLOAD_UNIT_START_INDICATOR(prt) ==1)
adjust_PAT_table(&patData,prt + 5); // ts package head 4*8 =32b + 8
else
adjust_PAT_table(&patData,prt + 4); // ts package head 4*8 =32b + 0
break;
} else {
printf("is pack error PAT pid =%d\n",pid);
}
}
// printf("is PAT pid =%d\n",pid);
}
}
int i=0;
for(i=0; i< TS_program.size(); i++) {
printf("PMT pid =%d program_number=%d \n",TS_program[i].program_map_PID,TS_program[i].program_number);
}
printf("is end \n");
}