live555原始碼下載(VC6工程):http://download.csdn.net/detail/leixiaohua1020/6374387
liveMedia 項目(http://www.live555.com/)的原始碼包括四個基本的庫,各種測試代碼以及Media Server。四個基本的庫分別是: UsageEnvironment&TaskScheduler, groupsock, liveMedia和BasicUsageEnvironment。UsageEnvironment 和TaskScheduler 類用於事件的調度,實現非同步讀取事件的控制代碼的設定以及錯誤資訊的輸出。另外,還有一個HashTable 類定義了一個通用的hash 表,其它代碼要用到這個表。這些都是抽象類別,在應用程式中基於這些類來實現自己的子類。groupsock 類是對網路介面的封裝,用於收發資料包。正如名字本身,groupsock 主要是面向多播資料的收發的,它也同時支援單播資料的收發。liveMedia 庫中有一系列類,基類是Medium,這些類針對不同的流媒體類型和編碼。
各種測試代碼在testProgram 目錄下,比如openRTSP 等,這些代碼有助於理解liveMedia 的應用。
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 的控制台作為輸入輸出,處於應用程式原形或者調試的目的,可以用這個庫使用者可以開發傳統的運行與控制台的應用。通過使用自訂的“UsageEnvironment”和“TaskScheduler”抽象類別的子類,這些應用程式就可以在特定的環境中運行, 不需要做過多的修改。需要指出的是在圖形環境(GUI toolkit)下,抽象類別TaskScheduler 的子類在實現doEventLoop()的時候應該與圖形環境自己的事件處理框架組成。 基本概念
先來熟悉在liveMedia 庫中Source,Sink 以及Filter 等概念。Sink 就是消費資料的對象,比如把接收到的資料存放區到檔案, 這個檔案就是一個Sink。Source 就是生產資料的對象,比如通過RTP 讀取資料。資料流經過多個'source'和'sink's,下面是一個樣本:
'source1' -> 'source2' (a filter) -> 'source3' (a filter) -> 'sink'
從其它Source 接收資料的source 也叫做"filters"。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 都有相應的實現。
Each 'source' module's implementation of "doGetNextFrame()" works by arranging for an 'after getting' function to be called (from an event handler) when new data becomes available for the caller.
Note that the flow of data from 'sources' to 'sinks' happens within each application, and doesn't necessarily correspond to the sending or receiving of network packets. For example, a server application (such as "testMP3Streamer") that sends RTP packets will do so using one or more "RTPSink" modules. These "RTPSink" modules receive data from other, "*Source" modules (e.g., to read data from a file), and, as a side effect, transmit RTP packets.
live555代碼解讀之一:RTSP 串連的建立過程
RTSPServer 類用於構建一個RTSP 伺服器,該類同時在其內部定義了一個RTSPClientSession類,用於處理單獨的客戶會話。
首先建立RTSP 伺服器( 具體實作類別是DynamicRTSPServer) , 在建立過程中, 先建立Socket(ourSocket) 在TCP 的554 連接埠進行監聽, 然後把串連處理函數控制代碼(RTSPServer::incomingConnectionHandler)和socket 控制代碼傳給任務調度器(taskScheduler)。
任務調度器把socket 控制代碼放入後面select 調用中用到的socket 控制代碼集(fReadSet)中,同時將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),找到對應的流媒體資源, 返迴響應訊息。live555中的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
Medium <- ServerMediaSubsession <- OnDemandServerMediaSubsession <-MPEG1or2DemuxedServerMediaSubsession
Medium <- MediaSource <- FramedSouse <- FramedFileSource <- ByteStreamFileSource
Medium <- MediaSource <- FramedSouse <- MPEG1or2DemuxedElementaryStream
Medium <- MPEG1or2FileServerDemux
Medium <- MPEG1or2Demux
Medium <- MediaSource <- FramedSouse <- MPEG1or2DemuxedElementaryStream
Medium <- MediaSource <- FramedSouse <- FramedFilter <- MPEGVideoStreamFramer <-MPEG1or2VideoStreamFramer
Medium <- 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
rtsp 簡介(ZT)
Real Time Streaming Protocol 或者RTSP(即時資料流媒體協議),是由Real network 和Netscape共同提出的如何有效地在IP 網路上傳輸串流媒體資料的應用程式層協議。RTSP 提供一種可擴充的架構,使能夠提供能控制的,按需傳輸即時資料,比如音頻和視頻檔案。來源資料可以包括現場資料的反饋和存貯的檔案。rtsp 對流媒體提供了諸如暫停,快進等控制,而它本身並不傳輸資料,rtsp 作用相當於流媒體伺服器的遠端控制。傳輸資料可以通過傳輸層的tcp,udp協議,rtsp 也提供了基於rtp 傳輸機制的一些有效方法。
RTSP 訊息格式:
RTSP 的訊息有兩大類,一是請求訊息(request),一是回應訊息(response),兩種訊息的格式不同.
請求訊息:
方法URI RTSP 版本CR LF
訊息頭CR LF CR LF
訊息體CR LF
其中方法包括OPTION 回應中所有的命令,URI 是接受方的地址,例如:rtsp://192.168.20.136。
RTSP 版本一般都是RTSP/1.0.每行後面的CR LF 表示斷行符號換行,需要接受端有相應的解析,最後一個訊息頭需要有兩個CR LF
回應訊息:
RTSP 版本狀態代碼解釋CR LF
訊息頭CR LF CR LF
訊息體CR LF
其中RTSP 版本一般都是RTSP/1.0,狀態代碼是一個數值,200表示成功,解釋是與狀態代碼對應的文本解釋。
簡單的rtsp 互動過程:
C 表示rtsp 用戶端,S 表示rtsp 服務端
1.C->S:OPTION request //詢問S 有哪些方法可用1.S->C:OPTION response //S 回應資訊中包括提供的所有可用方法2.C->S:DESCRIBE request //要求得到S 提供的媒體初始化描述資訊2.S->C:DESCRIBE response //S 回應媒體初始化描述資訊,主要是sdp3.C->S:SETUP request //設定會話的屬性,以及傳輸模式,提醒S 建立會話3.S->C:SETUP response //S 建立會話,返回工作階段識別項,以及會話相關資訊4.C->S:PLAY request //C 請求播放4.S->C:PLAY response //S 回應該請求的資訊S->C:發送流媒體資料5.C->S:TEARDOWN request //C 請求關閉會話5.S->C:TEARDOWN response //S 回應該請求
上述的過程是標準的、友好的rtsp 流程,但實際的需求中並不一定按部就班來。其中第3和4步是必需的。第一步,只要伺服器用戶端約定好,有哪些方法可用,則option 請求可以不要。第二步,如果我們有其他途徑得到媒體初始化描述資訊(比如http 請求等等),則我們也不需要通過rtsp 中的describe 請求來完成。第五步,可以根據系統需求的設計來決定是否需要。
rtsp 中常用方法:
1.OPTION
目的是得到伺服器提供的可用方法:
OPTIONS rtsp://192.168.20.136:5000/xxx666 RTSP/1.0
CSeq: 1 //每個訊息都有序號來標記,第一個包通常是option 請求訊息
User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10)
伺服器的回應資訊包括提供的一些方法,例如:
RTSP/1.0 200 OK
Server: UServer 0.9.7_rc1
Cseq: 1 //每個回應訊息的cseq 數值和請求訊息的cseq 相對應
Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, SCALE,GET_PARAMETER //伺服器提供的可用的方法
2.DESCRIBE
C 向S 發起DESCRIBE 請求,為了得到會話描述資訊(SDP):
DESCRIBE rtsp://192.168.20.136:5000/xxx666 RTSP/1.0
CSeq: 2
token:
Accept: application/sdp
User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10)
伺服器回應一些對此會話的描述資訊(sdp):
RTSP/1.0 200 OK
Server: UServer 0.9.7_rc1
Cseq: 2
x-prev-url: rtsp://192.168.20.136:5000
x-next-url: rtsp://192.168.20.136:5000
x-Accept-Retransmit: our-retransmit
x-Accept-Dynamic-Rate: 1
Cache-Control: must-revalidate
Last-Modified: Fri, 10 Nov 2006 12:34:38 GMT
Date: Fri, 10 Nov 2006 12:34:38 GMT
Expires: Fri, 10 Nov 2006 12:34:38 GMT
Content-Base: rtsp://192.168.20.136:5000/xxx666/
Content-Length: 344
Content-Type: application/sdp
v=0 //以下都是sdp 資訊
o=OnewaveUServerNG 1451516402 1025358037 IN IP4 192.168.20.136
s=/xxx666
u=http:///
e=admin@
c=IN IP4 0.0.0.0
t=0 0
a=isma-compliance:1,1.0,1
a=range:npt=0-
m=video 0 RTP/AVP 96 //m 表示媒體描述,下面是對會話中視頻通道的媒體描述
a=rtpmap:96 MP4V-ES/90000
a=fmtp:96
profile-level-id=245;config=000001B0F5000001B509000001000000012000C888B0E0E0FA62D
089028307
a=control:trackID=0//trackID=0表示視頻流用的是通道0
3.SETUP
用戶端提醒伺服器建立會話,並確定傳輸模式:
SETUP rtsp://192.168.20.136:5000/xxx666/trackID=0 RTSP/1.0
CSeq: 3
Transport: RTP/AVP/TCP;unicast;interleaved=0-1
User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10)
//uri 中帶有trackID=0,表示對該通道進行設定。Transport 參數設定了傳輸模式,包的結構。接下來的資料包頭部第二個位元組位置就是interleaved,它的值是每個通道都不同的,trackID=0的interleaved 值有兩個0或1,0表示rtp 包,1表示rtcp 包,接受端根據interleaved 的值來區別是哪種資料包。
伺服器回應資訊:
RTSP/1.0 200 OK
Server: UServer 0.9.7_rc1
Cseq: 3
Session: 6310936469860791894 //伺服器回應的工作階段識別項
Cache-Control: no-cache
Transport: RTP/AVP/TCP;unicast;interleaved=0-1;ssrc=6B8B4567
4.PLAY
用戶端發送播放請求:
PLAY rtsp://192.168.20.136:5000/xxx666 RTSP/1.0
CSeq: 4
Session: 6310936469860791894
Range: npt=0.000- //設定播放時間的範圍
User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10)
伺服器回應資訊:
RTSP/1.0 200 OK
Server: UServer 0.9.7_rc1
Cseq: 4
Session: 6310936469860791894
Range: npt=0.000000-
RTP-Info: url=trackID=0;seq=17040;rtptime=1467265309
//seq 和rtptime 都是rtp 包中的資訊
5.TEARDOWN
用戶端發起關閉請求:
TEARDOWN rtsp://192.168.20.136:5000/xxx666 RTSP/1.0
CSeq: 5
Session: 6310936469860791894
User-Agent: VLC media player (LIVE555 Streaming Media v2005.11.10)
伺服器回應:
RTSP/1.0 200 OK
Server: UServer 0.9.7_rc1
Cseq: 5
Session: 6310936469860791894
Connection: Close
以上方法都是互動過程中最為常用的,其它還有一些重要的方法如get/set_parameter,pause,redirect 等等
附錄
sdp 的格式
v=<version>o=<username> <session id> <version> <network type> <address type> <address>s=<session name>i=<session description>u=<URI>e=<email address>p=<phone number>c=<network type> <address type> <connection address>b=<modifier>:<bandwidth-value>t=<start time> <stop time>r=<repeat interval> <active duration> <list of offsets from start-time>z=<adjustment time> <offset> <adjustment time> <offset> ....k=<method>k=<method>:<encryption key>a=<attribute>a=<attribute>:<value>m=<media> <port> <transport> <fmt list>v = (協議版本)o = (所有者/建立者和工作階段識別項)s = (會話名稱)i = * (會話資訊)u = * (URI 描述)e = * (Email 地址)p = * (電話號碼)c = * (串連資訊)b = * (頻寬資訊)z = * (時間地區調整)k = * (加密金鑰)a = * (0 個或多個會話屬性行)時間描述:t = (會話啟用時間)r = * (0或多次重複次數)媒體描述:m = (媒體名稱和傳輸地址)i = * (媒體標題)c = * (串連資訊— 如果包含在會話層則該欄位可選)b = * (頻寬資訊)k = * (加密金鑰)a = * (0 個或多個媒體屬性行)
參考文章:rfc2326(rtsp);rfc2327(sdp)
RTSP 點播訊息流程程執行個體
(用戶端:VLC, RTSP 伺服器:LIVE555 Media Server)1)C(Client)-> M(Media Server)
OPTIONS rtsp://192.168.1.109/1.mpg RTSP/1.0CSeq: 1user-Agent: VLC media player(LIVE555 Streaming Media v2007.02.20)1)M -> CRTSP/1.0 200 OKCSeq: 1Date: wed, Feb 20 2008 07:13:24 GMTPublic: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE
2)C -> M
DESCRIBE rtsp://192.168.1.109/1.mpg RTSP/1.0CSeq: 2Accept: application/sdpUser-Agent: VLC media player(LIVE555 Streaming Media v2007.02.20)
2)M -> C
RTSP/1.0 200 OKCSeq: 2Date: wed, Feb 20 2008 07:13:25 GMTContent-Base: rtsp://192.168.1.109/1.mpg/Content-type: application/sdpContent-length: 447v=0o =- 2284269756 1 IN IP4 192.168.1.109s=MPEG-1 or 2 program Stream, streamed by the LIVE555 Media Serveri=1.mpgt=0 0a=tool:LIVE555 Streaming Media v2008.02.08a=type:broadcasta=control:*a=range:npt=0-66.181a=x-qt-text-nam:MPEG-1 or Program Stream, streamed by the LIVE555 Media Servera=x-qt-text-inf:1.mpgm=video 0 RTP/AVP 32c=IN IP4 0.0.0.0a=control:track1m=audio 0 RTP/AVP 14c=IN IP4 0.0.0.0a=control:track2
3)C -> M
SETUP rtsp://192.168.1.109/1.mpg/track1 RTSP/1.0CSeq: 3Transport: RTP/AVP; unicast;client_port=1112-1113User-Agent: VLC media player(LIVE555 Streaming Media v2007.02.20)
3)M -> C
RTSP/1.0 200 OKCSeq: 3Date: wed, Feb 20 2008 07:13:25 GMTTransport:RTP/AVP;unicast;destination=192.168.1.222;source=192.168.1.109;client_port=1112-1113;server_port=6970-6971Session: 3
4)C -> M
SETUP rtsp://192.168.1.109/1.mpg/track2 RTSP/1.0CSeq: 4Transport: RTP/AVP; unicast;client_port=1114-1115Session: 3User-Agent: VLC media player(LIVE555 Streaming Media v2007.02.20)
4)M -> C
RTSP/1.0 200 OKCSeq: 4Date: wed, Feb 20 2008 07:13:25 GMTTransport:RTP/AVP;unicast;destination=192.168.1.222;source=192.168.1.109;client_port=1114-1115;server_port=6972-6973Session: 3
5)C -> M
PLAY rtsp://192.168.1.109/1.mpg/ RTSP/1.0CSeq: 5Session: 3Range: npt=0.000-User-Agent: VLC media player(LIVE555 Streaming Media v2007.02.20)
5)M -> C
RTSP/1.0 200 OKCSeq: 5Range: npt=0.000-Session: 3RTP-Info:url=rtsp://192.168.1.109/1.mpg/track1;seq=9200;rtptime=214793785,url=rtsp://192.168.1.109/1.mpg/track2;seq=12770;rtptime=31721(開始傳輸串流媒體...)