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

实验目的:

  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;
}

(二)实验结果

在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值