流媒體學習筆記2(live555中的Session)

畢業課題打算從最原始的地方做起。好吧,那就從live555採集轉發本地攝像頭視頻開始吧。首先從源碼開始吧,今天看了點liveMedia中的session,這裏做個總結。

整個源碼中的繼承順序爲

H264VideoFileServerMediaSubsession::FileServerMediaSubsession::                                                                       OnDemandServerMediaSubsession::ServerMediaSubsession ::Medium

ServerMediaSession ::Medium

Medium:抽象了基本的接口,包括環境,task和媒體名和媒體查找函數以及一些輔助函數,幾乎所有得處理單元都繼承自Medium類。

ServerMediaSession:添加了子會話鏈表,SDP(Session Description Protocol 會話協議)描述以及一些媒體相關處理函數。其中靜態成員函數lookupByName可以從session鏈表中找到對應的媒體

ServerMediaSubsession:定義了指向ServerMediaSession的父指針,指向下個一個對象的指針。該媒體的SDP信息,該媒體的讀取定位函數等。

ServerMediaSubsessionIterator:一個迭代器類,用來遍歷subsession鏈表。

程序爲容器中的每一個流建立一個subseesion,然後通過 ServerMediaSession::addSubsession 函數,將subsession 加入到ServerMediaSession。具體代碼如下

ServerMediaSession::addSubsession(ServerMediaSubsession* subsession) {
  if (subsession->fParentSession != NULL) return False; // it's already used

  if (fSubsessionsTail == NULL) {
    fSubsessionsHead = subsession;
  } else {
    fSubsessionsTail->fNext = subsession;
  }
  fSubsessionsTail = subsession;

  subsession->fParentSession = this;
  subsession->fTrackNumber = ++fSubsessionCounter;
  return True;
}

ServerMediaSession與流名字所指定與文件是沒有關係的,也就是說它不會操作文件,而文件的操作是放在 ServerMediaSubsession中的。具體應該是在ServerMediaSubsession的sdpLines()函數中打開。sdpLines()是在派生類OnDemandServerMediaSubsession中實現,代碼如下

char const*
OnDemandServerMediaSubsession::sdpLines() {
  if (fSDPLines == NULL) {
    // We need to construct a set of SDP lines that describe this
    // subsession (as a unicast stream).  To do so, we first create
    // dummy (unused) source and "RTPSink" objects,
    // whose parameters we use for the SDP lines:

	//構建一套SDP行來描述這個Subsession。創建未使用的source和RTPSink對象
    unsigned estBitrate;
    FramedSource* inputSource = createNewStreamSource(0, estBitrate);
    if (inputSource == NULL) return NULL; // file not found

    struct in_addr dummyAddr;
    dummyAddr.s_addr = 0;
    Groupsock dummyGroupsock(envir(), dummyAddr, 0, 0);
    unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic
    RTPSink* dummyRTPSink
      = createNewRTPSink(&dummyGroupsock, rtpPayloadType, inputSource);
	//Sink中的到SDP
    setSDPLinesFromRTPSink(dummyRTPSink, inputSource, estBitrate);
    Medium::close(dummyRTPSink);
    closeStreamSource(inputSource);
  }

  return fSDPLines;
}

OnDemandServerMediaSubsession類繼承 ServerMediaSubsession類,OnDemand實際上用來描述需求,Subsession表示只是一種類型媒體的會話。所以可以通過繼承OnDemandServerMediaSubsession來實現不同類型的媒體轉發,比如OnDemandServerMediaSubsession的兩個子類

1.ProxyServerMediaSubsession:用於實現一個單播RTSP的服務器代理另一個RTSP流

2.FileServerMediaSubsession:虛基類,不同類型媒體通過繼承它來實現對於需求,比如音頻,視頻,比如h263,h264編解碼。FileServerMediaSubsession類只是添加了兩個成員變量 fFileName,fFileSize用來描述轉發的媒體。構造函數如下:

FileServerMediaSubsession
::FileServerMediaSubsession(UsageEnvironment& env, char const* fileName,
			    Boolean reuseFirstSource)
  : OnDemandServerMediaSubsession(env, reuseFirstSource),
    fFileSize(0) {
  fFileName = strDup(fileName);
}

而H264VideoFileServerMediaSubsession類繼承了FileServerMediaSubsession,它將構造函數放入protected中,並用靜態的成員方法createNew來實例對象,這是設計模式的工廠模式。createNew(env, fileName, reuseSource)是每一種類型的流媒體自己的subsession實現。如果 reuseSource == True,則多個客戶端共享 StreamState 對象,也即意味着多個客戶端播放同一流文件時,服務器端使用同一FileSource 對象對該流文件進行數據讀取操作,使用同一RTPSink 對象對流數據進行封裝發送操作,這時,多個客戶端播放的內容就是同步的,這適合於實時數據播放;如果reuseSource==False,則對每個客戶端,服務器端單獨維護一個StreamState 對象進行播放操作,此時,多個客戶端播放的內容就是獨立的,這適合於數據回放。

當然,單看session看不出什麼門道來,那看下面

SDP消息組裝過程:
      ServerMediaSession負責產生會話公共描述信息,子會話描述由H264VideoFileServerMediaSubsession產生。 H264VideoFileServerMediaSubsession在其父類成員函數OnDemandServerMediaSubsession::sdpLines()中生成會話描述信息。在sdpLines()實現裏面,創建一個FramedSource(具體實現類爲H264VideoStreamFramer)和RTPSink(具體實現類爲H264VideoRTPSink),最後調用OnDemandServerMediaSubsession::setSDPLinesFromRTPSink(...)成員函數生成子會話描述。

好吧,這樣思路基本清楚了點,以後要寫自己需要的編解碼類,那就繼承OnDemandServerMediaSubsession吧。對於souce-sink 機制下次講了....

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章