H264码合成TS专用API

       为方便264码转换为TS码,针对TSTOOL源码进行分析修改,做成函数接口,供方便调用。目前该接口在VS2013工程环境已经测试通过,不废话,直接上货。

   1.函数API-------  void   taransTs(TNAL* pNal)

     输入参数:TNAL* pNal----264码流帧nalu;TNAL结构见下

     返回:  无

     注:生成的ts码流数据在该函数中,用户可根据自己需要决定是否修改

  2.相关函数结构

    1)API函数taransTs具体内容

     

void taransTs(TNAL* pNal)
{
	NALU_t * nalu=NULL;
	Ts_Adaptation_field  ts_adaptation_field_Head;
	Ts_Adaptation_field  ts_adaptation_field_Tail;
	unsigned long  Timestamp_video = 0;    //一帧视频所用时间
	unsigned long  Timestamp_audio = 0;    //一帧音频所用时间 
	unsigned int framerate = 60;
	unsigned int   videoframetype = 0;    //视频帧类型
     //赋值s
	//分配nal 资源
	nalu = AllocNALU(MAX_VIDEO_TAG_BUF_SIZE);
	nalu->len = pNal->size;       //设置包含nal 头的数据长度	
	memcpy(nalu->buf, pNal->data, pNal->size);//拷贝一个nal 数据到数组中
	nalu->forbidden_bit = nalu->buf[4] & 0x80;                     //1 bit  设置nal 头
	nalu->nal_reference_idc = nalu->buf[4] & 0x60;                 // 2 bit
	nalu->nal_unit_type = (nalu->buf[4]) & 0x1f;                   // 5 bit
	//判断帧类型
	GetFrameType(nalu);	
	FreeNALU(nalu);

	//获得数据值
	Take_Out_Pes(&m_video_tspes, Timestamp_video, 0x00, &videoframetype, pNal->size, pNal->data);
	if (nalu->Frametype == FRAME_I || nalu->Frametype == FRAME_P || nalu->Frametype == FRAME_B)
	{
		//填写自适应段标志
		printf("3PES_VIDEO  :  SIZE = %d\n", m_video_tspes.Pes_Packet_Length_Beyond);
		WriteAdaptive_flags_Head(&ts_adaptation_field_Head, Timestamp_video); //填写自适应段标志帧头
		WriteAdaptive_flags_Tail(&ts_adaptation_field_Tail); //填写自适应段标志帧尾
		//计算一帧视频所用时间
		m_video_tspes.Pes_Packet_Length_Beyond = pNal->size;
		PES2TS(&m_video_tspes, TS_H264_PID, &ts_adaptation_field_Head, &ts_adaptation_field_Tail, Timestamp_video, Timestamp_audio);
		Timestamp_video += 1000 * 90 / framerate;   //90khz
	}
	else
	{
		
		//填写自适应段标志
		printf("3+++PES_VIDEO  :  SIZE = %d\n", m_video_tspes.Pes_Packet_Length_Beyond);
		WriteAdaptive_flags_Tail(&ts_adaptation_field_Head); //填写自适应段标志  ,这里注意 其它帧类型不要算pcr 所以都用帧尾代替就行
		WriteAdaptive_flags_Tail(&ts_adaptation_field_Tail); //填写自适应段标志帧尾
		m_video_tspes.Pes_Packet_Length_Beyond = pNal->size;//lzy
		PES2TS(&m_video_tspes, TS_H264_PID, &ts_adaptation_field_Head, &ts_adaptation_field_Tail, Timestamp_video, Timestamp_audio);//具体内容见下

	}

}
   2)输出参数TNAL结构体    

struct DLL_EXPORT TNAL
{
    int size;  //264码nalu长度
    unsigned char* data;  //内容
    TNAL(): size(0), data(NULL) {}
};
3)合成所用的主角函数--PES2TS函数

int PES2TS(TsPes * ts_pes, unsigned int Video_Audio_PID, Ts_Adaptation_field * ts_adaptation_field_Head, Ts_Adaptation_field * ts_adaptation_field_Tail,
	unsigned long  Videopts, unsigned long Adudiopts)
{
	TsPacketHeader ts_header;
	unsigned int ts_pos = 0;
	unsigned int FirstPacketLoadLength = 0;                                   //分片包的第一个包的负载长度
	unsigned int NeafPacketCount = 0;                                          //分片包的个数
	unsigned int AdaptiveLength = 0;                                           //要填写0XFF的长度
	unsigned char * NeafBuf = NULL;                                            //分片包 总负载的指针
	unsigned char TSbuf[TS_PACKET_SIZE];

	memset(TSbuf, 0, TS_PACKET_SIZE);
	FirstPacketLoadLength = 188 - 4 - 1 - ts_adaptation_field_Head->adaptation_field_length - 14; //计算分片包的第一个包的负载长度
	NeafPacketCount += 1;                                                                   //第一个分片包  

	//一个包的情况
	//	printf("Pes_Packet_Length_Beyond=%d,FirstPacketLoadLength=%d\n", ts_pes->Pes_Packet_Length_Beyond, FirstPacketLoadLength);

	if (ts_pes->Pes_Packet_Length_Beyond < FirstPacketLoadLength)                           //这里是 sps ,pps ,sei等
		// if (lens < FirstPacketLoadLength)                           //这里是 sps ,pps ,sei等 lzy
	{
		memset(TSbuf, 0xFF, TS_PACKET_SIZE);
		WriteStruct_Packetheader(TSbuf, Video_Audio_PID, 0x01, 0x03);                          //PID = TS_H264_PID,有效荷载单元起始指示符_play_init = 0x01, ada_field_C,0x03,含有调整字段和有效负载 ;
		ts_pos += 4;
		TSbuf[ts_pos + 0] = 184 - ts_pes->Pes_Packet_Length_Beyond - 9 - 5 - 1;
		TSbuf[ts_pos + 1] = 0x00;
		ts_pos += 2;
		memset(TSbuf + ts_pos, 0xFF, (184 - ts_pes->Pes_Packet_Length_Beyond - 9 - 5 - 2));
		ts_pos += (184 - ts_pes->Pes_Packet_Length_Beyond - 9 - 5 - 2);

		TSbuf[ts_pos + 0] = (ts_pes->packet_start_code_prefix >> 16) & 0xFF;
		TSbuf[ts_pos + 1] = (ts_pes->packet_start_code_prefix >> 8) & 0xFF;
		TSbuf[ts_pos + 2] = ts_pes->packet_start_code_prefix & 0xFF;
		TSbuf[ts_pos + 3] = ts_pes->stream_id;
		TSbuf[ts_pos + 4] = ((ts_pes->PES_packet_length) >> 8) & 0xFF;
		TSbuf[ts_pos + 5] = (ts_pes->PES_packet_length) & 0xFF;
		TSbuf[ts_pos + 6] = ts_pes->marker_bit << 6 | ts_pes->PES_scrambling_control << 4 | ts_pes->PES_priority << 3 |
			ts_pes->data_alignment_indicator << 2 | ts_pes->copyright << 1 | ts_pes->original_or_copy;
		TSbuf[ts_pos + 7] = ts_pes->PTS_DTS_flags << 6 | ts_pes->ESCR_flag << 5 | ts_pes->ES_rate_flag << 4 |
			ts_pes->DSM_trick_mode_flag << 3 | ts_pes->additional_copy_info_flag << 2 | ts_pes->PES_CRC_flag << 1 | ts_pes->PES_extension_flag;
		TSbuf[ts_pos + 8] = ts_pes->PES_header_data_length;
		ts_pos += 9;

		if (ts_pes->stream_id == TS_H264_STREAM_ID)
		{
			TSbuf[ts_pos + 0] = (((0x3 << 4) | ((Videopts >> 29) & 0x0E) | 0x01) & 0xff);
			TSbuf[ts_pos + 1] = (((((Videopts >> 14) & 0xfffe) | 0x01) >> 8) & 0xff);
			TSbuf[ts_pos + 2] = ((((Videopts >> 14) & 0xfffe) | 0x01) & 0xff);
			TSbuf[ts_pos + 3] = (((((Videopts << 1) & 0xfffe) | 0x01) >> 8) & 0xff);
			TSbuf[ts_pos + 4] = ((((Videopts << 1) & 0xfffe) | 0x01) & 0xff);
			ts_pos += 5;

		}
		else if (ts_pes->stream_id == TS_AAC_STREAM_ID)
		{
			TSbuf[ts_pos + 0] = (((0x3 << 4) | ((Adudiopts >> 29) & 0x0E) | 0x01) & 0xff);
			TSbuf[ts_pos + 1] = (((((Adudiopts >> 14) & 0xfffe) | 0x01) >> 8) & 0xff);
			TSbuf[ts_pos + 2] = ((((Adudiopts >> 14) & 0xfffe) | 0x01) & 0xff);
			TSbuf[ts_pos + 3] = (((((Adudiopts << 1) & 0xfffe) | 0x01) >> 8) & 0xff);
			TSbuf[ts_pos + 4] = ((((Adudiopts << 1) & 0xfffe) | 0x01) & 0xff);
			ts_pos += 5;
		}
		else
		{
			printf("ts_pes->stream_id  error 0x%x \n", ts_pes->stream_id);
			return getchar();
		}
		memcpy(TSbuf + ts_pos, ts_pes->Es, ts_pes->Pes_Packet_Length_Beyond);

		//将包写入文件
		fwrite(TSbuf, 188, 1, pVideo_Audio_Ts_File);                               //将一包数据写入文件
		memcpy(fTo, TSbuf, 188);


		WritePacketNum++;                                                      //已经写入文件的包个数++
		return WritePacketNum;
	}

	NeafPacketCount += (ts_pes->Pes_Packet_Length_Beyond - FirstPacketLoadLength) / 184;
	NeafPacketCount += 1;                                                                   //最后一个分片包
	AdaptiveLength = 188 - 4 - 1 - ((ts_pes->Pes_Packet_Length_Beyond - FirstPacketLoadLength) % 184);  //要填写0XFF的长度
	if ((WritePacketNum % 40) == 0)                                                         //每40个包打一个 pat,一个pmt
	{
		Write_Pat(m_One_Frame_Buf);                                                         //创建PAT,具体内容见下
		Write_Pmt(m_One_Frame_Buf);                                                         //创建PMT,具体内容见下
	}
	//开始处理第一个包,分片包的个数最少也会是两个 
	WriteStruct_Packetheader(TSbuf, Video_Audio_PID, 0x01, 0x03);                              //PID = TS_H264_PID,有效荷载单元起始指示符_play_init = 0x01, ada_field_C,0x03,含有调整字段和有效负载 ;
	ts_pos += 4;
	TSbuf[ts_pos] = ts_adaptation_field_Head->adaptation_field_length;                      //自适应字段的长度,自己填写的
	ts_pos += 1;

	CreateAdaptive_Ts(ts_adaptation_field_Head, TSbuf + ts_pos, (188 - 4 - 1 - 14));          //填写自适应字段
	ts_pos += ts_adaptation_field_Head->adaptation_field_length;                            //填写自适应段所需要的长度

	TSbuf[ts_pos + 0] = (ts_pes->packet_start_code_prefix >> 16) & 0xFF;
	TSbuf[ts_pos + 1] = (ts_pes->packet_start_code_prefix >> 8) & 0xFF;
	TSbuf[ts_pos + 2] = ts_pes->packet_start_code_prefix & 0xFF;
	TSbuf[ts_pos + 3] = ts_pes->stream_id;
	TSbuf[ts_pos + 4] = ((ts_pes->PES_packet_length) >> 8) & 0xFF;
	TSbuf[ts_pos + 5] = (ts_pes->PES_packet_length) & 0xFF;
	TSbuf[ts_pos + 6] = ts_pes->marker_bit << 6 | ts_pes->PES_scrambling_control << 4 | ts_pes->PES_priority << 3 |
		ts_pes->data_alignment_indicator << 2 | ts_pes->copyright << 1 | ts_pes->original_or_copy;
	TSbuf[ts_pos + 7] = ts_pes->PTS_DTS_flags << 6 | ts_pes->ESCR_flag << 5 | ts_pes->ES_rate_flag << 4 |
		ts_pes->DSM_trick_mode_flag << 3 | ts_pes->additional_copy_info_flag << 2 | ts_pes->PES_CRC_flag << 1 | ts_pes->PES_extension_flag;
	TSbuf[ts_pos + 8] = ts_pes->PES_header_data_length;
	ts_pos += 9;

	if (ts_pes->stream_id == TS_H264_STREAM_ID)
	{
		TSbuf[ts_pos + 0] = (((0x3 << 4) | ((Videopts >> 29) & 0x0E) | 0x01) & 0xff);
		TSbuf[ts_pos + 1] = (((((Videopts >> 14) & 0xfffe) | 0x01) >> 8) & 0xff);
		TSbuf[ts_pos + 2] = ((((Videopts >> 14) & 0xfffe) | 0x01) & 0xff);
		TSbuf[ts_pos + 3] = (((((Videopts << 1) & 0xfffe) | 0x01) >> 8) & 0xff);
		TSbuf[ts_pos + 4] = ((((Videopts << 1) & 0xfffe) | 0x01) & 0xff);
		ts_pos += 5;

	}
	else if (ts_pes->stream_id == TS_AAC_STREAM_ID)
	{
		TSbuf[ts_pos + 0] = (((0x3 << 4) | ((Adudiopts >> 29) & 0x0E) | 0x01) & 0xff);
		TSbuf[ts_pos + 1] = (((((Adudiopts >> 14) & 0xfffe) | 0x01) >> 8) & 0xff);
		TSbuf[ts_pos + 2] = ((((Adudiopts >> 14) & 0xfffe) | 0x01) & 0xff);
		TSbuf[ts_pos + 3] = (((((Adudiopts << 1) & 0xfffe) | 0x01) >> 8) & 0xff);
		TSbuf[ts_pos + 4] = ((((Adudiopts << 1) & 0xfffe) | 0x01) & 0xff);
		ts_pos += 5;
	}
	else
	{
		printf("ts_pes->stream_id  error 0x%x \n", ts_pes->stream_id);
		return getchar();
	}

	NeafBuf = ts_pes->Es;



	memcpy(TSbuf + ts_pos, NeafBuf, FirstPacketLoadLength);

	NeafBuf += FirstPacketLoadLength;
	ts_pes->Pes_Packet_Length_Beyond -= FirstPacketLoadLength;
	//将包写入文件
	fwrite(TSbuf, 188, 1, pVideo_Audio_Ts_File);                               //将一包数据写入文件  lzy
	memcpy(fTo,TSbuf,188);


	WritePacketNum++;                                                      //已经写入文件的包个数++

	while (ts_pes->Pes_Packet_Length_Beyond)
	{
		ts_pos = 0;
		memset(TSbuf, 0, TS_PACKET_SIZE);

		if ((WritePacketNum % 40) == 0)                                                         //每40个包打一个 pat,一个pmt
		{
			Write_Pat(m_One_Frame_Buf);                                                         //创建PAT
			Write_Pmt(m_One_Frame_Buf);                                                         //创建PMT
		}
		if (ts_pes->Pes_Packet_Length_Beyond >= 184)
		{
			//处理中间包   
			WriteStruct_Packetheader(TSbuf, Video_Audio_PID, 0x00, 0x01);     //PID = TS_H264_PID,不是有效荷载单元起始指示符_play_init = 0x00, ada_field_C,0x01,仅有有效负载;    
			ts_pos += 4;
			memcpy(TSbuf + ts_pos, NeafBuf, 184);
			NeafBuf += 184;
			ts_pes->Pes_Packet_Length_Beyond -= 184;
			fwrite(TSbuf, 188, 1, pVideo_Audio_Ts_File);
			memcpy(fTo, TSbuf, 188);
		}
		else
		{
			if (ts_pes->Pes_Packet_Length_Beyond == 183 || ts_pes->Pes_Packet_Length_Beyond == 182)
			{
				if ((WritePacketNum % 40) == 0)                                                         //每40个包打一个 pat,一个pmt
				{
					Write_Pat(m_One_Frame_Buf);                                                         //创建PAT
					Write_Pmt(m_One_Frame_Buf);                                                         //创建PMT
				}

				WriteStruct_Packetheader(TSbuf, Video_Audio_PID, 0x00, 0x03);   //PID = TS_H264_PID,不是有效荷载单元起始指示符_play_init = 0x00, ada_field_C,0x03,含有调整字段和有效负载;
				ts_pos += 4;
				TSbuf[ts_pos + 0] = 0x01;
				TSbuf[ts_pos + 1] = 0x00;
				ts_pos += 2;
				memcpy(TSbuf + ts_pos, NeafBuf, 182);

				NeafBuf += 182;
				ts_pes->Pes_Packet_Length_Beyond -= 182;
				fwrite(TSbuf, 188, 1, pVideo_Audio_Ts_File);
				memcpy(fTo, TSbuf, 188);
			
			}
			else
			{
				if ((WritePacketNum % 40) == 0)                                                         //每40个包打一个 pat,一个pmt
				{
					Write_Pat(m_One_Frame_Buf);                                                         //创建PAT
					Write_Pmt(m_One_Frame_Buf);                                                         //创建PMT
				}

				WriteStruct_Packetheader(TSbuf, Video_Audio_PID, 0x00, 0x03);  //PID = TS_H264_PID,不是有效荷载单元起始指示符_play_init = 0x00, ada_field_C,0x03,含有调整字段和有效负载;
				ts_pos += 4;
				TSbuf[ts_pos + 0] = 184 - ts_pes->Pes_Packet_Length_Beyond - 1;
				TSbuf[ts_pos + 1] = 0x00;
				ts_pos += 2;
				memset(TSbuf + ts_pos, 0xFF, (184 - ts_pes->Pes_Packet_Length_Beyond - 2));
				ts_pos += (184 - ts_pes->Pes_Packet_Length_Beyond - 2);
				memcpy(TSbuf + ts_pos, NeafBuf, ts_pes->Pes_Packet_Length_Beyond);
				ts_pes->Pes_Packet_Length_Beyond = 0;
				fwrite(TSbuf, 188, 1, pVideo_Audio_Ts_File);   //将一包数据写入文件
				memcpy(fTo, TSbuf, 188);

				WritePacketNum++;
			}
		}
		WritePacketNum++;
	}
	printf("\nWritePacketNum=%d\n", WritePacketNum);
	return WritePacketNum;
}
注:该函数中,合成的TS流都放置在 TSbuf中。


4)写PAT函数---Write_Pat、Write_Pmt函数

int Write_Pat(unsigned char * buf)
{
	WriteStruct_Pat(buf);
	memcpy(fTo, (char *)buf,188);
	printf("pmt++++");
	return WriteFile(pVideo_Audio_Ts_File, (char *)buf, TS_PACKET_SIZE);
	
}
<pre name="code" class="cpp">int Write_Pmt(unsigned char * buf)
{
	WriteStruct_Pmt(buf);
	memcpy(fTo, (char *)buf, 188);
	return WriteFile(pVideo_Audio_Ts_File, (char *)buf, TS_PACKET_SIZE);

}


 

以上为该API中重要函数,但是由于该API在tstool基础上改编而来,自然少不了要加上TSTOOL库文件。

 

库文件我已经打包,下载地址为:http://download.csdn.net/detail/xiahua882/9636902。

最后,上一张我在VS2013工程中引用图





 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值