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
原创粉丝点击