轉(zhuǎn)載自:http://blog.sina.com.cn/s/blog_77c632410101as1i.html
liveMedia項(xiàng)目的源代碼包括四個(gè)基本的庫(kù),各種測(cè)試代碼以及Media Server。四個(gè)基本的庫(kù)分別是:
UsageEnvironment&TaskScheduler, groupsock, liveMedia和BasicUsageEnvironment。
1,基礎(chǔ)類介紹:
BasicUsageEnvironment和UsageEnvironment中的類都是用于整個(gè)系統(tǒng)的基礎(chǔ)功能類.用于事件的調(diào)度,實(shí)現(xiàn)異步讀取事件的句柄的設(shè)置以及錯(cuò)誤信息的輸出。比如UsageEnvironment代表了整個(gè)系統(tǒng)運(yùn)行的環(huán)境,它提供了錯(cuò)誤記錄和錯(cuò)誤報(bào)告的功能,無(wú)論哪一個(gè)類要輸出錯(cuò)誤,就需要保存UsageEnvironment的指針.而TaskScheduler則提供了任務(wù)調(diào)度功能.整個(gè)程序的運(yùn)行發(fā)動(dòng)機(jī)就是它,它調(diào)度任務(wù),執(zhí)行任務(wù)(任務(wù)就是一個(gè)函數(shù)).TaskScheduler由于在全局中只有一個(gè),所以保存在了UsageEnvironment中.而所有的類又都保存了UsageEnvironment的指針,所以誰(shuí)想把自己的任務(wù)加入調(diào)度中,那是很容易的.在此還看到一個(gè)結(jié)論:整個(gè)live555(服務(wù)端)只有一個(gè)線程.
類HashTable:實(shí)現(xiàn)了哈稀表.定義了一個(gè)通用的hash表,其它代碼要用到這個(gè)表。
liveMedia庫(kù)中有一系列類,基類是Medium,這些類針對(duì)不同的流媒體類型和編碼。
基于liveMedia的程序,需要通過(guò)繼承UsageEnvironment抽象類和TaskScheduler抽象類,定義相應(yīng)的類來(lái)處理事件調(diào)度,數(shù)據(jù)讀寫以及錯(cuò)誤處理。live項(xiàng)目的源代碼里有這些類的一個(gè)基本實(shí)現(xiàn),這就是“BasicUsageEnvironment”庫(kù)。BasicUsageEnvironment主要是針對(duì)簡(jiǎn)單的控制臺(tái)應(yīng)用程序,利用select實(shí)現(xiàn)事件獲取和處理。這個(gè)庫(kù)利用Unix或者Windows的控制臺(tái)作為輸入輸出,出于應(yīng)用程序原形或者調(diào)試的目的,用戶可以用這個(gè)庫(kù)開發(fā)傳統(tǒng)的運(yùn)行與控制臺(tái)的應(yīng)用。
類DelayQueue:譯為"延遲隊(duì)列",它是一個(gè)隊(duì)列,每一項(xiàng)代表了一個(gè)要調(diào)度的任務(wù)(在它的fToken變量中保存).同時(shí)保存了這個(gè)任務(wù)離執(zhí)行時(shí)間點(diǎn)的剩余時(shí)間.可以預(yù)見,它就是在TaskScheduler中用于管理調(diào)度任務(wù)的東西.注意,此隊(duì)列中的任務(wù)只被執(zhí)行一次!執(zhí)行完后這一項(xiàng)即被無(wú)情拋棄!
類HandlerSet:Handler集合.Handler是什么呢?它是一種專門用于執(zhí)行socket操作的任務(wù)(函數(shù)),HandlerSet被TaskScheduler用來(lái)管理所有的socket任務(wù)(增刪改查).所以TaskScheduler中現(xiàn)在已調(diào)度兩種任務(wù)了:socket任務(wù)(handlerSet)和延遲任務(wù)(DelayQueue).其實(shí)TaskScheduler還調(diào)度第三種任務(wù):Event,這個(gè)后面再說(shuō).
類Groupsock:這個(gè)是放在單獨(dú)的庫(kù)Groupsock中。它封裝了socket操作,增加了多播支持和一對(duì)多單播的功能.但好像不支持TCP。它管理著一個(gè)本地socket和多個(gè)目的地址,因?yàn)槭?/span>UDP,所以只需知道對(duì)方地址和端口即可發(fā)送數(shù)據(jù)。Groupsock的構(gòu)造函數(shù)有一個(gè)參數(shù)是struct in_addr const& groupAddr,在構(gòu)造函數(shù)中首先會(huì)調(diào)用父類構(gòu)造函數(shù)創(chuàng)建socket對(duì)象,然后判斷這個(gè)地址,若是多播地址,則加入多播組。Groupsock的兩個(gè)成員變量destRecord* fDests和DirectedNetInterfaceSet fMembers都表示目的地址集和,但貌似這個(gè)變量DirectedNetInterfaceSet fMembers沒(méi)有用到,且DirectedNetInterfaceSet是一個(gè)沒(méi)有被繼承的虛類,看起來(lái)fMembers沒(méi)有什么用。僅fDesk也夠用了,在addDestination()和removeDestination()函數(shù)中就是操作fDesk,添加或刪除目的地址。
2,基本概念
先來(lái)熟悉在liveMedia庫(kù)中Source,Sink以及Filter等概念。Sink就是消費(fèi)數(shù)據(jù)的對(duì)象,比如把接收到的數(shù)據(jù)存儲(chǔ)到文件,這個(gè)文件就是一個(gè)Sink。Source就是生產(chǎn)數(shù)據(jù)的對(duì)象,比如通過(guò)RTP讀取數(shù)據(jù)。數(shù)據(jù)流經(jīng)過(guò)多個(gè)'source'和'sinks',下面是一個(gè)示例:
source1' -> 'source2' (a filter) -> 'source3' (a filter) -> 'sink'
從其它Source接收數(shù)據(jù)的source也叫做"filters"。Module是一個(gè)sink或者一個(gè)filter。數(shù)據(jù)接收的終點(diǎn)是Sink類,MediaSink是所有Sink類的基類。Sink類實(shí)現(xiàn)對(duì)數(shù)據(jù)的處理是通過(guò)實(shí)現(xiàn)純虛函數(shù)continuePlaying(),通常情況continuePlaying調(diào)用fSource -> getNextFrame來(lái)為Source設(shè)置數(shù)據(jù)緩沖區(qū),處理數(shù)據(jù)的回調(diào)函數(shù)等,fSource是MediaSink的類型為FramedSource*的類成員。
3,計(jì)劃任務(wù)(TaskScheduler)深入探討
我們且把三種任務(wù)命名為:socket handler,event handler,delay task。
這三種任務(wù)的特點(diǎn)是,前兩個(gè)加入執(zhí)行隊(duì)列后會(huì)一直存在,而delay task在執(zhí)行完一次后會(huì)立即棄掉。
socket handler保存在隊(duì)列BasicTaskScheduler0::HandlerSet* fHandlers中;
event handler保存在數(shù)組BasicTaskScheduler0::TaskFunc *
fTriggeredEventHandlers[MAX_NUM_EVENT_TRIGGERS]中;
delay task保存在隊(duì)列BasicTaskScheduler0::DelayQueue fDelayQueue中。
下面看一下三種任務(wù)的執(zhí)行函數(shù)的定義:
socket handler為
typedef void BackgroundHandlerProc(void* clientData, int mask);
event handler為
typedef void TaskFunc(void* clientData);
delay task 為
typedef void TaskFunc(void* clientData);//跟event handler一樣。
再看一下向任務(wù)調(diào)度對(duì)象添加三種任務(wù)的函數(shù)的樣子:
socket handler為:
void setBackgroundHandling(int socketNum, int conditionSet ,BackgroundHandlerProc* handlerProc, void* clientData)
event handler為:
EventTriggerId createEventTrigger(TaskFunc* eventHandlerProc)
delay task為:
TaskToken scheduleDelayedTask(int64_t microseconds, TaskFunc* proc,void* clientData)
socket handler添加時(shí)為什么需要那些參數(shù)呢?socketNum是需要的,因?yàn)橐?/span>select socket(socketNum即是socket()返回的那個(gè)socket對(duì)象)。conditionSet也是需要的,它用于表明socket在select時(shí)查看哪種裝態(tài),是可讀?可寫?還是出錯(cuò)?再看BackgroundHandlerProc的參數(shù),socketNum不必解釋,mask是什么呢?它正是對(duì)應(yīng)著conditionSet,但它表明的是select之后的結(jié)果,比如一個(gè)socket可能需要檢查其讀/寫狀態(tài),而當(dāng)前只能讀,不能寫,那么mask中就只有表明讀的位被設(shè)置。
event handler是被存在數(shù)組中。數(shù)組大小固定,是32項(xiàng),用EventTriggerId來(lái)表示數(shù)組中的項(xiàng),EventTriggerId是一個(gè)32位整數(shù),因?yàn)閿?shù)組是32項(xiàng),所以用EventTriggerId中的第n位置1表明對(duì)應(yīng)數(shù)組中的第n項(xiàng)。成員變量fTriggersAwaitingHandling也是EventTriggerId類型,它里面置1的那些位對(duì)應(yīng)了數(shù)組中所有需要處理的項(xiàng)。這樣做節(jié)省了內(nèi)存和計(jì)算,但降低了可讀性,而且也不夠靈活,只能支持32項(xiàng)或64項(xiàng),其它數(shù)量不被支持。