賀靜海,華云松
(上海理工大學(xué) 光電信息與計算機工程學(xué)院,上海 200093)
目前常采用基于OpenMAX標(biāo)準(zhǔn)接口與多媒體協(xié)處理器的多媒體解決方案,來開發(fā)手機多媒體功能,上層應(yīng)用通過OpenMAX組件在協(xié)處理器中運行相關(guān)Codec,處理數(shù)據(jù)。這種常用的解決方案的優(yōu)點是:移植性高,設(shè)計周期短,成本低;缺點是:受協(xié)處理器內(nèi)存限制,無法同時運行所有Codec,若多個組件同時申請資源時,就會產(chǎn)生資源沖突,影響系統(tǒng)運行,甚至發(fā)生死機。
針對上述目前常用方案的缺點,文中提出的解決方法基于OpenMAX流程規(guī)范,根據(jù)Codec類型將協(xié)處理器內(nèi)存資源劃分為音頻解碼、音頻編碼、視頻解碼、視頻編碼4種不同運行空間(數(shù)據(jù)和指令空間),并對其進(jìn)行管理及維護(hù),為OpenMAX組件進(jìn)行資源獲取、釋放、搶占等操作行為提供接口。在多組件同時訪問協(xié)處理器資源時,根據(jù)組件優(yōu)先級對資源實施實時仲裁,實現(xiàn)資源被單一組件互斥使用,完成系統(tǒng)并發(fā)需求。
OpenMAX[1]是由Khronos制定的多媒體應(yīng)用程序標(biāo)準(zhǔn)接口,主要針對嵌入式設(shè)備或移動設(shè)備,在架構(gòu)底層上為多媒體Codec和數(shù)據(jù)處理定義了一套統(tǒng)一的編程接口(OpenMAX IL API),對多媒體數(shù)據(jù)的處理功能進(jìn)行系統(tǒng)級抽象,為用戶屏蔽了底層的細(xì)節(jié)。圖1是OpenMAX IL API軟件全貌,OpenMAX IL API有個高層實體,稱為IL客戶端(IL client),該客戶端通常是一個filter graph多媒體框架或者應(yīng)用程序的一個功能片,IL client通過OpenMAX組件調(diào)用OpenMAX IL API可以以一種統(tǒng)一的方式來使用Codec和其他多媒體數(shù)據(jù)處理功能,無需擔(dān)心其底層的硬件結(jié)構(gòu)。
OpenMAX組件代表一個具體的功能模塊,可以是文件解析組件,也可以是編解碼組件等。OpenMAX組件有Loaded,Idle,Executin與WaitingForResource等6種狀態(tài)。每個組件最開始處于Loaded狀態(tài),當(dāng)組件開始執(zhí)行任務(wù)時,先轉(zhuǎn)到Idle狀態(tài),這時需要獲取資源,如果獲取資源失敗,則轉(zhuǎn)入WaitingForResource狀態(tài),之后從Idle狀態(tài)轉(zhuǎn)入Executing狀態(tài)開始執(zhí)行任務(wù),當(dāng)執(zhí)行完任務(wù)時,組件釋放資源并轉(zhuǎn)入Loaded狀態(tài)。一旦組件正在使用的資源遭搶占,組件釋放資源再進(jìn)入WaitForResource狀態(tài)等待該資源可用。
圖2是以O(shè)penMAX部分組件為例的資源管理器框架示意圖,圖的右側(cè)根據(jù)不同類型的Codec對協(xié)處理器資源進(jìn)行劃分,不同的Codec在運行時用到對應(yīng)的資源。左側(cè)羅列了常用的OpenMAX編解碼組件,并根據(jù)組件種類分成4組,同一組內(nèi)的組件在運行時會用到相同的資源。例如,F(xiàn)R編碼和AMR編碼均會用到音頻編碼的數(shù)據(jù)段和程序段,當(dāng)這兩個組件同時申請資源時就會發(fā)生資源沖突。
圖1 OpenMAX IL API軟件全貌Fig.1 OpenMAX IL API software landscape
圖2 系統(tǒng)框架Fig.2 System framework
資源管理器目前維護(hù)多個組件對一個互斥資源的訪問,即在系統(tǒng)出現(xiàn)多個組件同時需要占用一個資源的情況下,根據(jù)組件的優(yōu)先級進(jìn)行資源的分配。每個組件由IL Client設(shè)置一個優(yōu)先級值,當(dāng)比較兩個含有相同優(yōu)先級值的組件時,新近注冊等待該資源的組件的優(yōu)先級高于較長時間前注冊的組件。如下是資源管理器需在相應(yīng)情形下應(yīng)完成的相應(yīng)功能:
(1)資源空閑時,組件發(fā)起資源請求:組件獲得資源。
(2)低優(yōu)先級的組件正占用資源時,高優(yōu)先級組件發(fā)起資源請求:通知低優(yōu)級組件資源將被搶占,等待低優(yōu)先級組件釋放資源,低優(yōu)先級組件釋放資源后可根據(jù)需要選擇是否進(jìn)入資源等待隊列,高優(yōu)先級組件獲得資源。
(3)高優(yōu)先級的組件正占用資源時,低優(yōu)先級組件發(fā)起資源請求:通知低優(yōu)先級組件資源不可用,上層將組件注冊進(jìn)入資源等待隊列,在資源可用的時候得到通知。
(4)接受組件釋放資源。
(5)當(dāng)組件使用資源完畢時,資源等待隊列為空:資源釋放后不做其他操作。
(6)當(dāng)組件使用資源完畢,資源等待隊列不為空:資源釋放后,找到資源等待隊列中優(yōu)先級最高的組件,知組件資源可用。
圖3是系統(tǒng)發(fā)生資源的獲取、搶占與恢復(fù)的主要流程,其中當(dāng)前組件為正在使用資源的組件。
組件調(diào)用AcquireResource接口申請資源,如果資源空閑,組件注冊為資源使用者。如果資源正在被使用,組件與當(dāng)前組件進(jìn)行優(yōu)先級的比較,組件優(yōu)先級高則資源管理器調(diào)用內(nèi)部接口ReleaseResourceRequest請求當(dāng)前組件釋放資源,等當(dāng)前組件釋放完資源,組件注冊為資源使用者;不然組件則調(diào)用WaitForResourceReques申請等待該資源,資源管理器響應(yīng)該請求并把組件添加到等待對列中。
組件處理完任務(wù)后調(diào)用接口ReleaseResource釋放資源,資源管理器查看等待隊列是否有等待該資源的組件,沒有則進(jìn)行反初始化,有則調(diào)用內(nèi)部接口WaitForResourceResponse給優(yōu)先級最高的組件,通知其資源可用,并把它注冊為資源使用者。
圖3 系統(tǒng)流程圖Fig.3 System flow chart
資源對象與資源管理器對象是資源管理器最主要的兩個數(shù)據(jù)結(jié)構(gòu)體。資源對象記錄了資源名稱,資源使用者指針等數(shù)據(jù),資源管理器通過此結(jié)構(gòu)體實現(xiàn)對資源的操作。資源管理器對象維護(hù)了一張可用資源鏈表。
3.1.1 資源對象
3.1.2 資源管理器
組件到資源管理器的交互通過接口函數(shù),資源管理器到組件通信通過消息傳遞。接口函數(shù)內(nèi)部既可以用函數(shù)執(zhí)行直接實現(xiàn),也可通過消息機制實現(xiàn),資源管理器主要基于直接執(zhí)行模式。
3.2.1 資源管理器操作相關(guān)接口
資源管理器操作主要完成資源管理器和資源的創(chuàng)建刪除以及信息查詢等。在實現(xiàn)中,在資源管理器操作類接口的訪問不做保護(hù),這些保護(hù)主要涉及到rm_Deinit()和rm_DeleteResource(),即在進(jìn)行資源銷毀之前不對資源當(dāng)前的狀態(tài)做任何檢查,同時對這兩個函數(shù)與組件調(diào)用類接口之間也不做互斥訪問保護(hù)。這樣,就要求rm_Deinit()和rm_DeleteResource()的調(diào)用時機由調(diào)用者確認(rèn),即保證沒有任何組件使用或注冊資源的時候進(jìn)行操作。主要包括以下函數(shù);
rm_Init()創(chuàng)建一個資源管理器,初始化并返回句柄,需確??芍貜?fù)調(diào)用。
rm_Deinit()釋放資源管理器中的所有資源,并最終釋放資源管理器。在釋放資源時,會通知所有關(guān)聯(lián)的組件釋放該資源。
rm_AddResource()為資源管理器增加一個資源。
rm_DeleteResource()刪除資源管理器中的一個資源。該函數(shù)對被釋放資源不做任何檢查,在調(diào)用該函數(shù)前需要確保資源已經(jīng)被所有相關(guān)組件釋放,否則該函數(shù)釋放資源后相關(guān)組件會發(fā)生不可預(yù)知后果。
3.2.2 組件調(diào)用接口
所有組件調(diào)用函數(shù)都會對等待列表進(jìn)行操作,檢查等待者隊列,如果等待者符合執(zhí)行條件,就會被加為使用者。以下組件調(diào)用接口是在組件資源操作過程中頻繁使用的接口,通過互斥量pRsrc->mtxOp,保證互斥訪問。
rm_AcquireResource():請求一個資源,可設(shè)定搶占超時,搶占在規(guī)定時間內(nèi)無法完成,則資源請求失敗。函數(shù)工作流程:
rm_ReleaseResourceResponse():搶占請求時,被搶占組件釋放指定的資源,在實現(xiàn)中,該接口的功能可以統(tǒng)一到rm_ReleaseResource(),但為了兼容性該接口仍保留,實質(zhì)上調(diào)用這兩接口沒有區(qū)別。
3.2.3 組件回調(diào)函數(shù)
回調(diào)函數(shù)完成從資源管理器向組件的通信。由于回調(diào)函數(shù)在資源管理器的線程中執(zhí)行,因此它必須是非阻塞的,所有需要延遲處理的工作一般需要在回調(diào)函數(shù)中通過向組件發(fā)送事件的方式完成。每個資源資源管理器維護(hù)一組組件回調(diào)函數(shù)指針和對應(yīng)用戶指針,組件回調(diào)包括以下兩個:
ReleaseResourceRequest():它向OpenMAX組件發(fā)送釋放資源消息[5],通知組件應(yīng)當(dāng)讓出當(dāng)前資源(給更高優(yōu)先級組件使用),OpenMAX組件的消息線程根據(jù)消息調(diào)用rm_ReleaseResource()來釋放資源。函數(shù)實現(xiàn):
WaitForResourceResponse():penMAX發(fā)送事件通知處于等待資源狀態(tài)的組件資源可以使用,組件消息線程根據(jù)事件初始化等待資源的組件,進(jìn)行相關(guān)處理。
3.2.4 內(nèi)部實現(xiàn)函數(shù)
內(nèi)部實現(xiàn)函數(shù)主要供組件調(diào)用函數(shù)調(diào)用,主要函數(shù)如下:
InsertClient():用于在組件鏈表(RM_LIST類型)中添加一個組件。
RemoveClient():用于根據(jù)組件單元指針(RM_CLIENT*)類型組件鏈表中刪除一個組件。
Serve()[6]:維護(hù)資源,被組件接口調(diào)用,執(zhí)行組件pUser指針為空,則從等待鏈表中提取最高優(yōu)先級的組件作為pUser;當(dāng)執(zhí)行組件pUser的優(yōu)先級低于等待鏈表中最高優(yōu)先級組件則進(jìn)行搶占。函數(shù)工作
流程如下;
通過測試用例對資源獲取,搶占及恢復(fù)進(jìn)行測試,測試其功能性,規(guī)范性及正確性。
在ADS環(huán)境下編譯包含資源管理器和相關(guān)測試組件的測試工程,并通過TRACE將代碼下載到EVB板上。硬件配置:EVB板,橫河仿真器。軟件配置:ADS1.2,TRACE32
資源的獲取,搶占等操作是在組件進(jìn)行狀態(tài)轉(zhuǎn)換過程中,通過組件消息線程調(diào)用資源管理器接口進(jìn)行,資源管理器一旦成功完成相關(guān)的操作,線程就會釋放事件信號量,如果資源管理器操作失敗系統(tǒng)就會死在線程里。測試用例的原理就是兩個組件先后申請資源,通過在等待事件信號量后加LOG打印函數(shù)TEST_CRIT來反映系統(tǒng)運行情況,從而體現(xiàn)資源管理器的相關(guān)操作是否成功。測試用例代碼如下:
測試結(jié)果如圖4所示。
結(jié)果顯示組件能順利的進(jìn)行狀態(tài)的轉(zhuǎn)換,表明資源管理器能成功進(jìn)行資源的調(diào)配。但發(fā)現(xiàn)當(dāng)組件正在處理幀數(shù)據(jù)時,發(fā)生資源被其他組件搶占,會導(dǎo)致當(dāng)前幀的處理出現(xiàn)錯誤并丟棄。為了防止這種情況的出現(xiàn),在系統(tǒng)中增加一個互斥量[8]將數(shù)據(jù)處理過程與搶占過程進(jìn)行互斥。組件調(diào)用獲取資源接口前,先申請該互斥量,完成后續(xù)工作之后再釋放該互斥量,使用這種方法來可以保證搶占時數(shù)據(jù)處理的正確性。
圖4 測試結(jié)果Fig.4 The result of test
目前,組件發(fā)生資源沖突時,通過該資源管理器OpenMAX用戶可以接收到相應(yīng)的消息事件,自動完成資源的調(diào)度,從而解決資源沖突問題。該方法思路簡單清晰,易于實現(xiàn)。但當(dāng)出現(xiàn)資源與資源、資源與組件之間關(guān)系比較復(fù)雜,不能表現(xiàn)出簡單的互斥性時,例如,音頻解碼空間可能需要占用音頻編碼空間或者視頻解碼空間時,音頻解碼空間資源與音頻編碼空間資源就不能表現(xiàn)出簡單的互斥性,這時將需要用到內(nèi)存復(fù)用技術(shù)[9],對資源的管理也會有更高的要求。資源管理器的后續(xù)設(shè)計需要對這方面的擴展問題做充分考慮。
[1] The Khronos Group Inc.OpenMAXTMintegration layer application programming interface specification[M].New York:The Khronos Group Inc,2008.
[2] Packet Video Corporation.OMX core integration guide[M].New York:Packet Video Corporation,2009.
[3] The Khronos Group Inc.OpenMAXTMweb site[EB/OL].[2010-03-01].http:∥www.khronos.org/openmax
[4] The Khronos Group Inc.Embedded system[EB/OL].[2010-02-01].http:∥en.wikipedia.org/wiki/Embedded_system
[5] Packet Video Corporation.Guide to supplying decoder buffers from the MIO component[M].New York:Packet Video Corporation,2008.
[6] Packet Video Corporation.OMX core integration guide[M].New York:Packet Video Corporation,2009.
[7] Packet Video Corporation.OpenMax call sequences[M].New York:Packet Video Corporation,2009.
[8] ITRI.EMDMA controller user manual[M].New York:ITRI,2008.
[9] REEK K A.Pointers on C[M].New York:Pearson Education Press,1998.