GB28181视频打包传输采用 ps打包+rtp传输 的方式;看下《28181安全防范视频监控联网系统信息传输》文档里面关于打包的介绍吧:
*/ES->PES
uint64 m_nDts, m_nFrameRate, m_nAudioPts;
/*
1.PES_packet_length=0,即不限制PES包长,只能用于视频PES包。
2.视频I帧和P帧的PES包中必须加入PTS和DTS,并且两者相等。
3.音频帧的PES包中只需包含PTS即可,但PTS必须根据实际情况计算,而不能直接加一个常数。
4.描述PTS与DTS的变量应为无符号64位的整数,而不是32位。
*/
int Packet_Video_frame(const char* pSrcBuf, int nSrcLen, char* pDestBuf, int& nLen, bool bFirst /*= true*/)/* 封装视频帧 */
{
int nTempLen = 0;
if((NULL == pSrcBuf)||(NULL == pDestBuf))
{
return PS_Error_Param;
}
/* 0~2字节为:包头起始码前缀,3字节为:数据流识别 */
memcpy(pDestBuf, PS_Video_Pes_Header, PS_Packet_Start_Code_Len);/* PS_Packet_Start_Code_Len:4个字节 */
/* 4~5字节为:PES包长/为0,即不限制后面ES的长度 */
pDestBuf[4] = 0x00;
pDestBuf[5] = 0x00;
/* 6~7字节为:PES包头识别标识 */
pDestBuf[6] = 0x88;
pDestBuf[7] = 0xC0;/* PTS_DTS_flag=11B */
/* 8字节为:PES包头长 */
/* 0011填充字段,表示既含有PTS,又含有DTS */
pDestBuf[8] = 0x0A;/* 可选字段和填充字段所占的字节数为10 */
/* #define OFFSET(x) (90000/x) */
m_nDts = m_nVideoPts + OFFSET(m_nFrameRate);/* DTS时标 */
m_nVideoPts = m_nVideoPts + OFFSET(m_nFrameRate);/* 视频PTS时标 */
/* 视频PTS */
pDestBuf[9] = ((0x0E&(m_nVideoPts>>29))|0x31);/* 0011填充字段 */
pDestBuf[10] = ((m_nVideoPts>>22)&(0xFF));
pDestBuf[11] = (((m_nVideoPts>>14)&(0xFE))|0x01);
pDestBuf[12] = ((m_nVideoPts>>7)&(0xFF));
pDestBuf[13] = (((m_nVideoPts<<1)&0xFE)|0x01);
/* 视频DTS */
pDestBuf[14] = ((0x0E&(m_nDts>>29))|0x11);/* 0001填充字段 */
pDestBuf[15] = ((m_nDts>>22)&(0xFF));
pDestBuf[16] = (((m_nDts>>14)&(0xFE))|0x01);
pDestBuf[17] = ((m_nDts>>7)&(0xFF));
pDestBuf[18] = (((m_nDts<<1)&0xFE)|0x01);
nTempLen = 19 ;
memcpy(pDestBuf+nTempLen, pSrcBuf, nSrcLen);/* 添加原始ES数据 */
nLen = nTempLen + nSrcLen;
return PS_Error_OK;
}
/*不对ES流/视频帧进行拆包*/
int GeneratePacketsFromFrame(const char* pSrcBuf, int nSrcLen, char* pDestBuf, int& nLen)
{
Packet_Video_frame(pSrcBuf, nSrcLen, pDestBuf, nLen);
m_nal_list.clear();
return PS_Error_OK;
}
int SetAudioPTS( int aPTS )/* 设置音频PTS时标间隔值 */
{
m_uaudioPTS = aPTS;
return 0;
}
int Packet_Audio_frame_G711(const char* pSrcBuf, int nSrcLen, char* pDestBuf, int& nLen)/* 封装音频帧 */
{
int nTempLen = 0;
if((NULL == pSrcBuf)||(NULL == pDestBuf))
{
return PS_Error_Param;
}
/* 0~2字节为:包头起始码前缀,3字节为:数据流识别 */
memcpy(pDestBuf, PS_Audio_Pes_Header, PS_Packet_Start_Code_Len);/* PS_Packet_Start_Code_Len:4个字节 */
nTempLen = 8 + nSrcLen;
/* 4~5字节为:PES包长 */
pDestBuf[4] = (nTempLen>>8)&0xFF;
pDestBuf[5] = nTempLen&0xFF;
/* 6~7字节为:PES包头识别标识 */
pDestBuf[6] = 0x88;
pDestBuf[7] = 0x80;/* PTS_DTS_flag=10B */
/* 8字节为:PES包头长 */
/* 0010填充字段,表示只含有PTS,不含有DTS */
pDestBuf[8] = 0x05;/* 可选字段和填充字段所占的字节数为5 */
/* 音频PTS */
m_nAudioPts = m_nAudioPts + m_uaudioPTS;/* 音频PTS时标 */
if((m_nVideoPts-m_nAudioPts)>500000)
{
m_nAudioPts = m_nVideoPts;
printf("now audio pts=%d\n", m_nVideoPts);
}
pDestBuf[9] = ((0x0E&(m_nAudioPts>>29))|0x21);/* 0010填充字段 */
pDestBuf[10] = ((m_nAudioPts>>22)&(0xFF));
pDestBuf[11] = (((m_nAudioPts>>14)&(0xFE))|0x01);
pDestBuf[12] = ((m_nAudioPts>>7)&(0xFF));
pDestBuf[13] = (((m_nAudioPts<<1)&0xFE)|0x01);
nTempLen = 14 ;
memcpy(pDestBuf+nTempLen, pSrcBuf, nSrcLen);/* 添加原始ES数据 */
nLen = nTempLen + nSrcLen;
return PS_Error_OK;
}
*/PES->PS
uint64 m_nScrb;
/* PS头 */
int Packet_PS_header(char* pDestBuf, int& nLen, bool bVideo, bool bAligned /* = false */)
{
if(NULL == pDestBuf)
{
return PS_Error_Param;
}
/* PS头起始码前缀:0x000001BA */
memcpy(pDestBuf, PS_header, PS_Packet_Start_Code_Len);/* PS_Packet_Start_Code_Len:4个字节 */
/* 4~9字节为:SCR */
m_nScrb = m_nVideoPts;/* 系统时钟参考 */
pDestBuf[4] = (((m_nScrb>>27)&0x38)|0x44);
pDestBuf[4] = (((m_nScrb>>28)&0x03)|pDestBuf[4]);
pDestBuf[5] = ((m_nScrb>>20)&0xFF);
pDestBuf[6] = (((m_nScrb>>12)&0xF8)|0x04);
pDestBuf[6] = (((m_nScrb>>13)&0x03)|pDestBuf[6]);
pDestBuf[7] = ((m_nScrb>>5)&0xFF);
pDestBuf[8] = (((m_nScrb<<3)&0xF8)|0x04);
pDestBuf[9] = 0x01;/* SCR_EXT=0 */
/* 10~12字节为:PS流速率 */
pDestBuf[10] = MUX_RATE>>14;
pDestBuf[11] = MUX_RATE>>6;
pDestBuf[12] = (((MUX_RATE<<2)&0xFC)|0x03);
pDestBuf[13] = 0xFA;/* 填充字节数:2 */
/* 填充2个字节 */
pDestBuf[14] = 0xFF;
pDestBuf[15] = 0xFF;
nLen = PS_Header_Len_aligned;
return PS_Error_OK;
}
/* 系统头 */
int Packet_System_header(char* pDestBuf, int& nLen)
{
if(NULL == pDestBuf)
{
return PS_Error_Param;
}
/* 系统头起始码前缀:0x000001BB */
memcpy(pDestBuf, PS_System_Header, PS_Packet_Start_Code_Len);/* PS_Packet_Start_Code_Len:4个字节 */
/* 4~5字节为:该字段后的系统头长度 */
pDestBuf[4] = 0x00;/* 12字节 */
pDestBuf[5] = 0x0C;
/* rate_bound:0x0F7F */
/* rate_bound为大于或等于在任意节目流包中编码的program_mux_rate字段的最大值的整数值 */
pDestBuf[6] = 0x80;
pDestBuf[7] = 0x1E;
pDestBuf[8] = 0xFF;
/* audio_bound:0x3F */
/* audio_bound为大于或等于ISO/IEC 13818-3和ISO/IEC 11172-3音频流最大数的整数值 */
/* fixed_flag:1 */
/* fixed_flag为1时表示固定的比特速率操作,为0时表示可变比特速率操作 */
/* CSPS_flag:0 */
/* CSPS_flag为1表示节目流满足2.7.9中规定的限制 */
pDestBuf[9] = 0xFE;
/* system_audio_lock_flag:1 */
/* system_audio_lock_flag为1表示音频采样速率和系统目标解码器的system_clock_frequency之间存在特定的常量比率关系 */
/* system_video_lock_flag:1 */
/* system_video_lock_flag为1表示视频时间基和系统目标解码器的系统时钟频率之间存在特定的常量比率关系 */
/* video_bound:1 */
/* 在解码过程同时被激活的节目流中,video_bound被设置为大于或等于视流的最大数的整数值 */
pDestBuf[10] = 0xE1;
/* packet_rate_restriction_flag:0 */
/* 若CSPS标志设置为1,则packet_rate_restriction_flag指示适用于该包速率的那些限制,如2.7.9 中所指定的 */
/* 若CSPS标志设置为0,则packet_rate_restriction_flag的含义未确定 */
pDestBuf[11] = 0x7F;
/* stream_id:0xE0 */
/* stream_id为下面P-STD_buffer_bound_scale和P-STD_buffer_size_bound字段所涉及的流的编码与基本流编号 */
pDestBuf[12] = 0xE0;
/* P-STD_buffer_bound_scale:1/视频 */
/* P-STD_buffer_bound_scale指示用于解释后续P-STD_buffer_size_bound字段的标度因子 */
/* 若前导stream_id指示音频流,则P-STD_buffer_bound_scale必为0 */
/* 若前导stream_id指示视频流,则P-STD_buffer_bound_scale必为1 */
pDestBuf[13] = 0xE0;
/* P-STD_buffer_size_bound:0x0D8*/
/* P-STD_buffer_size_bound大于或等于节目流中流n的所有包上的最大P-STD输入缓冲器尺寸BSn */
/* 若P-STD_buffer_bound_scale为0,那么P-STD_buffer_size_bound以128字节为单位度量该缓冲器尺寸限制 */
/* 若P-STD_buffer_bound_scale为1,那么P-STD_buffer_size_bound以1024字节为单位度量该缓冲器尺寸限制 */
pDestBuf[14] = 0xD8;
/* stream_id:0xC0 */
pDestBuf[15] = 0xC0;
/* P-STD_buffer_bound_scale:0/音频 */
pDestBuf[16] = 0xC0;
/* P-STD_buffer_size_bound:0x020*/
pDestBuf[17] = 0x20;
nLen = 18;
return PS_Error_OK;
}
/* 节目流映射 */
int Packet_PS_map(char* pDestBuf, int& nLen, int Compression)
{
if(NULL == pDestBuf)
{
return PS_Error_Param;
}
/* 节目流映射起始码前缀:0x000001BC */
memcpy( pDestBuf, PS_Map_Header, PS_Packet_Start_Code_Len);/* PS_Packet_Start_Code_Len:4个字节 */
/* 4~5字节为:该字段后的节目流映射长度 */
pDestBuf[4] = 0x00;/* 24字节 */
pDestBuf[5] = 0x18;
/* current_next_indicator:1 */
/* 当current_next_indicator为1时表示发送的节目流映射为当前有效,为0时表示发送的节目流映射尚未有效并且下一个节目流映射表将生效 */
/* program_stream_map_version:1*/
/* 当current_next_indicator为1时,program_stream_map_version是当前有效的节目流映射的版本 */
pDestBuf[6] = 0xE1;
pDestBuf[7] = 0xFF;
/* program_stream_info_length:0*/
/* program_stream_info_length表示紧随此字段的描述符的总长 */
pDestBuf[8] = 0x00;
pDestBuf[9] = 0x00;
/* elementary_stream_map_length:8 */
/* elementary_stream_map_length表示在此节目流映射中所有基本流信息的总长度(以字节为单位) */
/* 它包括stream_type、elementary_stream_id和elementary_stream_info_length字段 */
pDestBuf[10] = 0x00;
pDestBuf[11] = 0x08;
/* stream_type:0x1B */
/* stream_type标识PES包中包含的基本流 */
pDestBuf[12] = 0x1B; //H.264
/* elementary_stream_id:0xE0 */
/* elementary_stream_id标识存储此基本流的PES包的PES包头内的stream_id字段的赋值/视频帧PES为0xE0 */
pDestBuf[13] = 0xE0;
/* elementary_stream_info_length:0x06 */
/* elementary_stream_info_length表示紧随此字段的描述符长度,以字节为单位 */
pDestBuf[14] = 0x00;
pDestBuf[15] = 0x06;
/* descriptor */
pDestBuf[16] = 0x0A;
pDestBuf[17] = 0x04;
pDestBuf[18] = 0x65;
pDestBuf[19] = 0x6E;
pDestBuf[20] = 0x67;
pDestBuf[21] = 0x00;
/* stream_type:0x90 */
/* stream_type标识PES包中包含的基本流 */
pDestBuf[22] = 0x90;
/* elementary_stream_id:0xC0 */
/* elementary_stream_id标识存储此基本流的PES包的PES包头内的stream_id字段的赋值/音频帧PES为0xC0 */
pDestBuf[23] = 0xC0;
/* elementary_stream_info_length:0 */
/* elementary_stream_info_length表示紧随此字段的描述符长度,以字节为单位 */
pDestBuf[24] = 0x00;
/* elementary_stream_info_length:0 */
/* elementary_stream_info_length表示紧随此字段的描述符长度,以字节为单位 */
pDestBuf[25] = 0x00;
/* CRC32 */
pDestBuf[26] = 0x23;
pDestBuf[27] = 0xB9;
pDestBuf[28] = 0x0F;
pDestBuf[29] = 0x3D;
nLen = 30;/* 现在PS_Map的长度都是固定的 */
return PS_Error_OK;
}
*/PS->RTP
/* 将PS经过RTP打包后添加到队列中 */
int sendFU_A( int iCh, unsigned int frameType, char* fui, char* fuh, char* data, int len, bool bMarker)
{
if((len <= 0)||(NULL == data))
{
return -1;
}
PACKET_NODE_T* node = new PACKET_NODE_T;
int& rtp_size = node->len;
char *pRtpBuf = node->buf;
if(m_rtpModel)/* RTP打包模式:1为UDP打包/0为TCP打包 */
{
RTPHDR_EXT *pszHdr = (RTPHDR_EXT *)(pRtpBuf);/* RTPHDR_EXT:RTP头结构 */
memset((char *)pszHdr, 0, RTPHDR_EXT_SIZE);/* RTPHDR_EXT_SIZE:RTP头结构长度 */
pszHdr->version = 2;/* 版本号 */
pszHdr->padding = 0;/* 填充标识 */
pszHdr->extension = 0;/* 扩展标识 */
pszHdr->csrccount = 0;/* CSRC计数器 */
pszHdr->payloadtype = 96;/* 负载类型 */
pszHdr->marker = bMarker;/* 标记 */
pszHdr->seqnum = htons((unsigned short)getSequenceNum());/* 序列号 */
pszHdr->timestamp = htonl(m_iTimeStep);/* 时间戳 */
pszHdr->ssrc = htonl(m_iRtpSsrc);/* SSRC识别符/标识本次会话 */
if(NULL == fui)/* 不存在fui */
{
memcpy(pRtpBuf+RTPHDR_EXT_SIZE, data, len);
rtp_size = RTPHDR_EXT_SIZE + len;
}
else/* 存在fui的话,先添加fui与fuh,之后再添加帧数据 */
{
memcpy(pRtpBuf + RTPHDR_EXT_SIZE, fui, 1);
memcpy(pRtpBuf + RTPHDR_EXT_SIZE+1, fuh, 1);
memcpy(pRtpBuf + RTPHDR_EXT_SIZE+2, data, len);
rtp_size = RTPHDR_EXT_SIZE + 2 + len;
}
}
else/* TCP打包,需要在RTP包之前加2个字节的长度 */
{
RTPHDR_EXT pszHdr;/* RTPHDR_EXT:RTP头结构 */
memset(&pszHdr, 0, RTPHDR_EXT_SIZE);/* RTPHDR_EXT_SIZE:RTP头结构长度 */
pszHdr.version = 2;
pszHdr.padding = 0;
pszHdr.extension = 1;/* 扩展标识 */
pszHdr.csrccount = 0;
pszHdr.payloadtype = 96;
pszHdr.marker = bMarker;
pszHdr.seqnum = htons((unsigned short)getSequenceNum());
pszHdr.timestamp = htonl(m_iTimeStep);
pszHdr.ssrc = htonl(m_iRtpSsrc);
/* extension/扩展字段 */
RTP_EXT_Header RTPEXTHeader;/* RTP_EXT_Header:RTP头扩展字段结构 */
memset(&RTPEXTHeader, 0, sizeof(RTP_EXT_Header));
RTPEXTHeader.profile = htons(1);/* 概况 */
RTPEXTHeader.len = htons(1);/* 长度:指示扩展项中32比特字的个数 */
if( PACK_TYPE_FRAME_I == frameType )/* 视频I帧 */
{
RTPEXTHeader.FrameType = 0;
}
else if( PACK_TYPE_FRAME_P == frameType )/* 视频P帧 */
{
RTPEXTHeader.FrameType = 1;
}
else if( PACK_TYPE_FRAME_B == frameType )/* 视频B帧 */
{
RTPEXTHeader.FrameType = 2;
}
else if( PACK_TYPE_FRAME_AUDIO == frameType )/* 音频帧 */
{
RTPEXTHeader.FrameType = 8;
}
if(bMarker)
{
RTPEXTHeader.Framemarker = 1;
}
else
{
RTPEXTHeader.Framemarker = 0;
}
unsigned short packetlen = htons((unsigned short)(RTPHDR_EXT_SIZE + sizeof(RTPEXTHeader) + len));
memcpy(pRtpBuf, (void *)&packetlen, 2);
memcpy(pRtpBuf+2, (void *)&pszHdr, sizeof(RTPHDR_EXT));
memcpy(pRtpBuf+2+RTPHDR_EXT_SIZE, (void *)&RTPEXTHeader, sizeof(RTP_EXT_Header));
memcpy(pRtpBuf+2+RTPHDR_EXT_SIZE + sizeof(RTPEXTHeader), data, len);
rtp_size = RTPHDR_EXT_SIZE + sizeof(RTPEXTHeader) + len + 2;
}
m_Packet_list.push_back(node);/* 将当前帧数据节点加入队列 */
return 0;
}