live555 基本框架

 

從程序的結構來看,live項目包括了四個基本庫、程序入口類(在mediaServer中)和一些測試代碼(在testProgs中)。四個基本庫是UsageEnvironment,BasicUsageEnvironment、groupsock和liveMedia。html

UsageEnvironment包括抽象類UsageEnvironment和抽象類TaskScheduler,這兩個類用於事件調度,其中包括實現了對事件的異步讀取、對事件句柄的設置及對錯誤信息的輸出等;UsageEnvironment表明了整個系統運行的環境,它提供了錯誤記錄和錯誤報告的功能,不管哪個類要輸出錯誤,就須要保存UsageEnvironment的指針.而TaskScheduler則提供了任務調度功能.整個程序的運行發動機就是它,它調度任務,執行任務(任務就是一個函數).TaskScheduler因爲在全局中只有一個,因此保存在了UsageEnvironment中.而全部的類又都保存了UsageEnvironment的指針,因此誰想把本身的任務加入調度中,那是很容易的.在此還看到一個結論:整個live555(服務端)只有一個線程.服務器

 

  1.  
    class UsageEnvironment {
  2.  
    public:
  3.  
    void reclaim();
  4.  
     
  5.  
    // task scheduler:
  6.  
    TaskScheduler& taskScheduler() const {return fScheduler;}
  7.  
     
  8.  
    // result message handling:
  9.  
    typedef char const* MsgString;
  10.  
    virtual MsgString getResultMsg() const = 0;
  11.  
     
  12.  
    virtual void setResultMsg(MsgString msg) = 0;
  13.  
    virtual void setResultMsg(MsgString msg1, MsgString msg2) = 0;
  14.  
    virtual void setResultMsg(MsgString msg1, MsgString msg2, MsgString msg3) = 0;
  15.  
    virtual void setResultErrMsg(MsgString msg, int err = 0) = 0;
  16.  
    // like setResultMsg(), except that an 'errno' message is appended. (If "err == 0", the "getErrno()" code is used instead.)
  17.  
     
  18.  
    virtual void appendToResultMsg(MsgString msg) = 0;
  19.  
     
  20.  
    virtual void reportBackgroundError() = 0;
  21.  
    // used to report a (previously set) error message within
  22.  
    // a background event
  23.  
     
  24.  
    virtual void internalError(); // used to 'handle' a 'should not occur'-type error condition within the library.
  25.  
     
  26.  
    // 'errno'
  27.  
    virtual int getErrno() const = 0;
  28.  
     
  29.  
    // 'console' output:
  30.  
    virtual UsageEnvironment& operator<<(char const* str) = 0;
  31.  
    virtual UsageEnvironment& operator<<(int i) = 0;
  32.  
    virtual UsageEnvironment& operator<<(unsigned u) = 0;
  33.  
    virtual UsageEnvironment& operator<<(double d) = 0;
  34.  
    virtual UsageEnvironment& operator<<(void* p) = 0;
  35.  
     
  36.  
    // a pointer to additional, optional, client-specific state
  37.  
    void* liveMediaPriv;
  38.  
    void* groupsockPriv;
  39.  
     
  40.  
    protected:
  41.  
    UsageEnvironment(TaskScheduler& scheduler); // abstract base class
  42.  
    virtual ~UsageEnvironment(); // we are deleted only by reclaim()
  43.  
     
  44.  
    private:
  45.  
    TaskScheduler& fScheduler;
  46.  

該庫中還有一個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

 

  1.  
    //改變目的地址的參數
  2.  
    //newDestAddr是新的目的地址
  3.  
    //newDestPort是新的目的端口
  4.  
    //newDestTTL是新的TTL
  5.  
    void Groupsock::changeDestinationParameters(
  6.  
    struct in_addr const& newDestAddr,
  7.  
    Port newDestPort,
  8.  
    int newDestTTL)
  9.  
    {
  10.  
    if (fDests == NULL)
  11.  
    return;
  12.  
     
  13.  
    //獲取第一個目的地址(此處不是很明白:fDest是一個單向鏈表,每次添加一個目的地址,
  14.  
    //都會把它插入到最前目,難道這個函數僅改變最後一個添加的目的地址?)
  15.  
    struct in_addr destAddr = fDests->fGroupEId.groupAddress();
  16.  
    if (newDestAddr.s_addr != 0) {
  17.  
    if (newDestAddr.s_addr != destAddr.s_addr
  18.  
    && IsMulticastAddress(newDestAddr.s_addr))
  19.  
    {
  20.  
    //若是目的地址是一個多播地址,則離開老的多播組,加入新的多播組。
  21.  
    socketLeaveGroup(env(), socketNum(), destAddr.s_addr);
  22.  
    socketJoinGroup(env(), socketNum(), newDestAddr.s_addr);
  23.  
    }
  24.  
    destAddr.s_addr = newDestAddr.s_addr;
  25.  
    }
  26.  
     
  27.  
    portNumBits destPortNum = fDests->fGroupEId.portNum();
  28.  
    if (newDestPort.num() != 0) {
  29.  
    if (newDestPort.num() != destPortNum &&
  30.  
    IsMulticastAddress(destAddr.s_addr))
  31.  
    {
  32.  
    //若是端口也不同,則先更改自己socket的端口
  33.  
    //(實際上是關掉原先的socket的,再以新端口打開一個socket)。
  34.  
    changePort(newDestPort);
  35.  
    //而後把新的socket加入到新的多播組。
  36.  
    // And rejoin the multicast group:
  37.  
    socketJoinGroup(env(), socketNum(), destAddr.s_addr);
  38.  
    }
  39.  
    destPortNum = newDestPort.num();
  40.  
    fDests->fPort = newDestPort;
  41.  
    }
  42.  
     
  43.  
    u_int8_t destTTL = ttl();
  44.  
    if (newDestTTL != ~0)
  45.  
    destTTL = ( u_int8_t) newDestTTL;
  46.  
     
  47.  
    //目標地址的全部信息都在fGroupEId中,因此改變成員fGroupEId。
  48.  
    fDests->fGroupEId = GroupEId(destAddr, destPortNum, destTTL);
  49.  
     
  50.  
    //(看起來這個函數好像只用於改變多播時的地址參數,
  51.  
    //以上分析是否合理,肯請高人指點)
  52.  
    }


 

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的類居多。

 

  1.  
    class H264VideoFileServerMediaSubsession: public FileServerMediaSubsession {
  2.  
    public:
  3.  
    static H264VideoFileServerMediaSubsession*
  4.  
    createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource);
  5.  
     
  6.  
    // Used to implement "getAuxSDPLine()":
  7.  
    void checkForAuxSDPLine1();
  8.  
    void afterPlayingDummy1();
  9.  
     
  10.  
    protected:
  11.  
    H264VideoFileServerMediaSubsession(UsageEnvironment& env,
  12.  
    char const* fileName, Boolean reuseFirstSource);
  13.  
    // called only by createNew();
  14.  
    virtual ~H264VideoFileServerMediaSubsession();
  15.  
     
  16.  
    void setDoneFlag() { fDoneFlag = ~0; }
  17.  
     
  18.  
    protected: // redefined virtual functions
  19.  
    virtual char const* getAuxSDPLine(RTPSink* rtpSink,
  20.  
    FramedSource* inputSource);
  21.  
    virtual FramedSource* createNewStreamSource(unsigned clientSessionId,
  22.  
    unsigned& estBitrate);
  23.  
    virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock,
  24.  
    unsigned char rtpPayloadTypeIfDynamic,
  25.  
    FramedSource* inputSource);
  26.  
     
  27.  
    private:
  28.  
    char* fAuxSDPLine;
  29.  
    char fDoneFlag; // used when setting up "fAuxSDPLine"
  30.  
    RTPSink* fDummyRTPSink; // ditto
  31.  
    };
  32.  
     
  33.  
    #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創建及收發數據包的過程已經用代碼寫得很是清楚(這個好好分析一下源碼就能夠了),但我想,學習使用一下一些網絡分析工具對自身也是頗爲有益的。

相關文章
相關標籤/搜索