RTSP服务器实例live555源代码分析
1. RTSP連接的建立過程
??????RTSPServer類用于構(gòu)建一個(gè)RTSP服務(wù)器,該類同時(shí)在其內(nèi)部定義了一個(gè)RTSPClientSession類,用于處理單獨(dú)的客戶會話。
??????首先創(chuàng)建RTSP服務(wù)器(具體實(shí)現(xiàn)類是DynamicRTSPServer),在創(chuàng)建過程中,先建立Socket(ourSocket)在TCP的554端口進(jìn)行監(jiān)聽,然后把連接處理函數(shù)句柄(RTSPServer::incomingConnectionHandler)和socket句柄傳給任務(wù)調(diào)度器(taskScheduler)。
??????任務(wù)調(diào)度器把socket句柄放入后面select調(diào)用中用到的socket句柄集(fReadSet)中,同時(shí)將socket句柄和incomingConnectionHandler句柄關(guān)聯(lián)起來。接著,主程序開始進(jìn)入任務(wù)調(diào)度器的主循環(huán)(doEventLoop),在主循環(huán)中調(diào)用系統(tǒng)函數(shù)select阻塞,等待網(wǎng)絡(luò)連接。
??????當(dāng)RTSP客戶端輸入(rtsp://192.168.0.1/1.mpg)連接服務(wù)器時(shí),select返回對應(yīng)的socket,進(jìn)而根據(jù)前面保存的對應(yīng)關(guān)系,可找到對應(yīng)處理函數(shù)句柄,這里就是前面提到的incomingConnectionHandler了。在incomingConnectionHandler中創(chuàng)建了RTSPClientSession,開始對這個(gè)客戶端的會話進(jìn)行處理。
?
?
?
2. DESCRIBE請求消息處理過程
??????RTSP服務(wù)器收到客戶端的DESCRIBE請求后,根據(jù)請求URL(rtsp://192.168.0.1/1.mpg),找到對應(yīng)的流媒體資源,返回響應(yīng)消息。live555中的ServerMediaSession類用來處理會話中描述,它包含多個(gè)(音頻或視頻)的子會話描述(ServerMediaSubsession)。
??????RTSP服務(wù)器收到客戶端的連接請求,建立了RTSPClientSession類,處理單獨(dú)的客戶會話。在建立RTSPClientSession的過程中,將新建立的socket句柄(clientSocket)和RTSP請求處理函數(shù)句柄RTSPClientSession::incomingRequestHandler傳給任務(wù)調(diào)度器,由任務(wù)調(diào)度器對兩者進(jìn)行一對一關(guān)聯(lián)。
??????當(dāng)客戶端發(fā)出RTSP請求后,服務(wù)器主循環(huán)中的select調(diào)用返回,根據(jù)socket句柄找到對應(yīng)的incomingRequestHandler,開始消息處理。先進(jìn)行消息的解析,如果發(fā)現(xiàn)請求是DESCRIBE則進(jìn)入handleCmd_DESCRIBE函數(shù)。根據(jù)客戶端請求URL的后綴(如1.mpg),調(diào)用成員函數(shù)DynamicRTSPServer::lookupServerMediaSession查找對應(yīng)的流媒體信息ServerMediaSession。如果ServerMediaSession不存在,但是本地存在1.mpg文件,則創(chuàng)建一個(gè)新的ServerMediaSession。在創(chuàng)建ServerMediaSession過程中,根據(jù)文件后綴.mpg,創(chuàng)建媒體MPEG-1or2的解復(fù)用器(MPEG1or2FileServerDemux)。再由MPEG1or2FileServerDemux創(chuàng)建一個(gè)子會話描述MPEG1or2DemuxedServerMediaSubsession。最后由ServerMediaSession完成組裝響應(yīng)消息中的SDP信息(SDP組裝過程見下面的描述),然后將響應(yīng)消息發(fā)給客戶端,完成一次消息交互。
?
SDP消息組裝過程:
?
??????ServerMediaSession負(fù)責(zé)產(chǎn)生會話公共描述信息,子會話描述由MPEG1or2DemuxedServerMediaSubsession產(chǎn)生。 MPEG1or2DemuxedServerMediaSubsession在其父類成員函數(shù)OnDemandServerMediaSubsession::sdpLines()中生成會話描述信息。在sdpLines()實(shí)現(xiàn)里面,創(chuàng)建一個(gè)虛構(gòu)(dummy)的FramedSource(具體實(shí)現(xiàn)類為MPEG1or2AudioStreamFramer和MPEG1or2VideoStreamFramer)和RTPSink(具體實(shí)現(xiàn)類為MPEG1or2AudioRTPSink和MPEG1or2VideoRTPSink),最后調(diào)用setSDPLinesFromRTPSink(...)成員函數(shù)生成子會話描述。
?
Live555庫是一個(gè)使用開放標(biāo)準(zhǔn)協(xié)議如RTP/RTCP、RTSP、SIP等實(shí)現(xiàn)多媒體流式傳輸?shù)拈_源C?庫集。這些函數(shù)庫可以在Unix、Windows、QNX等操作系統(tǒng)下編譯使用,基于此建立RTSP/SIP服務(wù)器和客戶端來實(shí)現(xiàn)多媒體流的傳輸。下面給出具體實(shí)現(xiàn)過程[4]:
(1)客戶端發(fā)起RTSP OPTION請求,目的是得到服務(wù)器提供什么方法。RTSP提供的方法一般包括OPTIONS、DESCRIBE、SETUP、TEARDOWN、PLAY、PAUSE、SCALE、GET_PARAMETER。
(2)服務(wù)器對RTSP OPTION回應(yīng),服務(wù)器實(shí)現(xiàn)什么方法就回應(yīng)哪些方法。在此系統(tǒng)中,我們只對DESCRIBE、SETUP、TEARDOWN、PLAY、PAUSE方法做了實(shí)現(xiàn)。
(3)客戶端發(fā)起RTSP DESCRIBE請求,服務(wù)器收到的信息主要有媒體的名字,解碼類型,視頻分辨率等描述,目的是為了從服務(wù)器那里得到會話描述信息(SDP)。
(4)服務(wù)器對RTSP DESCRIBE響應(yīng),發(fā)送必要的媒體參數(shù),在傳輸H.264文件時(shí),主要包括SPS/PPS、媒體名、傳輸協(xié)議等信息。
(5)客戶端發(fā)起RTSP SETUP請求,目的是請求會話建立并準(zhǔn)備傳輸。請求信息主要包括傳輸協(xié)議和客戶端端口號。
(6)服務(wù)器對RTSP SETUP響應(yīng),發(fā)出相應(yīng)服務(wù)器端的端口號和會話標(biāo)識符。
(7)客戶端發(fā)出了RTSP PLAY的請求,目的是請求播放視頻流。
(8)服務(wù)器對RTSP PLAY響應(yīng),響應(yīng)的消息包括會話標(biāo)識符,RTP包的序列號,時(shí)間戳。此時(shí)服務(wù)器對H264視頻流封裝打包進(jìn)行傳輸。
(9)客戶端發(fā)出RTSP TEARDOWN請求,目的是關(guān)閉連接,終止傳輸。
(10)服務(wù)器關(guān)閉連接,停止傳輸。
?
3. SETUP請求消息處理過程
????????RTSPClientSession類用于處理單獨(dú)的客戶會話。其類成員函數(shù)handleCmd_SETUP()處理客戶端的SETUP請求。調(diào)用parseTransportHeader()對SETUP請求的傳輸頭解析,調(diào)用子會話(這里具體實(shí)現(xiàn)類為OnDemandServerMediaSubsession)的getStreamParameters()函數(shù)獲取流媒體發(fā)送傳輸參數(shù)。將這些參數(shù)組裝成響應(yīng)消息,返回給客戶端。
????????獲取發(fā)送傳輸參數(shù)的過程:調(diào)用子會話(具體實(shí)現(xiàn)類MPEG1or2DemuxedServerMediaSubsession)的createNewStreamSource(...)創(chuàng)建MPEG1or2VideoStreamFramer,選擇發(fā)送傳輸參數(shù),并調(diào)用子會話的createNewRTPSink(...)創(chuàng)建MPEG1or2VideoRTPSink。同時(shí)將這些信息保存在StreamState類對象中,用于記錄流的狀態(tài)。
????????客戶端發(fā)送兩個(gè)SETUP請求,分別用于建立音頻和視頻的RTP接收。
?
?
?
?
4. PLAY請求消息處理過程
??????RTSPClientSession類成員函數(shù)handleCmd_PLAY()處理客戶端的播放請求。首先調(diào)用子會話的startStream(),內(nèi)部調(diào)用MediaSink::startPlaying(...),然后是MultiFramedRTPSink::continuePlaying(),接著調(diào)用MultiFramedRTPSink::buildAndSendPacket(...)。buildAndSendPacke內(nèi)部先設(shè)置RTP包頭,內(nèi)部再調(diào)用MultiFramedRTPSink::packFrame()填充編碼幀數(shù)據(jù)。
??????packFrame內(nèi)部通過FramedSource::getNextFrame(), 接著MPEGVideoStreamFramer::doGetNextFrame(),再接著經(jīng)過MPEGVideoStreamFramer::continueReadProcessing(), FramedSource::afterGetting(...), MultiFramedRTPSink::afterGettingFrame(...), MultiFramedRTPSink::afterGettingFrame1(...)等一系列繁瑣調(diào)用,最后到了MultiFramedRTPSink::sendPacketIfNecessary(), 這里才真正發(fā)送RTP數(shù)據(jù)包。然后是計(jì)算下一個(gè)數(shù)據(jù)包發(fā)送時(shí)間,把MultiFramedRTPSink::sendNext(...)函數(shù)句柄傳給任務(wù)調(diào)度器,作為一個(gè)延時(shí)事件調(diào)度。在主循環(huán)中,當(dāng)MultiFramedRTPSink::sendNext()被調(diào)度時(shí),又開始調(diào)用MultiFramedRTPSink::buildAndSendPacket(...)開始新的發(fā)送數(shù)據(jù)過程,這樣客戶端可以源源不斷的收到服務(wù)器傳來的RTP包了。
發(fā)送RTP數(shù)據(jù)包的間隔計(jì)算方法:
????????Update the time at which the next packet should be sent, based on the duration of the frame that we just packed into it.
總結(jié)
以上是生活随笔為你收集整理的RTSP服务器实例live555源代码分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sqlite 数据类型 全面
- 下一篇: vim E492: Not an edi