GB28181设备端PS流封装和发送

本文详细介绍了GB28181标准中I帧的RTP流格式,包括RTP包头、PSH头部、SYS头部、PSM和PES头部的构建过程。每个部分的字节布局和重要字段如RTP版本、标记位、负载类型、系统时钟、流类型、编码格式等都进行了阐述,旨在帮助理解H.264裸流如何转化为符合GB28181标准的RTP数据包。
摘要由CSDN通过智能技术生成

GB28181要求的RTP流格式

        首先,我们来看看I帧的PS流格式,这里需要注意的是SPS、PPS之前要加上PES头部。如下图所示,其中绿色部分就是我们拿到的H.264裸流数据,须将它拆分成三段并在前面加上PES头部。

1、头部信息:

    首先是RTP包头信息,它一般长度为12个字节:

#define RTP_HDR_LEN 12
static 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;
}

2、然后是PSH头部,它占了14个字节:

#define PS_HDR_LEN  14
static 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;
}

3、后面是SYS,它包含了流类型信息,比如音频还是视频、视频编码格式:

#define SYS_HDR_LEN 18
static 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;
}

4、接下来是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*/
    /*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 */
    /*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*/
    /*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 19
static 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;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
GB28181是一种视频监控领域常用的协议,其支持拉取RTSP和RTP两种类型的数据。其中,RTP数据就是一系列以UDP协议进行传输的视频数据包,其负责视频信息及其时间信息的传输。而PS作为RTP数据的一种,其优点在于可以同时传输音频和视频数据,并且在网络不畅的情况下稳定性更高。 下面是GB28181PS分析: 1. PS格式 PS是一种由包含多个包的MPEG-2传输构成的格式,其中每个包的大小为188字节。其包含了一个称为PES(Packetized Elementary Stream)的数据单元,同时还包括了一些元数据信息,例如视频码率、帧率、分辨率等。 2. PS构成 一个PS由多个PES包组成,其中每个PES包代表一个时间片段的音频或视频数据。在整个时间切片中,所有的数据包会按照时间顺序进行排列。其中,音频和视频的PES包可以通过PID值进行区分。 3. PS解析 在解析PS时,需要先解出MPEG2-TS首部,然后解析TS中的PMT、PAT表,最后才能解析得到视频和音频数据。其中每个TS包分别由188个字节组成,最后4个字节为CRC校验码。其他字节代表位同步字节和不同PID的封装数据,其中每个PID对应着一种视频或音频的数据。 综上所述,GB28181PS分析需要解析MPEG2-TS首部,PMT和PAT表以及PID封装数据来获取音视频数据信息。同时,对于PS的使用还需要考虑网络环境质量和视频质量问题,以保证视频监控系统的正常运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大王算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值