TS流解析PAT


一、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");

}

猜你喜欢

转载自blog.csdn.net/qq_35831940/article/details/120947591