對於並發量並不大而且對效能要求不是很高的流媒體伺服器,live555還是很好的選擇,下面說一下我所實現的流媒體Proxy 伺服器(目前只能實現對H264單視頻的轉寄)
代理轉寄主要分為對RTSP的轉寄與對RTP/RTCP的轉寄,盡量做到不破壞原有程式架構,所以還是要將整個代理過程融合於ServerMediaSubsession、Source、Sink的迴圈中,按照流程,RTSP OPTIONS不需要進行轉寄,直接轉到DESCRIBE的轉寄過程。
DECRIBE轉寄:看過很多大型的流媒體伺服器以後,會發現有一個相同點:前端裝置在註冊到流媒體伺服器以後會將其自身的無論是即時資源還是錄影資源都上報到流媒體伺服器中集中管理,那麼此處同理,在流媒體伺服器上線後改為主動向前端請求資源,到此處也就是發送DESCRIBE請求,我實現的Proxy 伺服器中,專門定義了一個類,繼承自RTSPClient,向前端裝置發送DESCRIBE請求,成功接收到攜帶SDP資訊的反饋以後,根據SDP資訊產生MediaSession,再執行其中每一個MediaSubsession的initiate(),這樣擷取由前端發送來資料的Source就已經準備就緒,同時,在每一個MediaSubsession建立以後,在對應流的ServerMediaSession中加入ServerMediaSubsession(此處ServerMediaSubsession繼承自OnDemandServerMediaSubsession),這樣就做到了一個ServerMediaSubsession對應一個MediaSubsession(這裡一定要區分ServerMediaSubsession與MediaSubsession),兩路會話的串連,下面就是用戶端發起了DESCRIBE請求,轉到RTSPServer::RTSPClientSession::handleCmd_DESCRIBE(),再轉到ServerMediaSession::generateSDPDescription(),因為是轉寄,而且不能讓用戶端知道是轉寄,所以sdp資訊在m欄位前面的參數都是基於Proxy 伺服器本身,從m開始便是真正的媒體資訊,原有的live555結構中,擷取每一個track的sdpLine是由virtual
char const* OnDemandServerMediaSubsession::sdpLines();得到,於是,我們可以重寫此virtual函數,返回什麼呢,返回的就是我們剛才傳入的MediaSubsession的savedSDPLines()傳回值。這樣,SDP資訊就可以在不破壞原有live555迴圈的基礎上構造出來,並實現轉寄了。
SETUP轉寄:同DESCRIBE一樣,原有架構已經形成,在收到SETUP請求以後,找到RTSPServer::RTSPClientSession::handleCmd_SETUP(),再找到virtual void OnDemandServerMediaSubsession::getStreamParameters(),在原有live555迴圈中,此函數作用為建立本地接收埠,建立createNewSource與createNewSink,將資料轉送迴圈中的各個組件都準備妥當,一旦收到Play命令就開始迴圈工作,那麼同樣重寫此virtual函數,在重寫中實現向前端發送SETUP請求,等待響應成功,再執行本地的SETUP,向前端發送SETUP實現可以同樣由剛才傳入的"RTSPClient繼承"與MediaSubsession來實現發送命令,等待返回,再繼續執行OnDemandServerMediaSubsession::getStreamParameters()實現本地的SETUP,如此一來,本地與遠端SETUP都已完成。
PLAY轉寄:同樣,按照流程,重寫OnDemandServerMediaSubsession::startStream()函數,發送Play請求到遠程,等待返回,再執行本地的startStream(),本地與遠端Play都已完成。
上面已經將RTSP的轉寄實現,而且基本是在live555原有基礎上進行,沒有破壞原有架構結構,下面進行rtp的轉寄。
rtp的轉寄實現的重點是在建立source到sink的迴圈,重寫OnDemandServerMediaSubsession::createNewStreamSource,與OnDemandServerMediaSubsession::createNewRTPSink,理想中的轉寄是能夠實現收到rtp包不進行任何重組,直接發送即可,但我所實現的只能是由MediaSubsession中的readSource擷取完整的一幀後,再交給rtpSink進行重新切片組裝,具體到實現上,我實現了一個整合自H264VideoStreamFramer的類,並將MediaSubsession->readSource作為inputSource傳入,重寫doGetNextFrame(),從inputSource中擷取完整一幀,copy到fTo,再交由createNewRTPSink()返回的H264VideoRTPSink進行重新組裝並發送,後來考慮到此種做法,有利有弊,與不重新組裝,直接發送,各有考慮。
如此,便實現了RTSP與RTP的轉寄功能,多有不妥,後續會持續改進,還望能夠在留言中多多指正!
轉自http://blog.csdn.net/xiejiashu