三页搞定GB2818/SIP/RTP、PS封装

三页搞定GB2818/SIP/RTP、PS封装

 (2016-08-23 18:27:20)

转载

标签: 

it

 

互联网

 

gb28181

 

sip

 

rtp

分类: 技术

GB2818集成了sip通讯、RTP封装及PS流封装。初涉者不了解整体框架,如果每一项去啃读,每项有几百页的标准文档,啃完估计该吐血了。实际上虽然GB28181里用了3个项目,但每个单元基本都是固定的,用法比较简单。

一、关于SIP:GB28181里只是简单用了开源的eXosip2和osip2,有兴趣可以下载编绎,或直接使用别人编绎好和.h、.lib、.dll,初始化也蛮简单

1> 初始化

osip_trace_initialize(OSIP_INFO1, NULL);

long result = eXosip_init();

if (result != OSIP_SUCCESS)

       return -1;

result = eXosip_listen_addr(IPPROTO_UDP, NULL, m_iMySipPort, AF_INET, 0);

if (result != OSIP_SUCCESS)

       return -2;

result = eXosip_listen_addr(IPPROTO_TCP, NULL, m_iMySipPort, AF_INET, 0);

if (result != OSIP_SUCCESS)

       return -3;

2>SIP消息处理线程

eXosip_event_t *pSipEvent;

while(m_bActiveSipMsgThread)

{

       pSipEvent = eXosip_event_wait(0, 50);

       eXosip_lock();

       eXosip_default_action(pSipEvent);

       eXosip_automatic_refresh();

       eXosip_automatic_action();

       eXosip_unlock();

       if(pSipEvent==NULL)

              continue;

       switch(pSipEvent->type)

       {

              case EXOSIP_REGISTRATION_NEW://有注册进来

                     break;

              case EXOSIP_REGISTRATION_REFRESHED:

                     break;

              case EXOSIP_REGISTRATION_TERMINATED:

                     break;

              case EXOSIP_CALL_NOANSWER:

                     break;

              case EXOSIP_CALL_ANSWERED://请求视频流回复成功

                     break;

              case EXOSIP_CALL_CANCELLED:

                     break;

              case EXOSIP_CALL_TIMEOUT:

                     break;

              case EXOSIP_CALL_CLOSED:

                     break;

              case EXOSIP_CALL_MESSAGE_ANSWERED:

                     break;

              case EXOSIP_MESSAGE_NEW://下级平台保活、设备查询回复

                     break;

              case EXOSIP_MESSAGE_ANSWERED://查询

                     break;

              case EXOSIP_REGISTRATION_FAILURE:

                     break;

              case EXOSIP_REGISTRATION_SUCCESS:

                     break;

              default:

                     break;

       }

       eXosip_event_free(pSipEvent);//释放

}

3>关于sdp

sSDP.Format("v=0\r\n"                      

            "o=%s 0 0 IN IP4 %s\r\n"        //owner/creator and session identifier

            "s=%s\r\n"                  //session name

            "c=IN IP4 %s\r\n"//connection information

            "t=%d %d\r\n"                   //time the session is active

            "m=video %d RTP/AVP 96 98\r\n"  //media name and transport address

            "a=recvonly\r\n"                //zero or more session attribute lines

            "a=rtpmap:96 PS/90000\r\n"      //

            "a=rtpmap:98 H264/90000\r\n"

            "y=%d%sd\r\n",               //SSRC Y字段:为十进制整数字符串,表示SSRC值。格式如下:D ddddd dddd(第一位为历史或实时媒体,2-5为SipID的中间(-8),4位StreamID

二、关于RTP

RTP定义本身很复杂,但在GB28181里很简单,基本就是固定的12个字节

每一帧视频或音频数据,先封装成ps流,再封装成RTP包,这个处理是gb28181里最为复杂的部分。

RTP

struct RTPHeader

{

    uint8_t csrccount:4;

    uint8_t extension:1;

    uint8_t padding:1;

    uint8_t version:2;

    uint8_t payloadtype:7;

    uint8_t marker:1;

    uint16_t sequencenumber;

    uint32_t timestamp;

    uint32_t ssrc;

};

细看比较复杂,其实就是一个12字节的头,后面是av数据。需要注意以下几个标识

Marker:如果为1,表明该帧已经结束,为0表示是连接的音视频数据

Sequencenumber:RTP包顺序,比如一帧K帧,200K,顺序可能是0-199,最后一个包Marker位为1。

Ssrc:为流标识,实际可以多个流往一个端口上发,通过此位标识。

Payloadlength:为该包的长度,如果是前面的包,此值通常为1024,最后一个长度为总长除1024的余数

Payloadoffset:通常为12,rtp头信息。

Timestamp:这个值并非每帧的时间戳,但是一个音频或视频包此项是相同的。

三、关于PS流封装

若干个PS包会组成一个AV包(Marker标识一帧结束),以00、00、01在个字节固定开头,至少需要6个字节,根据第4个字节判断是音频帧还是视频帧

0xBA :I帧(关键帧),后面还跟有8字节的ps pack header信息,即ps pack header信息长度为14字节。

0xBB: // ps system header <18字节>

0xBC:// ps map header <30字节>

0xC0:// 音频头

0xE0: //视频头 <19字节>

最后根据各字节解析出音视频包的实际长度。比如一个I帧为64400,则后面的64400/1024=63个包全是该I帧数据。音频帧要简单一些,没有ps header及map header.

四、注意事项

l          使用多线程接受UDP数据,如果用单线程,需要使用map去检索。

l          实际UDP包传输时如果网络情况不太好,它的到达顺序是不固定的,即有可能先发的包后收到,这个处理起来非常麻烦。如果使用链表排序又会降低系统性能。因此需要做好内存管理。

猜你喜欢

转载自blog.csdn.net/xswy1/article/details/81609379