技術解碼 | GB28181協議簡介及實踐

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":"br"}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GB28181協議是視頻監控領域的國家標準,本文將解析如何在FFmpeg中增加對GB28181協議的支持,使其可以與支持GB28181協議的設備進行通信與控制,實現設備的註冊、保活以及流媒體的傳輸。","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/80/8090e0ce74507ec227a89c9f681bf601.webp","alt":"圖片","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":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ed/ed30cc3eead2ab4676ea078175e9250d.webp","alt":"圖片","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":" GB28181協議指的是國家標準GB/T 28181—2016《公共安全視頻監控聯網系統信息傳輸、交換、控制技術要求》1,該標準規定了公共安全視頻監控聯網系統的互聯結構, 傳輸、交換、控制的基本要求和安全性要求, 以及控制、傳輸流程和協議接口等技術要求,是視頻監控領域的國家標準。GB28181協議信令層面使用的是SIP(Session Initiation Protocol)協議2,流媒體傳輸層面使用的是實時傳輸協議(Real-time Transport Protocol,RTP)協議3,因此可以理解爲GB28181是在國際通用標準的基礎之上進行了私有化定製以滿足視頻監控聯網系統互聯傳輸的標準化需求。本文旨在說明在FFmpeg中增加對GB28181協議的支持,使其可以與支持GB28181協議的設備進行通信與控制,實現設備的註冊、保活以及流媒體的傳輸。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/00/0072dfa2e7bf22cc883c77cc92d3578e.webp","alt":"圖片","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":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2.1 GB28181協議","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GB28181協議會話通道實際上使用的是SIP協議,並且在SIP協議的基礎之上做了些私有化處理。SIP是一個由IETF MMUSIC工作組開發的協議,作爲標準被提議用於創建,修改和終止包括視頻,語音,即時通信,在線遊戲和虛擬現實等多種多媒體元素在內的交互式用戶會話。SIP中一個比較重要的概念是用戶代理(User Agent),指的是一個SIP邏輯網絡端點,用於創建、發送、接收SIP消息並管理一個SIP會話。SIP用戶代理又可分爲用戶代理客戶端UAC(User Agent Client)和用戶代理服務端UAS(User Agent Server)。UAC創建併發送SIP請求,UAS接收處理SIP請求,發送SIP響應。SIP協議會與許多其它的協議協同工作,如SIP報文內容發送會話描述協議(Session Description Protocol,SDP)4,SDP協議描述了會話所使用流媒體細節,如:使用哪個IP端口,採用哪種編解碼器等等。SIP的一個典型用途是:SIP會話傳輸一些簡單的經過報文的實時傳輸協議流,RTP本身才是語音或視頻的載體。在GB28181協議中,聯網系統在進行視音頻傳輸及控制時應建立兩個傳輸通道: 會話通道和媒體流通道。會話通道用於在設備之間建立會話並傳輸系統控制命令; 媒體流通道用於傳輸視音頻數據, 經過壓縮編碼的視音頻流採用流媒體協議RTP/RTCP傳輸。GB28181協議中具體通信協議結構圖如下圖1所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/2d/2d9e8ebecd0ae769ddc8dc47c09ed4a4.png","alt":"圖片","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":"圖1 通信協議結構圖","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":"會話通道中,註冊、實時視音頻點播、歷史視音頻的回放等應用的會話控制採用SIP協議IETF RFC3261中規定的REGISTER、INVITE等請求和響應方法實現, 歷史視音頻回放控制採用SIP擴展協議IETF RFC29765規定的INFO方法實現,前端設備控制、信息查詢、報警事件通知和分發等應用的會話控制採用SIP擴展協議IETF RFC34287規定的MESSAGE方法實現。下面詳細介紹下注冊、保活和實時視音頻點播的SIP消息結構。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2.1.1 註冊","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"註冊指的是設備或系統進入聯網系統時向SIP服務器(SIP UAS)進行註冊登記的工作模式,在本文中FFmpeg即爲一個SIP服務器,設備向FFmpeg發送註冊請求,FFmpeg在接收到設備的註冊請求後返回相應的回覆消息,則完成設備註冊流程。GB28181協議中基於數字摘要的挑戰應答式安全技術進行註冊流程如下圖2所示: ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/49/49d1f4ccfb19d8975fdca2c68048907d.webp","alt":"圖片","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":"圖2 基本註冊流程示意圖","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},"content":[{"type":"text","text":"(a) SIP代理向SIP服務器發送Register請求;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(b) SIP服務器向SIP代理髮送響應401,並在響應的消息頭WWW_Authenticate字段中給出適合SIP代理的認證體制和參數;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(c) SIP代理重新向SIP服務器發送REGISTER請求, 在請求的Authorization字段給出信任書,包含認證信息;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(d) SIP服務器對請求進行驗證,如果檢查出SIP代理身份合法,向SIP代理髮送成功響應200OK,如果身份不合法則發送拒絕服務應答。","attrs":{}}]},{"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},"content":[{"type":"text","text":"1 REGISTER sip:34020000002000000001@3402000000 SIP/2.0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2 Via: SIP/2.0/UDP 192.168.137.11:5060;rport;branch=z9hG4bK1371463273","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3 From: sip:34020000001320000003@3402000000;tag=2043466181","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4 To: sip:34020000001320000003@3402000000","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5 Call-ID: 1011047669","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6 CSeq: 1 REGISTER","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7 Contact: sip:[email protected]:5060","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"8 Max-Forwards: 70","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"9 User-Agent: IP Camera","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"10 Expires: 3600","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"11 Content-Length: 0","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第1行表明這條SIP消息的方法(Method)是REGISTER,34020000002000000001是SIP服務器的國標ID,國標ID指的是由中心編碼(8位) 、行業編碼(2位) 、類型編碼(3位)和序號(7位)四個碼段共20位十進制數字字符構成,具體國標ID的編碼方法可以參考GB/T 28181—2016中的附錄D。3402000000指的是SIP服務器的域國標ID,SIP/2.0指的是SIP協議版本。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第2行爲Via頭,Via頭中包含了發送請求方的相關信息,後續需要使用這些信息進行回覆。SIP/2.0/UDP表示使用的是2.0版本的SIP協議,使用的傳輸協議是UDP,也可以使用TCP協議。192.168.137.11:5060爲請求發送方的IP地址和端口號。Via頭中必須包含branch參數,具體值是一個在整個SIP通信過程中不重複的數值。branch是一個事務ID(Transaction ID),用於區分同一個UA所發起的不同Transaction,它不會對未來的request或者是response造成影響,對於遵循IETF RFC3261規範的實現,這個branch參數的值必須用”z9hG4bK”打頭. 其它部分是對To, From, Call-ID頭域和Request-URI按一定的算法加密後得到。rport字段表示使用rport機制路由響應,即發送的響應時,按照rport中的端口發送SIP響應,也就是說IP和端口均完全遵照從哪裏來的,發回哪裏去的原則,如果沒有rport字段時,服務端的策略是IP使用UDP包中的地址,即從哪裏來回哪裏去,但是端口使用的是via中的端口,詳情見IETF RFC35818。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第3行爲From頭,From頭中包含了請求發送方的邏輯標識,在GB28181協議中是發送請求的設備國標ID和域國標ID信息。tag參數是爲了身份認證的,值爲隨機數字字符。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第4行爲To頭,To頭在SIP協議中是爲了標明請求接收方的邏輯標識的,在GB28181協議中填寫的是發送請求的設備國標ID和域國標ID信息。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第5行爲Call-ID頭,Call-ID頭是全局唯一的,在同一個session中保持一致,在不同session中不同。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第6行爲CSeq頭,CSeq頭又叫Command Seqence(命令隊列),用於標識命令順序,值爲序號+Method,序號部分爲無符號整數,最大值爲2^31。序號起始值是隨機的,後續在同一個session中依次遞增,比如發1 REGISTER沒返回--->再發2 REGISTER--->沒返回--->再發3 REGISTER--->這時返回了2 REGISTER就知道是第2個請求得到了響應。對於ACK和CANCLE中的CSeq與INVITE中的Cseq保持一致。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第7行爲Contact頭,Contact頭包含源的URI信息,用來給響應消息直接和源建立連接用。在GB28181協議中爲SIP設備編碼@源IP地址端口。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第8行爲Max-Forwards頭,Max-Forwards頭用於設置包最大中轉次數,默認是70。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第9行爲User-Agent頭,User-Agent頭用於設置關於UA的信息,用戶可以自定義。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第10行爲Expires頭,Expires頭表示超時時間。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"第11行爲Content-Length頭,Content-Length頭表示SDP消息的長度,因爲REGISTER消息不需要SDP,因此爲0。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}],"attrs":{}},{"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},"content":[{"type":"text","text":"1 SIP/2.0 200 OK","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2 Via: SIP/2.0/UDP 192.168.137.11:5060;rport;branch=z9hG4bK1371463273","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3 From: sip:34020000001320000003@3402000000","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4 To: sip:34020000001320000003@3402000000","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5 CSeq: 1 REGISTER","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6 Call-ID: 1011047669","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7 Contact: sip:[email protected]:5060","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"8 User-Agent: FFmpeg GB28181 v1.0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"9 Expires: 3600","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"10 Content-Length: 0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2.1.2 保活","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當UA發現工作異常時, 應立即向本SIP監控域的SIP服務器發送狀態信息; 無異常時,應定時向本SIP監控域的SIP服務器發送狀態信息。狀態信息報送採用IETF RFC3427中定義的方法MESSAGE實現。通過週期性的狀態信息報送,實現註冊服務器與源設備之間的狀態檢測即心跳機制。心跳發送方、接收方需統一配置“心跳間隔”參數,按照“心跳間隔”定時發送心跳消息,默認心跳間隔60s。心跳發送方、接收方需統一配置“心跳超時次數”參數,心跳消息連續超時達到“心跳超時次數”則認爲對方下線,默認心跳超時次數3次。心跳接收方在心跳發送方上線狀態下檢測到心跳消息連續超時達到商定次數則認爲心跳發送方離線; 心跳發送方在心跳接收方上線狀態下檢測到心跳消息響應消息連續超時達到商定次數則認爲心跳接收方離線。具體命令流程如圖3:            ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a6/a6e9bfc7b299c7b6f0bd0692cb3f1881.webp","alt":"圖片","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":"圖3 保活命令流程","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},"content":[{"type":"text","text":"(a) 源設備向SIP服務器發送設備狀態信息報送命令。設備狀態信息報送命令採用MESSAGE方法攜帶;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(b) SIP服務器收到命令後返回200 OK。","attrs":{}}]},{"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},"content":[{"type":"text","text":"1 MESSAGE sip:34020000002000000001@3402000000 SIP/2.0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2 Via: SIP/2.0/UDP 192.168.137.11:5060;rport;branch=z9hG4bK1066375804","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3 From: sip:34020000001320000003@3402000000;tag=1925919231","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4 To: sip:34020000002000000001@3402000000","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5 Call-ID: 1185236415","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6 CSeq: 20 MESSAGE","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7 Content-Type: Application/MANSCDP+xml","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"8 Max-Forwards: 70","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"9 User-Agent: IP Camera","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"10 Content-Length: 175","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"11 ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"12 ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"13 Keepalive","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"14 1","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"15 34020000001320000003","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"16 OK","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"17 ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"18 ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"19 ","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MESSAGE消息頭Content-type頭爲Content-type: Application/MANSCDP+xml。狀態信息報送命令採用MANSCDP(監控報警聯網系統控制描述協議,Monitoringand Alarming Network System Control Description Protocol)協議格式定義, 詳細描述見GB/T 28181—2016中A.2.5狀態信息報送。狀態信息報送命令應包括命令類型(CmdType)、設備/系統編碼(DeviceID)、是否正常工作(Status)等, 採用MESSAGE方法的消息體攜帶。Message消息的成功和錯誤應答均無消息體,Message回覆消息內容範例如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1 SIP/2.0 200 OK","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2 Via: SIP/2.0/UDP 192.168.137.11:5060;rport;branch=z9hG4bK1066375804","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3 From: sip:34020000001320000003@3402000000","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4 To: sip:34020000002000000001@3402000000","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5 CSeq: 20 MESSAGE","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6 Call-ID: 1185236415","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7 User-Agent: FFmpeg GB28181 v1.0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"8 Content-Length: 0","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"2.1.3 實時音視頻播放","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"實時視音頻點播採用SIP協議中的INVITE方法實現會話連接,採用RTP/RTCP協議(IETF RFC3550)實現媒體傳輸。需要注意的是,實時視音頻點播需要上述的媒體流保活機制。客戶端主動發起的實時視音頻點播流程見圖4:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c9/c9f0de1bcc6cb2fba6c5896e22adbd16.webp","alt":"圖片","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":"圖4 客戶端主動發起的實時視音頻點播流程圖","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中,信令1、8、9、10、11、12爲SIP服務器接收到客戶端的呼叫請求後通過B2BUA代理方式建立媒體流接收者與媒體服務器之間的媒體流信令過程,信令2-7爲SIP服務器通過三方呼叫控制建立媒體服務器與媒體流發送者之間的媒體流信令過程,信令13-16爲媒體流接收者斷開與媒體服務器之間的媒體流信令過程,信令17-20爲SIP服務器斷開媒體服務器與媒體流發送者之間的媒體流信令過程。","attrs":{}}]},{"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},"content":[{"type":"text","text":"(a) 媒體流接收者向SIP服務器發送INVITE消息, 消息頭域中攜帶Subject字段, 表明點播的視頻源ID、發送方媒體流序列號、媒體流接收者ID、接收端媒體流序列號等參數,SDP消息體中s字段爲“Play”代表實時點播。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(b) SIP服務器收到INVITE請求後,通過三方呼叫控制建立媒體服務器和媒體流發送者之間的媒體連接。向媒體服務器發送INVITE消息,此消息不攜帶SDP消息體。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(c) 媒體服務器收到SIP服務器的INVITE請求後,回覆200 OK響應,攜帶SDP消息體,消息體中描述了媒體服務器接收媒體流的IP、端口、媒體格式等內容。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(d) SIP服務器收到媒體服務器返回的200 OK響應後,向媒體流發送者發送INVITE請求,請求中攜帶消息3中媒體服務器回覆的200 OK響應消息體,s字段爲“Play”代表實時點播, 增加y字段描述SSRC值,f字段描述媒體參數。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(e) 媒體流發送者收到SIP服務器的INVITE請求後,回覆200 OK響應,攜帶SDP消息體,消息體中描述了媒體流發送者發送媒體流的IP、端口、媒體格式、SSRC字段等內容。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(f) SIP服務器收到媒體流發送者返回的200 OK響應後,向媒體服務器發送ACK請求,請求中攜帶消息5中媒體流發送者回復的200 OK響應消息體, 完成與媒體服務器的INVITE會話建立過程。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(g) SIP服務器收到媒體流發送者返回的200 OK響應後,向媒體流發送者發送ACK請求,請求中不攜帶消息體,完成與媒體流發送者的INVITE會話建立過程。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(h) 完成三方呼叫控制後,SIP服務器通過B2BUA代理方式建立媒體流接收者和媒體服務器之間的媒體連接。在消息1中增加SSRC值,轉發給媒體服務器。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(i) 媒體服務器收到INVITE請求,回覆200OK響應,攜帶SDP消息體,消息體中描述了媒體服務器發送媒體流的IP、端口、媒體格式、SSRC值等內容。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(j) SIP服務器將消息9轉發給媒體流接收者。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(k) 媒體流接收者收到200 OK響應後,回覆ACK消息,完成與SIP服務器的INVITE會話建立過程。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(l) SIP服務器將消息11轉發給媒體服務器,完成與媒體服務器的INVITE會話建立過程。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(m) 媒體流接收者向SIP服務器發送BYE消息,斷開消息1、10、11建立的同媒體流接收者的INVITE會話。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(n) SIP服務器收到BYE消息後回覆200 OK響應, 會話斷開。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(o) SIP服務器收到BYE消息後向媒體服務器發送BYE消息,斷開消息8、9、12建立的同媒體服務器的INVITE會話。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(p) 媒體服務器收到BYE消息後回覆200 OK響應, 會話斷開。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(q) SIP服務器向媒體服務器發送BYE消息,斷開消息2、3、6建立的同媒體服務器的INVITE會話。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(r) 媒體服務器收到BYE消息後回覆200 OK響應,會話斷開。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(s) SIP服務器向媒體流發送者發送BYE消息,斷開消息4、5、7建立的同媒體流發送者的INVITE會話。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(t) 媒體流發送者收到BYE消息後回覆200 OK響應, 會話斷開。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上述流程較爲複雜,原因是在實際視頻監控系統中,用戶不是直接跟前端監控設備交互,而是與監控管理平臺交互。媒體流接收者通常是用戶的客戶端,SIP服務器是單獨的服務器,媒體服務器通常是監控系統中的媒體網關,媒體流發送者爲前端攝像機。本文中FFmpeg既作爲SIP服務器,也作爲用戶客戶端向前端設備發送INVITE請求,因此可以簡化爲FFmpeg向前端設備發送INVITE請求後,前端設備向FFmpeg回覆200OK,然後FFmpeg再向前端設備回覆ACK,這樣前端設備即開始發送媒體流。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"INVITE消息範例如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1 INVITE sip:34020000001320000003@3402000000 SIP/2.0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2 Via: SIP/2.0/UDP 39.100.155.146:15063;rport;branch=z9hG4bK34208805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3 From: sip:[email protected]:15063;tag=512358805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4 To: sip:34020000001320000003@3402000000","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5 Call-ID: 200008805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6 CSeq: 20 INVITE","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7 Content-Type: Application/SDP","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"8 Contact: sip:34020000001320000003@3402000000","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"9 Max-Forwards: 70","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"10 User-Agent: FFmpeg GB28181 v1.0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"11 Subject: 34020000001320000003:630886,34020000002000000001:0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"12 Content-Length: 164","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"13 v=0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"14 o=34020000001320000003 0 0 IN IP4 39.100.155.146","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"15 s=Play","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"16 c=IN IP4 39.100.155.146","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"17 t=0 0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"18 m=video 9000 RTP/AVP 96","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"19 a=recvonly","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"20 a=rtpmap:96 PS/90000","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"21 y=630886","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SIP消息頭部分上述已經解釋過了,這裏解釋下SDP相關字段含義。","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"v=表示的SDP版本,固定值,爲0。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"o=表示INVITE發起者的相關信息,後面的內容依次爲設備國標ID、session ID、session版本、網絡類型(IN/OUT)、地址類型(IPV4/IPV6)、發起者IP。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"s=表示session名稱,GB28181協議中規定實時點播必須填“Play”。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"c=表示連接數據,依次是網絡類型(IN/OUT)、地址類型(IPV4/IPV6)、發起者IP。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"t=表示起始時間和終止時間,由於是實時點播,沒有起始時間和終止時間,因此均爲0.","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"m=表示的媒體流參數,m字段描述媒體的媒體類型、端口、傳輸層協議、負載類型等內容。媒體類型採用“video”標識傳輸視頻或視音頻混合內容,採用“audio”標識傳輸音頻內容; 傳輸方式採用“RTP/AVP”標識傳輸層協議爲RTP over UDP,採用“TCP/RTP/AVP”標識傳輸層協議爲RTP over TCP。例如:“m=video 6000 RTP/AVP 96”標識媒體類型爲視頻或視音頻, 傳輸端口爲6000,採用RTP over UDP傳輸方式,負載類型爲96。“m=video 6000 TCP/RTP/AVP 96”標識媒體類型爲視頻或視音頻,傳輸端口爲6000,採用RTP over TCP傳輸方式, 負載類型爲96。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"a=可以用於表示媒體相關的參數,如啓用IETF RFC 4566中對a字段的定義a=rtpmap:  / [/]中的, 利用該屬性攜帶編碼器廠商名稱(如:企業1或企業2編碼名稱DAHUA或HIKVISION)。該屬性表明該流爲某廠商編碼器編碼且是不符合本標準規定的媒體流, 符合本標準規定的媒體流無需該屬性。recvonly表示僅接收媒體流,sendonly表示僅發送。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"y=表示SSRC,可以在端口複用模式情況下區分不同路的媒體流,SSRC值全局唯一,用戶可以自定義。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"INVITE回覆消息範例如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1 SIP/2.0 200 OK","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2 Via: SIP/2.0/UDP 39.100.155.146:15063;rport=15063;branch=z9hG4bK34208805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3 From: sip:[email protected]:15063;tag=512358805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4 To: sip:34020000001320000003@3402000000;tag=1083111311","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5 Call-ID: 200008805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6 CSeq: 20 INVITE","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7 Contact: sip:[email protected]:5060","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"8 Content-Type: application/sdp","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"9 User-Agent: IP Camera","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"10 Content-Length: 263","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"11 v=0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"12 o=34020000001320000003 1073 1073 IN IP4 192.168.137.11","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"13 s=Play","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"14 c=IN IP4 192.168.137.11","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"15 t=0 0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"16 m=video 15060 RTP/AVP 96","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"17 a=setup:active","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"18 a=sendonly","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"19 a=rtpmap:96 PS/90000","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"20 y=0000630886","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":"ACK消息範例如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1 ACK sip:34020000001320000003@3402000000 SIP/2.0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2 Via: SIP/2.0/UDP 39.100.155.146:15063;rport;branch=z9hG4bK34208805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3 From: sip:[email protected]:15063;tag=512358805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4 To: sip:34020000001320000003@3402000000","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5 Call-ID: 200008805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6 CSeq: 20 ACK","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7 Max-Forwards: 70","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"8 User-Agent: FFmpeg GB28181 v1.0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"9 Content-Length: 0","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":"BYE消息範例如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1 BYE sip:34020000001320000003@3402000000 SIP/2.0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2 Via: SIP/2.0/UDP 39.100.155.146:15063;rport;branch=z9hG4bK34208805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3 From: sip:34020000002000000001@3402000000;tag=512358805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4 To: sip:34020000001320000003@3402000000;tag=1083111311","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5 Call-ID: 200008805","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6 CSeq: 79 BYE","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7 Max-Forwards: 70","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"8 User-Agent: FFmpeg GB28181 v1.0","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"9 Content-Length: 0","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":"2.2 RTP協議","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"RTP是一個網絡傳輸協議,IETF RFC3550詳細描述了RTP協議內容。GB28181協議中規定了兩種方式傳輸媒體流,一種是將音視頻數據打包成MPEG2-PS流然後再通過RTP協議傳輸,另外一種是直接使用RTP傳輸裸的音視頻流,在實際應用中主要以第一種方式爲主,因此本文着重介紹下第一種方式。基於RTP的PS封裝首先按照ISO/IEC13818-1:20008將視音頻流封裝成PES包,然後再將PES包封裝成PS包, 再將PS包以負載的方式封裝成RTP包。進行PS封裝時,應將每個視頻幀封裝爲一個PS包,且每個關鍵幀的PS包中應包含系統頭(System Header)和PSM(Program Stream Map),系統頭和PSM放置於PS包頭之後、第一個PES包之前。典型的視頻關鍵幀PS包結構如圖6所示,其中PESV爲視頻PES包,PESA爲音頻PES包,視頻非關鍵幀的PS包結構中一般不包含系統頭和PSM。PS包中各部分的具體數據結構參見ISO/IEC13818-1:2000中的相關描述。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a8/a86abd32ff361a41d9a917fbcec9b16f.webp","alt":"圖片","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":"圖5 典型的視頻關鍵幀PS包結構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"系統頭應包含對PS包中碼流種類的描述, 其中視頻和音頻的流ID(stream_id)取值如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(a) 視頻流ID:0xE0;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(b) 音頻流ID:0xC0。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對幾種視音頻格式,PSM中流類型(stream_type)的取值如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(a) MPEG-4 視頻流:0x10;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(b) H.264 視頻流:0x1B;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(c) SVAC 視頻流:0x80;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(d) G.711 音頻流:0x90;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(e) G.722.1 音頻流:0x92;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(f) G.723.1 音頻流:0x93;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(g) G.729 音頻流:0x99;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(h) SVAC 音頻流:0x9B。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"PS包的RTP封裝格式參照IETF RFC2250,RTP的主要參數設置如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(a) 負載類型(payloadtype):96;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(b) 編碼名稱(encoding_name):PS;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(c) 時鐘頻率(clockrate):90 kHz;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(d) SDP描述中“m”字段的“media”項:video。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/eb/eba9b88b7f3f7655ed96184a5e06eedd.png","alt":"圖片","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":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.1 GB28181 demuxer","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先我們在FFmpeg中實現了GB28181協議的demuxer,方案的框架圖如圖6所示。主要包含兩個子模塊,一個是SIP stack模塊,負責SIP協議功能,一個GB28181 demuxer模塊,負責調用SIP接口與前端設備IPC進行交互,同時解析IPC通過RTP發送過來的MPEG2-PS流,得到音視頻數據流後以packet的形式返回給lavf上層,再依次往FFmpeg上層傳。SIP stack模塊提供單一功能的SIP接口,比如發送回覆消息,發送INVITE/BYE/ACK請求;GB28181 demuxer模塊需要按照FFmpeg上層接口調用順序與IPC進行相關的交互,同時創建與設備之間的RTP鏈接,在拿到MPEG2-PS流後進行解析。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a9/a90115e324c36142eecca99fa9b81a72.webp","alt":"圖片","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":"圖6 demuxer方案的框架圖","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於FFmpeg只有解析PS流封裝的本地視頻demuxer,並沒有解析PS流的demuxer,因此本文也在本地PS流封裝視頻demuxer的基礎之上實現了PS流的demuxer。核心思路是從RTP包中解析PS頭信息,再根據PS頭信息找到PES頭,從PES頭中取出每個PES包的長度。由於RTP長度限制,一個PES包會被切分成很多份分成多個RTP包傳輸過來,因此PS demuxer需要緩存這些PES切片,等一個完整的PES包湊齊後再解析取出音視頻流並以packet格式返回上FFmpeg上層模塊。由於IETF RFC22509並沒有規定PS流應該如何封裝到RTP中,因此PES頭可能出現在RTP包的任何位置,demuxer也針對不同的情況做了處理。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.2 GB28181 Server","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上述方案存在侷限性,只能對單一設備進行管理和拉流,但實際場景中一個SIP域中存在衆多設備。因此在上述GB28181 demuxer的基礎之上,我們也實現了GB28181 server,方案的框架圖如下圖7所示。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/de/def1a7de367fb728a052a8412fd22836.png","alt":"圖片","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":"圖7 server方案的框架圖","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GB28181 server功能包括:","attrs":{}}]},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"作爲SIP server,管理多設備的註冊、保活監控、拉流/停止拉流信令交互;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"作爲media server,對外提供HTTP接口,用戶可以獲取設備信息、對指定設備進行拉流並轉推RTMP、停止拉流等操作。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"GB28181 server可以使用戶不感知GB28181協議的存在,用戶只需要對感興趣的設備進行操作即可。具體實現中,我們對上述GB28181 demuxer進行了功能擴展,使其具備兩種工作模式,一種就是上述的單一設備模式,一種就是多設備管理模式。後者將設備狀態信息、發送拉流/停止拉流接口暴露出來供GB28181 server調用。因此當GB28181 server運行後,其自動會對發出註冊請求的設備進行管理,監控設備是否在線或離線並更新設備信息。同時監聽用戶請求,當接收到用戶的HTTP請求時做相應的拉流/停止拉流等操作。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule","attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"參考文獻","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[1] GB/T 28181—2016. 安全防範視頻監控聯網系統信息傳輸, 交換, 控制技術要求[D]. , 2016.","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[2] Rosenberg J, Schulzrinne H, Camarillo G, et al. RFC3261: SIP: session initiation protocol[J]. 2002.","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[3] Casner S, Frederick R, Jacobson V, et al. RFC 3550, RTP: A Transport Protocol for Real-Time Applications[J]. Network Working Group, 2003.","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[4] Handley M, Jacobson V, Perkins C. RFC 4566: SDP: session description protocol[J]. 2006.","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[5] Donovan S. IETF RFC 2976 the SIP INFO Method[J]. 2000.","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[6] RFC3428 I. SIP extension for instant messaging[J]. 2002.","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[7] Rosenberg J, Schulzrinne H. IETF RFC 3581[J]. An Extension to the Session Initiation, 2003.","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[8] Rec I. H. 222.0| ISO/IEC 13818-1: 2000[J]. Information Technology—Generic coding of moving pictures and associated audio—Part, 1.","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[9] Hoffman D, Fernando G, Goyal V, et al. RFC2250: RTP payload format for MPEG1/MPEG2 video[J]. 1998.","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章