关于音视频:音频和视频流最佳选择SRT-协议解析及报文识别

72次阅读

共计 6308 个字符,预计需要花费 16 分钟才能阅读完成。

咱们所晓得 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 协定流式传输视频,您必定会受害于它的劣势。该协定爱护您的视频流,并确保所有数据在发送时都通过加密。它还打消了非凡互联网连贯的累赘,因为该协定可保障您交付的视频内容的品质。

正文完
 0