首页 > 其他分享 >GB28181基于TCP协议的视音频媒体传输探究及实现

GB28181基于TCP协议的视音频媒体传输探究及实现

时间:2022-10-30 23:31:44浏览次数:56  
标签:sender GB28181 des TCP 视音频 video rtp device id

我们先看看官方规范针对TCP协议的视音频传输描述:

实时视频点播、历史视频回放与下载的 TCP媒体传输应支持基于RTP封装的视音频PS流,封装格式参照IETFRFC4571。

流媒体服务器宜同时支持作为TCP媒体流传输服务端和客户端。默认情况下,前端设备向流媒体服务器发送媒体流时前端设备应作为TCP媒体流传输客户端,流媒体服务器作为 TCP媒体流传输服务端;同级或跨级流媒体服务器间基于 TCP协议传输视频流时,媒体流的接收方宜作为TCP媒体流传输服务端。

媒体流的发送方和接收方可扩展SDP参数进行TCP媒体流传输服务端和客户端的协商,协商机制参考附录 F及IETFRFC4571的定义。

这里我们看个INVITE信令交互示例:

INVITE sip:34020000001320000001@3402000000 SIP/2.0
Via: SIP/2.0/TCP 192.168.0.105:15060;rport;branch=z9hG4bK630055772
From: <sip:34020000002000000001@3402000000>;tag=562055772
To: <sip:34020000001320000001@3402000000>
Call-ID: 589055668
CSeq: 183 INVITE
Content-Type: APPLICATION/SDP
Contact: <sip:[email protected]:15060>
Max-Forwards: 70
User-Agent: LiveGB28181
Subject: 34020000001320000001:0200000001,34020000002000000001:0
Content-Length: 222

v=0
o=34020000001320000001 0 0 IN IP4 192.168.0.105
s=Play
c=IN IP4 192.168.0.105
t=0 0
m=video 30076 RTP/AVP 96 97 98
a=recvonly
a=rtpmap:96 PS/90000
a=rtpmap:97 MPEG4/90000
a=rtpmap:98 H264/90000
y=0200000001

判断媒体流走TCP还是UDP,主要看这里:

m=video 30076 RTP/AVP 96 97 98

传输方式采用“RTP/AVP”标识传输层协议为 RTP over UDP,采用“TCP/RTP/AVP”标识传输层协议为 RTP over TCP,需要注意的是,我们实际对接的时候,部分厂商SDP非常随意,有的甚至直接标记个tcp,这让我们对接的时候,很困惑。

技术实现:

GB28181基于TCP协议的视音频媒体传输探究及实现_GB28181 TCP

本文以大牛直播SDK的Android平台GB28181设备接入端为例,启动GB28181,完成注册、catalog等交互后,Invite上来后,设置媒体流通过TCP还是UDP发送出去:

@Override
public void ntsOnInvitePlay(String deviceId, SessionDescription session_des) {
handler_.postDelayed(new Runnable() {
@Override
public void run() {
// 先振铃响应下
gb28181_agent_.respondPlayInvite(180, device_id_);

MediaSessionDescription video_des = null;
SDPRtpMapAttribute ps_rtpmap_attr = null;

// 28181 视频使用PS打包
Vector<MediaSessionDescription> video_des_list = session_des_.getVideoPSDescriptions();
if (video_des_list != null && !video_des_list.isEmpty()) {
for(MediaSessionDescription m : video_des_list) {
if (m != null && m.isValidAddressType() && m.isHasAddress() ) {
video_des = m;
ps_rtpmap_attr = video_des.getPSRtpMapAttribute();
break;
}
}
}

if (null == video_des) {
gb28181_agent_.respondPlayInvite(488, device_id_);
Log.i(TAG, "ntsOnInvitePlay get video description is null, response 488, device_id:" + device_id_);
return;
}

if (null == ps_rtpmap_attr) {
gb28181_agent_.respondPlayInvite(488, device_id_);
Log.i(TAG, "ntsOnInvitePlay get ps rtp map attribute is null, response 488, device_id:" + device_id_);
return;
}

Log.i(TAG,"ntsOnInvitePlay, device_id:" +device_id_+", is_tcp:" + video_des.isRTPOverTCP()
+ " rtp_port:" + video_des.getPort() + " ssrc:" + video_des.getSSRC()
+ " address_type:" + video_des.getAddressType() + " address:" + video_des.getAddress());

long rtp_sender_handle = libPublisher.CreateRTPSender(0);
if ( rtp_sender_handle == 0 ) {
gb28181_agent_.respondPlayInvite(488, device_id_);
Log.i(TAG, "ntsOnInvitePlay CreateRTPSender failed, response 488, device_id:" + device_id_);
return;
}

gb28181_rtp_payload_type_ = ps_rtpmap_attr.getPayloadType();
gb28181_rtp_encoding_name_ = ps_rtpmap_attr.getEncodingName();

libPublisher.SetRTPSenderTransportProtocol(rtp_sender_handle, video_des.isRTPOverUDP()?0:1);
libPublisher.SetRTPSenderIPAddressType(rtp_sender_handle, video_des.isIPv4()?0:1);
libPublisher.SetRTPSenderLocalPort(rtp_sender_handle, 0);
libPublisher.SetRTPSenderSSRC(rtp_sender_handle, video_des.getSSRC());
libPublisher.SetRTPSenderSocketSendBuffer(rtp_sender_handle, 2*1024*1024); // 设置到2M
libPublisher.SetRTPSenderClockRate(rtp_sender_handle, ps_rtpmap_attr.getClockRate());
libPublisher.SetRTPSenderDestination(rtp_sender_handle, video_des.getAddress(), video_des.getPort());

if ( libPublisher.InitRTPSender(rtp_sender_handle) != 0 ) {
gb28181_agent_.respondPlayInvite(488, device_id_);
libPublisher.DestoryRTPSender(rtp_sender_handle);
return;
}

int local_port = libPublisher.GetRTPSenderLocalPort(rtp_sender_handle);
if (local_port == 0) {
gb28181_agent_.respondPlayInvite(488, device_id_);
libPublisher.DestoryRTPSender(rtp_sender_handle);
return;
}

Log.i(TAG,"get local_port:" + local_port);

String local_ip_addr = IPAddrUtils.getIpAddress(context_);

MediaSessionDescription local_video_des = new MediaSessionDescription(video_des.getType());

local_video_des.addFormat(String.valueOf(ps_rtpmap_attr.getPayloadType()));
local_video_des.addRtpMapAttribute(ps_rtpmap_attr);

local_video_des.setAddressType(video_des.getAddressType());
local_video_des.setAddress(local_ip_addr);
local_video_des.setPort(local_port);

local_video_des.setTransportProtocol(video_des.getTransportProtocol());
local_video_des.setSSRC(video_des.getSSRC());

if (!gb28181_agent_.respondPlayInviteOK(device_id_,local_video_des) ) {
libPublisher.DestoryRTPSender(rtp_sender_handle);
Log.e(TAG, "ntsOnInvitePlay call respondPlayInviteOK failed.");
return;
}

gb28181_rtp_sender_handle_ = rtp_sender_handle;
}

private String device_id_;
private SessionDescription session_des_;

public Runnable set(String device_id, SessionDescription session_des) {
this.device_id_ = device_id;
this.session_des_ = session_des;
return this;
}
}.set(deviceId, session_des),0);
}

接口设计如下:

  /**
*设置 RTP Sender传输协议
*
* @param rtp_sender_handle, CreateRTPSender返回值
* @param transport_protocol, 0:UDP, 1:TCP, 默认是UDP
*
* @return {0} if successful
*/
public native int SetRTPSenderTransportProtocol(long rtp_sender_handle, int transport_protocol);

以上是GB28181基于TCP协议的视音频媒体传输探究及实现,感兴趣的开发者,可以查看相关协议规范,根据需求实现自己的业务逻辑即可。

标签:sender,GB28181,des,TCP,视音频,video,rtp,device,id
From: https://blog.51cto.com/daniusdk/5807896

相关文章

  • TCP/IP分层
    TCP/IP分层TCP/IP网络分层模型TCP/IP协议共有4层,每一层需要下一层的支撑,同时也支撑着上层,顺序就是从下向上链接层:在以太网、Wifi上发送原始数据,工作在网卡的层次,使用M......
  • 如何kill一条TCP连接?
    原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处。简介如果你的程序写得有毛病,打开了很多TCP连接,但一直没有关闭,即常见的连接泄露场景,你可能想要在排查问题的......
  • 工业网关BL110实现西门子S7-1200 PLC接入Modbus TCP Server云平台
    LAN接口的配置COM口采集西门子S7-1200PLC的配置工业智能网关BL110一共有一个LAN接口,一个WAN接口,可以通过LAN接口采集数据,通过WAN接口接入局域网,设置过程不一样,WAN接口......
  • C# tcp 多线程服务端和客户端
    主要是服务端usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Net;usingSystem.Net.Sockets;usingSystem.Text;usingSystem.Threading;n......
  • 解决轻量级服务器 HttpProcessor TcpClient 跨域问题
    添加:processor.httpHeaders.Add("Access-Control-Allow-Origin:*");//(正确)processor.httpHeaders.Add("Access-Control-Allow-Method......
  • TCP-三次握手
    1、三次握手的概念TCP三次握手是浏览器和服务器建立连接的方式,目的是为了使二者能够建立连接,便于后续的数据交互传输。第一次握手:浏览器向服务器发起建立连接的请求第二次......
  • TCP 端来链接为什么一定要等2MSL
    我们知道tcp传输中需要三次握手和四次挥手2MSL发生在挥手阶段原因保证可靠的TCP通讯安全的断开保证旧的的消息在网络消失安全断开我们知道一个IP包最大的声明......
  • TCP与UDP的区别
    引言网络协议是每个前端工程师都必须要掌握的知识,TCP/IP中有两个具有代表性的传输层协议,分别是TCP和UDP,本文将介绍下这两者以及它们之间的区别。一、TCP/IP网络模型......
  • TCP链接详解
    一.TCP协议传输控制协议(TCP,TransmissionControlProtocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。基于流的方式;面向连接;(在通信之前要通过......
  • 重新思考TCP三次握手,两次握手的缺点
    两次握手也能保证有序可达两次握手在CS架构中是能保证有序、可达的,因为客户端在收到服务器的确认后,双方知道客户端下一次消息的正确序号,客户端到服务器的单向连接就......