liveMedia 項目(http://www.live555.com/)的源碼包括四個基本的庫、測試代碼及Media Server。 四個基本庫分别是:UsageEnvironment&TaskScheduler、groupsock、liveMedia、BasicUsageEnvironment。 (1) UsageEnvironment 和TaskScheduler類,用于事件排程,實作異步讀取事件的句柄的設定、錯誤資訊輸出。還有一個HashTable類,定義了一個通用的hash表。這些都是抽象類,在程式中實作自己的子類。 (2) groupsock類,是對網絡接口的封裝,用于收發資料包。主要面向多點傳播資料的收發,同時也支援單點傳播資料的收發。 (3) liveMedia庫,是Live555最重要的子產品。該子產品聲明了一個抽象類Medium,其他所有類都派生自該類,下面簡要介紹這些類: ? RTSPClient:該類實作RTSP請求的發送和響應的解析,同時根據解析的結果建立對應的RTP會話。 ? MediaSession:用于表示一個RTP會話,一個MediaSession可能包含多個子會話(MediaSubSession),子會話可以是音頻子會話、視訊子會話等。 ? RTCPInstance:該類實作RTCP協定的通信。 ? Source和Sink:Source抽象了資料源,比如通過RTP讀取資料。Sink是資料消費者的抽象,比如把接收到資料存儲到檔案,該檔案就是一個Sink。資料的流動可能經過多個Source和Sink。MediaSink是各種類型的Sink的基類,MediaSource是各種類型Source的基類,各種類型的流媒體格式和編碼的支援即是通過對這兩個類的派生實作的。Source和Sink通過RTP子會話(MediaSubSession)聯系在一起。 (4) BasicUsageEnvironment 是UsageEnvironment 和TaskScheduler類的一個基本實作。 (5) 測試代碼,在testProgram目錄下,比如openRTSP等,這些代碼有助于了解liveMedia的應用。 (6) Media Server是一個純粹的RTSP伺服器。支援多種格式的媒體檔案: * TS流檔案,擴充名ts。 * PS流檔案,擴充名mpg。 * MPEG-4視訊基本流檔案,擴充名m4e。 * MP3檔案,擴充名mp3。 * WAV檔案(PCM),擴充名wav。 * AMR音頻檔案,擴充名.amr。 * AAC檔案,ADTS格式,擴充名aac。 用live555開發應用程式 基于liveMedia的程式,需要通過繼承抽象類UsageEnvironment和TaskScheduler,來處理事件排程、資料讀寫以及錯誤處理。live項目的源代碼裡有這些類的一個基本實作,這就是“BasicUsageEnvironment”庫。 BasicUsageEnvironment,是針對簡單的控制台應用程式,利用select實作事件擷取和處理。這個庫利用Unix或者 Windows的控制台作為輸入輸出,可以用這個庫使用者可以開發傳統的運作與控制台的應用。 可以通過使用自定義子類,使應用程式運作在特定的環境中。需要指出的是:在圖形環境下,TaskScheduler 的子類在實作 doEventLoop()的時候應該與圖形環境的事件處理架構內建。 基本概念 Sink,是消費資料的對象,如把接收到的資料存儲到檔案,這個檔案就是一個Sink。 Source,是生産資料的對象,比如通過RTP讀取資料。資料流經過多個'source'和'sink's,如下: 'source1' -> 'source2' (a filter) -> 'source3' (a filter) -> 'sink' filter,從其它Source接收資料的source也叫filter。 Module,是一個sink或者一個filter。 資料接收的終點是Sink類,MediaSink是所有Sink類的基類。Sink類通過實作純虛函數continuePlaying()對資料進行處理。通常情況下 continuePlaying調用 fSource->getNextFrame 來為Source設定資料緩沖區、處理資料的回調函數等,fSource是MediaSink的類型為FramedSource*的類成員。 基本控制流程 基于liveMedia的應用程式的控制流程如下: 應用程式是事件驅動的,使用如下方式的循環 while (1) { 通過查找讀網絡句柄的清單和延遲隊列(delay queue)來發現需要完成的任務 完成這個任務 } 對于每個sink,在進入這個循環之前,通常調用下面的方法來啟動需要做的任務: someSinkObject->startPlaying()。任何時候,一個Module需要擷取資料都通過調用它之前的Module的FramedSource::getNextFrame()方法。這是通過純虛函數 FramedSource::doGetNextFrame() 實作的,每一個Source module都有相應的實作。 live555代碼解讀之一:RTSP連接配接的建立過程 RTSPServer類用于建構一個RTSP伺服器,該類其内部定義了一個RTSPClientSession類,用于處理單獨的客戶會話。 首先建立RTSP伺服器(具體實作類是DynamicRTSPServer),在建立過程中:先建立 Socket(ourSocket)在TCP的554端口進行監聽,然後把連接配接處理函數句柄 (RTSPServer::incomingConnectionHandler)和socket句柄傳給任務排程器(taskScheduler)。 任務排程器把socket句柄放入socket句柄集(fReadSet)中(後面select調用中用會到),同時将 socket句柄和incomingConnectionHandler句柄關聯起來。接着,主程式開始進入任務排程器的主循環 (doEventLoop),在主循環中調用系統函數select阻塞,等待網絡連接配接。 當RTSP用戶端輸入(rtsp://192.168.1.109/1.mpg)連接配接伺服器時,select傳回對應的scoket,進而根據前 面儲存的對應關系,可找到對應處理函數句柄(前面提到的incomingConnectionHandler)。在 incomingConnectionHandler中建立了RTSPClientSession,開始對這個用戶端的會話進行處理。 live555代碼解讀之二:DESCRIBE請求消息處理過程 RTSP伺服器收到用戶端的DESCRIBE請求後,根據請求URL(rtsp://192.168.1.109/1.mpg),找到對應的流媒體資源, 傳回響應消息。ServerMediaSession類用來處理會話中描述,它包含多個(音頻或視訊)的子會話描述 (ServerMediaSubsession)。 上節談到RTSP伺服器收到用戶端的連接配接請求,建立了RTSPClientSession類,處理單獨的客戶會話。在建立 RTSPClientSession的過程中,将建立立的socket句柄(clientSocket)和RTSP請求處理函數句柄RTSPClientSession::incomingRequestHandler 傳給任務排程器,由任務排程器對兩者進行一對一關聯。當用戶端發出 RTSP請求後,伺服器主循環中的select調用傳回,根據socket句柄找到對應的incomingRequestHandler,開始消息處理。 先進行消息的解析,如果發現請求是DESCRIBE則進入handleCmd_DESCRIBE函數。根據用戶端請求URL的字尾(例如是1.mpg), 調用成員函數DynamicRTSPServer::lookupServerMediaSession查找對應的流媒體資訊 ServerMediaSession。如果ServerMediaSession不存在,但是本地存在1.mpg檔案,則建立一個新的 ServerMediaSession。在建立ServerMediaSession過程中,根據檔案字尾.mpg,建立媒體MPEG-1or2的解複用器(MPEG1or2FileServerDemux)。再由MPEG1or2FileServerDemux建立一個子會話描述 MPEG1or2DemuxedServerMediaSubsession。最後由ServerMediaSession完成組裝響應消息中的SDP資訊(SDP組裝過程見下面的描述),然後将響應消息發給用戶端,完成一次消息互動。 SDP消息組裝過程: ServerMediaSession負責産生會話公共描述資訊,子會話描述由 MPEG1or2DemuxedServerMediaSubsession産生。 MPEG1or2DemuxedServerMediaSubsession在其父類成員函數 OnDemandServerMediaSubsession::sdpLines()中生成會話描述資訊。在sdpLines()實作裡面,建立一個虛 構(dummy)的FramedSource(具體實作類為MPEG1or2AudioStreamFramer和 MPEG1or2VideoStreamFramer)和RTPSink(具體實作類為MPEG1or2AudioRTPSink和 MPEG1or2VideoRTPSink),最後調用setSDPLinesFromRTPSink(...)成員函數生成子會話描述。 以上涉及到的類以及繼承關系(所有類都是Medium 的子類): ServerMediaSession ServerMediaSubsession <- OnDemandServerMediaSubsession <- MPEG1or2DemuxedServerMediaSubsession MediaSource <- FramedSouse <- FramedFileSource <- ByteStreamFileSource MediaSource <- FramedSouse <- MPEG1or2DemuxedElementaryStream MPEG1or2FileServerDemux MPEG1or2Demux MediaSource <- FramedSouse <- MPEG1or2DemuxedElementaryStream MediaSource <- FramedSouse <- FramedFilter <- MPEGVideoStreamFramer <- MPEG1or2VideoStreamFramer MediaSink <- RTPSink <- MultiFramedRTPSink <- VideoRTPSink <- MPEG1or2VideoRTPSink live555代碼解讀之三:SETUP 和PLAY請求消息處理過程 前面提到RTSPClientSession類,用于處理單獨的客戶會話。其類成員函數handleCmd_SETUP()處理用戶端的SETUP請求。調用parseTransportHeader() 對SETUP請求的傳輸頭解析,調用子會話(這裡具體實作類為 OnDemandServerMediaSubsession)的getStreamParameters()函數擷取流媒體發送傳輸參數。将這些參數組 裝成響應消息,傳回給用戶端。 擷取發送傳輸參數的過程:調用子會話(具體實作類MPEG1or2DemuxedServerMediaSubsession)的 createNewStreamSource(...)建立MPEG1or2VideoStreamFramer,選擇發送傳輸參數,并調用子會話的 createNewRTPSink(...)建立MPEG1or2VideoRTPSink。同時将這些資訊儲存在StreamState類對象中,用于 記錄流的狀态。 用戶端發送兩個SETUP請求,分别用于建立音頻和視訊的RTP接收。 PLAY請求消息處理過程: RTSPClientSession類成員函數handleCmd_PLAY() 處理用戶端的播放請求。 首先調用子會話的startStream(),内部調用MediaSink::startPlaying(...), 然後調用MultiFramedRTPSink::continuePlaying(), 接着調用 MultiFramedRTPSink::buildAndSendPacket(...)。buildAndSendPacke内部先設定RTP標頭, 内部再調用MultiFramedRTPSink::packFrame()填充編碼幀資料。 packFrame内部通過 FramedSource::getNextFrame(),接着MPEGVideoStreamFramer::doGetNextFrame(),再接着經過 MPEGVideoStreamFramer::continueReadProcessing(), FramedSource::afterGetting(...), MultiFramedRTPSink::afterGettingFrame(...), MultiFramedRTPSink::afterGettingFrame1(...)等一系列調用, 最後到了 MultiFramedRTPSink::sendPacketIfNecessary(), 這裡才真正發送RTP資料包。然後是計算下一個資料包發送時間,把MultiFramedRTPSink::sendNext(...)函數句柄傳給任務 排程器,作為一個延時事件排程。在主循環中,當MultiFramedRTPSink::sendNext()被排程時,又開始調用 MultiFramedRTPSink::buildAndSendPacket(...)開始新的發送資料過程,這樣用戶端可以源源不斷的收到伺服器傳 來的RTP包了。 發送RTP資料包的間隔計算方法: Update the time at which the next packet should be sent, based on the duration of the frame that we just packed into it. 涉及到一些類有: MPEGVideoStreamFramer:A filter that breaks up an MPEG video elementary stream into headers and frames MPEG1or2VideoStreamFramer:A filter that breaks up an MPEG 1 or 2 video elementary stream into frames for: Video_Sequence_Header, GOP_Header, Picture_Header MPEG1or2DemuxedElementaryStream:A MPEG 1 or 2 Elementary Stream, demultiplexed from a Program Stream MPEG1or2Demux:Demultiplexer for a MPEG 1 or 2 Program Stream ByteStreamFileSource:A file source that is a plain byte stream (rather than frames) MPEGProgramStreamParser:Class for parsing MPEG program stream StreamParser:Abstract class for parsing a byte stream StreamState:A class that represents the state of an ongoing stream (開始傳輸流媒體...) 整理自:http://hi.baidu.com/bohryan/blog/item/7d18b9e85134bed8d439c9d1.html