編輯:關於Android編程
前言:上篇中介紹OMX事件回調,從今天開始,走入Codec部分之OpenMAX框架裡。看下今天的Agenda如下:
一張圖回顧音視頻同步 一張圖看清OpenMAX在Android系統中位置 OpenMAX是什麼 OpenMax IL簡介 OpenMax IL結構 Android中OpenMax的使用情況 OpenMax的接口與實現 Android中OpenMax的適配層 mp3,aac解碼時序圖
一張圖回顧音視頻同步
一張圖看清OpenMAX在Android系統中位置:
OpenMAX是什麼?
以下是官網翻譯:
OpenMAX? 是無授權費的,跨平台的應用程序接口API,通過使媒體加速組件能夠在開發、集成和編程環節中實現跨多操作系統和處理器硬件平台,提供全面的流媒體編解碼器和應用程序便攜化。 OpenMAX API將會與處理器一同提供,以使庫和編解碼器開發者能夠高速有效地利用新器件的完整加速潛能 - 無需擔心其底層的硬件結構。
OpenMAX分為3層:
第一層:OpenMax DL(Development Layer,開發層)
OpenMax DL定義了一個API,它是音頻、視頻和圖像功能的集合。供應商能夠在一個新的處理器上實現並優化,然後編解碼供應商使用它來編寫更廣泛的編解碼器功能。它包括音頻信號的處理功能,如FFT和filter,圖像原始處理,如顏色空間轉換、視頻原始處理,以實現例如MPEG-4、H.264、MP3、AAC和JPEG等編解碼器的優化。 第二層:OpenMax IL(Integration Layer,集成層)
OpenMax IL作為音頻、視頻和圖像編解碼器能與多媒體編解碼器交互,並以統一的行為支持組件(例如,資源和皮膚)。這些編解碼器或許是軟硬件的混合體,對用戶是透明的底層接口應用於嵌入式、移動設備。它提供了應用程序和媒體框架,透明的。S編解碼器供應商必須寫私有的或者封閉的接口,集成進移動設備。IL的主要目的是使用特征集合為編解碼器提供一個系統抽象,為解決多個不同媒體系統之間輕便性的問題。 第三層:OpenMax AL(Appliction Layer,應用層)
OpenMax AL API在應用程序和多媒體中間件之間提供了一個標准化接口,多媒體中間件提供服務以實現被期待的API功能。
OpenMax的三個層次如圖所示(來自OpenMax官網):
提示:在實際的應用中,OpenMax的三個層次中使用較多的是OpenMax IL集成層,由於操作系統到硬件的差異和多媒體應用的差異,OpenMax的DL和AL層使用相對較少。
OpenMax IL簡介
OpenMax IL 處在中間層的位置,OpenMAX IL 作為音頻,視頻和圖像編解碼器 能與多媒體編解碼器交互,並以統一的行為支持組件(例如資源和皮膚)。這些編解碼器或許是軟硬件的混合體,對用戶是的底層接口應用於嵌入式或 / 和移動設備。它提供了應用程序和媒體框架, 透明的。本質上不存在這種標准化的接口,編解碼器供 應商必須寫私有的或者封閉的接口,集成進移動設備。 IL 的主要目的 是使用特征集合為編解碼器提供一個系統抽象,為解決多個不同媒體系統之間輕便性的問題。
OpenMax IL 的目的就是為硬件平台的圖形及音視頻提供一個抽象層,可以為上層的應用提供一個可跨平台的支撐。這一點對於跨平台的媒體應用來說十分重要。不同廠商的芯片底層的音視頻接口雖然功能上大致相同,但是接口設計及用法上各有不同,而且相差很多。你要想讓自己開發的媒體 應用完美的運行在不同的硬件廠商平台上,就得適應不同芯片的底層解碼接口。這個對於應用開發來說十分繁瑣。所以就需要類似於OpenMax IL 這種接口規范。應用假如涉及到音視頻相關功能時,只需調用這些標准的接口,而不需要關心接口下方硬件相關的實現。假如換了硬件平台時,只需要把接口層與硬件適配好了就行了。上層應用不需要頻繁改動。你可以把OpenMax IL看作是中間件中的porting層接口,但是現在中間件大部分都是自家定義自己的。
OpenMax IL結構
OpenMax IL的層次結構如圖:
虛線中的內容是OpenMax IL層的內容,其主要實現了OpenMax IL中的各個組件(Component)。對下層,OpenMax IL可以調用OpenMax DL層的接口,也可以直接調用各種Codec實現。對上層,OpenMax IL可以給OpenMax AL 層等框架層(Middleware)調用,也可以給應用程序直接調用。
OpenMax IL主要內容如下所示。
客戶端(Client):OpenMax IL的調用者 組件(Component):OpenMax IL的單元,每一個組件實現一種功能 端口(Port):組件的輸入輸出接口 隧道化(Tunneled):讓兩個組件直接連接的方式
組件、端口、隧道化思想和GStreamer (一種多媒體框架)中的 pipeline 十分類似。
Component實現單一功能、或是Source、Host、Accelerator和Sink。
Port 是 Component對外的輸入輸出口。
通過Tunneled 將單一Component串聯起來形成一個完整功能。
OpenMax Core是輔助各個組件運行的部分
OpenMax IL 的基本運作過程如圖
如圖所示,openMAX IL的客戶端,通過調用四個OpenMAX IL組件,實現了一個功能。四個組件分別是Source組件、Host組件、Accelerator組件和Sink組件。Source組件只有一個輸出端口;而Host組件有一個輸入端口和一個輸出端口;Accelerator組件具有一個輸入端口,調用了硬件的編解碼器,加速主要體現在這個環節上。Accelerator組件和Sink組件通過私有通訊方式在內部進行連接,沒有經過明確的組件端口。
OpenMAL IL在使用的時候,其數據流也有不同的處理方式:
既可以經由客戶端,也可以不經由客戶端。 圖中,Source組件到Host組件的數據流就是經過客戶端的; 而Host組件到Accelerator組件的數據流就沒有經過客戶端,使用了隧道化的方式; Accelerator組件和Sink組件甚至可以使用私有的通訊方式。
OpenMax Core是輔助各個組件運行的部分,它通常需要完成各個組件的初始化等工作,在真正運行過程中,重點是各個OpenMax IL的組件,OpenMax Core不是重點,也不是標准。
OpenMAL IL的組件是OpenMax IL實現的核心內容,一個組件以輸入、輸出端口為接口,端口可以被連接到另一個組件上。外部對組件可以發送命令,還進行設置/獲取參數、配置等內容。組件的端口可以包含緩沖區(Buffer)的隊列。 組件的處理的核心內容是:通過輸入端口消耗Buffer,通過輸出端口填充Buffer,由此多組件相聯接可以構成流式的處理。
OpenMAL IL中一個組件的結構如圖:
組件的功能和其定義的端口類型密切相關,通常情況下:
只有一個輸出端口的,為Source組件; 只有一個輸入端口的,為Sink組件; 有多個輸入端口,一個輸出端口的為Mux組件; 有一個輸入端口,多個輸出端口的為DeMux組件; 輸入輸出端口各一個組件的為中間處理環節,這是最常見的組件。 端口具體支持的數據也有不同的類型。例如,對於一個輸入、輸出端口各一個組件,其輸入端口使用MP3格式的數據,輸出端口使用PCM格式的數據,那麼這個組件就是一個MP3解碼組件。 隧道化(Tunneled)是一個關於組件連接方式的概念。通過隧道化可以將不同的組件的一個輸入端口和一個輸出端口連接到一起,在這種情況下,兩個組件的處理過程合並,共同處理。尤其對於單輸入和單輸出的組件,兩個組件將作為類似一個使用。
Android中OpenMax的使用情況
Android系統的一些部分對OpenMax IL層進行使用,基本使用的是標准OpenMax IL層的接口,只是進行了簡單的封裝。標准的OpenMax IL實現很容易以插件的形式加入到Android系統中。 Android的多媒體引擎OpenCore和StageFright都可以使用OpenMax作為多媒體編解碼的插件,只是沒有直接使用OpenMax IL層提供的純C接口,而是對其進行了一定的封裝(C++封裝)。 在Android2.x版本之後,Android的框架層也對OpenMax IL層的接口進行了封裝定義,甚至使用Android中的Binder IPC機制。Stagefright使用了這個層次的接口,OpenCore沒有使用。 OpenCore使用OpenMax IL層作為編解碼插件在前,Android框架層封裝OpenMax接口在後面的版本中才引入。
Android OpenMax實現的內容
Android中使用的主要是OpenMax的編解碼功能。雖然OpenMax也可以生成輸入、輸出、文件解析-構建等組件,但是在各個系統(不僅是Android)中使用的最多的還是編解碼組件。媒體的輸入、輸出環節和系統的關系很大,引入OpenMax標准比較麻煩;文件解析-構建環節一般不需要使用硬件加速。編解碼組件也是最能體現硬件加速的環節,因此最常使用。 在Android中實現OpenMax IL層和標准的OpenMax IL層的方式基本,一般需要實現以下兩個環節。
編解碼驅動程序:位於Linux內核空間,需要通過Linux內核調用驅動程序,通常使用非標准的驅動程序。 OpenMax IL層:根據OpenMax IL層的標准頭文件實現不同功能的組件。
Android中還提供了OpenMax的適配層接口(對OpenMax IL的標准組件進行封裝適配),它作為Android本地層的接口,可以被Android的多媒體引擎調用。
OpenMax的接口與實現
OpenMax IL層的接口(1)
OpenMax IL層的接口定義由若干個頭文件組成,這也是實現它需要實現的內容,它們的基本描述如下所示。
提示:OpenMax標准只有頭文件,沒有標准的庫,設置沒有定義函數接口。對於實現者,需要實現的主要是包含函數指針的結構體。
其中,OMX_Component.h中定義的OMX_COMPONENTTYPE結構體是OpenMax IL層的核心內容,表示一個組件,其內容如下所示:
OpenMax IL層的接口(2)
OMX_COMPONENTTYPE結構體實現後,其中的各個函數指針就是調用者可以使用的內容。各個函數指針和OMX_core.h中定義的內容相對應。
EmptyThisBuffer和FillThisBuffer是驅動組件運行的基本的機制,前者表示讓組件消耗緩沖區,表示對應組件輸入的內容;後者表示讓組件填充緩沖區,表示對應組件輸出的內容。 UseBuffer,AllocateBuffer,FreeBuffer為和端口相關的緩沖區管理函數,對於組件的端口有些可以自己分配緩沖區,有些可以使用外部的緩沖區,因此有不同的接口對其進行操作。 SendCommand表示向組件發送控制類的命令。GetParameter,SetParameter,GetConfig,SetConfig幾個接口用於輔助的參數和配置的設置和獲取。
ComponentTunnelRequest用於組件之間的隧道化連接,其中需要制定兩個組件及其相連的端口。 ComponentDeInit用於組件的反初始化。
提示:OpenMax函數的參數中,經常包含OMX_IN和OMX_OUT等宏,它們的實際內容為空,只是為了標記參數的方向是輸入還是輸出。
OMX_Component.h中端口類型的定義為OMX_PORTDOMAINTYPE枚舉類型,內容如下所示:
音頻類型,視頻類型,圖像類型,其他類型是OpenMax IL層此所定義的四種端口的類型。
端口具體內容的定義使用OMX_PARAM_PORTDEFINITIONTYPE類(也在OMX_Component.h中定義)來表示,其內容如下所示:
對於一個端口,其重點的內容如下:
端口的方向(OMX_DIRTYPE):包含OMX_DirInput(輸入)和- -OMX_DirOutput(輸出)兩種 端口分配的緩沖區數目和最小緩沖區數目 端口的類型(OMX_PORTDOMAINTYPE):可以是四種類型 端口格式的數據結構:使用format聯合體來表示,具體由四種不同類型來表示,與端口的類型相對應
OMX_AUDIO_PORTDEFINITIONTYPE,OMX_VIDEO_PORTDEFINITIONTYPE,OMX_IMAGE_PORTDEFINITIONTYPE和OMX_OTHER_PORTDEFINITIONTYPE等幾個具體的格式類型,分別在OMX_Audio.h,OMX_Video.h,OMX_Image.h和OMX_Other.h這四個頭文件中定義。
OMX_BUFFERHEADERTYPE是在OMX_Core.h中定義的,表示一個緩沖區的頭部結構。
OMX_Core.h中定義的枚舉類型OMX_STATETYPE命令表示OpenMax的狀態機,內容如下所示:
OpenMax組件的狀態機可以由外部的命令改變,也可以由內部發生的情況改變。OpenMax IL組件的狀態機的遷移關系如圖所示:
OMX_Core.h中定義的枚舉類型OMX_COMMANDTYPE表示對組件的命令類型,內容如下所示:
OMX_COMMANDTYPE類型在SendCommand調用中作為參數被使用,其中OMX_CommandStateSet就是改變狀態機的命令。
OpenMax IL實現的內容
對於OpenMax IL層的實現,一般的方式並不調用OpenMax DL層。具體實現的內容就是各個不同的組件。OpenMax IL組件的實現包含以下兩個步驟。
組件的初始化函數:硬件和OpenMax數據結構的初始化,一般分成函數指針初始化、私有數據結構的初始化、端口的初始化等幾個步驟,使用其中的pComponentPrivate成員保留本組件的私有數據為上下文,最後獲得填充完成OMX_COMPONENTTYPE類型的結構體。 OMX_COMPONENTTYPE類型結構體的各個指針實現:實現其中的各個函數指針,需要使用私有數據的時候,從其中的pComponentPrivate得到指針,轉化成實際的數據結構使用。端口的定義是OpenMax IL組件對外部的接口。OpenMax IL常用的組件大都是輸入和輸出端口各一個。對於最常用的編解碼(Codec)組件,通常需要在每個組件的實現過程中,調用硬件的編解碼接口來實現。在組件的內部處理中,可以建立線程來處理。OpenMax的組件的端口有默認參數,但也可以在運行時設置,因此一個端口也可以支持不同的編碼格式。音頻編碼組件的輸出和音頻編碼組件的輸入通常是原始數據格式(PCM格式),視頻編碼組件的輸出和視頻編碼組件的輸入通常是原始數據格式(YUV格式)。
提示:在一種特定的硬件實現中,編解碼部分具有相似性,因此通常可以構建一個OpenMax組件的”基類”或者公共函數,來完成公共性的操作。
Android中OpenMax的適配層
Android中的OpenMax適配層的接口在frameworks/base/include/media/目錄中的IOMX.h文件定義,其內容如下所示:
IOMX表示的是OpenMax的一個組件,根據Android的Binder IPC機制,BnOMX繼承IOMX,實現者需要繼承實現BnOMX。IOMX類中,除了和標准的OpenMax的GetParameter,SetParameter,GetConfig,SetConfig,SendCommand,UseBuffer,AllocateBuffer,FreeBuffer,FillThisBuffer和EmptyThisBuffer等接口之外,還包含了創造渲染器的接口createRenderer(),創建的接口為IOMXRenderer類型。 IOMX中只有第一個createRenderer()函數是純虛函數,第二個的createRenderer()函數和createRendererFromJavaSurface()通過調用第一個createRenderer()函數實現。
IOMXRenderer類表示一個OpenMax的渲染器,其定義如下所示:
IOMXRenderer只包含了一個render接口,其參數類型IOMX::buffer_id實際上是void*,根據不同渲染器使用不同的類型。 在IOMX.h文件中,另有表示觀察器類的IOMXObserver,這個類表示OpenMax的觀察者,其中只包含一個onMessage()函數,其參數為omx_message接口體,其中包含Event事件類型、FillThisBuffer完成和EmptyThisBuffer完成幾種類型。
提示:Android中OpenMax的適配層是OpenMAX IL層至上的封裝層,在Android系統中被StageFright調用,也可以被其他部分調用。
mp3 aac格式解碼時序圖
osgi中bundle之間的通信,可以使用eventadmin來完成,eventadmin是osgi中的一種基於發布訂閱的方式,一個Bundle進行發布發布一個事件之後,
本文實例講述了Android實現模仿UCweb菜單效果的方法。分享給大家供大家參考。具體如下:UCWeb的菜單看起來不錯,自己模仿做一個,思路實現如下:1、保留menu按
下拉刷新對於一個app來說是必不可少的一個功能,在早期大多數使用的是chrisbanes的PullToRefresh,或是修改自該框架的其他庫。而到現在已經有了更多的選擇
Android UI- PullToRrefresh自定義下拉刷新動畫 如果覺得本文不錯,麻煩投一票,2014年博客之星投票地址:http://vote.blog.csd