H264码合成TS专用API
来源:互联网 发布:软件标题修改器 编辑:程序博客网 时间:2024/06/05 22:58
为方便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 bitnalu->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;//lzyPES2TS(&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); //将一包数据写入文件 lzymemcpy(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); //创建PATWrite_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); //创建PATWrite_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); //创建PATWrite_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 0
- H264码合成TS专用API
- H264码合成TS专用API
- ffmpeg将h264和aac合成ts,内存输入输出
- H264 TS/ES
- H264 TS/ES
- H264 TS/ES
- H264 TS/ES
- H264 TS/ES(zz)
- H264 TS/ES
- H264 TS/ES
- H264 TS/ES
- h264封装ts
- H264 TS/ES
- H264 TS/ES
- h264+aac=ts
- 将h264和aac码流合成flv文件
- 使用ffmpeg将mp4文件中的h264码流转为raw h264文件格式或ts文件格式
- ffmpeg h264+ts +udp传输
- iOS 10 的适配问题总结
- 将资源文件的图片转换成bitmap 的两种方法
- Android主题和样式之系统篇(上级)
- C#面向对象_封装_160922
- Android实现NavigationView使用教程
- H264码合成TS专用API
- 定位功能
- laravel-发送邮件
- xml转换DataTable
- NSRunLoop_mode_timer
- 打印N个数组整体最大的Top K
- java测试代码运行时间
- [LeetCode] 9.Palindrome Number
- zookeeper常用指令