转自:http://www.cnblogs.com/lidabo/p/6604998.html
1 写在开始之前
在前段时间有分享一个H264封装ps流到相关文章的,这次和大家分享下将H264封装成TS流到相关实现,其实也是工作工作需要。依照上篇一样,分段说明每个数据头的封装情况,当然,一样也会加上rtp头,方便以后的这方面到需求,如果开发不需要的话,可 以自行屏蔽掉,当然需要主要buffer指针的移动情况
2 封装的各个头到规则要点
整个封装过程也是和ps类似,但是最大到区别在于TS流到数据长度都是固定188大小来传输的,而PS流则是可变包结构,正因为两者在结构上到差异,导致了它们在传输误码上的不同抵抗力.TS流由于采用了固定长度的数据包,当传输误码破坏了某一个TS包的同步信息时,接收端可在固定的位置检测到下一个TS包到同步信息,从而恢复同步,避免数据丢失,PS流则长度可变到数据包,当某一个ps包同步信息丢失时,接收端就无法进行信息同步,也就无法确认下一步到同步信息,导致了严重到信息丢失。因此在环境恶劣的情况下, 传输码丢失比较严重,一般都采用TS流来进行避免,当网络环境比较稳定,传输误码概率小,这个时候采用PS流进行传送。
关于TS流需要了解下节目映射表(PAT:Program Associate Table)以及节目映射表(PMT:Program Map Table),当发送到数据为视频数据关键帧的时候,需要在包头中添加PAT和PMT
具体结构体如下
封装组成:(PAT +PMT) + TS + PES + H264 + (TS + H264 + TS + H264 ....)
数据长度:PES包的长度=188字节-TS包头长度(4字节)-适应域长度(PES长度或者0)
注意:
a 每次数据定长包188个字节,如果不足的则用1填充,这里填充时值每一个bit位都填充,memset就是最好选择。
b 因为我个人习惯,在封装到时候当为关键帧的时候,我直接丢了PAM+PMT+TS+PES 然后填充满188个字节,这样做提醒大家 是错误到,完全错误的,PES后必须跟H264数据。
c PES能表示的数据长度只有short, 两个字节,所以当数据长度超过的话,则需要考虑多个PES头
3 各个部件到头的伪代码实现
- int rtsp_RTPPackage( RTP_SESSION_S *pRtpSender, int nFrameLen, StreamType_E enStreamType)
- {
- int nRet = 0;
- int bVideo = 1 ;
- int nSendDataOff = 0;
- int nSendSize = 0;
- int nPayLoadSize = 0;
- int nHasSend = 0;
- int IFrameFlag = 0;
- char TSFrameHdr[1024];
- int nHead = 0;
-
-
- memset(TSFrameHdr, 0, 1024);
- memset(pRtpSender->stRtpPack, 0, RTP_MAX_PACKET_BUFF);
- bVideo = ((enStreamType == VIDEO_STREAM ) ? 1 : 0);
-
-
- if( (bVideo == 1) && pRtpSender->stAvData.u8IFrame == 1)
- {
- if((nRet = mk_ts_pat_packet(TSFrameHdr +nSendDataOff,
- pRtpSender->hHdlTs)) <= 0)
- {
- DBG_INFO(" mk_ts_pat_packet failed!\n");
- return -1;
- }
-
- nSendDataOff += nRet;
- if((nRet = mk_ts_pmt_packet(TSFrameHdr + nSendDataOff,
- pRtpSender->hHdlTs)) <= 0)
- {
- DBG_INFO(" mk_ts_pmt_packet failed!\n");
- return -1;
- }
- nSendDataOff += nRet;
-
- }
-
- if((nRet = mk_ts_packet(TSFrameHdr + nSendDataOff, pRtpSender->hHdlTs,
- 1, bVideo, pRtpSender->stAvData.u8IFrame, pRtpSender->stAvData.u64TimeStamp)) <= 0 )
- {
- DBG_INFO(" mk_ts_packet failed!\n");
- return -1;
- }
- nSendDataOff += nRet;
-
- nHead = nRet;
-
-
- if((nRet = mk_pes_packet(TSFrameHdr + nSendDataOff, bVideo, nFrameLen, 1,
- pRtpSender->stAvData.u64TimeStamp, pRtpSender->stAvData.u64TimeStamp)) <= 0 )
- {
- DBG_INFO(" mk_pes_packet failed!\n");
- return -1;
- }
- nSendDataOff += nRet;
- nHead += nRet;
-
-
- if( nFrameLen > (TS_LOAD_LEN - nHead))
- {
- memcpy(TSFrameHdr + nSendDataOff, pRtpSender->stAvData.data, TS_LOAD_LEN - nHead);
- nSendDataOff += (TS_LOAD_LEN - nHead);
- nHasSend = (TS_LOAD_LEN - nHead);
- if( rtsp_send_rtppack(TSFrameHdr, &nSendDataOff, pRtpSender->stAvData.u64TimeStamp, 0, (pRtpSender->stAvData.u8IFrame?1:0), bVideo, 1, pRtpSender) != 0 )
- {
- DBG_INFO(" rtsp_send_pack failed!\n");
- return -1;
- }
- }
-
- else
- {
- memcpy(TSFrameHdr + nSendDataOff, pRtpSender->stAvData.data, nFrameLen);
- nSendDataOff += nFrameLen;
- nHasSend = nFrameLen;
- memset(TSFrameHdr +nSendDataOff, 0xFF, (TS_LOAD_LEN-nHead - nFrameLen));
- nSendDataOff += (TS_LOAD_LEN -nHead- nFrameLen);
- if( rtsp_send_rtppack(TSFrameHdr, &nSendDataOff, pRtpSender->stAvData.u64TimeStamp, 1, (pRtpSender->stAvData.u8IFrame?1:0), bVideo, 1, pRtpSender) != 0 )
- {
- DBG_INFO(" rtsp_send_rtppack failed!\n");
- return -1;
- }
- }
-
-
-
- nPayLoadSize = RTP_MAX_PACKET_BUFF - 4 - RTP_HDR_LEN - (4+6) * 7;
- nFrameLen -= (TS_LOAD_LEN - nHead);
-
-
- while(nFrameLen > 0 )
- {
-
- nSendSize = (nFrameLen > nPayLoadSize) ? nPayLoadSize : nFrameLen;
- if( rtsp_send_rtppack(pRtpSender->stAvData.data + nHasSend, &nSendSize, pRtpSender->stAvData.u64TimeStamp,
- ((nSendSize == nFrameLen) ? 1 : 0), IFrameFlag, bVideo, 0, pRtpSender) != 0 )
- {
- DBG_INFO(" rtsp_send_rtppack failed!\n");
- return -1;
- }
- nFrameLen -= nSendSize;
- nHasSend += nSendSize;
- memset(pRtpSender->stRtpPack, 0, RTP_MAX_PACKET_BUFF);
- IFrameFlag = 0;
- }
- return 0;
- }
- int mk_ts_pat_packet(char *buf, int handle)
- {
- int nOffset = 0;
- int nRet = 0;
-
- if (!buf)
- {
- return 0;
- }
-
- if (0 >= (nRet = ts_header(buf, handle, TS_TYPE_PAT, 1)))
- {
- return 0;
- }
- nOffset += nRet;
-
- if (0 >= (nRet = ts_pointer_field(buf + nOffset)))
- {
- return 0;
- }
- nOffset += nRet;
-
- if (0 >= (nRet = ts_pat_header(buf + nOffset)))
- {
- return 0;
- }
- nOffset += nRet;
-
-
- memset(buf + nOffset, 0xFF, TS_PACKET_SIZE - nOffset);
- return TS_PACKET_SIZE;
- }
- int ts_pat_header(char *buf)
- {
- BITS_BUFFER_S bits;
-
- if (!buf)
- {
- return 0;
- }
- bits_initwrite(&bits, 32, (unsigned char *)buf);
-
- bits_write(&bits, 8, 0x00);
-
- bits_write(&bits, 1, 1);
- bits_write(&bits, 1, 0);
- bits_write(&bits, 2, 0x03);
- bits_write(&bits, 12, 0x0D);
-
- bits_write(&bits, 16, 0x0001);
-
- bits_write(&bits, 2, 0x03);
- bits_write(&bits, 5, 0x00);
- bits_write(&bits, 1, 1);
-
- bits_write(&bits, 8, 0x00);
- bits_write(&bits, 8, 0x00);
-
- bits_write(&bits, 16, 0x0001);
- bits_write(&bits, 3, 0x07);
- bits_write(&bits, 13, TS_PID_PMT);
-
- bits_write(&bits, 8, 0x9F);
- bits_write(&bits, 8, 0xC7);
- bits_write(&bits, 8, 0x62);
- bits_write(&bits, 8, 0x58);
-
- bits_align(&bits);
- return bits.i_data;
- }
- int mk_ts_pmt_packet(char *buf, int handle)
- {
- int nOffset = 0;
- int nRet = 0;
-
- if (!buf)
- {
- return 0;
- }
-
- if (0 >= (nRet = ts_header(buf, handle, TS_TYPE_PMT, 1)))
- {
- return 0;
- }
- nOffset += nRet;
-
- if (0 >= (nRet = ts_pointer_field(buf + nOffset)))
- {
- return 0;
- }
- nOffset += nRet;
-
- if (0 >= (nRet = ts_pmt_header(buf + nOffset)))
- {
- return 0;
- }
- nOffset += nRet;
-
-
- memset(buf + nOffset, 0xFF, TS_PACKET_SIZE - nOffset);
- return TS_PACKET_SIZE;
- }
- int ts_pmt_header(char *buf)
- {
- BITS_BUFFER_S bits;
-
- if (!buf)
- {
- return 0;
- }
-
- bits_initwrite(&bits, 32, (unsigned char *)buf);
-
- bits_write(&bits, 8, 0x02);
-
- bits_write(&bits, 1, 1);
- bits_write(&bits, 1, 0);
- bits_write(&bits, 2, 0x03);
- bits_write(&bits, 12, 0x1C);
-
- bits_write(&bits, 16, 0x0001);
-
- bits_write(&bits, 2, 0x03);
- bits_write(&bits, 5, 0x00);
- bits_write(&bits, 1, 1);
-
- bits_write(&bits, 8, 0x00);
- bits_write(&bits, 8, 0x00);
-
- bits_write(&bits, 3, 0x07);
- bits_write(&bits, 13, TS_PID_VIDEO);
- bits_write(&bits, 4, 0x0F);
- bits_write(&bits, 12, 0x00);
-
- bits_write(&bits, 8, TS_PMT_STREAMTYPE_H264_VIDEO);
- bits_write(&bits, 3, 0x07);
- bits_write(&bits, 13, TS_PID_VIDEO);
- bits_write(&bits, 4, 0x0F);
- bits_write(&bits, 12, 0x00);
-
- bits_write(&bits, 8, TS_PMT_STREAMTYPE_11172_AUDIO);
- bits_write(&bits, 3, 0x07);
- bits_write(&bits, 13, TS_PID_AUDIO);
- bits_write(&bits, 4, 0x0F);
- bits_write(&bits, 12, 0x00);
-
- bits_write(&bits, 8, 0xA4);
- bits_write(&bits, 3, 0x07);
- bits_write(&bits, 13, 0x00A4);
- bits_write(&bits, 4, 0x0F);
- bits_write(&bits, 12, 0x00);
-
- bits_write(&bits, 8, 0x34);
- bits_write(&bits, 8, 0x12);
- bits_write(&bits, 8, 0xA3);
- bits_write(&bits, 8, 0x72);
-
- bits_align(&bits);
- return bits.i_data;
- }
- int mk_ts_packet(char *buf, int handle, int bStart, int bVideo, int bIFrame, unsigned long long timestamp)
- {
- int nOffset = 0;
- int nRet = 0;
-
- if (!buf)
- {
- return 0;
- }
-
- if (0 >= (nRet = ts_header(buf, handle, bVideo ? TS_TYPE_VIDEO : TS_TYPE_AUDIO, bStart)))
- {
- return 0;
- }
- nOffset += nRet;
-
- if (0 >= (nRet = ts_adaptation_field(buf + nOffset, bStart, bVideo && (bIFrame), timestamp)))
- {
- return 0;
- }
- nOffset += nRet;
-
- return nOffset;
- }
-
- int ts_header(char *buf, int handle, TS_TYPE_E type, int bStart)
- {
- BITS_BUFFER_S bits;
- TS_MNG_S *pMng = (TS_MNG_S *)handle;
-
- if (!buf || !handle || TS_TYPE_BEGIN >= type || TS_TYPE_END <= type)
- {
- return 0;
- }
-
- bits_initwrite(&bits, 32, (unsigned char *)buf);
-
- bits_write(&bits, 8, 0x47);
-
-
-
-
-
- bits_write(&bits, 1, 0);
- bits_write(&bits, 1, bStart);
- bits_write(&bits, 1, 0);
- if (TS_TYPE_PAT == type)
- {
- bits_write(&bits, 13, 0x00);
- }
- else if (TS_TYPE_PMT == type)
- {
- bits_write(&bits, 13, TS_PID_PMT);
- }
- else if (TS_TYPE_VIDEO == type)
- {
- bits_write(&bits, 13, TS_PID_VIDEO);
- }
- else if (TS_TYPE_AUDIO == type)
- {
- bits_write(&bits, 13, TS_PID_AUDIO);
- }
-
- bits_write(&bits, 2, 0);
- if (TS_TYPE_PAT == type || TS_TYPE_PMT == type)
- {
-
-
- bits_write(&bits, 2, 0x01);
- bits_write(&bits, 4, pMng->nPatCounter);
-
- if (TS_TYPE_PAT != type)
- {
- pMng->nPatCounter++;
- pMng->nPatCounter &= 0x0F;
- }
- }
- else
- {
- bits_write(&bits, 2, 0x03);
- bits_write(&bits, 4, pMng->nContinuityCounter);
- pMng->nContinuityCounter++;
- pMng->nContinuityCounter &= 0x0F;
- }
-
- bits_align(&bits);
- return bits.i_data;
- }
- int mk_pes_packet(char *buf, int bVideo, int length, int bDtsEn, unsigned long long pts, unsigned long long dts)
- {
- PES_HEAD_S pesHead;
- PES_OPTION_S pesOption;
- PES_PTS_S pesPts;
- PES_PTS_S pesDts;
-
- if (!buf)
- {
- return 0;
- }
-
- if( bVideo == 1)
- {
-
- pts = pts * 9 / 100;
- dts = dts * 9 / 100;
- }
- else
- {
-
- pts = pts * 8 / 1000;
- dts = dts * 8 / 1000;
-
- }
-
- memset(&pesHead, 0, sizeof(pesHead));
- memset(&pesOption, 0, sizeof(pesOption));
- memset(&pesPts, 0, sizeof(pesPts));
- memset(&pesDts, 0, sizeof(pesDts));
-
- pesHead.startcode = htonl(0x000001) >> 8;
- pesHead.stream_id = bVideo ? 0xE0 : 0xC0;
- if (PES_MAX_SIZE < length)
- {
- pesHead.pack_len = 0;
- }
- else
- {
- pesHead.pack_len = htons(length + sizeof(pesOption) + sizeof(pesPts) + (bDtsEn ? sizeof(pesDts) : 0));
- }
-
- pesOption.fixed = 0x02;
- pesOption.pts_dts = bDtsEn ? 0x03 : 0x02;
- pesOption.head_len = sizeof(pesPts) + (bDtsEn ? sizeof(pesDts) : 0);
-
- pesPts.fixed2 = pesPts.fixed3 = pesPts.fixed4 = 0x01;
- pesPts.fixed1 = bDtsEn ? 0x03 : 0x02;
- pesPts.ts1 = (pts >> 30) & 0x07;
- pesPts.ts2 = (pts >> 22) & 0xFF;
- pesPts.ts3 = (pts >> 15) & 0x7F;
- pesPts.ts4 = (pts >> 7) & 0xFF;
- pesPts.ts5 = pts & 0x7F;
-
- pesDts.fixed1 = pesDts.fixed2 = pesDts.fixed3 = pesDts.fixed4 = 0x01;
- pesDts.ts1 = (dts >> 30) & 0x07;
- pesDts.ts2 = (dts >> 22) & 0xFF;
- pesDts.ts3 = (dts >> 15) & 0x7F;
- pesDts.ts4 = (dts >> 7) & 0xFF;
- pesDts.ts5 = dts & 0x7F;
-
- char *head = buf;
- memcpy(head, &pesHead, sizeof(pesHead));
- head += sizeof(pesHead);
- memcpy(head, &pesOption, sizeof(pesOption));
- head += sizeof(pesOption);
- memcpy(head, &pesPts, sizeof(pesPts));
- head += sizeof(pesPts);
- if (bDtsEn)
- {
- memcpy(head, &pesDts, sizeof(pesDts));
- head += sizeof(pesPts);
- }
-
- return (head - buf);
- }
- int rtsp_send_rtppack(char *Databuf, int *datalen, unsigned long curtimestamp, int mark_flag, int IFrameFlag, int bVideo, int nFrameStart, RTP_SESSION_S *pRtpSender)
- {
- int nHasSend = 0;
- int nRet = 0;
- int nTsHeadNum = 0;
- int nHadDataLen = 0;
- int nTcpSendLen = 0;
- static unsigned short cSeqnum;
-
-
-
- if( nFrameStart == 1 )
- {
- nRet = mk_rtp_packet(pRtpSender->stRtpPack + nHasSend, mark_flag, IFrameFlag, bVideo, ++cSeqnum, (curtimestamp * 9/100));
- nHasSend += nRet;
- memcpy(pRtpSender->stRtpPack + nHasSend, Databuf, *datalen);
- nHasSend += *datalen;
- }
- else
- {
-
- nRet = mk_rtp_packet(pRtpSender->stRtpPack + nHasSend, mark_flag, IFrameFlag, bVideo, ++cSeqnum, (curtimestamp * 9/100));
- nHasSend += nRet;
- while(*datalen > 0 && nTsHeadNum < 7)
- {
- nRet = mk_ts_packet(pRtpSender->stRtpPack + nHasSend , pRtpSender->hHdlTs, 0, bVideo, (IFrameFlag > 0 ? 1:0), curtimestamp);
- nHasSend += nRet;
- if(*datalen < (TS_LOAD_LEN- nRet))
- {
- memcpy(pRtpSender->stRtpPack + nHasSend, Databuf + nHadDataLen, *datalen);
- nHasSend += *datalen;
- nHadDataLen += *datalen;
-
-
- memset(pRtpSender->stRtpPack + nHasSend, 0xFF, TS_LOAD_LEN- nRet - (*datalen));
- nHasSend += (TS_LOAD_LEN - nRet - *datalen);
- }
- else
- {
- memcpy(pRtpSender->stRtpPack + nHasSend, Databuf + nHadDataLen, TS_LOAD_LEN - nRet);
- nHasSend += (TS_LOAD_LEN - nRet);
- *datalen -= (TS_LOAD_LEN - nRet);
- nHadDataLen += (TS_LOAD_LEN - nRet);
- }
- nTsHeadNum ++;
- }
- *datalen = nHadDataLen;
- }
-
-
- if(pRtpSender->RtspsockFd <= 0 )
- {
- DBG_INFO("send rtp packet socket error\n");
- return -1;
- }
-
- nTcpSendLen = hi_tcp_noblock_send(pRtpSender->RtspsockFd, pRtpSender->stRtpPack, nHasSend, NULL,1500);
- if(nTcpSendLen != nHasSend )
- {
- DBG_INFO("send rtp packet failed:%s\n",strerror(errno));
- return -1;
- }
- return 0;
- }
5 写在最后
看过我上一篇的关于ps封装的可能会注意的,关于压字节的处理,两篇博文到处理方式有些差异。关于我这个我简单说两点
第一次是这个ts的处理里面封装是另外一个同事实现的,我因为用到所以拿来使用,但是上次调用封装都是自己完成。第二个就是
ps和ts的处理方式不一样。一个定长,一个不定长。所以这样处理,也挺好的,我也有点懒,所以没有改过来。
关于对H264码流的TS的封装的相关代码实现
标签:digital 原版 没有 oid copy 开发 封装 字节 bsp
原文地址:http://www.cnblogs.com/wanghui888/p/7081693.html