本文共 9448 字,大约阅读时间需要 31 分钟。
1. GB28181要求的RTP流格式
首先,我们来看看I帧的PS流格式,这里需要注意的是SPS、PPS之前要加上PES头部。如下图所示,其中绿色部分就是我们拿到的H.264裸流数据,须将它拆分成三段并在前面加上PES头部。这一点在GB28181标准中没有细说,需要通过分析海康IPC流才能看出。
一般情况下IDR帧很大,超过了RTP的负载长度限制(1400字节),所以上面这一个I帧要拆分成若干包RTP分多次发送。第一包的结构如上图所示,第二包以后RTP的结构就简单多了,它是这样的: 上面提到的是I帧的情况,相比它,P/B帧的帧格式真是太简单了,因为它既没有SYS、PSM,也没有SPS、PPS: P/B帧大小一般不超过1400字节,如果超过1400字节,也需分成多包RTP数据进行传输,超出1400部分的第二包RTP结构:2. 头部信息
首先是RTP包头信息,它一般长度为12个字节
#define RTP_HDR_LEN 12static int gb28181_make_rtp_header(char *pData, int marker_flag, unsigned short cseq, long long curpts, unsigned int ssrc){ bits_buffer_s bitsBuffer; if (pData == NULL) return -1; bitsBuffer.i_size = RTP_HDR_LEN; bitsBuffer.i_data = 0; bitsBuffer.i_mask = 0x80; bitsBuffer.p_data = (unsigned char *)(pData); memset(bitsBuffer.p_data, 0, RTP_HDR_SIZE); bits_write(&bitsBuffer, 2, RTP_VERSION); /* rtp version 版本号,固定为2 */ bits_write(&bitsBuffer, 1, 0); /* rtp padding */ bits_write(&bitsBuffer, 1, 0); /* rtp extension */ bits_write(&bitsBuffer, 4, 0); /* rtp CSRC count */ bits_write(&bitsBuffer, 1, (marker_flag)); /* rtp marker 结束标志位,一帧图像的最后一包RTP置1*/ bits_write(&bitsBuffer, 7, 96); /* rtp payload type,96代表PS*/ bits_write(&bitsBuffer, 16, (cseq)); /* rtp sequence */ bits_write(&bitsBuffer, 32, (curpts)); /* rtp timestamp */ bits_write(&bitsBuffer, 32, (ssrc)); /* rtp SSRC */ return 0;}
然后是PSH头部,它占了14个字节:
#define PS_HDR_LEN 14static int gb28181_make_ps_header(char *pData, unsigned long long s64Scr){ unsigned long long lScrExt = (s64Scr) % 100; s64Scr = s64Scr / 100; bits_buffer_s bitsBuffer; bitsBuffer.i_size = PS_HDR_LEN; bitsBuffer.i_data = 0; bitsBuffer.i_mask = 0x80; bitsBuffer.p_data = (unsigned char *)(pData); memset(bitsBuffer.p_data, 0, PS_HDR_LEN); bits_write(&bitsBuffer, 32, 0x000001BA); /*start codes 起始码*/ bits_write(&bitsBuffer, 2, 1); /*marker bits '01b'*/ bits_write(&bitsBuffer, 3, (s64Scr>>30)&0x07); /*System clock [32..30]*/ bits_write(&bitsBuffer, 1, 1); /*marker bit*/ bits_write(&bitsBuffer, 15, (s64Scr>>15)&0x7FFF); /*System clock [29..15]*/ bits_write(&bitsBuffer, 1, 1); /*marker bit*/ bits_write(&bitsBuffer, 15, s64Scr & 0x7fff); /*System clock [14..0]*/ bits_write(&bitsBuffer, 1, 1); /*marker bit*/ bits_write(&bitsBuffer, 9, 0); /*SCR extension*/ bits_write(&bitsBuffer, 1, 1); /*marker bit*/ bits_write(&bitsBuffer, 22, (255)&0x3fffff); /*bit rate(n units of 50 bytes per second.)*/ bits_write(&bitsBuffer, 2, 3); /*marker bits '11'*/ bits_write(&bitsBuffer, 5, 0x1f); /*reserved(reserved for future use)*/ bits_write(&bitsBuffer, 3, 0); /*stuffing length*/ return 0;}
后面是SYS,它包含了流类型信息,比如音频还是视频、视频编码格式
#define SYS_HDR_LEN 18static int gb28181_make_sys_header(char *pData){ bits_buffer_s bitsBuffer; bitsBuffer.i_size = SYS_HDR_LEN; bitsBuffer.i_data = 0; bitsBuffer.i_mask = 0x80; bitsBuffer.p_data = (unsigned char *)(pData); memset(bitsBuffer.p_data, 0, SYS_HDR_LEN); /*system header*/ bits_write( &bitsBuffer, 32, 0x000001BB); /*start code*/ bits_write( &bitsBuffer, 16, SYS_HDR_LEN-6); /* 减6,是因为start code加上length这两位,占了6个字节*/ bits_write( &bitsBuffer, 1, 1); /*marker_bit*/ bits_write( &bitsBuffer, 22, 50000); /*rate_bound*/ bits_write( &bitsBuffer, 1, 1); /*marker_bit*/ bits_write( &bitsBuffer, 6, 1); /*audio_bound*/ bits_write( &bitsBuffer, 1, 0); /*fixed_flag */ bits_write( &bitsBuffer, 1, 1); /*CSPS_flag */ bits_write( &bitsBuffer, 1, 1); /*system_audio_lock_flag*/ bits_write( &bitsBuffer, 1, 1); /*system_video_lock_flag*/ bits_write( &bitsBuffer, 1, 1); /*marker_bit*/ bits_write( &bitsBuffer, 5, 1); /*video_bound*/ bits_write( &bitsBuffer, 1, 0); /*dif from mpeg1*/ bits_write( &bitsBuffer, 7, 0x7F); /*reserver*/ /*audio stream bound*/ bits_write( &bitsBuffer, 8, 0xC0); /*stream_id 音频的流id*/ bits_write( &bitsBuffer, 2, 3); /*marker_bit */ bits_write( &bitsBuffer, 1, 0); /*PSTD_buffer_bound_scale*/ bits_write( &bitsBuffer, 13, 512); /*PSTD_buffer_size_bound*/ /*video stream bound*/ bits_write( &bitsBuffer, 8, 0xE0); /*stream_id 视频的流id*/ bits_write( &bitsBuffer, 2, 3); /*marker_bit */ bits_write( &bitsBuffer, 1, 1); /*PSTD_buffer_bound_scale*/ bits_write( &bitsBuffer, 13, 2048); /*PSTD_buffer_size_bound*/ return 0;}
接下来是PSM,这里面记录了媒体信息,比如音视频的编码格式:
static int gb28181_make_psm_header(char *pData){ bits_buffer_s bitsBuffer; bitsBuffer.i_size = PSM_HDR_LEN; bitsBuffer.i_data = 0; bitsBuffer.i_mask = 0x80; bitsBuffer.p_data = (unsigned char *)(pData); memset(bitsBuffer.p_data, 0, PSM_HDR_LEN);//24Bytes bits_write(&bitsBuffer, 24,0x000001); /*start code*/ bits_write(&bitsBuffer, 8, 0xBC); /*map stream id*/ bits_write(&bitsBuffer, 16,18); /*program stream map length*/ bits_write(&bitsBuffer, 1, 1); /*current next indicator */ bits_write(&bitsBuffer, 2, 3); /*reserved*/ bits_write(&bitsBuffer, 5, 0); /*program stream map version*/ bits_write(&bitsBuffer, 7, 0x7F); /*reserved */ bits_write(&bitsBuffer, 1, 1); /*marker bit */ bits_write(&bitsBuffer, 16,0); /*programe stream info length*/ bits_write(&bitsBuffer, 16, 8); /*elementary stream map length is*/ /*audio*/ bits_write(&bitsBuffer, 8, 0x90); /*stream_type 音频编码格式G711*/ bits_write(&bitsBuffer, 8, 0xC0); /*elementary_stream_id*/ bits_write(&bitsBuffer, 16, 0); /*elementary_stream_info_length is*/ /*video*/ bits_write(&bitsBuffer, 8, 0x1B); /*stream_type 视频编码格式H.264*/ bits_write(&bitsBuffer, 8, 0xE0); /*elementary_stream_id*/ bits_write(&bitsBuffer, 16, 0); /*elementary_stream_info_length */ /*crc (2e b9 0f 3d)*/ bits_write(&bitsBuffer, 8, 0x45); /*crc (24~31) bits*/ bits_write(&bitsBuffer, 8, 0xBD); /*crc (16~23) bits*/ bits_write(&bitsBuffer, 8, 0xDC); /*crc (8~15) bits*/ bits_write(&bitsBuffer, 8, 0xF4); /*crc (0~7) bits*/ return 0;}
最后是PES头部,它记录了帧的时间戳,DTS可以不填,如果填写要和PTS保持一致,且同一帧数据的PTS要也要一样(即SPS、PPS、IDR的PES要一致):
#define PES_HDR_LEN 19static int gb28181_make_pes_header(char *pData, int stream_id, int payload_len, unsigned long long pts, unsigned long long dts){ bits_buffer_s bitsBuffer; bitsBuffer.i_size = PES_HDR_LEN; bitsBuffer.i_data = 0; bitsBuffer.i_mask = 0x80; bitsBuffer.p_data = (unsigned char *)(pData); memset(bitsBuffer.p_data, 0, PES_HDR_LEN); /*system header*/ bits_write( &bitsBuffer, 24,0x000001); /*start code*/ bits_write( &bitsBuffer, 8, (stream_id)); /*streamID*/ bits_write( &bitsBuffer, 16,(payload_len)+13); /*packet_len pes剩余头部以及后面的es长度之和,比如SPS长度+13*/ bits_write( &bitsBuffer, 2, 2 ); /*'10'*/ bits_write( &bitsBuffer, 2, 0 ); /*scrambling_control*/ bits_write( &bitsBuffer, 1, 1 ); /*priority*/ bits_write( &bitsBuffer, 1, 1 ); /*data_alignment_indicator*/ bits_write( &bitsBuffer, 1, 0 ); /*copyright*/ bits_write( &bitsBuffer, 1, 0 ); /*original_or_copy*/ bits_write( &bitsBuffer, 1, 1 ); /*PTS_flag 是否有PTS*/ bits_write( &bitsBuffer, 1, 1 ); /*DTS_flag 是否有DTS信息*/ bits_write( &bitsBuffer, 1, 0 ); /*ESCR_flag*/ bits_write( &bitsBuffer, 1, 0 ); /*ES_rate_flag*/ bits_write( &bitsBuffer, 1, 0 ); /*DSM_trick_mode_flag*/ bits_write( &bitsBuffer, 1, 0 ); /*additional_copy_info_flag*/ bits_write( &bitsBuffer, 1, 0 ); /*PES_CRC_flag*/ bits_write( &bitsBuffer, 1, 0 ); /*PES_extension_flag*/ bits_write( &bitsBuffer, 8, 10); /*header_data_length*/ /*PTS,DTS*/ bits_write( &bitsBuffer, 4, 3 ); /*'0011'*/ bits_write( &bitsBuffer, 3, ((pts)>>30)&0x07 ); /*PTS[32..30]*/ bits_write( &bitsBuffer, 1, 1 ); bits_write( &bitsBuffer, 15,((pts)>>15)&0x7FFF); /*PTS[29..15]*/ bits_write( &bitsBuffer, 1, 1 ); bits_write( &bitsBuffer, 15,(pts)&0x7FFF); /*PTS[14..0]*/ bits_write( &bitsBuffer, 1, 1 ); bits_write( &bitsBuffer, 4, 1 ); /*'0001'*/ bits_write( &bitsBuffer, 3, ((dts)>>30)&0x07 ); /*DTS[32..30]*/ bits_write( &bitsBuffer, 1, 1 ); bits_write( &bitsBuffer, 15,((dts)>>15)&0x7FFF); /*DTS[29..15]*/ bits_write( &bitsBuffer, 1, 1 ); bits_write( &bitsBuffer, 15,(dts)&0x7FFF); /*DTS[14..0]*/ bits_write( &bitsBuffer, 1, 1 ); return 0;}
关于时间戳的比特位结构,下图表示的比较清晰: