live555 基本框架


 

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

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,添加或刪除目的地址。

Groupsock::changeDestinationParameters()函數

 

  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的類,該類解決了這樣的問題。

mediaServer下的live555MediaServer提供了main函數,DynamicRTSPServer繼承了RTSPServer並重寫了虛函數lookupServerMediaSession。

 

鑒於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建立及收發數據包的過程已經用代碼寫得非常清楚(這個好好分析一下源碼就可以了),但我想,學習使用一下一些網絡分析工具對自身也是頗為有益的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM