欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数字电视技术实验(一)——TS流中PAT的读取及分析

程序员文章站 2022-03-23 08:33:24
...

实验目的:

  1. 输出TS包的包长
  2. 节目套数及对应节目的PMT PID

(一)实验代码

#include <iostream>
#include <cstdio>
#include <stdio.h>
#include <string>
#include <fstream>

using namespace std;

int package_len=0;
int firstPackagePos = 0;
int ProgramTotalNumber = 0;//节目总数
int Program_count = 0;//用以表示现在存到第几个Program了

struct _Program{
	int Program_number;
	int PMT_PID;
	int PCR_PID;
	int Video_PID;
	int Audio_PID_1;
	int Audio_PID_2;
	bool flag;
}Program[16];

/*判断包长究竟是188还是204*/
void FindSyn(unsigned char *pBuffer_408)
{
	for(int i=0;i<204;i++)
	{
		//包长188字节的情况
		if (pBuffer_408[i]==0x47 && pBuffer_408[i+188]==0x47)
		{
			package_len=188;
			firstPackagePos=i;
			cout<<"packetage length = "<<188<<" & start from "<<i<<endl;	
			break;
		}
		//包长204字节的情况
		else if (pBuffer_408[i]==71 && pBuffer_408[i+204]==71)
		{
			package_len=204;
			firstPackagePos=i;
			cout<<"package length = "<<204<<" & start from "<<i<<endl;	
			break;
		}
		
	}
}

/*判断adaptation_field_control的值,共有00,01,10,11四种可能
adaptation_field_control==00或10,返回0  (没有有效载荷)
adaptation_field_control==01,    返回1  (没有适配域)
adaptation_field_control==11,    返回2  (有适配域)*/
int IsValid(unsigned char* pBuffer_package)
{
	unsigned char adaptation_field_control = (pBuffer_package[3] << 2) >> 6;
	if ((adaptation_field_control == 0) || (adaptation_field_control == 2))
		return 0;
	else if (adaptation_field_control == 1)
		return 1;
	else if (adaptation_field_control == 3)
		return 2;
	else
		return 3;
}

int GetNumber(int offset, unsigned char* pBuffer_package)
{
	int section_length = (pBuffer_package[offset + 1] % 16) * 256 + pBuffer_package[offset + 2];
	int number = (section_length - 9) / 4;
	return number;
}

/*return 0:表示这是PAT的最后一个包
  return 1:表示在之后依然会传输PAT包*/
int ReadPAT(unsigned char *pBuffer_package)
{
	//计算此时是不是PAT包
	int high5 = int(pBuffer_package[1]);
	int low8 = int(pBuffer_package[2]);
	int PID = (high5 % 32) * 256 + low8;
	
	if (PID == 0)//此时是PAT包了
	{
		//0:无效载荷;1:01;2:11
		int ValidFlag = IsValid(pBuffer_package);

		//确定净荷偏移为offset,开始读PAT表
		int offset = 0;
		unsigned char payload_unit_start_indicator = (pBuffer_package[1] << 1) >> 7;
		switch (ValidFlag)
		{
		case 0:
			return 1;
		case 1:
			offset = 4;
			if (payload_unit_start_indicator)
			{
				//从当前offset位置读取pointer_field字节
				int pointer_field = pBuffer_package[4];
				offset += pointer_field + 1;
			}
			break;
		case 2:
			int adaption_field_length = pBuffer_package[4];
			offset = adaption_field_length + 5;
			if (payload_unit_start_indicator)
			{
				//从当前offset位置读取pointer_field字节
				int pointer_field = pBuffer_package[4];
				offset += pointer_field + 1;
			}
			break;
		}

		//进行PAT包的读取
		if (pBuffer_package[offset] != 0)//如果table id!=0,读取下一个TS包
			return 1;
		int number = GetNumber(offset, pBuffer_package);//根据section_length,确定节目总数N
		ProgramTotalNumber += number;
		int tempPos = offset + 8;
		for (int i = 0; i < number; i++)
		{
			Program[Program_count].Program_number = (pBuffer_package[tempPos] % 256 * 256) + pBuffer_package[tempPos + 1];
			Program[Program_count].PMT_PID = ((pBuffer_package[tempPos + 2] % 32) * 256) + pBuffer_package[tempPos + 3];
			tempPos += 4;
			Program_count++;
		}
		unsigned char section_number = pBuffer_package[offset + 6];
		unsigned char last_section_number = pBuffer_package[offset + 7];
		if (section_number != last_section_number)
			return 1;
	}
	else if (PID != 0)
		return 1;
	return 0;
}


int main()
{
	string m_Analyze_OpenFile="2.TS";
	ifstream file_analyze("2.ts", ios::binary);
	unsigned char* pBuffer_408=new unsigned char[408];
	
	if(!file_analyze)
	{
		cout<<"Open File Error!!"<<endl;
		exit(1);
	}
	
	file_analyze.read((char*) pBuffer_408,408);//先将408个值读入文件中(204*2)
	
	//判断sync_byte==0x47
	FindSyn(pBuffer_408);//判断包长是188还是204
	file_analyze.seekg(firstPackagePos, ios::beg);//回归TS包最开始的数值
    delete []pBuffer_408;//前述工作全部完成,结论为包长为188
	
	unsigned char* pBuffer_package=new unsigned char[package_len];//一个包一个包进行读写。

	//16套节目
	for(int i=0;i<16;i++)
	{
		Program[i].Program_number=-1;
		Program[i].PMT_PID=-1;
		Program[i].PCR_PID=-1;
		Program[i].Video_PID=-1;
		Program[i].Audio_PID_1=-1;
		Program[i].Audio_PID_2=-1;
		Program[i].flag=false;
	}	
	
	int m, n;
	file_analyze.seekg(0, ios::beg);
	m = file_analyze.tellg();
	file_analyze.seekg(0, ios::end);
	n = file_analyze.tellg();
	int len = n - m;

	int package_counts=(len-firstPackagePos)/package_len;
	cout<<"共有"<<package_counts<<" 个包"<<endl;
	
	file_analyze.seekg(firstPackagePos, ios::beg);
	
	//读TS包,将所有PAT包读出来
	for(int j=0;j<package_counts;j++)
	{
		file_analyze.read((char*)pBuffer_package, package_len);
		int continue_flag = ReadPAT(pBuffer_package);
		if (continue_flag == 0)
		{
			break;
		}
	}
	
	cout << "共有 " << ProgramTotalNumber << " 套节目" << endl;
	for (int i = 0; i < ProgramTotalNumber; i++)
	{
		cout << "节目 " << Program[i].Program_number << " 的 PMT PID为 " << Program[i].PMT_PID << endl;
	}

	delete []pBuffer_package;
	
	return 0;
}

(二)实验结果

数字电视技术实验(一)——TS流中PAT的读取及分析