国网B接口实现(QGDW1517.1)

编程入门 行业动态 更新时间:2024-10-09 22:20:10

国网B<a href=https://www.elefans.com/category/jswz/34/1771365.html style=接口实现(QGDW1517.1)"/>

国网B接口实现(QGDW1517.1)

        上篇GB28181实现已经将实现sip所需要用到的三方库,以及一些注意点描述了。由于B接口与281都是基于sip,实现方式差不多,这里就不再描述。可以将GB28181实现_LinuxZQ的博客-CSDN博客_gb28181 实现 文章sip部分作为补充学习。本篇仅描述难点部分,也就是验收的硬性要求,视频预览着重讲解

        因手上只有B接口2014的验收软件,所以本篇以2014标准进行讲解。2019协议也是增加了tcp支持,与281类型,简单扩展就可以实现

视频预览

        与281一致,同样是基于RTP流的传输,交互流程也一致,都是基于SIP INVITE+SDP。

 支持的RTP Payload如下

        这里的Payload值定义与281里面还是有区别的,B接口种的264为100,我们也是以这种方式向平台进行推流

        2014种的视频以udp为通道传输,所以先创建udp通道。

        

bool CRtpVideo::rtpTrans::setupUDP(int localPort, const std::string &remoteIp, int remotePort, int payloadType, uint32_t ssrc)
{RTPUDPv4TransmissionParams transParams;RTPSessionParams sessParams;sessParams.SetOwnTimestampUnit(1.0 / 90000.0);// sessParams.SetAcceptOwnPackets(true);sessParams.SetUsePredefinedSSRC(true);  //设置使用预先定义的SSRCsessParams.SetPredefinedSSRC(ssrc);transParams.SetPortbase(localPort);int ret = sess.Create(sessParams, &transParams);if (ret < 0){errorf("setup rtp[%s:%d] failed, msg[%s]\n", remoteIp.c_str(), remotePort, RTPGetErrorString(ret).c_str());return false;}infof("payType is %d, ssrc[%u], remoteIP[%s], remotePort[%d]\n", payloadType, ssrc, remoteIp.c_str(), remotePort);sess.SetDefaultPayloadType(payloadType);//设置传输类型sess.SetDefaultMark(true);      //设置位sess.SetTimestampUnit(1.0 / 90000.0); //设置采样间隔sess.SetDefaultTimestampIncrement(3600);//设置时间戳增加间隔uint32_t destip;destip = inet_addr(remoteIp.c_str());if (destip == INADDR_NONE){errorf("bad ip[%s]\n", remoteIp.c_str());return false;}destip = ntohl(destip);RTPIPv4Address addr(destip, remotePort);ret = sess.AddDestination(addr);if (ret < 0){errorf("add dest[%s:%d] failed, masg[%s]\n", remoteIp.c_str(), remotePort, RTPGetErrorString(ret).c_str());return false;}H264 = payloadType;return true;
}

        通道搭建成功后,就可以着手推流了,由于仅是H264裸流推送,所以不需要额外的封装。但是考虑到MTU的大小,需要进行分包。协议也明确了,需要进行分包,参考multi-slice或者FU-A。我们选择FU-A的方式。这个实现,网上也是有很多代码,示例如下

/// 因264的流开头可能为00 00 00 01,也有可能为00 00 01,所以需要动态找到nalu头
int CRtpVideo::rtpTrans::findNalu(uint8_t *data)
{char code[3] = {0x0, 0x0, 0x1};char code1[4] = {0x0, 0x0, 0x0, 0x1};bool bFind = true;for (int i = 0; i < 3; i++){if (data[i] != code[i]){bFind = false;}}if (bFind){return 3;}bFind = true;for (int i = 0; i < 4; i++){if (data[i] != code1[i]){bFind = false;}}if (bFind){return 4;}return -1;
}

        

bool CRtpVideo::rtpTrans::sendNALU(uint8_t *data, int len)
{int posN = findNalu(data);if (posN == -1){warnf("not valid h264\n");return false;}unsigned char *pSendbuf = &data[posN]; //发送数据指针len = len - posN;char sendbuf[1500];   //发送的数据缓冲memset(sendbuf, 0, 1500);int ret = 0;/// MAX_RTP_PKT_LENTH 此处定义为1360,小于这个值的直接发送if ( len <= MAX_RTP_PKT_LENGTH ){// infof("min size is %d\n", len);ret = sess.SendPacket(pSendbuf, len, H264, true, 3600);if (ret < 0){errorf("send pkt failed, msg[%s]\n", RTPGetErrorString(ret).c_str());return false;}}else if(len > MAX_RTP_PKT_LENGTH){//设置标志位Mark为0sess.SetDefaultMark(false);//printf("buflen = %d\n",buflen);//得到该需要用多少长度为MAX_RTP_PKT_LENGTH字节的RTP包来发送int k = 0, l = 0;len = len - 1;k = len / MAX_RTP_PKT_LENGTH;l = len % MAX_RTP_PKT_LENGTH;int t = 0; //用指示当前发送的是第几个分片RTP包char nalHeader = pSendbuf[0]; // NALU 头while( t < k || ( t == k && l > 0 ) ){if( (0 == t ) || ( t < k && 0 != t ) ) //第一包到最后包的前一包{sendbuf[0] = (nalHeader & 0x60) | 28;sendbuf[1] = (nalHeader & 0x1f);if ( 0 == t ){sendbuf[1] |= 0x80;}memcpy(sendbuf + 2, &pSendbuf[t * MAX_RTP_PKT_LENGTH + 1], MAX_RTP_PKT_LENGTH);// infof("select size is %d\n", MAX_RTP_PKT_LENGTH + 2);/// 分包的时间戳不要增加ret = sess.SendPacket((void *)sendbuf, MAX_RTP_PKT_LENGTH + 2, H264, false, 0);if (ret < 0){errorf("send pkt failed, msg[%s]\n", RTPGetErrorString(ret).c_str());return false;}t++;memset(sendbuf, 0, 1500);}//最后一包else if( ( k == t && l > 0 ) || ( t == (k - 1) && l == 0 )){//设置标志位Mark为1sess.SetDefaultMark(true);int iSendLen;if ( l > 0){iSendLen = len - t * MAX_RTP_PKT_LENGTH;}else{iSendLen = MAX_RTP_PKT_LENGTH;}sendbuf[0] = (nalHeader & 0x60) | 28;sendbuf[1] = (nalHeader & 0x1f);sendbuf[1] |= 0x40;memcpy(sendbuf + 2, &pSendbuf[t * MAX_RTP_PKT_LENGTH + 1], iSendLen);// infof("last size is %d\n", iSendLen + 2);/// 最后一包时间戳再增加ret = sess.SendPacket((void *)sendbuf, iSendLen + 2, H264, true, 3600);if (ret < 0){errorf("send pkt failed, msg[%s]\n", RTPGetErrorString(ret).c_str());return false;}t++;memset(sendbuf, 0, 1500);}}}return true;
}

        基本上实现到此处,B接口的流已经可以推送了。264流的来源,通过ffmpeg的avpacket即可获取,代码如下

void CRtpVideo::process()
{AVPacket *packet = NULL;infof("process GB video thread enter\n");while (m_thread.looping()){if (!m_quePkt.recvMessage(packet, 1000)){continue;}if (m_bTrans){if (m_flowType == "PS"){sendPS(packet);}else if (m_flowType == "H264"){sendH264(packet);}}av_packet_unref(packet);av_packet_free(&packet);}
}
void CRtpVideo::sendH264(AVPacket *&packet)
{if (m_bSendIframe){if (packet->flags == AV_PKT_FLAG_KEY){m_rtpTrans.sendNALU(packet->data, packet->size);m_bSendIframe = false;infof("send iframe\n");}}else{m_rtpTrans.sendNALU(packet->data, packet->size);}
}

        demo程序已经和281程序整合在一起,地址如下

        

        没有积分可进行百度网盘下载,路径如下:

        链接: 
        提取码:4cp5
        二次开发接口及程序免费运行license请联系微信HardAndBetter获取,或者加入QQ群586166104讨论。

        B接口平台测试软件ABDemo,下载地址如下

        

        链接: 
        提取码:wnv2

        

更多推荐

国网B接口实现(QGDW1517.1)

本文发布于:2024-03-13 00:38:13,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1732793.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:接口   国网

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!