数字电视中TS包解码函数

/***************************************************************************** 
* dvbpsi_PushPacket                数字电视中TS包解码函数注解
*****************************************************************************
* Injection of a TS packet into a PSI decoder.
*****************************************************************************/
void dvbpsi_PushPacket(dvbpsi_handle h_dvbpsi, uint8_t* p_data)
{
	uint8_t i_expected_counter; 		/* 存储下一个数据包的连续计数器数字 */
	dvbpsi_psi_section_t* p_section; 	/* 当前段指针 */
	uint8_t* p_payload_pos; 			/* 当前位置指针 */
	uint8_t* p_new_pos = NULL; 		/* Beginning of the new section,updated to NULL when the new section is handled */
	int i_available; 					/* 包中可用字节数 */
	/* TS start code */
	if(p_data[0] != 0x47)				 //同步字节(sync byte:1B),应为0x47
	{
		DVBPSI_ERROR("PSI decoder", "not a TS packet");
		return;
	}
	/* 连续检查 */
	i_expected_counter = (h_dvbpsi->i_continuity_counter + 1) & 0xf; 	/*连续计数器累加1*/
	h_dvbpsi->i_continuity_counter = p_data[3] & 0xf; 				//TS头部最后4比特为连续计数器
	if(i_expected_counter != h_dvbpsi->i_continuity_counter)			 /*判断是否是连续传送的包*/
	{
		DVBPSI_ERROR_ARG("PSI decoder",
		"TS discontinuity (received %d, expected %d)",
		h_dvbpsi->i_continuity_counter, i_expected_counter);
		h_dvbpsi->b_discontinuity = 1; 				//将不连续标志置1
		if(h_dvbpsi->p_current_section) 			//删除当前段
		{
			dvbpsi_DeletePSISections(h_dvbpsi->p_current_section); 	//释放空间
			h_dvbpsi->p_current_section = NULL;
		}
	}
	/* 判断是否有有效负载,没有就返回*/
	if(!(p_data[3] & 0x10))	 //第28bit标识有无调整段
	{
		return;
	}
	/* 跳过自适应长度区 */
	if(p_data[3] & 0x20) 							//第27bit标识有无自适应区(adaption field)
		p_payload_pos = p_data + 5 + p_data[4]; 	//5为包头4字节及1字节的自适应长度 p_data[4]自适应区长度
	else
		p_payload_pos = p_data + 4;
	/* Unit start -> skip the pointer_field and a new section begins */
	if(p_data[1] & 0x40) 		//即"payload unit start indicator"bit位 有效荷载单元起始批示符位,值为1表示存在确定的起始信息
	{
		p_new_pos = p_payload_pos + *p_payload_pos + 1; //指向包数据起始位置
		p_payload_pos += 1; //跳过长度指示的1个字节
	}
	p_section = h_dvbpsi->p_current_section;
	/* If the psi decoder needs a begginning of section and a new section
	begins in the packet then initialize the dvbpsi_psi_section_t structure */
	if(p_section == NULL)
	{
		if(p_new_pos)
		{
			/* 为结构分配内存空间 */
			h_dvbpsi->p_current_section
			= p_section
			= dvbpsi_NewPSISection(h_dvbpsi->i_section_max_size);
			/* 更新当前位置指针 */
			p_payload_pos = p_new_pos;
			/* 有指针指向新段 */
			p_new_pos = NULL;
			/* Just need the header to know how long is the section */
			h_dvbpsi->i_need = 3;		 //在前3个字节中包含了表ID、section syntax indicator和长度批示,能确定是那种表,有多长
			h_dvbpsi->b_complete_header = 0;
		}
		else
		{
			/* No new section => return */
			return;
		}
	}
	/* Remaining bytes in the payload */
	i_available = 188 + p_data - p_payload_pos; //有效载荷长度
	while(i_available > 0)
	{
		if(i_available >= h_dvbpsi->i_need)
		{
			/* 有足够的字节存储头部或整个段的信息 */
			memcpy(p_section->p_payload_end, p_payload_pos, h_dvbpsi->i_need);
			p_payload_pos += h_dvbpsi->i_need;
			p_section->p_payload_end += h_dvbpsi->i_need;
			i_available -= h_dvbpsi->i_need;
			if(!h_dvbpsi->b_complete_header)
			{
				/* Header is complete */
				h_dvbpsi->b_complete_header = 1;
				/* Compute p_section->i_length and update h_dvbpsi->i_need */
				//不懂?????????
				h_dvbpsi->i_need = p_section->i_length = ((uint16_t)(p_section->p_data[1] & 0xf)) << 8 | p_section->p_data[2]; //从第12个比特位到第24个比特位为长度批示段
				/* 检查段是否超过最大长度 */
				if(h_dvbpsi->i_need > h_dvbpsi->i_section_max_size - 3) //包头3个字节
				{
					DVBPSI_ERROR("PSI decoder", "PSI section too long");
					dvbpsi_DeletePSISections(p_section);
					h_dvbpsi->p_current_section = NULL;
					/* 如果还有新段没有分析,则继续*/
					if(p_new_pos)
					{
						h_dvbpsi->p_current_section
						= p_section
						= dvbpsi_NewPSISection(h_dvbpsi->i_section_max_size);
						p_payload_pos = p_new_pos;
						p_new_pos = NULL;
						h_dvbpsi->i_need = 3;
						h_dvbpsi->b_complete_header = 0;
						i_available = 188 + p_data - p_payload_pos;
					}
					else
					{
						i_available = 0;
					}
				}
			}
			else
			{
				/* PSI section is complete */
				p_section->b_syntax_indicator = p_section->p_data[1] & 0x80; //读段语法标志 位
				p_section->b_private_indicator = p_section->p_data[1] & 0x40; //固定的'0',这是为了防止和ISO13818Video流格式中的控制字冲突而设置的
				/* 如果存在CRC校验数据,则更新p_payload_end指针 */
				if(p_section->b_syntax_indicator)
					p_section->p_payload_end -= 4;
				if(dvbpsi_ValidPSISection(p_section)) /*调用函数对数据进行CRC校验*/
				{
					/* 数据无误 */
					p_section->i_table_id = p_section->p_data[0]; //从第一个字节读取表ID,0x00为PAT,0x02为PMT
					if(p_section->b_syntax_indicator)
					{
						p_section->i_extension = (p_section->p_data[3] << 8)
						| p_section->p_data[4]; //16bits的当前流ID,DVB内唯一.(事实上很多都是自定义的TS ID)
						p_section->i_version = (p_section->p_data[5] & 0x3e) >> 1; //43到47的5bits为版本号码,标注当前节目的版本.这是个非常有用的参数,当检测到这个字段改变时,说明TS流中的节目已经变化了,程序必须重新搜索节目
						p_section->b_current_next = p_section->p_data[5] & 0x1; //第48比特位,当前还是未来使用标志符,一般情况下为'0'
						p_section->i_number = p_section->p_data[6]; //当前段号码
						p_section->i_last_number = p_section->p_data[7]; //最后段号码(section_number和last_section_number的功能是当PAT内容>184字节时,PAT表会分成多个段(sections),解复用程序必须在全部接收完成后再进行PAT的分析)从for()开始,就是描述了当前流中的频道数目(N),每一个频道对应的PMT PID是什么.解复用程序需要和上图类似的循环来接收所有的频道号码和对应的PMT PID,并把这些信息在缓冲区中保存起来.在后部的处理中需要使用到PMT PID.
						p_section->p_payload_start = p_section->p_data + 8; //前面已分析了8个字节,指向新的开始
					}
					else
					{
						p_section->p_payload_start = p_section->p_data + 3;
					}
					h_dvbpsi->pf_callback(h_dvbpsi, p_section);
					h_dvbpsi->p_current_section = NULL;
				}
				else
				{
					/* PSI section isn't valid => trash it */
					dvbpsi_DeletePSISections(p_section);
					h_dvbpsi->p_current_section = NULL;
				}
				/* If there is a new section not being handled then go forward
				in the packet */
				if(p_new_pos)
				{
					h_dvbpsi->p_current_section
					= p_section
					= dvbpsi_NewPSISection(h_dvbpsi->i_section_max_size);
					p_payload_pos = p_new_pos;
					p_new_pos = NULL;
					h_dvbpsi->i_need = 3;
					h_dvbpsi->b_complete_header = 0;
					i_available = 188 + p_data - p_payload_pos;
				}
				else
				{
				i_available = 0;
				}
			}
		}
		else
		{
			/* There aren't enough bytes in this packet to complete the
			header/section */
			memcpy(p_section->p_payload_end, p_payload_pos, i_available);
			p_section->p_payload_end += i_available;
			h_dvbpsi->i_need -= i_available;
			i_available = 0;
		}
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值