最近刚做了PS流的封装,网上也看了很多但是发现都没有成功最后自己分析ps的抓包,一个一个字节对才发现正确的格式 所以每帧的格式封包如下:
关键帧 封包:PS headle + PS SYS headle + PS map +(pes +h264 的SPS帧 )+( pes +h264 的PPS) +(pes+h264 的I帧)
次要帧 封包:PS headle+pes+h264
的次要帧数据
然后打rtp发送即可 ,rtp封包网上很多,就不多说了,这里的关键帧封包 我是没有按照顺序(pes +h264的SPS )+( pes +h264 的PPS) +(pes+h264 的I帧)
也是可以的
GBT 28181-2016 公共安全视频监控联网系统信息传输、交换、控制技术要求中的封装如下图。
下面是主要实现,后打rtp发送
if (h264_stream.nalu_cnt > 1)
{
int i = 0;
len += PS_HDR_LEN + SYS_HDR_LEN + PSM_HDR_LEN;
for (i = 0; i < h264_stream.nalu_cnt; i++)
{
len += PES_HDR_LEN + h264_stream.nalu[i].length;
}
om = allocb(len, 0);
gb28181_package_for_h264(d, &h264_stream, TRUE, om->b_wptr);
om->b_wptr += len;
}
else if (h264_stream.nalu_cnt == 1)
{
len = PS_HDR_LEN + PES_HDR_LEN + h264_stream.nalu[0].length;
om = allocb(len, 0);
gb28181_package_for_h264(d, &h264_stream, FALSE, om->b_wptr);
om->b_wptr += len;
}
**下面就是打rtp包 注意要分片,关键帧he非关键帧都要分片,不需要重新加头直接超过mtu就分**
封包函数
static int gb28181_package_for_h264(fhVideoReaderData_t *d, msFhH264StreamInfo_t *h264_stream, bool_t is_iframe, char *ps_stream)
{
int i = 0;
int stream_pos = 0;
gb28181_make_ps_header(ps_stream + stream_pos, d->timestamp);
stream_pos += PS_HDR_LEN;
if (is_iframe)
{
gb28181_make_sys_header(ps_stream + stream_pos);
stream_pos += SYS_HDR_LEN;
gb28181_make_psm_header(ps_stream + stream_pos);
stream_pos += PSM_HDR_LEN;
}
for (i = 0; i < h264_stream->nalu_cnt; i++)
{
gb28181_make_pes_header(ps_stream + stream_pos, 0xE0, h264_stream->nalu[i].length, d->timestamp, d->timestamp);
stream_pos += PES_HDR_LEN;
memcpy(ps_stream + stream_pos, h264_stream->nalu[i].start, h264_stream->nalu[i].length);
stream_pos += h264_stream->nalu[i].length;
}
return 0;
}
各个头的封包格式
int gb28181_make_ps_header(char *pData, unsigned long long s64Scr)
{
unsigned long long lScrExt = (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);
bits_write(&bitsBuffer, 2, 1);
bits_write(&bitsBuffer, 3, (s64Scr>>30)&0x07);
bits_write(&bitsBuffer, 1, 1);
bits_write(&bitsBuffer, 15, (s64Scr>>15)&0x7FFF);
bits_write(&bitsBuffer, 1, 1);
bits_write(&bitsBuffer, 15, s64Scr&0x7fff);
bits_write(&bitsBuffer, 1, 1);
bits_write(&bitsBuffer, 9, lScrExt&0x01ff);
bits_write(&bitsBuffer, 1, 1);
bits_write(&bitsBuffer, 22, (255)&0x3fffff);
bits_write(&bitsBuffer, 2, 3);
bits_write(&bitsBuffer, 5, 0x1f);
bits_write(&bitsBuffer, 3, 0);
return 0;
}
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);
bits_write( &bitsBuffer, 32, 0x000001BB);
bits_write( &bitsBuffer, 16, SYS_HDR_LEN-6);
bits_write( &bitsBuffer, 1, 1);
bits_write( &bitsBuffer, 22, 50000);
bits_write( &bitsBuffer, 1, 1);
bits_write( &bitsBuffer, 6, 1);
bits_write( &bitsBuffer, 1, 0);
bits_write( &bitsBuffer, 1, 1);
bits_write( &bitsBuffer, 1, 1);
bits_write( &bitsBuffer, 1, 1);
bits_write( &bitsBuffer, 1, 1);
bits_write( &bitsBuffer, 5, 1);
bits_write( &bitsBuffer, 1, 0);
bits_write( &bitsBuffer, 7, 0x7F);
bits_write( &bitsBuffer, 8, 0xC0);
bits_write( &bitsBuffer, 2, 3);
bits_write( &bitsBuffer, 1, 0);
bits_write( &bitsBuffer, 13, 512);
bits_write( &bitsBuffer, 8, 0xE0);
bits_write( &bitsBuffer, 2, 3);
bits_write( &bitsBuffer, 1, 1);
bits_write( &bitsBuffer, 13, 2048);
return 0;
}
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);
bits_write(&bitsBuffer, 24,0x000001);
bits_write(&bitsBuffer, 8, 0xBC);
bits_write(&bitsBuffer, 16,18);
bits_write(&bitsBuffer, 1, 1);
bits_write(&bitsBuffer, 2, 3);
bits_write(&bitsBuffer, 5, 0);
bits_write(&bitsBuffer, 7, 0x7F);
bits_write(&bitsBuffer, 1, 1);
bits_write(&bitsBuffer, 16,0);
bits_write(&bitsBuffer, 16, 8);
bits_write(&bitsBuffer, 8, 0x90);
bits_write(&bitsBuffer, 8, 0xC0);
bits_write(&bitsBuffer, 16, 0);
bits_write(&bitsBuffer, 8, 0x1B);
bits_write(&bitsBuffer, 8, 0xE0);
bits_write(&bitsBuffer, 16, 0);
bits_write(&bitsBuffer, 8, 0x45);
bits_write(&bitsBuffer, 8, 0xBD);
bits_write(&bitsBuffer, 8, 0xDC);
bits_write(&bitsBuffer, 8, 0xF4);
return 0;
}
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);
bits_write( &bitsBuffer, 24,0x000001);
bits_write( &bitsBuffer, 8, (stream_id));
bits_write( &bitsBuffer, 16,(payload_len)+13);
bits_write( &bitsBuffer, 2, 2 );
bits_write( &bitsBuffer, 2, 0 );
bits_write( &bitsBuffer, 1, 0 );
bits_write( &bitsBuffer, 1, 0 );
bits_write( &bitsBuffer, 1, 0 );
bits_write( &bitsBuffer, 1, 0 );
bits_write( &bitsBuffer, 1, 1 );
bits_write( &bitsBuffer, 1, 1 );
bits_write( &bitsBuffer, 1, 0 );
bits_write( &bitsBuffer, 1, 0 );
bits_write( &bitsBuffer, 1, 0 );
bits_write( &bitsBuffer, 1, 0 );
bits_write( &bitsBuffer, 1, 0 );
bits_write( &bitsBuffer, 1, 0 );
bits_write( &bitsBuffer, 8, 10);
bits_write( &bitsBuffer, 4, 3 );
bits_write( &bitsBuffer, 3, ((pts)>>30)&0x07 );
bits_write( &bitsBuffer, 1, 1 );
bits_write( &bitsBuffer, 15,((pts)>>15)&0x7FFF);
bits_write( &bitsBuffer, 1, 1 );
bits_write( &bitsBuffer, 15,(pts)&0x7FFF);
bits_write( &bitsBuffer, 1, 1 );
bits_write( &bitsBuffer, 4, 1 );
bits_write( &bitsBuffer, 3, ((dts)>>30)&0x07 );
bits_write( &bitsBuffer, 1, 1 );
bits_write( &bitsBuffer, 15,((dts)>>15)&0x7FFF);
bits_write( &bitsBuffer, 1, 1 );
bits_write( &bitsBuffer, 15,(dts)&0x7FFF);
bits_write( &bitsBuffer, 1, 1 );
return 0;
}
格式长度
#define PS_HDR_LEN 14
#define SYS_HDR_LEN 18
#define PSM_HDR_LEN 24
#define PES_HDR_LEN 19
typedef struct
{
unsigned char* p_data;
unsigned char i_mask;
int i_size;
int i_data;
}bits_buffer_s;
//字节按位压缩
#define bits_write(buffer, count, bits)\
{\
bits_buffer_s *p_buffer = (buffer);\
int i_count = (count);\
uint64_t i_bits = (bits);\
while( i_count > 0 )\
{\
i_count--;\
if( ( i_bits >> i_count )&0x01 )\
{\
p_buffer->p_data[p_buffer->i_data] |= p_buffer->i_mask;\
}\
else\
{\
p_buffer->p_data[p_buffer->i_data] &= ~p_buffer->i_mask;\
}\
p_buffer->i_mask >>= 1;\
if( p_buffer->i_mask == 0 )\
{\
p_buffer->i_data++;\
p_buffer->i_mask = 0x80;\
}\
}\
}
负载包数据
PS的格式网上也有很多,可以自己抓包看格式,对得上的话基本就没问题
也可以自己写到本地,看播放是否成功