音频和视频流最佳选择?SRT协议解析及报文识别

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们所知道SRT 是由 Haivision 和 Wowza 开发的开源视频流协议。很多人会认为在不久的将来,它被是 RTMP 的替代品。因为RTMP协议安全性稍低,延迟相对较高 ,而相对于SRT协议支持高质量、稳定性、亚秒级延迟、强大的编解码器支持。SRT被许多行业专家认为是视频流的新协议。SRT究竟是什么?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"什么是 SRT?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"安全可靠传输 (SRT) 是一种开源数据传输协议。SRT 使用用户数据报协议 (UDP),旨在通过公共互联网发送高质量视频,因此该协议是音频和视频流的最佳选择。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在许多主要的开源技术Wireshare、FFMpeg中,应用了SRT安全可靠传输协议。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SRT的应用在哪些领域?","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SRT协议主要的应用在直播、多流、视频编码、网关等领域。在技术方面,它提供类似于传输控制协议 (TCP) 的可靠传输。 然而,使用 UDP 协议作为底层传输层。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ae/ae5f6b53a738620e6db8ff852dacfd34.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SRT 还支持低延迟(默认为 120 毫秒)的数据包恢复和使用高级加密标准 (AES) 的加密。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"简而言之,通过 SRT,端到端流安全、视频弹性和基于网络条件的实时动态端点调整成为可能。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"高质量视频传输","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SRT 可以更轻松地通过互联网协议 (IP) 以低端到端延迟进行流式传输。截至目前,低延迟流媒体的协议偏好很少。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这是因为通过公共互联网流式传输可能会造成数据包丢失和抖动等障碍。 SRT 提供解决此问题的方法。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此外,该协议还包括防止数据包丢失、抖动和带宽波动的保护。这意味着如果网络状况不稳定,您的流可能会停止。但它几乎可以立即从这种丢包中恢复,您的观众在观看时几乎不会注意到任何问题。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其他有益于直播的功能包括:","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1、 基于时间戳的数据包传输,通过源时间传输实现更好的延迟控制\n2、 控制发送者的速度\n3、 防止丢包未及时恢复造成丢包\n4、数据包重传的定期 NAK 报告","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SRT如何更好的保护你的视频流","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果您使用 SRT 协议流式传输视频,您肯定会受益于它的优势。 该协议保护您的视频流,并确保所有数据在发送时都经过加密。 它还消除了特殊互联网连接的负担,因为该协议可保证您交付的视频内容的质量。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SRT 通过提供可确保安全传输即使是最高级别的产品的加密技术而闻名。 SRT 可以启用端到端 AES 128/256 位加密算法,这是任何需要保护的内容的理想选择。 即使在不可靠的 WiFi 或蜂窝连接导致带宽波动期间,SRT 也能防止视频抖动和数据包丢失,可保护您的视频内容免遭分发。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SRT数据包","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面我们要对SRT协议要做进一步分析。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1f/1fedc949c461e36be135624145c46825.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"根据上图的红色框起来的方格F:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"F=0 ;Data Packet","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Data (content to transmit)\nFiltering packet (FEC)","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"F=1;Control Packet","attrs":{}}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"HANDSHAKE\nKEEPALIVE\nACK\nNAK (Loss Report)\nSHUTDOWN\nACKACK","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SRT流媒体传输协议握手过程","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"caller作为连接的发起者,知道对应设置Listener模式设备的公网IP地址及其监听的UDP端口。而Listener监听发起的SRT请求,需要知道使用哪个UDP端口,并在这个端口一直监听。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Caller-Listener Handshake","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/af/afc23f99304d898aafca9b9249381506.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"caller发起建立一个点对点传输的SRT连接,Listener监听发起SRT会话的请求。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Rendezvous Handshake","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Rendezvous两端共同协商建立连接,基本不使用此种连接。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6e/6e08966fe48050c04045d325a734b0d9.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SRT在快速连接方面有明显优势,两次握手成功即可建连;简单了明白了握手过程,接来就是SRT协议解析了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"SRT协议解析及报文识别","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面我们对SRT协议进行解析。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"/* 实际解析数据包的代码 \n *\n */\n static void dissect_srt_control_packet(u_char *data_info,int PayloadLen)\n {\n     int offset = 0;\n\n     offset += 4;\n\n     if (data_info[0] == 0x80 && data_info[1] == 0x02)/*UMSG_ACK*/\n     {\n\n        int ack_number = ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"ACK Number: %d\\n\",ack_number);\n\n        offset += 4; /*Time Stamp*/\n\n        int time_stamp = ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"Time Stamp: %d\\n\",time_stamp);\n\n        offset += 4; /*Destination Socket ID*/\n\n        int dst_sock_id = ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"Destination Socket ID: %d\\n\",dst_sock_id);\n\n        offset += 4; /*ACKD_RCVLASTACK*/\n\n        int ack_rcv = ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"ACKD_RCVLASTACK: %d \\n\",ack_rcv);\n\n        offset += 4; /*ACKD_RTT*/\n\n        int ack_rtt = ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"ACKD_RTT: %d us \\n\",ack_rtt);\n\n        offset += 4; /*ACKD_RTTVAR*/\n\n        int ack_rttvar = ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"ACKD_RTTVAR: %d us \\n\",ack_rttvar);\n\n        offset += 4; /*ACKD_BUFFERLEFT*/\n\n        int ack_buffer= ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"ACKD_BUFFERLEFT: %d pkts \\n\",ack_buffer);\n\n        offset += 4; /*ACKD_RCVSPEED*/\n\n        int ack_rcvspeed= ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"ACKD_RCVSPEED: %d pkts/s \\n\",ack_rcvspeed);\n\n\n        offset += 4; /*ACKD_BANDWIDTH*/\n\n        int ack_banwidth= ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"ACKD_BANDWIDTH: %d pkts/s \\n\",ack_banwidth);\n\n        offset += 4; /*ACKD_RCVRATE*/\n\n        int ack_rcvate= ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"ACKD_RCVRATE: %d pkts/s \\n\",ack_rcvate);\n\n     }\n     else if (data_info[0] == 0x80 && data_info[1] == 0x00)/*UMSG_HANDSHAKE*/\n     {\n        char ipbuf[IP_BUFFER_SIZE];\n        const int final_length = PayloadLen;\n        int baselen = 64;\n        offset += 12;\n        const int version = ntohl(*(uint32_t*)(data_info + offset));\n        /*包含握手版本(当前为4或5) */\n        printf(\"Handshake version:%d\\n\",version);\n\n        offset += 2; /*Encryption Field*/\n\n        offset += 2; /*Extended Field*/\n\n        offset += 4; /*Initial Sequence Number*/\n\n        int srt_handshake_isn= ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"Initial Sequence Number: %d\\n\",srt_handshake_isn);\n\n        offset += 4; /*MTU*/\n\n        int srt_handshake_mtu= ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"MTU: %d \\n\",srt_handshake_mtu);\n\n        offset += 4; /*Flow Window*/\n\n        int srt_handshake_flow_window= ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"Flow Window: %d\\n\",srt_handshake_flow_window);\n\n        offset += 4; /*Hanshake Type*/\n\n        int srt_handshake_reqtype= ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"Hanshake Type: %d\\n\",srt_handshake_reqtype);\n\n        offset += 4; /*Socket ID*/\n\n        int srt_handshake_id= ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"Socket ID: %d\\n\",srt_handshake_id);\n\n        offset += 4; /*SYN Cookie*/\n\n        int srt_handshake_cookie= ntohl(*(uint32_t*)(data_info + offset));\n        printf(\"SYN Cookie: %d\\n\",srt_handshake_cookie);\n\n        offset += 4; /*Peer IP Address*/\n\n        srt_format_ip_address(ipbuf, sizeof ipbuf,strdup((const char*)(data_info+offset)));\n\n        printf(\"Peer IP Address: %s\\n\",ipbuf);\n\n        if (final_length > baselen)\n        {\n\n            /* 提取SRT握手扩展块\n             并相应地增加baselen。 \n            */\n            int begin = baselen;\n\n            for (;;)\n            {\n                const uint16_t blockid  = ntohs(*(uint16_t*)(data_info + begin));\n\n                begin += 2;\n                const uint16_t blocklen = ntohs(*(uint16_t*)(data_info + begin));\n\n\n                // Shift to the payload\n                begin += 2;\n\n                switch (blockid)\n                {\n                    case SRT_CMD_HSREQ:\n                    case SRT_CMD_HSRSP:\n                        if (blocklen == 3)\n                        {\n                            //uint32_t version = 0;\n                            const int vmajor = (data_info[begin+1]) & 0xff;\n                            const int vminor = (data_info[begin+2]) & 0xff;\n                            const int vpatch = data_info[begin+3] & 0xff;\n                            printf(\"SRT HS Extension type:%d \\n\",blockid);\n                            printf(\"SRT HS Extension size:%d \\n\",blocklen);\n                            printf(\"SRT Version(%d.%d.%d)\\n\", vmajor, vminor, vpatch);\n\n                        }\n                        else\n                        {\n\n                        }\n                        break;\n\n                    case SRT_CMD_KMREQ:\n                    case SRT_CMD_KMRSP:\n                        // Rely on the extracted blocklen\n                        //srt_format_kmx(tree, tvb, begin, blocklen*4);\n                        break;\n\n                    case SRT_CMD_SID:\n                        break;\n\n                    case SRT_CMD_CONJESTCTRL:\n                        break;\n\n                    default:\n                        printf( \"Ext Type value is %u\\n\",blockid);\n                        break;\n                }\n\n                /* Move the index pointer past the block and repeat. */\n                begin += blocklen * 4;\n\n                /* OK, once one block is done, interrupt the loop. */\n                if (begin >= final_length)\n                    break;\n            }\n            baselen = begin;\n        }\n\n\n     }\n     else\n     {\n\n     }\n\n\n }\n\nstatic void dissect_srt(u_char *data_info,int PayloadLen)\n{\n    /* Other misc. local variables. */\n    bool is_control = 0;\n\n    /*必须至少有24个捕获的字节才能进行检查 */\n    if (PayloadLen 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章