为方便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工程中引用图