音頻和視頻流最佳選擇?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 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章