28181開發之-視頻打包

GB28181視頻打包傳輸採用 ps打包+rtp傳輸 的方式;看下《28181安全防範視頻監控聯網系統信息傳輸》文檔裏面關於打包的介紹吧: node


封裝及傳輸標準

    媒體流在聯網系統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);
  ide

nTempLen = 19 ;
 
memcpy(pDestBuf+nTempLen, pSrcBuf, nSrcLen);/* 添加原始ES數據 */
 
nLen = nTempLen + nSrcLen;
  ui

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;
  spa

if((NULL == pSrcBuf)||(NULL == pDestBuf))
 
{
 
return PS_Error_Param;
 
}
  ssr

/* 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); rest

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;   }  

相關文章
相關標籤/搜索