使用p2p发送GB28181流的设计
Posted qianbo_insist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用p2p发送GB28181流的设计相关的知识,希望对你有一定的参考价值。
萌思特
1、p2p链接的必要性
其必要性在于:
1 能够显著减少服务器压力负担
2 随着国内带宽上传能力增加,非对称网络上传视频可能大大提升
3 减少服务费用
2、前提条件
1、由于p2p链接需要很多条件限制,因此并非所有网络方式能够打通p2p方式的链接,我们限制在cone net p2p上进行网关程序间分发。
2、限制udp方式分发流
3、限制联通和电信这类4g网络只能使用turn方式。
3、程序架构
1、udp服务器-主服务器
2、udp服务器-分发中转服务器
3、分发架构路由
4、ps读写构造器客户端进行解包,渲染
5、存储器 —部署在p2p的各端可进行
6、sip gb28181 ----信令服务
7、rtsp proxy
8、webrtc proxy
9、redis 订阅发布
10、tcpserver 可选
流程为:
a)在sip 接收到命令之后,可以invite相应的邀请流进入,这一部分不使用p2p方式,和webrtc本身所使用的方式一致,信令为直接tcp服务或者udp服务的传输,可以使用传统udp服务sip 5060端口。
b) 客户端负责打洞,根据分发配置信令来给服务器来通知,这时stun服务必须由分发内容。
c)打洞完毕(成功),信令服务sdp协议中可以加入接收rtp服务地址
d)传输开始
3.1层次
层次关系以及所需要的协议等等如下图所示
3.2程序框架辅助
分发功能
—config 分发配置
—config 路由
sipserver
—gb28181 分发信令服务器
rtp ps 分析器
—
投屏协议
— DLNA协议
p2p 服务
—传统的stun和turn服务器是可选项
更佳的配置是得到分析,p2p 打洞探测如果为对称立刻进行转发服务。
3.3 程序制作
给出udpserver的声明,p2p udp server如果使用非异步方式一定要使用多个线程接收,在接收线程中使用recvfrom来得到客户端的外网地址,才能帮助双方打通。
#include "c_decode.h"
#include "c_thread.h"
#include "c_sock.h"
#include <queue>
using namespace std;
typedef struct _RTP_HEAD
unsigned char version : 2;
unsigned char padding : 1;
unsigned char extension : 1;
unsigned char count : 4;
unsigned char marker : 1;
unsigned char payload : 7;
uint16_t sn; //16bits
uint32_t ts; //32
uint32_t ssrc; //32
uint32_t csrc; //32
RTP_HEAD, *pRTP_HEAD;
typedef struct _RTCP_HEAD
unsigned char version : 2;
unsigned char padding : 1;
unsigned char count : 5;
unsigned char payload; //8bits
uint16_t length; //16bits
uint32_t ssrc; //5,6,7,8 char
RTCP_HEAD, *pRTCP_HEAD;
//NACK报文是类型为205的RTCP 扩展反馈报文,在RFC4585中定义。
class c_udp:public c_thread
private:
queue<memory_cache*> _memcache;
private:
c_sock _udpserver;
unsigned int _port;
H264DecoderContext* _decoder;
public:
c_udp(void);
~c_udp(void);
void Run();
void StartReceive(unsigned int port,H264DecoderContext *decoder);
void StopServer();
memory_cache * GetBufferToDecode();
protected:
void HandlePacket(char * buffer, int len);
;
给出一个常用的thread class,以上udp 从thread类继承
#include <mutex>
#include <queue>
#include <thread>
#include <atomic>
#include <condition_variable>
using namespace std;
class c_thread
private:
//线程
thread _thread;
//等待信号
std::mutex _signal_mutex;
std::condition_variable _cond;
protected:
//char _running = false;
char _stop = true;
//锁定运行状态
std::mutex _mutex;
public:
c_thread()
virtual ~c_thread()
public:
char * status()
return &_stop;
void Join()
if (_thread.joinable())
_thread.join();
bool IsStop()
return _stop == 1 ? true : false;
void WaitForSignal()
std::unique_lock<std::mutex> ul(_signal_mutex);
_cond.wait(ul);
void Notify()
_cond.notify_one();
virtual int Start()
if (_stop == 1)//非運行中
_stop = 0;
_thread = std::thread(std::bind(&c_thread::Run, this));
return 0;
return -1;
virtual void Stop()
_stop = 1; // true;
virtual void Run() = 0;
;
#endif
线程内容就放在run函数中,主线程做收包使用,记录配对的地址和路由,才能做到分发。
其他内容待续。。。。
以上是关于使用p2p发送GB28181流的设计的主要内容,如果未能解决你的问题,请参考以下文章
Android平台音视频RTMP推送|GB28181对接之动态水印设计