live555 testOnDemandRTSPServer 源碼分析

live555 源碼框架結構,源碼版本最後修改日期:2018-12-13 21

官方相關圖解連接:http://www.live555.com/liveMedia/doxygen/html/inherits.html

相關的文章比較多,不過光看別人的介紹很難理解,自己拿源碼看,邊看邊作圖理清楚結構關係,再和他人的文章對比下圖解是否有誤,這樣學起來效果不錯。

 

:從 testOnDemandRTSPServer.cpp中分析,main函數中:

先創建了 RTSPServer *rtspServer,創建ServerMediaSession 並添加Subsession. 將ServerMediaSession add到RTSPServer

 RTSPServer* rtspServer = RTSPServer::createNew(*env, 8554, authDB);

 ServerMediaSession* sms
      = ServerMediaSession::createNew(*env, streamName, streamName,
				      descriptionString);
      sms->addSubsession(H264VideoFileServerMediaSubsession
		       ::createNew(*env, inputFileName, reuseFirstSource));

 rtspServer->addServerMediaSession(sms);



env->taskScheduler().doEventLoop();

GenericMediaServer內部,也可以說是RTSPServer內部,有 RTSPClientConnection和RTSPClientSession兩個內部類(友元類),分別表示一個 RTSP 連接(和客戶端連接的rtsp),和進行傳輸的rtsp會話。 GenericMediaServer類中有三個hash表,HashTable* fServerMediaSessions; //記錄添加進來的服務端會話 (也可理解爲服務端提供的rtsp服務會話層)
HashTable* fClientConnections;  //記錄連接的rtsp連接(客戶端rtsp使用的tcp連接,也可理解爲rtsp連接會話層)
HashTable* fClientSessions; //記錄客戶端setup 的會話連接(也可以理解爲rtp會話層)

在客戶端有連接時,創建 RTSPClientConnection,在客戶端要求setup時創建RTSPClinetSession具體的創建函數,都是純虛函數,即GenericMediaServer只提供規範,具體的實現,在子類RTSPServer中。

(1)【創建服務端socket】創建 rtspserver的過程中,先用setUpOurSocket(env, ourPort)創建listen socket,[對應代碼在RTSPServer::createNew()]  (2)[監聽] 然後調用RTSPServer的父類的構造函數,設置一個回調:當這個socket有數據時就調用這個回調,就使用accept得到一個連接的rtsp socket, [對應代碼在GenericMediaServer.cpp::incomingConnectionHandlerOnSocket] (3)【有客戶鏈接,創建對應RTSP使用的tcp連接層】同時創建一個ClientConnection,(顧名思義,這就是一個服務連接,在GenericMediaServer有基本定義,在RTSPServer具體的rtsp server中還有一層和RTSP服務掛鉤的ClientConnection的實現) 創建ClientConection是在GenericMediaServer中調用自己的存虛函數 createNewClientConnection(),也就是會調用子類RTSPServer中實現的createNewClientConnection. 【這裏注意這個接口return 了對象指針,但其實調用者GenericMediaServer的incomingConnectionHandlerOnSocket()函數 調用的時候直接忽略了其返回值的,而是在RTSPServer::createNewClientConnection(){ return new RTSPClientConnection(*this, clientSocket, clientAddr);}通過第一個參數把Server的引用傳遞了進去,那麼有沒有內存泄漏呢?怎麼把這個對象保存下來?是在,ClientConnection 類的構造函數中,會把自己通過這個傳入的GenericMediaServer ,把自己添加到GenericMediaServer中的成員 fClientConnections 哈希表中。這樣就保存下來了,當連接關閉的時候服務端就從自己的這個hash表中找出來這個連接,關閉,delete掉】(4)【用於rtsp協議的tcp連接,處理rtsp請求】創建ClientConnection 後,也要爲這個ClientConnection 設置一個回調,當這個連接有數據寫入的時候就讀取分析數據,然後調用進行會話層面的處理,這裏就是 rtsp的 option setup play pause stop 等等的控制了。 具體代碼,在GenericMediaServer.cpp GenericMediaServer::ClientConnection::incomingRequestHandler() { int bytesRead = readSocket(envir(), fOurSocket, &fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft, dummy);
  handleRequestBytes(bytesRead);// 同樣,這個handleRequestBytes也是個純虛函數,由具體的服務端 RTSPServer類實現,裏面真正處理 option setup play pase stop等等
}

:回調的設置,創建RTSPServer類的構造函數,會調用其父類GenericMediaServer的構造函數,在GenericMediaServer的構造函數中執行env.taskScheduler().turnOnBackgroundReadHandling(fServerSocket, incomingConnectionHandler, this);這個incomingConnectionHandler,就是socket有數據時執行的調用。(5)【處理請求,建立rtp】現在進入 ClientConnection 會話中的 RTSPServer::RTSPClientConnection::handleRequestBytes() //處理請求。在處理請求時,更根據需要調用 GenericMediaServer中的createNewClientSessionWithId()來創建一個 ClinetSession。(如上所述,可以理解爲rtp會話層)然後才調用RTSPClientSession::handleCmd_SETUP, (6)[play,啓動對應rtp--ServerMediaSubsession]這現在進入RTSPClientSession,(如上所述,可理解爲rtp連接層,所以之前往ServerMediaSession添加的ServerMediaSubsession,就相當於往rtsp會話中加入rtp會話)該函數裏面會從GenericMediaServer中的fServerMediaSessions哈希表中查找是否有對應的server。 即在最開始,在main函數裏面使用rtspServer->addServerMediaSession(sms) 添加的server。 這裏會從之前添加的server中取出來,執行:  ServerMediaSubsession* subsession->getStreamParameters()。 也就是調用 H264VideoFileServerMediaSubsession::getStreamParameters(); 它的函數具體實現,在 OnDemandServerMediaSubsession中 OnDemandServerMediaSubsession 類 (6.1)[創建rtp]ServerMediaSubsession 【ServerMediaSubsession就相當於一個rtp】定義的純虛函數getStreamParameters()要求獲取對rtp流的參數,所以子類,必須在調用這個函數返回搭建好的rtp流的信息,首先就是要創建好rtp流,在OnDemandServerMediaSubsession 中實現了這個純虛函數,創建rtp流,調用 createNewStreamSource()來創建StreamSource,調用createNewRTPSink()來創建rtpSink,如果是用的rtp-over-udp,還需要先創建好供rtp和rtcp使用udp socket. 另,還給OnDemandServerMediaSubsession(如上所述,即可理解爲rtp) 創建了兩個相關的數據結構(類)StreamStateDestinations
StreamState中,有RTPSink和FrameSource,也是在上述函數getStreamParameters中創建,ServerMediaSubsession的子類必須實現這個純虛函數,並且在裏面實例化數據源FrameSource和數據輸出RTPSink,即在H264VideoFileServerMediaSubsession中的createNewStreamSource和createNewRTPSink
當GenericMediaServer中給ClientConnection設置的回調中,處理play命令請求時,即RTSPServer::RTSPClientSession(如上所述,可以理解對應爲rtp) handleCmd_PLAY() 函數,調用到fStreamStates[i].subsession->startStream(),  ->
OnDemandServerMedai::sartStream ()->
StreamState::startPlaying()->
MediaSink::startPlaying()->
continuePlaying()-> 調用到 H264or5VideoRTPSink::continuePlaying()
-> MultiFramedRTPSink::continuePlaying()
補充一張大圖,結構,調用關係等待。

https://blog.csdn.net/u012459903/article/details/102936752

 

 

 

 

 

 

 

 

 

圖一:

從上往下爲子類到父類。

 

圖二:紅色箭頭可以看出 讀h264文件 數據的調用過程

 

圖三: 事件驅動,主循環

圖三, h264文件讀數據詳細 調用流程:

 

圖四:從h264讀文件數據簡要結構流程

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章