GB/T28181-2016公共安全视频监控联网系统 信息传输、交换、控制技术要求相关的传输要求如下:
联网系统网络层应支持IP协议,传输层应支持 TCP和 UDP协议。
视音频流在基于IP的网络上传输时应支持 RTP/RTCP协议;视音频流的数据封装格式应符合4.3.6 中的要求。
视音频流在基于IP的网络上传输时宜扩展支持 TCP协议,协议应符合附录 L的规定。
当信息(包括视音频信息、控制信息及报警信息等)经由IP网络传输时,端到端的信息延迟时间(包
括发送端信息采集、编码、网络传输、信息接收端解码、显示等过程所经历的时间)应满足下列要求:
a) 前端设备与信号直接接入的监控中心相应设备间端到端的信息延迟时间应不大于2s;
b) 前端设备与用户终端设备间端到端的信息延迟时间应不大于4s。
联网系统网络带宽设计应能满足前端设备接入监控中心、监控中心互联、用户终端接入监控中心的
带宽要求,并留有余量。前端设备接入监控中心单路的网络传输带宽应不低于512kbps,重要场所的
11GB/T28181—2016前端设备接入监控中心单路的网络传输带宽应不低于2Mbps,各级监控中心间网络单路的网络传输带宽应不低于2.5Mbps。
联网系统IP网络的传输质量(如传输时延、包丢失率、包误差率、虚假包率等)应符合如下要求:
a) 网络时延上限值为400ms;
b) 时延抖动上限值为50ms;
c) 丢包率上限值为1×10-3;
d) 包误差率上限值为1×10-4。
本地录像时可支持的视频帧率应不低于25帧/s;图像格式为 CIF时,网络传输的视频帧率应不低于25帧/s;图像格式为4CIF以上时,网络传输的视频帧率应不低于15帧/s,重要图像信息宜25帧/s。
Android平台GB28181接入SDK,实现不具备国标音视频能力的 Android终端,通过平台注册接入到现有的GB/T28181—2016服务,可用于如智能监控、智慧零售、智慧教育、远程办公、生产运输、智慧交通、车载或执法记录仪等场景。Android终端除支持常规的音视频数据接入外,还可以支持移动设备位置(MobilePosition)订阅和通知、语音广播和语音对讲。
除了符合技术规范里面的传输要求外,延迟方面,目前测试下来,Android平台GB28181设备接入延迟在毫秒级。
功能设计如下:
平台功能扩展:
Android平台,主要是采集设备接入这块的考量,由于GB28181设备接入行业应用广泛,常见的数据对接类型有:
其他方面不再赘述,以下展示下,和语音广播语音对讲相关的设计:
/*
* CameraPublishActivity.java
* CameraPublishActivity
*
* WebSite: https://daniusdk.com
* Github: https://github.com/daniulive/SmarterStreaming
*
*/
@Override
public void ntsOnNotifyBroadcastCommand(String fromUserName, String fromUserNameAtDomain, String sn, String sourceID, String targetID) {
handler_.postDelayed(new Runnable() {
@Override
public void run() {
Log.i(TAG, "ntsOnNotifyBroadcastCommand, fromUserName:"+ from_user_name_ + ", fromUserNameAtDomain:"+ from_user_name_at_domain_
+ ", SN:" + sn_ + ", sourceID:" + source_id_ + ", targetID:" + target_id_);
if (gb28181_agent_ != null ) {
gb28181_agent_.respondBroadcastCommand(from_user_name_, from_user_name_at_domain_,sn_,source_id_, target_id_, true);
btnGB28181AudioBroadcast.setText("收到GB28181语音广播通知");
}
}
private String from_user_name_;
private String from_user_name_at_domain_;
private String sn_;
private String source_id_;
private String target_id_;
public Runnable set(String from_user_name, String from_user_name_at_domain, String sn, String source_id, String target_id) {
this.from_user_name_ = from_user_name;
this.from_user_name_at_domain_ = from_user_name_at_domain;
this.sn_ = sn;
this.source_id_ = source_id;
this.target_id_ = target_id;
return this;
}
}.set(fromUserName, fromUserNameAtDomain, sn, sourceID, targetID),0);
}
@Override
public void ntsOnAudioBroadcast(String commandFromUserName, String commandFromUserNameAtDomain, String sourceID, String targetID) {
handler_.postDelayed(new Runnable() {
@Override
public void run() {
Log.i(TAG, "ntsOnAudioBroadcastPlay, fromFromUserName:" + command_from_user_name_
+ " FromUserNameAtDomain:" + command_from_user_name_at_domain_
+ " sourceID:" + source_id_ + ", targetID:" + target_id_);
stopAudioPlayer();
destoryRTPReceiver();
if (gb28181_agent_ != null ) {
String local_ip_addr = IPAddrUtils.getIpAddress(context_);
boolean is_tcp = true; // 考虑到跨网段, 默认用TCP传输rtp包
rtp_receiver_handle_ = lib_player_.CreateRTPReceiver(0);
if (rtp_receiver_handle_ != 0 ) {
lib_player_.SetRTPReceiverTransportProtocol(rtp_receiver_handle_, is_tcp?1:0);
lib_player_.SetRTPReceiverIPAddressType(rtp_receiver_handle_, 0);
if (0 == lib_player_.CreateRTPReceiverSession(rtp_receiver_handle_, 0) ) {
int local_port = lib_player_.GetRTPReceiverLocalPort(rtp_receiver_handle_);
boolean ret = gb28181_agent_.inviteAudioBroadcast(command_from_user_name_,command_from_user_name_at_domain_,
source_id_, target_id_, "IP4", local_ip_addr, local_port, is_tcp?"TCP/RTP/AVP":"RTP/AVP");
if (!ret ) {
destoryRTPReceiver();
btnGB28181AudioBroadcast.setText("GB28181语音广播");
}
else {
btnGB28181AudioBroadcast.setText("GB28181语音广播呼叫中");
}
} else {
destoryRTPReceiver();
btnGB28181AudioBroadcast.setText("GB28181语音广播");
}
}
}
}
private String command_from_user_name_;
private String command_from_user_name_at_domain_;
private String source_id_;
private String target_id_;
public Runnable set(String command_from_user_name, String command_from_user_name_at_domain, String source_id, String target_id) {
this.command_from_user_name_ = command_from_user_name;
this.command_from_user_name_at_domain_ = command_from_user_name_at_domain;
this.source_id_ = source_id;
this.target_id_ = target_id;
return this;
}
}.set(commandFromUserName, commandFromUserNameAtDomain, sourceID, targetID),0);
}
@Override
public void ntsOnInviteAudioBroadcastException(String sourceID, String targetID, String errorInfo) {
handler_.postDelayed(new Runnable() {
@Override
public void run() {
Log.i(TAG, "ntsOnInviteAudioBroadcastException, sourceID:" + source_id_ + ", targetID:" + target_id_);
destoryRTPReceiver();
btnGB28181AudioBroadcast.setText("GB28181语音广播");
}
private String source_id_;
private String target_id_;
public Runnable set(String source_id, String target_id) {
this.source_id_ = source_id;
this.target_id_ = target_id;
return this;
}
}.set(sourceID, targetID),0);
}
@Override
public void ntsOnInviteAudioBroadcastTimeout(String sourceID, String targetID) {
handler_.postDelayed(new Runnable() {
@Override
public void run() {
Log.i(TAG, "ntsOnInviteAudioBroadcastTimeout, sourceID:" + source_id_ + ", targetID:" + target_id_);
destoryRTPReceiver();
btnGB28181AudioBroadcast.setText("GB28181语音广播");
}
private String source_id_;
private String target_id_;
public Runnable set(String source_id, String target_id) {
this.source_id_ = source_id;
this.target_id_ = target_id;
return this;
}
}.set(sourceID, targetID),0);
}
感兴趣的开发者,可以直接查看相关规范。