live555源代碼分析html
源代碼下載(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 LFsession
迴應消息:
RTSP 版本狀態碼解釋CR LF
消息頭CR LF CR LF
消息體CR LF
其中RTSP 版本通常都是RTSP/1.0,狀態碼是一個數值,200表示成功,解釋是與狀態碼對應
的文本解釋.app
簡單的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 迴應媒體初始化描述信息,主要是sdp 3.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 等等
ps:
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 個或多個媒體屬性行)
OPTIONS rtsp://192.168.1.109/1.mpg RTSP/1.0 CSeq: 1 user-Agent: VLC media player(LIVE555 Streaming Media v2007.02.20) 1)M -> C RTSP/1.0 200 OK CSeq: 1 Date: wed, Feb 20 2008 07:13:24 GMT Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE
DESCRIBE rtsp://192.168.1.109/1.mpg RTSP/1.0 CSeq: 2 Accept: application/sdp User-Agent: VLC media player(LIVE555 Streaming Media v2007.02.20)
RTSP/1.0 200 OK CSeq: 2 Date: wed, Feb 20 2008 07:13:25 GMT Content-Base: rtsp://192.168.1.109/1.mpg/ Content-type: application/sdp Content-length: 447 v=0 o =- 2284269756 1 IN IP4 192.168.1.109 s=MPEG-1 or 2 program Stream, streamed by the LIVE555 Media Server i=1.mpg t=0 0 a=tool:LIVE555 Streaming Media v2008.02.08 a=type:broadcast a=control:* a=range:npt=0-66.181 a=x-qt-text-nam:MPEG-1 or Program Stream, streamed by the LIVE555 Media Server a=x-qt-text-inf:1.mpg m=video 0 RTP/AVP 32 c=IN IP4 0.0.0.0 a=control:track1 m=audio 0 RTP/AVP 14 c=IN IP4 0.0.0.0 a=control:track2
SETUP rtsp://192.168.1.109/1.mpg/track1 RTSP/1.0 CSeq: 3 Transport: RTP/AVP; unicast;client_port=1112-1113 User-Agent: VLC media player(LIVE555 Streaming Media v2007.02.20)
RTSP/1.0 200 OK CSeq: 3 Date: wed, Feb 20 2008 07:13:25 GMT Transport: RTP/AVP;unicast;destination=192.168.1.222;source=192.168.1.109;client_port=1112-1113;server _port=6970-6971 Session: 3
SETUP rtsp://192.168.1.109/1.mpg/track2 RTSP/1.0 CSeq: 4 Transport: RTP/AVP; unicast;client_port=1114-1115 Session: 3 User-Agent: VLC media player(LIVE555 Streaming Media v2007.02.20)
RTSP/1.0 200 OK CSeq: 4 Date: wed, Feb 20 2008 07:13:25 GMT Transport: RTP/AVP;unicast;destination=192.168.1.222;source=192.168.1.109;client_port=1114-1115;server _port=6972-6973 Session: 3
PLAY rtsp://192.168.1.109/1.mpg/ RTSP/1.0 CSeq: 5 Session: 3 Range: npt=0.000- User-Agent: VLC media player(LIVE555 Streaming Media v2007.02.20)
RTSP/1.0 200 OK CSeq: 5 Range: npt=0.000- Session: 3 RTP-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 (開始傳輸流媒體...)