從程序的結構來看,live項目包括了四個基本庫、程序入口類(在mediaServer中)和一些測試代碼(在testProgs中)。四個基本庫是UsageEnvironment,BasicUsageEnvironment、groupsock和liveMedia。html
UsageEnvironment包括抽象類UsageEnvironment和抽象類TaskScheduler,這兩個類用於事件調度,其中包括實現了對事件的異步讀取、對事件句柄的設置及對錯誤信息的輸出等;UsageEnvironment表明了整個系統運行的環境,它提供了錯誤記錄和錯誤報告的功能,不管哪個類要輸出錯誤,就須要保存UsageEnvironment的指針.而TaskScheduler則提供了任務調度功能.整個程序的運行發動機就是它,它調度任務,執行任務(任務就是一個函數).TaskScheduler因爲在全局中只有一個,因此保存在了UsageEnvironment中.而全部的類又都保存了UsageEnvironment的指針,因此誰想把本身的任務加入調度中,那是很容易的.在此還看到一個結論:整個live555(服務端)只有一個線程.服務器
-
class UsageEnvironment {
-
public:
-
void reclaim();
-
-
// task scheduler:
-
TaskScheduler& taskScheduler() const {return fScheduler;}
-
-
// result message handling:
-
typedef char const* MsgString;
-
virtual MsgString getResultMsg() const = 0;
-
-
virtual void setResultMsg(MsgString msg) = 0;
-
virtual void setResultMsg(MsgString msg1, MsgString msg2) = 0;
-
virtual void setResultMsg(MsgString msg1, MsgString msg2, MsgString msg3) = 0;
-
virtual void setResultErrMsg(MsgString msg, int err = 0) = 0;
-
// like setResultMsg(), except that an 'errno' message is appended. (If "err == 0", the "getErrno()" code is used instead.)
-
-
virtual void appendToResultMsg(MsgString msg) = 0;
-
-
virtual void reportBackgroundError() = 0;
-
// used to report a (previously set) error message within
-
// a background event
-
-
virtual void internalError(); // used to 'handle' a 'should not occur'-type error condition within the library.
-
-
// 'errno'
-
virtual int getErrno() const = 0;
-
-
// 'console' output:
-
virtual UsageEnvironment& operator<<(char const* str) = 0;
-
virtual UsageEnvironment& operator<<(int i) = 0;
-
virtual UsageEnvironment& operator<<(unsigned u) = 0;
-
virtual UsageEnvironment& operator<<(double d) = 0;
-
virtual UsageEnvironment& operator<<(void* p) = 0;
-
-
// a pointer to additional, optional, client-specific state
-
void* liveMediaPriv;
-
void* groupsockPriv;
-
-
protected:
-
UsageEnvironment(TaskScheduler& scheduler); // abstract base class
-
virtual ~UsageEnvironment(); // we are deleted only by reclaim()
-
-
private:
-
TaskScheduler& fScheduler;
-
』
該庫中還有一個HashTable,這是一個通用的HashTable,在整個項目中均可以使用它,固然該HashTable也是一個抽象類。
BasicUsageEnvironment中的類主要是對UsageEnvironment中對應類的實現。網絡
groupsock,顧名思義,用於數據包的接收和發送,其同時支持多播和單播。groupsock庫中包括了GroupEId、Groupsock、GroupsockHelper、NetAddress、NetInterface等類,其中Groupsock類有兩個構造函數,一個是「for a source-independent multicast group」,另外一個是「for a source-specific multicast group」;而GroupsockHelper類主要用於讀寫Socket。Groupsock的構造函數有一個參數是struct in_addr const& groupAddr,在構造函數中首先會調用父類構造函數建立socket對象,而後判斷這個地址,如果多播地址,則加入多播組。Groupsock的兩個成員變量destRecord* fDests和DirectedNetInterfaceSet fMembers都表示目的地址集和,但我始終看不出DirectedNetInterfaceSet fMembers有什麼用,且DirectedNetInterfaceSet是一個沒有被繼承的虛類,看起來fMembers沒有什麼用。僅fDesk也夠用了,在addDestination()和removeDestination()函數中就是操做fDesk,添加或刪除目的地址。session
Groupsock::changeDestinationParameters()函數app
-
//改變目的地址的參數
-
//newDestAddr是新的目的地址
-
//newDestPort是新的目的端口
-
//newDestTTL是新的TTL
-
void Groupsock::changeDestinationParameters(
-
struct in_addr const& newDestAddr,
-
Port newDestPort,
-
int newDestTTL)
-
{
-
if (fDests == NULL)
-
return;
-
-
//獲取第一個目的地址(此處不是很明白:fDest是一個單向鏈表,每次添加一個目的地址,
-
//都會把它插入到最前目,難道這個函數僅改變最後一個添加的目的地址?)
-
struct in_addr destAddr = fDests->fGroupEId.groupAddress();
-
if (newDestAddr.s_addr != 0) {
-
if (newDestAddr.s_addr != destAddr.s_addr
-
&& IsMulticastAddress(newDestAddr.s_addr))
-
{
-
//若是目的地址是一個多播地址,則離開老的多播組,加入新的多播組。
-
socketLeaveGroup(env(), socketNum(), destAddr.s_addr);
-
socketJoinGroup(env(), socketNum(), newDestAddr.s_addr);
-
}
-
destAddr.s_addr = newDestAddr.s_addr;
-
}
-
-
portNumBits destPortNum = fDests->fGroupEId.portNum();
-
if (newDestPort.num() != 0) {
-
if (newDestPort.num() != destPortNum &&
-
IsMulticastAddress(destAddr.s_addr))
-
{
-
//若是端口也不同,則先更改自己socket的端口
-
//(實際上是關掉原先的socket的,再以新端口打開一個socket)。
-
changePort(newDestPort);
-
//而後把新的socket加入到新的多播組。
-
// And rejoin the multicast group:
-
socketJoinGroup(env(), socketNum(), destAddr.s_addr);
-
}
-
destPortNum = newDestPort.num();
-
fDests->fPort = newDestPort;
-
}
-
-
u_int8_t destTTL = ttl();
-
if (newDestTTL != ~0)
-
destTTL = ( u_int8_t) newDestTTL;
-
-
//目標地址的全部信息都在fGroupEId中,因此改變成員fGroupEId。
-
fDests->fGroupEId = GroupEId(destAddr, destPortNum, destTTL);
-
-
//(看起來這個函數好像只用於改變多播時的地址參數,
-
//以上分析是否合理,肯請高人指點)
-
}
liveMedia是很重要的一個庫,其不只包含了實現RTSP Server的類,還包含了針對不一樣流媒體類型(如TS流、PS流等)編碼的類。在該庫中,基類是Medium,層次關係很是清晰。在該庫中,有幾個很重要的類,如RTSPServer、ServerMediaSession、RTPSink、RTPInterface、FramedSource等。異步
在http://www.live555.com上的相關文檔中提到穿透防火牆的問題,方法是開啓一個HTTP的tunnel,而後咱們能夠在liveMedia庫中找到一個RTSPOverHTTPServer的類,該類解決了這樣的問題。socket
mediaServer下的live555MediaServer提供了main函數,DynamicRTSPServer繼承了RTSPServer並重寫了虛函數lookupServerMediaSession。ide
鑑於UsageEnvironment庫、BasicUsageEnvironment庫和groupsock庫中的類較少,就暫且不做分析了。這裏主要針對liveMedia庫中的主要類結構進行分析。經過查看類關係圖,能夠從總體把握,可是苦於類太多,用類關係圖看起來也不方便,因而就本身從新整理了一下,下面是 liveMedia庫的主要類結構。(注:其餘單類及結構體等不在此列出)函數
l Medium工具
n RTSPServer
n RTSPOverHTTPServer
n MediaSession
n ServerMediaSession
n ServerMediaSubsession
u OnDemandServerMediaSubsession
l FileServerMediaSubsession
n ADTSAudioFileServerMediaSubsession
n AMRAudioFileServerMediaSubsession
n H263plusVideoFileServerMediaSubsession
n MP3AudioFileServerMediaSubsession
n MPEG1or2VideoFileServerMediaSubsession
n MPEG2TransportFileServerMediaSubsession
n MPEG4VideoFileServerMediaSubsession
n WAVAudioFileServerMediaSubsession
l MPEG1or2DemuxedServerMediaSubsession
u PassiveServerMediaSubsession
n MediaSource
u FramedSource
l FramedFileSource
n ByteStreamFileSource
n ADTSAudioFileSource
n MP3FileSource
u MP3HTTPSource
l BasicUDPSource
l RTPSource
n MultiFramedRTPSource
u RawQCELPRTPSource
u AC3AudioRTPSource
u MPEG4GenericRTPSource
u RawAMRRTPSource
u H261VideoRTPSource
u H263plusVideoRTPSource
u H264VideoRTPSource
u JPEGVideoRTPSource
u MP3ADURTPSource
u MPEG1or2AudioRTPSource
u MPEG1or2VideoRTPSource
u MPEG4ESVideoRTPSource
u MPEG4GenericRTPSource
u MPEG4LATMAudioRTPSource
u DVVideoRTPSource
u QuickTimeGenericRTPSource
u SimpleRTPSource
l AMRAudioSource
n AMRDeinterleaver
n AMRAudioFileSource
l ByteStreamMultiFileSource
l DeviceSource
l JPEGVideoSource
l MPEG1or2DemuxedElementaryStream
l MPEG2TransportStreamMultiplexor
n MPEG2TransportStreamFromESSource
n MPEG2TransportStreamFromPESSource
l AudioInputDevice
n WAVAudioFileSource
l FramedFilter
n H264FUAFragmenter
n QCELPDeinterleaver
n AC3AudioStreamFramer
n ADUFromMP3Source
n uLawFromPCMAudioSource
n H264VideoStreamFramer
n MP3FromADUSource
u MP3Transcoder
n PCMFromuLawAudioSource
n MPEG2IFrameIndexFromTransportStream
n NetworkFromHostOrder16
n HostFromNetworkOrder16
n MP3ADUinterleaverBase
u MP3ADUinterleaver
u MP3ADUdeinterleaver
n MPEG2TransportStreamFramer
n EndianSwap16
n H263plusVideoStreamFramer
n MPEGVideoStreamFramer
u MPEG1or2VideoStreamFramer
l MPEG1or2VideoStreamDiscreteFramer
u MPEG4VideoStreamFramer
l MPEG4VideoStreamDiscreteFramer
n MPEG1or2AudioStreamFramer
n DVVideoStreamFramer
n MP3ADUTranscoder
n MPEG2TransportStreamTrickModeFilter
n MediaSink
u DummySink
u BasicUDPSink
u RTPSink
l MultiFramedRTPSink
n MPEG4GenericRTPSink
n VideoRTPSink
u H264VideoRTPSink
u MPEG1or2VideoRTPSink
u H263plusVideoRTPSink
u JPEGVideoRTPSink
u DVVideoRTPSink
u MPEG4ESVideoRTPSink
n AudioRTPSink
u AC3AudioRTPSink
u MPEG4LATMAudioRTPSink
u GSMAudioRTPSink
u MPEG1or2AudioRTPSink
u AMRAudioRTPSink
u MP3ADURTPSink
n SimpleRTPSink
u HTTPSink
l MPEG1or2VideoHTTPSink
u FileSink
l AMRAudioFileSink
l H264VideoFileSink
n RTCPInstance
n RTSPClient
n SIPClient
n DarwinInjector
n QuickTimeFileSink
n MPEG1or2Demux
n MPEG2TransportStreamIndexFile
n MPEG1or2FileServerDemux
n AVIFileSink
l BufferedPacketFactory
n QCELPBufferedPacketFactory
n AMRBufferedPacketFactory
n MPEG4GenericBufferedPacketFactory
n ADUBufferedPacketFactory
n QTGenericBufferedPacketFactory
n LATMBufferedPacketFactory
n H264BufferedPacketFactory
n JPEGBufferedPacketFactory
l BufferedPacket
n QCELPBufferedPacket
n AMRBufferedPacket
n MPEG4GenericBufferedPacket
n ADUBufferedPacket
n QTGenericBufferedPacket
n LATMBufferedPacket
n H264BufferedPacket
n JPEGBufferedPacket
l StreamParser
n AC3AudioStreamParser
n MPEGVideoStreamParser
u MPEG1or2VideoStreamParser
u MPEG4VideoStreamParser
n MPEG1or2AudioStreamParser
n H263plusVideoStreamParser
n MPEGProgramStreamParser
從上面這個主要的類結構能夠看出,liveMedia庫中的基類爲Medium,其下又有幾個很是重要的部分,一個是×××Subsession,除Medium父類外,全部的×××Subsession類都繼承於ServerMediaSubsession;一個是×××Source,MediaSource的frameSource下主要包含FramedFileSource、RTPSource、FramedFilter等幾個主要的部分;一個是MediaSink,以繼承於RTPSink的類居多。
-
class H264VideoFileServerMediaSubsession: public FileServerMediaSubsession {
-
public:
-
static H264VideoFileServerMediaSubsession*
-
createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource);
-
-
// Used to implement "getAuxSDPLine()":
-
void checkForAuxSDPLine1();
-
void afterPlayingDummy1();
-
-
protected:
-
H264VideoFileServerMediaSubsession(UsageEnvironment& env,
-
char const* fileName, Boolean reuseFirstSource);
-
// called only by createNew();
-
virtual ~H264VideoFileServerMediaSubsession();
-
-
void setDoneFlag() { fDoneFlag = ~0; }
-
-
protected: // redefined virtual functions
-
virtual char const* getAuxSDPLine(RTPSink* rtpSink,
-
FramedSource* inputSource);
-
virtual FramedSource* createNewStreamSource(unsigned clientSessionId,
-
unsigned& estBitrate);
-
virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock,
-
unsigned char rtpPayloadTypeIfDynamic,
-
FramedSource* inputSource);
-
-
private:
-
char* fAuxSDPLine;
-
char fDoneFlag; // used when setting up "fAuxSDPLine"
-
RTPSink* fDummyRTPSink; // ditto
-
};
-
-
#endif
此外,還包含了用於處理packet的BufferedPacketFactory和BufferedPacket及其相關子類,用於處理流分析的StreamParser及其子類。
基本上,整個liveMedia庫的主要類結構就是這樣。不過,類太多了,分析起來仍是有較大的困難。因而乎,採起去掉枝葉保留主幹的作法,將整個服務器精簡成支持一種格式的服務器,如MP3流服務器。通過分離,一個基於MP3的測試服務器的主要類結構以下所示。(注:其餘單類及結構體等不在此列出)
l Medium
n RTSPServer
n MediaSession
n ServerMediaSession
n ServerMediaSubsession
u OnDemandServerMediaSubsession
l FileServerMediaSubsession
n MP3AudioFileServerMediaSubsession
n MediaSource
u FramedSource
l FramedFileSource
n MP3FileSource
u MP3HTTPSource
l BasicUDPSource
l RTPSource
n MultiFramedRTPSource
u MP3ADURTPSource
u MPEG1or2AudioRTPSource
u SimpleRTPSource
l FramedFilter
n ADUFromMP3Source
n MP3FromADUSource
u MP3Transcoder
n MP3ADUinterleaverBase
u MP3ADUinterleaver
u MP3ADUdeinterleaver
n MP3ADUTranscoder
n MediaSink
u BasicUDPSink
u RTPSink
l MultiFramedRTPSink
n AudioRTPSink
u MPEG1or2AudioRTPSink
u MP3ADURTPSink
n RTCPInstance
l BufferedPacketFactory
n ADUBufferedPacketFactory
l BufferedPacket
n ADUBufferedPacket
根據上面這種相對簡單的類結構,分析起來就方便多了。因而,開始進入具體的分析細節了,這是一個相對漫長的過程,再加上本人的C++水平有限,這又將是一個相對艱苦的過程,一切慢慢來吧……
末了,講講啓動服務器的過程:
LIVE555是一個純粹的RTSP服務器,其服務器主類爲liveMedia庫下的RTSPServer;mediaServer下的live555MediaServer爲主程序的入口類,DynamicRTSPServer是RTSPServer的實現類。
從live555MediaServer類的入口函數main中能夠很是清晰地分析出服務器的啓動過程。
首先是createNew一個TaskSchedulers對象和一個UsageEnvironment對象,這是初始工做。
以後是一段訪問控制的代碼。而後開始進入建立RTSP服務器的代碼段,服務器指定了一個默認端口554和一個可供替代的端口8554。
接下來,createNew一個DynamicRTSPServer,這裏創建了Socket(ourSocket)在TCP的554端口(默認端口)進行監聽,而後把鏈接處理函數句柄和socket句柄傳給任務調度器(即taskScheduler),既是RTSPServer類中的這句代碼:env.taskScheduler().turnOnBackgroundReadHandling(fServerSocket, (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandler,this)。緊接着就是對socket句柄和incomingConnectionHandler句柄的處理,主要是進行關聯等。
最後,進入主循環(即env->taskScheduler().doEventLoop();),等待客戶端鏈接。服務器啓動完畢。
文章的最後,須要說明的是,在編譯運行的過程當中,我是使用VLC播放器來進行測試的,同時經過使用Ethereal的網絡分析工具抓包分析其創建到傳輸的過程,雖然在live555源代碼中關於RTSP創建及收發數據包的過程已經用代碼寫得很是清楚(這個好好分析一下源碼就能夠了),但我想,學習使用一下一些網絡分析工具對自身也是頗爲有益的。