1. 程式人生 > >庖丁解牛-----Live555原始碼徹底解密(v0.78--2013.09.18)

庖丁解牛-----Live555原始碼徹底解密(v0.78--2013.09.18)

#define LIVEMEDIA_LIBRARY_VERSION_STRING "2013.09.18"

live555中主要包括以下幾個庫:UsageEnvironment ,BasicUsageEnvironment,groupsock,LiveMedia;其中

UsageEnvironment包括抽象類UsageEnvironment和抽象類TaskScheduler,這兩個類用於事件排程,其中包括實現了對事件的非同步讀取、對事件控制代碼的設定及對錯誤資訊的輸出等;該庫中還有一個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。

liveMedia是很重要的一個庫,其不僅包含了實現RTSP Server的類,還包含了針對不同流媒體型別(如TS流、PS流等)編碼的類。在該庫中,基類是Medium,層次關係非常清晰。在該庫中,有幾個很重要的類,如RTSPServer、ServerMediaSession、RTPSink、RTPInterface、FramedSource等。

下面直接上原始碼:

class TaskScheduler; // forward

// An abstract base class, subclassed for each use of the library

class UsageEnvironment

{

public:

  void reclaim();

  // task scheduler:

  TaskScheduler& taskScheduler() const {returnfScheduler;}

  // result message handling:

  typedef char const* MsgString;

  virtual MsgString getResultMsg() const = 0;

  virtual void setResultMsg(MsgStringmsg) = 0;

  virtual void setResultMsg(MsgStringmsg1,MsgStringmsg2) = 0;

  virtual void setResultMsg(MsgStringmsg1,MsgStringmsg2,MsgStringmsg3) = 0;

  virtual void setResultErrMsg(MsgStringmsg,interr = 0) = 0;

     // like setResultMsg(), except that an 'errno' message is appended. (If "err == 0", the "getErrno()" code is used instead.)

  virtual void appendToResultMsg(MsgStringmsg) = 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<<(charconst*str) = 0;

  virtual UsageEnvironment& operator<<(inti) = 0;

  virtual UsageEnvironment& operator<<(unsignedu) = 0;

  virtual UsageEnvironment& operator<<(doubled) = 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;

};

1.1UsageEnvironment中包含TaskScheduler的引用,可以通過fScheduler呼叫TaskScheduler類中的函式;

private:

  TaskScheduler& fScheduler;

 

UsageEnvironment類中的建構函式式保護的,TaskScheduler類中的建構函式是私有的;因為它們都是一個抽象的基類,不能生成物件,所以不需要呼叫建構函式;因為UsageEnvironment的建構函式是保護的,所以在派生類中可以呼叫該建構函式,比如在派生類的建構函式中就可以呼叫它。

UsageEnvironment類中有2個指標liveMediaPriv和groupsockPriv;

  // a pointer to additional, optional, client-specific state

  void* liveMediaPriv;

  void* groupsockPriv;

1.2) BasicUsageEnvironment0類和BasicUsageEnvironment

 

為什麼要增加中間的一層繼承類呢;BasicUsageEnvironment0中實現了setResultMsg等函式,而BasicUsageEnvironment中實現了'console' output,<<運算子過載;

class BasicTaskScheduler: public BasicTaskScheduler0 {

public:

  static BasicTaskScheduler* createNew(unsignedmaxSchedulerGranularity = 10000/*microseconds*/);

    // "maxSchedulerGranularity" (default value: 10 ms) specifies the maximum time that we wait (in "select()") before

    // returning to the event loop to handle non-socket or non-timer-based events, such as 'triggered events'.

    // You can change this is you wish (but only if you know what you're doing!), or set it to 0, to specify no such maximum time.

    // (You should set it to 0 only if you know that you will not be using 'event triggers'.)

  virtual ~BasicTaskScheduler();

protected:

  BasicTaskScheduler(unsignedmaxSchedulerGranularity);

      // called only by "createNew()"

  static void schedulerTickTask(void*clientData);

  void schedulerTickTask();

protected:

  // Redefined virtual functions:

  virtual void SingleStep(unsignedmaxDelayTime);

  virtual void setBackgroundHandling(intsocketNum,intconditionSet,BackgroundHandlerProc*handlerProc,void*clientData);

  virtual void moveSocketHandling(intoldSocketNum,intnewSocketNum);

protected:

  unsigned fMaxSchedulerGranularity;

  // To implement background operations:

  int fMaxNumSockets;

  fd_set fReadSet;

  fd_set fWriteSet;

  fd_set fExceptionSet;

};

BasicTaskScheduler中包含有讀寫sokcet的操作  int fMaxNumSockets; fReadSet,fWriteSet,fExceptionSet。

1)  socket類(groupsock)的繼承關係圖如下:

 

Groupsock有一個讀的函式:

Boolean Groupsock::handleRead(unsignedchar*buffer,unsignedbufferMaxSize,

                    unsigned& bytesRead,

                    struct sockaddr_in& fromAddress) {

  // Read data from the socket, and relay it across any attached tunnels

  //##### later make this code more general - independent of tunnels

  bytesRead = 0;

  int maxBytesToRead = bufferMaxSize - TunnelEncapsulationTrailerMaxSize;

  int numBytes = readSocket(env(),socketNum(),

                  buffer, maxBytesToRead, fromAddress);

  if (numBytes < 0) {

    if (DebugLevel >= 0) {// this is a fatal error

      env().setResultMsg("Groupsock read failed: ",

               env().getResultMsg());

    }

    return False;

  }

  // If we're a SSM group, make sure the source address matches:

  if (isSSM()

      && fromAddress.sin_addr.s_addr !=sourceFilterAddress().s_addr) {

    return True;

  }

  // We'll handle this data.

  // Also write it (with the encapsulation trailer) to each member,

  // unless the packet was originally sent by us to begin with.

  bytesRead = numBytes;

  int numMembers = 0;

  if (!wasLoopedBackFromUs(env(),fromAddress)) {

    statsIncoming.countPacket(numBytes);

    statsGroupIncoming.countPacket(numBytes);

    numMembers =

      outputToAllMembersExcept(NULL,ttl(),

                     buffer, bytesRead,

                     fromAddress.sin_addr.s_addr);

    if (numMembers > 0) {

      statsRelayedIncoming.countPacket(numBytes);

      statsGroupRelayedIncoming.countPacket(numBytes);

    }

  }

  if (DebugLevel >= 3) {

    env() << *this <<": read " <<bytesRead <<" bytes from " <<AddressString(fromAddress).val();

    if (numMembers > 0) {

      env() << "; relayed to " << numMembers << " members";

    }

    env() << "\n";

  }

  return True;

}

groupsock 支援tcp操作嗎?

4)LiveMedia

LiveMedia是一個相當複雜的庫,包括流媒體的傳輸等操作;下次單獨講解;