TS流解析-提取PSI信息
来源:互联网 发布:远视 眼镜 知乎 编辑:程序博客网 时间:2024/06/06 00:20
TS流解析-提取PSI信息等
代码加注释如下:
- #include <iostream>
- #include <fstream>
- using namespace std;
- struct programs //封装节目信息的结构体
- {
- int programID;//节目编号
- int pmtPID;//所属PMT的pid
- int videoPID;//视频pid
- int audioPID1;//音频pid
- int audioPID2;//音频pid
- }myProg[20];
- bool FindAndParsePAT(unsigned char *buffer,int pID,int curPack);//传入BUF和PID的值
- bool FindAndParsePMT(unsigned char *buffer,int pID,int curPack);
- int program=0;
- int prog_count=0;
- void main()
- {
- unsigned char *buffer=new unsigned char[500];
- int startPos=0;//第一个TS分组在流中的位置序号
- int packageLen=0;//分组长度
- int pmtCount=-1;//PMT表序号
- int pID=0;
- int nullpack=0;
- //0.以二进制方式打开TS文件
- ifstream myFile("test.ts",ios::binary|ios::in);
- //1.读入文件的前500个字节,找同步头、确定包长
- myFile.read((char *)buffer,500);
- for(int i=0;i<500;i++)
- { //判断有无压缩
- if(buffer[i]==0x47&&buffer[i+188]==0x47)
- {
- startPos=i;//第一个TS分组在流中的位置序号
- packageLen=188;//分组长度
- break;
- }
- else if(buffer[i]==0x47&&buffer[i+204]==0x47)
- {
- startPos=i;
- packageLen=204;
- break;
- }
- }
- //2.遍历流中的TS分组,查找PAT
- myFile.seekg(0,ios::end);//定位到文件尾部
- int totalBytes=myFile.tellg();//获取尾部距离首部的偏移量,即TS文件字节总数totalBytes
- int packageCount=(totalBytes-startPos)/packageLen;//确定进行遍历的循环次数 即总TS包数
- int curPack=0;
- while (curPack<packageCount)//遍历分组
- {
- myFile.seekg(startPos+curPack*packageLen);//定位到第curPack个分组的首字节
- myFile.read((char *)buffer,packageLen);//读出当前分组,保存到缓存buffer中,读一段分组长度188或204
- pID=((buffer[1]&31)<<8)+buffer[2];//解析出当前分组的pid(13位=第2个字节的后5位+第3个字节全8位)
- if(pID==0x1fff) //检查空包数
- {
- nullpack++;
- }
- if(FindAndParsePAT(buffer,pID,curPack))//执行程序:解析PAT 有效
- break; //表明只要解析一个PAT就行
- curPack++;
- }
- curPack=0;
- int a=0;
- while (curPack<packageCount)
- {
- myFile.seekg(startPos+curPack*packageLen);//定位到第curPack个分组的首字节
- myFile.read((char *)buffer,packageLen);//读出当前分组,保存到缓存buffer中,读一段分组长度188或204
- pID=((buffer[1]&31)<<8)+buffer[2];//解析出当前分组的pid(13位=第2个字节的后5位+第3个字节全8位)
- for(int k=0;k<prog_count;k++)
- {
- if(pID==myProg[k].pmtPID)
- //根据PAT表内容确定如何查PMT表
- {
- cout<<"第"<<k+1<<"套节目:"<<endl;
- FindAndParsePMT(buffer,pID,curPack);//执行程序:解析PMT
- a++;
- }
- }
- if(a==prog_count)
- {
- break;
- }
- curPack++;
- }
- cout<<endl;
- cout<<"TS流相关信息:流中第一个TS分组起始位置"<<startPos<<","<<"TS分组长度"<<packageLen<<","<<"节目数"<<program<<","<<"空包数"<<nullpack<<endl;
- cout<<"所有节目相关PID信息"<<endl;
- delete[]buffer;
- myFile.close();
- }
- //查找并解析PAT
- bool FindAndParsePAT(unsigned char *buffer,int pID,int curPack)
- {
- //3.根据pid值是否为0确认PAT分组,并从中读PMT的PID
- int adapLen=0;//TS分组适配字段长度
- int offset=0;//实际净荷在当前分组中的偏移量
- if(pID==0)
- {
- int payload_unit_start = (buffer[1]>>6) & 0X01;//净荷单元起始指示
- int adaptation_field_control = (buffer[3]>>4) & 0X03;//自适应字段控制
- //3.1 确定净荷起始位置(4字节固定首部+适配字段长度,adaption_field_control)
- if(adaptation_field_control==0x01)//无调整字段,仅净荷
- {
- adapLen=0;//TS分组适配字段长度为0
- }
- else if(adaptation_field_control==0x11)//有调整字段和净荷
- {
- adapLen=buffer[4];//自适应字段长度
- }
- else//无有效载荷,查找下一个分组
- {
- curPack++;
- //continue;
- }
- offset=4+adapLen;//确定净荷在当前分组中的偏移量,头的字节长度
- //3.2 确定PAT首部在净荷中的偏移量(如payload_unit_start_indicator为1,
- //则净荷首字节为偏移指针,指示PAT首部与其之间的偏移值)
- if(payload_unit_start==0x01)//如果净荷单元起始指示为1
- {
- offset+=buffer[offset]+1;//pointer_field字段长为1字节
- }
- //3.3 开始解析PAT表
- int tableID=buffer[offset];//从净荷起始
- if(tableID==0)//进入节目关联表PAT
- {
- int section_len=((buffer[offset+1]&0x0F)<<8)+buffer[offset+2];//code here:初始化
- int transport_stream_idd=(buffer[offset+3]<<8)+buffer[offset+4];//code here:初始化
- int current_next_indicator=buffer[offset+5]&0x01;//code here:初始化
- if (current_next_indicator)//当前PAT有效
- {
- prog_count=(section_len-9)/4-1;
- for(int i=0;i<prog_count;i++)
- {
- myProg[i].programID=(buffer[offset+12+i*4]<<8)+buffer[offset+12+i*4+1];//用2个字节表示节目号
- cout<<"节目号"<<myProg[i].programID<<" ";
- myProg[i].pmtPID=(buffer[offset+14+i*4]&0x1F<<8)+buffer[offset+14+i*4+1];//用13位表示映射表
- cout<<"映射表ID"<<myProg[i].pmtPID<<"\n";
- program++;
- }
- //your code here 读出PAT包中存储的有关节目PMT的信息,确定节目数以及每路节目的PMT表pid,存储到myProg中
- return true;
- }
- }
- }
- return false;
- }
- //查找并解析PMT
- bool FindAndParsePMT(unsigned char *buffer,int pID,int curPack)
- {
- //PMT 标志位
- int payload_unit_start_indicator; //1比特标志位,用来指示传送流分组带有PES分组或PSI数据时的情况
- int adaption_field_length; //自适应字段长度。
- int pointer_field; //
- int section_length; //规定此字段之后此分段的字节数,包括CRC
- int section_number;
- int last_section_number; //8位字段,值总为0x00
- int i=0;
- if (((buffer[3])<<2)/64==1)
- //判断adaption_field_control '01',无调整字段,仅含有有效负载
- //2位字段。用于指示本传送流分组首部是否跟随有调整字段和/或有效负载。
- /*00 为ISO/IEC未来使用保留
- 01 无调整字段,仅含有效负载
- 10 仅含调整字段,无有效负载
- 11 调整字段后为有效负载
- */
- {
- adaption_field_length=0;
- }
- else if (((buffer[3])<<2)/64==2)
- //判断adaption_field_control'10',仅含有调整字段,无有效负载
- {
- return true;
- }
- else if (((buffer[3])<<2)/64==3)
- //判断adaption_field_control'11',调整字段后为有效负载
- {
- adaption_field_length=buffer[4];//获得自适应字段长度
- }
- i=adaption_field_length;//指针指向有效负载部分
- /*
- 如果传输流分组带有一个 PSI部分的第一个字节,payload_unit_start_indicator值应被置'1',表明传输流分组的第一个字
- 节带有 pointer_field。如果传输流分组不带有一个 PSI部分的第一个字节payload_unit_start_indicator值应被置'0',表明在有
- 效负载中没有pointer_field。空分组的payload_unit_start_indicator应置'0'。
- */
- payload_unit_start_indicator=( (buffer[1])<<1 )/128;
- //1bit,1表示有pointer-field
- //0表示无
- if(payload_unit_start_indicator) //判断payload_unit_start_indicator
- {
- pointer_field=buffer[i+4];
- //8位,其值为在此字段之后到传输流分组有效负载的第一个字段的第一个字节之间的字节数。
- }
- else
- {
- pointer_field=-1;
- }
- i=i+pointer_field+1+4;//确定净荷在当前分组中的偏移量,头的字节长度
- if(buffer[i]==2) //判断table_id,PMT==0x02
- {
- section_length=buffer[i+1]%16*256+buffer[i+2];
- //section_length,12bit,表明在section_length字段之后此分段的字节数,包括CRC
- }
- section_number=buffer[i+6];
- last_section_number=buffer[i+7];
- for(int m=0;m<(section_length-57)/5;m++)
- //视频或音频流数目N的计算方法是N=(section_length--57)/5
- //section_length后面占用9字节+一堆从tsr.exe中看到的字节共57,CRC占用4字节
- {
- if(buffer[i+23+m*5]==0x02)
- {
- cout<<"视频PID:"<<buffer[i+24+m*5]%32*256+buffer[i+25+m*5]<<"\t";
- }
- if(buffer[i+23+m*(5+16)]==0x04)
- {
- cout<<"音频PID:"<<buffer[i+24+m*(5+16)]%32*256+buffer[i+25+m*(5+16)]<<"\t";
- }
- }
- cout<<endl;
- //your code here
- return true;
- }
0 0
- TS流解析-提取PSI信息
- 解析TS的PSI信息
- PSI、TS流总结
- PSI、TS流总结
- PSI、TS流总结
- PSI信息解析
- PSI信息解析
- PSI信息解析
- PSI信息解析
- PSI信息解析
- ts流psi/si:学习笔记1
- ts流psi/si:学习笔记2
- ts流psi/si:学习笔记3
- ts流psi/si:学习笔记4
- 能分析TS流,提取其中的SI表信息
- 【PSI/SI学习系列】2.PSI/SI深入学习2——PSI信息解析(PAT,PMT,CAT)
- 【PSI/SI学习系列】2.PSI/SI深入学习2——PSI信息解析(PAT,PMT,CAT)
- PSI/SI深入学习2——PSI信息解析(PAT,PMT,CAT)
- windows 8 PE 装VMware Tools 提示Microsoft Runtime DLL安装程序未能完成安装解决方法
- 在iOS7中修改状态栏字体的颜色
- [转]开源日志系统比较:scribe、chukwa、kafka、flume
- 【软工视频】软件设计
- js中string和number类型互转换技巧
- TS流解析-提取PSI信息
- Iterator迭代器及增强FOR(for-each)
- BSON C 学习笔记
- Srping 注解注入
- android log你不知道的小技巧
- GIS 二维常见算法-入门篇
- 从RDA平台HX8357D屏驱动分析platform_driver_register、platform_device_register
- Spring配置文件的
- 黑马程序员-c语言学习之指针的心得