版权声明:本文为博主原创文章,未经博主允许不得转载。
GB28181视频打包传输采用 ps打包+rtp传输 的方式;看下《28181安全防范视频监控联网系统信息传输》文档里面关于打包的介绍吧:
封装及传输标准 媒体流在联网系统IP 网络上传输时应支持RTP 传输,RTP 的负载应采用如下两种格式之一:基于PS 封装的视音频数据 或 视音频基本流数据,详细的请看《28181安全防范视频监控联网系统信息传输》附录C。 媒体流的传输应采用RFC 3550 规定的RTP协议,提供实时数据传输中的时间戳信息及各数据流的同步;应采用RFC 3550 规定的RTCP 协议,为按序传输数据包提供可靠保证,提供流量控制和拥塞控制(RTCP应该不是必须的)。 音视频编码标准 联网系统中视频压缩编解码和音频编解码应符合《28181安全防范视频监控联网系统信息传输》附录E 的相关要求,采用视频编解码标准H.264/MPEG-4 , 应优先采用适用于安防监控的SVAC 标准; 音频编解码标准推荐采用 G.711/G.723.1/G.729/SVAC。 PS打包详细信息参考ISO/IEC 13818-1:2000,rtp方面参考RFC 3550*/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; }