音频和视频流最佳选择?SRT 协议解析及报文识别
我们所知道 SRT 是由 Haivision 和 Wowza 开发的开源视频流协议。很多人会认为在不久的将来,它被是 RTMP 的替代品。因为 RTMP 协议安全性稍低,延迟相对较高 ,而相对于 SRT 协议支持高质量、稳定性、亚秒级延迟、强大的编解码器支持。SRT 被许多行业专家认为是视频流的新协议。SRT 究竟是什么?
什么是 SRT?
安全可靠传输 (SRT) 是一种开源数据传输协议。SRT 使用用户数据报协议 (UDP),旨在通过公共互联网发送高质量视频,因此该协议是音频和视频流的最佳选择。
在许多主要的开源技术 Wireshare、FFMpeg 中,应用了 SRT 安全可靠传输协议。
SRT 的应用在哪些领域?
SRT 协议主要的应用在直播、多流、视频编码、网关等领域。在技术方面,它提供类似于传输控制协议 (TCP) 的可靠传输。 然而,使用 UDP 协议作为底层传输层。
SRT 还支持低延迟(默认为 120 毫秒)的数据包恢复和使用高级加密标准 (AES) 的加密。
简而言之,通过 SRT,端到端流安全、视频弹性和基于网络条件的实时动态端点调整成为可能。
高质量视频传输
SRT 可以更轻松地通过互联网协议 (IP) 以低端到端延迟进行流式传输。截至目前,低延迟流媒体的协议偏好很少。
这是因为通过公共互联网流式传输可能会造成数据包丢失和抖动等障碍。 SRT 提供解决此问题的方法。
此外,该协议还包括防止数据包丢失、抖动和带宽波动的保护。这意味着如果网络状况不稳定,您的流可能会停止。但它几乎可以立即从这种丢包中恢复,您的观众在观看时几乎不会注意到任何问题。
其他有益于直播的功能包括:
1、 基于时间戳的数据包传输,通过源时间传输实现更好的延迟控制
2、 控制发送者的速度
3、 防止丢包未及时恢复造成丢包
4、数据包重传的定期 NAK 报告
SRT 如何更好的保护你的视频流
如果您使用 SRT 协议流式传输视频,您肯定会受益于它的优势。 该协议保护您的视频流,并确保所有数据在发送时都经过加密。 它还消除了特殊互联网连接的负担,因为该协议可保证您交付的视频内容的质量。
SRT 通过提供可确保安全传输即使是最高级别的产品的加密技术而闻名。 SRT 可以启用端到端 AES 128/256 位加密算法,这是任何需要保护的内容的理想选择。 即使在不可靠的 WiFi 或蜂窝连接导致带宽波动期间,SRT 也能防止视频抖动和数据包丢失,可保护您的视频内容免遭分发。
SRT 数据包
下面我们要对 SRT 协议要做进一步分析。
根据上图的红色框起来的方格 F:
F=0 ;Data Packet
Data (content to transmit)
Filtering packet (FEC)
F=1;Control Packet
HANDSHAKE
KEEPALIVE
ACK
NAK (Loss Report)
SHUTDOWN
ACKACK
SRT 流媒体传输协议握手过程
caller 作为连接的发起者,知道对应设置 Listener 模式设备的公网 IP 地址及其监听的 UDP 端口。而 Listener 监听发起的 SRT 请求,需要知道使用哪个 UDP 端口,并在这个端口一直监听。
Caller-Listener Handshake
caller 发起建立一个点对点传输的 SRT 连接,Listener 监听发起 SRT 会话的请求。
Rendezvous Handshake
Rendezvous 两端共同协商建立连接,基本不使用此种连接。
SRT 在快速连接方面有明显优势,两次握手成功即可建连;简单了明白了握手过程,接来就是 SRT 协议解析了。
SRT 协议解析及报文识别
下面我们对 SRT 协议进行解析。
/* 实际解析数据包的代码
*
*/
static void dissect_srt_control_packet(u_char *data_info,int PayloadLen)
{
int offset = 0; offset += 4; if (data_info[0] == 0x80 && data_info[1] == 0x02)/*UMSG_ACK*/
{ int ack_number = ntohl(*(uint32_t*)(data_info + offset));
printf("ACK Number: %d\n",ack_number); offset += 4; /*Time Stamp*/ int time_stamp = ntohl(*(uint32_t*)(data_info + offset));
printf("Time Stamp: %d\n",time_stamp); offset += 4; /*Destination Socket ID*/ int dst_sock_id = ntohl(*(uint32_t*)(data_info + offset));
printf("Destination Socket ID: %d\n",dst_sock_id); offset += 4; /*ACKD_RCVLASTACK*/ int ack_rcv = ntohl(*(uint32_t*)(data_info + offset));
printf("ACKD_RCVLASTACK: %d \n",ack_rcv); offset += 4; /*ACKD_RTT*/ int ack_rtt = ntohl(*(uint32_t*)(data_info + offset));
printf("ACKD_RTT: %d us \n",ack_rtt); offset += 4; /*ACKD_RTTVAR*/ int ack_rttvar = ntohl(*(uint32_t*)(data_info + offset));
printf("ACKD_RTTVAR: %d us \n",ack_rttvar); offset += 4; /*ACKD_BUFFERLEFT*/ int ack_buffer= ntohl(*(uint32_t*)(data_info + offset));
printf("ACKD_BUFFERLEFT: %d pkts \n",ack_buffer); offset += 4; /*ACKD_RCVSPEED*/ int ack_rcvspeed= ntohl(*(uint32_t*)(data_info + offset));
printf("ACKD_RCVSPEED: %d pkts/s \n",ack_rcvspeed); offset += 4; /*ACKD_BANDWIDTH*/ int ack_banwidth= ntohl(*(uint32_t*)(data_info + offset));
printf("ACKD_BANDWIDTH: %d pkts/s \n",ack_banwidth); offset += 4; /*ACKD_RCVRATE*/ int ack_rcvate= ntohl(*(uint32_t*)(data_info + offset));
printf("ACKD_RCVRATE: %d pkts/s \n",ack_rcvate); }
else if (data_info[0] == 0x80 && data_info[1] == 0x00)/*UMSG_HANDSHAKE*/
{
char ipbuf[IP_BUFFER_SIZE];
const int final_length = PayloadLen;
int baselen = 64;
offset += 12;
const int version = ntohl(*(uint32_t*)(data_info + offset));
/*包含握手版本(当前为4或5) */
printf("Handshake version:%d\n",version); offset += 2; /*Encryption Field*/ offset += 2; /*Extended Field*/ offset += 4; /*Initial Sequence Number*/ int srt_handshake_isn= ntohl(*(uint32_t*)(data_info + offset));
printf("Initial Sequence Number: %d\n",srt_handshake_isn); offset += 4; /*MTU*/ int srt_handshake_mtu= ntohl(*(uint32_t*)(data_info + offset));
printf("MTU: %d \n",srt_handshake_mtu); offset += 4; /*Flow Window*/ int srt_handshake_flow_window= ntohl(*(uint32_t*)(data_info + offset));
printf("Flow Window: %d\n",srt_handshake_flow_window); offset += 4; /*Hanshake Type*/ int srt_handshake_reqtype= ntohl(*(uint32_t*)(data_info + offset));
printf("Hanshake Type: %d\n",srt_handshake_reqtype); offset += 4; /*Socket ID*/ int srt_handshake_id= ntohl(*(uint32_t*)(data_info + offset));
printf("Socket ID: %d\n",srt_handshake_id); offset += 4; /*SYN Cookie*/ int srt_handshake_cookie= ntohl(*(uint32_t*)(data_info + offset));
printf("SYN Cookie: %d\n",srt_handshake_cookie); offset += 4; /*Peer IP Address*/ srt_format_ip_address(ipbuf, sizeof ipbuf,strdup((const char*)(data_info+offset))); printf("Peer IP Address: %s\n",ipbuf); if (final_length > baselen)
{ /* 提取SRT握手扩展块
并相应地增加baselen。
*/
int begin = baselen; for (;;)
{
const uint16_t blockid = ntohs(*(uint16_t*)(data_info + begin)); begin += 2;
const uint16_t blocklen = ntohs(*(uint16_t*)(data_info + begin)); // Shift to the payload
begin += 2; switch (blockid)
{
case SRT_CMD_HSREQ:
case SRT_CMD_HSRSP:
if (blocklen == 3)
{
//uint32_t version = 0;
const int vmajor = (data_info[begin+1]) & 0xff;
const int vminor = (data_info[begin+2]) & 0xff;
const int vpatch = data_info[begin+3] & 0xff;
printf("SRT HS Extension type:%d \n",blockid);
printf("SRT HS Extension size:%d \n",blocklen);
printf("SRT Version(%d.%d.%d)\n", vmajor, vminor, vpatch); }
else
{ }
break; case SRT_CMD_KMREQ:
case SRT_CMD_KMRSP:
// Rely on the extracted blocklen
//srt_format_kmx(tree, tvb, begin, blocklen*4);
break; case SRT_CMD_SID:
break; case SRT_CMD_CONJESTCTRL:
break; default:
printf( "Ext Type value is %u\n",blockid);
break;
} /* Move the index pointer past the block and repeat. */
begin += blocklen * 4; /* OK, once one block is done, interrupt the loop. */
if (begin >= final_length)
break;
}
baselen = begin;
} }
else
{ } } static void dissect_srt(u_char *data_info,int PayloadLen)
{
/* Other misc. local variables. */
bool is_control = 0; /*必须至少有24个捕获的字节才能进行检查 */
if (PayloadLen < 24)
return ;
printf("SrtHdr 0x%.2X,0x%.2X,0x%.2X,0x%.2X\n",data_info[0],data_info[1],data_info[2],data_info[3]); if ((data_info[0] == 0x80 && data_info[1] == 0x00 && data_info[2] == 0x00 && data_info[3] == 0x00)
|| (data_info[0] == 0x80 && data_info[1] == 0x02 && data_info[2] == 0x00 && data_info[3] == 0x00)/*UMSG_ACK*/
|| (data_info[0] == 0x80 && data_info[1] == 0x06 && data_info[2] == 0x00 && data_info[3] == 0x00)/*UMSG_ACKACK*/
)
{
is_control = true;
} if (is_control)
{ dissect_srt_control_packet(data_info,PayloadLen);
}
else
{
/*srt data type*/
}
}
编译运行:
这里把 srt 协议识别出来,并且解析各个字段。
对比 RTMP 和 SRT 协议特点
RTMP 是实时消息协议,它保持持久、稳定的连接并允许低延迟通信。RTMP 协议的另一个缺点是可能由于带宽低而中断,直到您的流可能根本无法启动。添加到缺点列表中,由于交付视频的安全性低,一些严密的防火墙可能不允许 RTMP 连接。虽然,我们不得不说这种情况很少发生。
RTMP 协议目前使用 H.264 视频编解码器和 AAC 音频编解码器,它们相当陈旧,不能提供最佳质量。
最后总结一下 RTMP 优点及缺点:
优点:多播支持、低缓冲、宽平台支持。
缺点:旧的编解码器,安全性稍低,延迟相对较高。
SRT 是安全可靠传输协议,SRT 是由 Haivision 和 Wowza 开发的开源视频流协议。在不久的将来,它被广泛认为是 RTMP 的替代品。共享相同的优势,SRT 正在迈出下一步,使亚秒级延迟的稳定直播的梦想成为现实。它允许您通过次优网络直播您的内容。然而,一个很大的缺点是播放选项不可用。
SRT 可以保护您的实时视频免受抖动、带宽波动和数据包丢失的影响。此外,在亚秒级延迟方面,SRT 与 FTL 和 WebRTC 类似,可以实现近乎实时的通信。
此外,还声明该协议与编解码器无关,这意味着它支持任何现代视频和音频编解码器。
说了这么多,SRT 优点及缺点分别是:
优点:高质量、稳定性、亚秒级延迟、强大的编解码器支持。
缺点:平台支持弱,无法播放。
总结
如果您使用 SRT 协议流式传输视频,您肯定会受益于它的优势。 该协议保护您的视频流,并确保所有数据在发送时都经过加密。 它还消除了特殊互联网连接的负担,因为该协议可保证您交付的视频内容的质量。
音频和视频流最佳选择?SRT 协议解析及报文识别的更多相关文章
- 视音频数据处理入门:UDP-RTP协议解析
===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB.YUV像素数据处理 视音频数据处理 ...
- AOSP中的HLS协议解析
[时间:2018-04] [状态:Open] [关键词:流媒体,stream,HLS, AOSP, 源码分析,HttpLiveSource, LiveSession,PlaylistFetcher] ...
- SOCKS5 协议解析
代理 根据 HTTP 1.1 的定义,proxy 是: An intermediary program which acts as both a server and a client for the ...
- 修改wireshark协议解析规则
不同的协议有不同的解码器,wireshark尝试为每个包尝试找到正确的解码器,特定的情况有可能会选择错误的解码器. 1.使用了其它协议的标准端口,被错误解码,使用udp的80端口发送数据被当作QUIC ...
- 视音频数据处理入门:FLV封装格式解析
===================================================== 视音频数据处理入门系列文章: 视音频数据处理入门:RGB.YUV像素数据处理 视音频数据处理 ...
- nodejs 实践:express 最佳实践(四) express-session 解析
nodejs 实践:express 最佳实践(四) express-session 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs ...
- 协议解析Bug分析
协议解析Bug分析 源自邮件协议RPC(远程过程调用)处理的Request请求数据包的bug. 一.Bug描写叙述 腾讯收购的Foxmailclient能够作为outlookclient ...
- ts 协议解析
pes : http://wenku.baidu.com/link?url=KjcA0qXqZ1bWVQTa8i1YOmygofldSQL7Pjj-zGRw1e_6_LFmVLo5DIWF0SNwVn ...
- [转]netty对http协议解析原理
本文主要介绍netty对http协议解析原理,着重讲解keep-alive,gzip,truncked等机制,详细描述了netty如何实现对http解析的高性能. 1 http协议 1.1 描述 标示 ...
- twemproxyRedis协议解析探索——剖析twemproxy代码正编
这篇文章会对twemproxyRedis协议解析代码部分进行一番简单的分析,同时给出twemproxy目前支持的所有Redis命令.在这篇文章开始前,我想大家去简单地理解一下有限状态机,当然不理解也是 ...
随机推荐
- WinExec("D:\\MY_tool\\APPLICATION\\calc.exe", SW_SHOW);
1 #pragma comment(lib,"shell32.lib")2 3 4 ShellExecute(NULL, NULL,"calc.exe", NU ...
- ADOConnection调用连接窗口
uses AdoConEd; 使用函数 1.EditConnectionString(ADOConnection); 2.PromptDataSource
- halcon学习
apply_metrology_model: 目标和背景灰度差别很小,但目标大概位置确定,需要确定目标位置的圆或者矩形: ball:圆形或矩形和图像其他部分相比为特殊图样
- Jmeter添加JSR223对Python的支持
通过下载:org.python : jython-standalone : 2.7.2 - Maven Central Repository Search jython-standalone-2.7. ...
- python批量导出、安装依赖库文件
导出: 在原环境中 pip freeze > fname.txt 安装: 在新环境中 pip install -r fname.txt 其中fname.txt 可以随意命名,其存储安装库文件列 ...
- linux 基础命令 apt
Linux apt 命令 apt(Advanced Packaging Tool)是一个在 Debian 和 Ubuntu 中的 Shell 前端软件包管理器. apt 命令提供了查找.安装.升级.删 ...
- http hook
class XMLHttp { request = function(param) {} ; response = function(param) {} ; } let httpCopy = new ...
- 一,创建一个electron应用程序
之前我们已经用html+css+js创建了一个项目,现在将这个项目用electron以应用程序呈现. 1,首先新建一个文件夹,从终端进入该文件夹: 2,在该文件夹下执行npm init,初始化该项目. ...
- Springboot中@Autowired为何获取了我们没有注入的Bean?
Springboot中@Autowired为何获取了我们没有注入的Bean? 在做仿牛客网项目的时候,有这样一段话: @Autowired private TemplateEngine templat ...
- 软件工程作业:个人项目—wc项目
软件工程作业:个人项目-WC项目 项目相关要求 wc.exe 是一个常见的工具,它能统计文本文件的字符数.单词数和行数.这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程 ...