Android OMX介紹(總括)

一、OpenMax簡介(縮寫爲:OMX)

    OpenMAX是一個多媒體應用程序的標準。由NVIDIA公司和Khronos™在2006年推出。

    它是無授權費的、跨平臺的C語言程序接口序列,這些接口對音頻、視頻、靜態圖片的常用操作進行封裝。

    它包括三層,分別是應用層(AI)、集成層(IL)和開發層(DL)。其中IL層已經成爲了事實上的多媒體框架標準。嵌入式處理器或者多媒體編解碼模塊的硬件生產者,通常提供標準的OpenMax IL層的軟件接口,這樣軟件的開發者就可以基於這個層次的標準化接口進行多媒體程序的開發。

 

二、OpenMax在Android中的位置

        在Android中,OpenMax IL層,通常可以用於多媒體引擎的插件,Android的多媒體引擎OpenCore和StageFright都可以使用OpenMax作爲插件,主要用於編解碼(Codec)處理。在Android的框架層,也定義了由Android封裝的OpenMax接口,和標準的接口概念基本相同,但是使用C++類型的接口,並且使用了Android的Binder IPC機制。Android封裝OpenMax的接口被StageFright使用,OpenCore沒有使用這個接口,而是使用其他形式對OpenMax IL層接口進行封裝。

        

        

三、OpenMax的主要概念

  • 客戶端(Client):訪問IL core或IL component的軟件層,可能是位於GUI應用程序的下層,如GStreamer。IL client是一個典型的功能塊,如filter graph multimedia framework, OpenMAX AL, 或application都可以調用它。IL client與OpenMAX IL core進行交互,利用IL core加載和卸載組件、在組件間建立直接通信以及獲得組件方法的入口。
  • core:相關平臺的代碼,具有將IL component載入主存儲器的功能,當應用程序不再需要某組件時,IL core將負責把該組件從存儲器卸去。一般來說,組件一旦載入存儲器,IL core將不在參與應用程序與組件之間的通信。
  • 端口(Port):組件的輸入輸出接口
  • 組件(Component):OpenMax IL的單元,每一個組件實現一種功能。組件按照端口可分類爲Source(只有一個輸出端口)、Sink(只有一個輸入端口)和Host組件(一個輸入端口和一個輸出端口),此外有一個Accelerator組件,它具有一個輸入端口,調用了硬件的編解碼器,加速主要體現在這個環節上。
  • 隧道化(Tunneled):讓兩個組件直接連接的方式。通過隧道化可以將不同的組件的一個輸入端口和一個輸出端口連接到一起,在這種情況下,兩個組件的處理過程合併,共同處理。尤其對於單輸入和單輸出的組件,兩個組件將作爲類似一個使用。

四、OpenMax的工作方式

        首先,搭建好OpenMax的工作環境:設置組件端口、加載組件,建立連接方式等等。

     

        然後通過輸入端口消耗Buffer,通過輸出端口填充Buffer,由此多組件相聯接可以構成流式的處理。

 

五、OpenMax的測試方式

參考《Build OpenCORE 2.05 on x86 Linux.PDF》和《omx_decoder_test_app_guide.pdf》

 

六、OpenMax接口和集成過程(以android平臺的爲例)

 

七、android中支持的組件和Role

根據pv_omxregistry.cpp,得到如下表格(其中黃綠色部分表示沒有相應編碼器)

組件 角色 動態庫名
OMX.PV.mpeg4dec video_decoder.mpeg4 libomx_m4vdec_sharedlibrary
OMX.PV.h263dec video_decoder.h263 libomx_m4vdec_sharedlibrary
OMX.PV.avcdec video_decoder.avc libomx_avcdec_sharedlibrary
OMX.PV.wmvdec video_decoder.wmv libomx_wmvdec_sharedlibrary
OMX.PV.rvdec video_decoder.rv libomx_rvdec_sharedlibrary
OMX.PV.aacdec audio_decoder.aac libomx_aacdec_sharedlibrary
OMX.PV.amrdec audio_decoder.amr

audio_decoder.amrnb

audio_decoder.amrwb

libomx_amrdec_sharedlibrary
OMX.PV.mp3dec audio_decoder.mp3 libomx_mp3dec_sharedlibrary
OMX.PV.wmadec audio_decoder.wma libomx_wmadec_sharedlibrary
OMX.PV.radec audio_decoder.ra libomx_radec_sharedlibrary
     
OMX.PV.amrencnb audio_encoder.amrnb libomx_amrenc_sharedlibrary
OMX.PV.mpeg4enc video_encoder.mpeg4 libomx_m4venc_sharedlibrary
OMX.PV.h263enc video_encoder.h263 libomx_m4venc_sharedlibrary
OMX.PV.avcenc video_encoder.avc libomx_avcenc_sharedlibrary
OMX.PV.aacenc audio_encoder.aac libomx_aacenc_sharedlibrary

 

八、Openmax 一些函數的簡單介紹

1 OMX core methods

1)OMX_Init
2)OMX_Deinit
3)OMX_GetHandle
4)OMX_FreeHandle
5)OMX_ComponentNameEnum
6)OMX_GetComponentsOfRole
7)OMX_GetRolesOfComponent
8)OMX_SetupTunnel
9)OMX_GetContentPipe


2 The configuration parser API
除了以上methods,強烈推薦OMX核心插件庫包含此API
2.1函數原型
OMX_BOOL OMXConfigParser ( OMX_PTR aInputParameters,OMX_PTR aOutputParameters);

2.2 傳遞參數
aInputParameters 指向如下結構
typedef struct
{
OMX_U8* inPtr;    //codec 配置頭部指針
OMX_U32 inBytes;   //codec 配置頭部長度
OMX_STRING cComponentRole; //OMX codec類型 eg "video_decoder.mpeg4"
OMX_STRING cComponentName; //OMX 組件名稱
} OMXConfigParserInputs;

2.3 返回值
OMX_FALSE : 處理codec配置頭部錯誤或不支持該格式
OMX_TURE : 正確處理codec配置頭部

2.4 函數作用
填充aOutputParameters,有兩種選擇:audio coded or vedio codec

for audio
typedef struct
{
OMX_U16 Channels;   //通道:單聲道、立體聲、5.1
OMX_U16 BitsPerSample;   //位寬(eg16)
OMX_U32 SamplesPerSec;   //採樣率
} AudioOMXConfigParserOutputs;

typedef struct
{
OMX_U32 width;    //檢測到的視頻剪輯寬度
OMX_U32 height;    //檢測到的視頻剪輯高度
OMX_U32 profile;   //參數
OMX_U32 level;    //級別?
} VideoOMXConfigParserOutputs;

3 動態加載OMX內核
解釋了\system\system\etc\pvplayer.cfg文件中最後一行的含義
(0xa054369c,0x22c5,0x412e,0x19,0x17,0x87,0x4c,0x1a,0x19,0xd4,0x5f),"libomx_sharedlibrary.so"

作用:將OMX內核動態加載進OpenCORE框架
位置:\system\system\etc\pvplayer.cfg
形式:(OMX Core API OsclUuid), “shared library name.so”
eg:(0xa054369c,0x22c5,0x412e,0x19,0x17,0x87,0x4c,0x1a,0x19,0xd4,0x5f),"libomx_core_vendorXYZ.so"

注意:(0xa054369c,0x22c5,0x412e,0x19,0x17,0x87,0x4c,0x1a,0x19,0xd4,0x5f) 提供獨立API ID,不可修改

 

數據格式及OMX輸入緩衝細節

1.1 幀起始代碼
一般不用,H.264可能使用。

1.2 OMX緩衝區
三個值得信賴的關鍵參數
nFilledLen 緩衝區長度
nTimestamp 緩衝區時間戳
OMX_BUFFERLAG_ENDOFFRAME 緩衝區結束標誌位

1.3多幀合併輸入緩衝
一些音頻信息,單幀過小(eg ARM),將其合併作爲一個緩衝區處理。
nFilledLen爲所有幀總長度,nTimestamp指向緩衝區第一幀時間。

1.4部分幀
視頻解碼單幀過大情況下,可能將單幀拆分後傳遞給緩衝區。
部分幀情況下,只有最後一幀的緩衝區才擁有OMX_BUFFERLAG_ENDOFFRAME。
部分幀緩衝區不會包含兩幀信息。
流媒體可能包含多幀。
部分幀的nTimestamp應當相同。

總結:OMX輸出緩衝區可能包含
——完整多幀
——完整單幀
——部分幀

1.5 錯誤的數據封裝
多幀的部分幀封裝 eg wrong(Frame1+Frame2 part)

1.6 Codec配置數據
Codec配置緩衝區使用OMX_BUFFERLAG_ENDOFFRAME 和OMX_BUFFERFLAG_CODECCONFIG標誌位。
H.264的SPS和PPS使用獨立的OMX輸入緩衝區。

2 H264/AVC 解碼器格式
Codec配置頭部:
SPS和PPS NAL單元位於起始的OMX輸入緩衝區。
SPS和PPS NALs使用獨立的OMX輸入緩衝區,並使用OMX_BUFFERLAG_ENDOFFRAME 和OMX_BUFFERFLAG_CODECCONFIG標記。

2.1 AVC NAL模式與AVC Frame模式
通過設置iOMXComponentUsesFullAVCFrame標誌位,可以決定AVC數據使用哪種模式解碼。
默認使用NAL模式,此種模式下OpenCORE框架同時提供完整單幀和部分幀輸入緩衝區。
在Frame模式下,OpenCORE框架積累NALs並提供完整單幀給輸入緩衝區。
OMX_OTHER_EXTRADATA結構體用來區分NAL邊界。
如果iOMXComponentUsesFullAVCFrame和iOMXComponentUsesNALStratCodes都被置爲OMX_TRUE,
NAL邊界可被start codes區分,此時OMX_OTHER_EXTRADATA無用。

數據結構——NAL模式:
輸入緩衝區包含一個或多個NAL,但只包含同一幀的NAL,一幀最後一個NAL才含有OMX_BUFFERLAG_ENDOFFRAME標誌位。

數據結構——Frame模式:
每個輸入緩衝區包含完整幀。
如果使用NAL start codes,可通過讀取NAL start codes區分NAL邊界。
否則使用OMX_OTHER_EXTRADATA結構體區分NAL邊界。
在Frame模式中,每個緩衝區都含有OMX_BUFFERLAG_ENDOFFRAME標誌位。
在Frame模式中,每個緩衝區都含有位於OMX_BUFFERLAGHEADERTYPE結構體nFlags區域的OMX_BUFFERLAG_EXTRADATA標誌位。

緩衝區最後包含AVC frame,追加以下數據:
OMX_OTHER_EXTRADATATYPE extra;
OMX_OTHER_EXTRADATATYPE terminator;

extra.eType = OMX_ExtraDataNALSizeArray;
extra.nSize = 20+4*(number of NALs in the frame); // 20 is the size of
OMX_OTHER_EXTRADATATYPE structure + 4 bytes per NAL size
extra.nDataSize = 4 * (number of NALs in the frame)
extra.data[4*i] = size of the i-th NAL (data is declared as byte array – so offset is 4*i, since 4 bytes
is assigned to signal the size of each NAL unit)
terminator.eType = OMX_ExtraDataNone;
terminator.nSize = 20;
terminator.nDataSize = 0;

#define OMX_ExtraDataNALSizeArray 0x7F123321

通過獲取OMX_OTHER_EXTRADATA結構體信息,可以得知每一幀包含NAL單元的數目並確定NAL邊界。

一個例子:AVC Frame模式,包含2個NAL,包含extra數據結構
總結:
1)每個緩衝區都含有位於OMX_BUFFERLAGHEADERTYPE結構體nFlags區域的OMX_BUFFERLAG_EXTRADATA標誌位
2)每個NAL的長度應當使用獨立的4byte無符號整型數表示(eg OMX_U32)
3)所有NAL的長度被編碼成OMX_U32的數組存放在buffer最後。
4)包含完整幀的緩衝區必須含有位於OMX_BUFFERLAGHEADERTYPE結構體nFlags區域的OMX_BUFFERLAG_ENDOFFRAME標誌位。
5)一個獨立的緩衝區不包含多幀數據。

 

3 YUV和RGB數據格式
OMX編碼組件中,生肉提供YUV或者RGB格式,OpenCORE框架將提供一幀完成的YUR或RGB數據給OMX組件。

 

OpenMax 調用順序(OpenMax Call Sequences)
1 OMX 核心初始化 _OMX_MasterInit

1)調用OMX_Init函數
->OsclInit::Init(error, &select); //init all Oscl layers except Oscl scheduler.
->_Try_OMX_Create(error, data); //create the OMX singleton
->OsclSingletonRegistry::registerInstanceAndUnlock(data, OSCL_SINGLETON_ID_OMX, error); //Release the singleton.
->_Try_OMX_Init(error, status); //If create succeeded, then init the OMX globals.

2)PV框架列舉所有OMX

OMX_ComponentNameEnum //列舉所有組件的名稱
->OsclSingletonRegistry::getInstance(OSCL_SINGLETON_ID_OMX, error);
->oscl_strncpy(cComponentName, (data->ipRegTemplateList[Index])->ComponentName, nNameLength);

OMX_GetRolesOfComponent // 通過組件名稱找到組件,返回其角色(role)
->OsclSingletonRegistry::getInstance(OSCL_SINGLETON_ID_OMX, error);
->data->ipRegTemplateList[ii])->GetRolesOfComponent(RoleString)
->oscl_strncpy((OMX_STRING) roles[ii], (OMX_STRING)RoleString[ii], oscl_strlen((OMX_STRING)RoleString[ii]) + 1);

2 OMX組件實例、功能及端口
OMX核心初始化後,下一步爲列舉每個組件的功能和端口。
1)調用OMX_GetHandle獲取所需的OMX組件信息。

2)調用OMX_GetParameter及“PV_OMX_CAPABILITY_TYPE_INDEX”這個index去獲取組件的功能。
萬一組件不是OpenMax全兼容或者OpenMax的特性不明確,以上獲取的功能決定了OMX是否支持輸入/輸出端口“UseBufeer”和“AllocateBuffer”調用,以及OMX是否支持部分幀等等。

注意:如果OMX組件返回“OMX_ErrorUnsupportedIndex”給index(或其他比如“OMX_ErrorNone”),PV框架將爲組件功能賦默認值。

3)調用OMX_GetParameter,針對視頻組件再調用“OMX_IndexVideoInit”,針對音頻組件則調用“OMX_IndexAudioIni”以獲取可用的端口號。

4)循環查找可用的端口號以找到輸入端口。

5)循環查找可用的端口號以找到輸出端口。

注意:
Index “PV_OMX_CAPABILITY_TYPE_INDEX” is defined as:
#define PV_OMX_COMPONENT_CAPABILITY_TYPE_INDEX 0xFF7A347
The OMX_GetParameter call expects the following structure to be filled for this index:
typedef struct PV_OMXComponentCapabilityFlagsType
{
////////////////// OMX COMPONENT CAPABILITY RELATED MEMBERS
OMX_BOOL iIsOMXComponentMultiThreaded;
OMX_BOOL iOMXComponentSupportsExternalOutputBufferAlloc;
OMX_BOOL iOMXComponentSupportsExternalInputBufferAlloc;
OMX_BOOL iOMXComponentSupportsMovableInputBuffers;
OMX_BOOL iOMXComponentSupportsPartialFrames;
OMX_BOOL iOMXComponentUsesNALStartCode;
OMX_BOOL iOMXComponentCanHandleIncompleteFrames;
OMX_BOOL iOMXComponentUsesFullAVCFrames;
} PV_OMXComponentCapabilityFlagsType;

功能參數的默認值:
1)iIsOMXComponentMultiThreaded ——默認值OMX_TRUE。
OMX組件一般運行與獨立的線程(與PV框架線程不同),有可能將OMX組件集成進PV框架線程(e.g.,通過同步調用)。

2)iOMXComponentSupportsExternalOutputBufferAlloc ——默認值OMX_TRUE。
OMX規範要求OMX組件支持外部分配輸出緩衝(就是輸出緩衝的OMX_UseBuffer調用)。
如果組件不支持,必須通知PV框架,以便其調用“OMX_AllocateBuffer”代替。

3)iOMXComponentSupportsExternalInputBufferAlloc ——默認值OMX_TRUE。
OMX規範要求OMX組件支持外部分配輸入緩衝(就是輸入緩衝的OMX_UseBuffer調用)。
如果組件不支持,必須通知PV框架,以便其調用“OMX_AllocateBuffer”代替。

4)iOMXComponentSupportsMovableInputBuffers ——默認值OMX_TRUE。
如果OMX緩衝是外部分配的,爲了提高穩定性和優化性能,可以分離OMX緩衝頭部信息(OMX_BUFFERHEADERTYPE)與數據區(“pBuffer”)。換句話說,使OMX緩衝更有“移動性”,當傳遞一個輸入緩衝到OMX組件時,“pBuffer”區域和頭部信息不一定指向相同的緩衝區。因此,可以分配更多的數據緩衝在框架中循環工作,只有在需要把緩衝傳遞到OMX組件時才附加到頭部信息去。如果OMX組件要求頭部和數據一直指向相同的緩衝,則iOMXComponentSupportsMovableInputBuffers應該被置爲OMX_FALSE。

5)iOMXComponentSupportsPartialFrames ——默認值OMX_TRUE。
OMX規範要求OMX組件支持將任意數據打包進OMX緩衝,包括獨立單幀、NAL和被拆分到多個緩衝區的解碼單元。PV框架支持“OMX_BUFFERFLAG_ENDOFFRAME”標記去組裝部分幀。然而,如果OMX組件不支持組裝部分幀,也就是OMX組件要求PV框架來組裝部分幀並提供給OMX組件完整單幀或NAL,此時iOMXComponentSupportsPartialFrames需要被設置爲OMX_FALSE。
注意:設置爲OMX_FALSE將影響性能。

6)iOMXComponentUsesNALStartCode ——默認值OMX_FALSE。
這個標誌位將影響H264解碼。PV框架提供所有信息以重建立H264 NALs(通過OMX緩衝的大小和OMX_BUFFERFLAG_ENDOFFRAME的大小)。因此沒有必要由OMX組件解碼輸出流來獲取0x0001的NAL初始代碼。如果OMX的H264組件及解碼單元需要NAL起始代碼,可將iOMXComponentUsesNALStartCode置爲OMX_TRUE。

7)iOMXComponentCanHandleIncompleteFrames ——默認值OMX_TRUE。
如果丟失部分數據流(比如數據包丟失),假定OMX組件及解碼單元可以解決這個問題。如果不可以,則將iOMXComponentCanHandleIncompleteFrames 設置爲OMX_FALSE。當“iOMXComponentSupportsPartialFrames”也被設置爲OMX_FALSE時,這點相當重要,因爲OMX組件不提供組裝部分幀,也就是說PV框架必須提供組裝好的frame/NALs,因此需要通知OMX組件不完整的幀數據是否可以傳遞進來。

8)iOMXComponentUsesFullAVCFrames ——默認值OMX_FALSE。
這個標誌位決定AVC解碼中使用NAL模式還是frame模式。AVC數據可由以上兩種模式提供給OMX組件。默認爲NAL模式(設置爲OMX_FALSE),此模式下OpenCore框架可以爲OMX輸入緩衝同時提供完整或者部分AVC NAL。Frame模式下(OMX_TRUE),OpenCore框架積累NAL,並提供給OMX輸入緩衝一幀完整的數據。
NAL邊界的問起前面討論過了,此處省略。

 

3 OMX組件輸入輸出緩衝協商
在任何數據交換前,輸入輸出緩衝需要進行協商。PV框架需要做以下工作:、
1)調用OMX_GetParameter獲取輸入端口緩衝參數(最小/實際緩衝數,緩衝區大小等等)
2)檢查有效的輸入緩衝參數(修改一些參數,比如幀的長度和寬度,以及緩衝區的數目等等)
3)調用OMX_SetParameter函數設置輸入緩衝參數
4)調用OMX_GetParameter獲取輸出端口緩衝參數(最小/實際緩衝數,緩衝區大小等等)
5)檢查有效的輸出緩衝參數(修改一些參數,比如幀的長度和寬度,以及緩衝區的數目等等)
6)調用OMX_SetParameter函數設置輸出緩衝參數

過程如圖三(省略)

一些設想:
1)緩衝區尺寸的設想:
對於編碼器組件,最終分配的輸出緩衝區尺寸可能小於profile/level/target比特率所要求的最大幀尺寸。出於內存消耗考慮,OMX編碼器組件應當能夠輸出frame或NAL的比特流劃分到多個輸出緩衝區去。老調重彈,最後一個部分緩衝區使用“OMX_BUFFERFLAG_ENDOFFRAME”標記結尾。

對於解碼器組件,最終分配的輸入緩衝區尺寸可能小於profile/level/target比特率所要求的最大幀尺寸。出於內存消耗考慮,PV框架在適當的時候提供採用“OMX_BUFFERFLAG_ENDOFFRAME”標記結尾的輸入緩衝區。如果輸入緩衝包含完整幀(H264也可能是NAL單元 )或多幀,“OMX_BUFFERFLAG_ENDOFFRAME”將會用來標記一幀的結尾。如果完整的frame/NAL不能放入一個輸入緩衝區,則會被拆分放入多個緩衝區。包含部分信息的緩衝區,“OMX_BUFFERFLAG_ENDOFFRAME”標記位將會被置爲0。一幀數據的最後一個緩衝區中“OMX_BUFFERFLAG_ENDOFFRAME”纔會被置爲1。通過這種做法,組件可以方便的重構一幀數據。

如果OMX解碼器組件不兼容組長部分幀,PV框架將負責做這件事情。

2)輸入/輸出緩衝區數量。
框架或許希望分配比OMX要求更多的的輸入/輸出緩衝區以提供更優的性能(比如解碼器輸出緩衝或編碼器輸入緩衝——緩衝更多的數據可以提高性能)。儘管性能提升了,但無法送到OMX組件去(不太理解,應該還是協商不好的意思)。

4 OMX狀態變換 加載->空閒 
如果部分已分配的緩衝區進入空閒狀態,緩衝區分配將掛起。在變化過程中,PV框架將“
1)通過“OMX_SendCommand”調用發送命令給OMX組件,將狀態由OMX_StateLoaded改變爲OMX_StateIdle
2)調用一系列“OMX_UseBuffer” 或者“OMX_AllocateBuffer”通知OMX組件。這些調用使用NumInputBuffer記錄輸入輸入端口的數目,使用NumOutputBuffer記錄輸入輸入端口的數目。
3)等待OMX組件的EventHandler事件回調,通知框架狀態變換完成(OMX_EventCmdComplete)

一些設想與推薦參數:
根據OMX規範,兼容的OMX組件必須同時支持OMX_UseBuffer 和 OMX_AllocateBuffer調用。然而,出於一些內在原因,完全實現是不可能的,組件應當通知PV框架其所具有的功能。

推薦將INPUT緩衝分配在OMX組件外部,這樣可以減少額外的內存拷貝(也就是說輸入緩衝使用OMX_UseBuffer)。

5 變換到“執行”狀態與數據交換
狀態變化到執行時纔開始真正處理數據。本步驟中,PV框架將:
1)通過“OMX_SendCommand”調用發送命令給OMX組件,將狀態由OMX_StateIdle改變爲OMX_StateExecuting。
2)等待OMX組件的EventHandler事件回調,通知框架狀態變換完成(OMX_EventCmdComplete)。
3)通過OMX_EmptyThisBuffer調用將輸入緩衝發送給OMX組件,通過OMX_FillThisBuffer調用將輸出緩衝發送給OMX組件,組件使用合適的回調函數返回緩衝區。

過程如圖5

 

注意:
1)在任意時刻OMX組件如果擁有所有輸入緩衝區(也就是所有的輸入緩衝都通過EmptyThisBuffer調用傳給了OMX組件),此時將不能再傳遞任何輸入緩衝區給OMX組件,知道OMX通過EmptyBufferDone釋放一個緩衝。對於輸出緩衝區同樣。

2)如果PV框架沒有及時將緩衝區發給OMX框架,OMX組件不會多次返回同一個緩衝區(也就是一旦OMX框架返回一個緩衝區,只有PV框架再次調用這個緩衝,OMX組件纔可使用)。這是OMX緩衝交換APSs所規定的基本規則。

6 暫停
PV框架常見的功能包括暫停和恢復,PV框架將:
1)通過“OMX_SendCommand”調用發送命令給OMX組件,將狀態由OMX_StateExecuting改變爲OMX_StatePause。
2)等待OMX組件的EventHandler事件回調,通知框架狀態變換完成(OMX_EventCmdComplete)。

PV框架向OMX組件發送暫停命令後,立刻停止發送輸入輸出緩衝。

有暫停就有恢復,PV框架將:
1)通過“OMX_SendCommand”調用發送命令給OMX組件,將狀態由OMX_StatePause改變爲OMX_StateExecuting。
2)等待OMX組件的EventHandler事件回調,通知框架狀態變換完成(OMX_EventCmdComplete)。

PV框架的狀態恢復到執行後,將恢復發送OMX輸入輸出緩衝。

過程如圖6

7 端口刷新(如果可用)
端口刷新調用一般用於重新配置解碼器組件,這樣會清空所有數據。在此情況下,PV框架將:
1)通過“OMX_SendCommand”調用發送刷新全部端口指令。
2)等待輸入緩衝的輸出緩衝的兩個EventHandler事件回調,通知框架狀態變換完成(OMX_EventCmdComplete)。

刷新命令來了之後,PV框架立刻停止向OMX組件發送輸入/輸出緩衝。當組件接收到2個回調函數後,PV框架開始恢復發送輸入/輸出緩衝。

端口刷新的順序和通告並不相關。

過程如圖7。

爲了防止動態端口被重複配置,也可以先於OMX IL用戶關閉OMX組件端口調用端口刷新指令。

8 停止/變化到“IDLE”狀態
爲了停止處理過程,PV框架將:
1)通過“OMX_SendCommand”調用發送命令給OMX組件,將狀態由OMX_StatePause改變爲OMX_StateIdle。
2)等待OMX組件的EventHandler事件回調,通知框架狀態變換完成(OMX_EventCmdComplete)。

過程見圖8。

一些設想:
當命令完成“IDEL”態的回調後,PV框架假設所有輸入輸出緩衝按照OMX規範要求那樣返回。

9 OMX組件狀態轉換 IDLE->Loaded State和 De-initialization
當PV框架結束與一個OMX組件的所有交互後,將:
1)通過“OMX_SendCommand”調用發送命令給OMX組件,將狀態由OMX_StateIdle改變爲OMX_StateLoaded。
2)向OMX組件發送一系列“OMX_FreeBuffer”調用。
3)等待OMX組件的EventHandler事件回調,通知框架狀態變換完成(OMX_EventCmdComplete)。使用NumInputBuffer記錄輸入輸入端口的數目,使用NumOutputBuffer記錄輸入輸入端口的數目。
4)對OMX核心執行OMX_FreeHandle調用,釋放組件句柄。

流程圖見圖9

注意:在向OMX組件發送卸載命令之前,PV框架一直在等待OMX組件返回的輸入輸出緩衝。由於回調的過程的不同步性,一些EmptyBufferDone/FillBufferDone的回調有可能在OMX組件狀態由“executing” 到 “idle”之後纔到達。

10 OMX Core 卸載
PV框架調用函數OMX_Deinit()。


 

OMX_Init()

沒有什麼好說的,初始化函數,一定要運行的.

 

OMX_GetHandle

得到某一個組件的句柄

OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(
    OMX_OUT OMX_HANDLETYPE* pHandle, 
    OMX_IN  OMX_STRING cComponentName,
    OMX_IN  OMX_PTR pAppData,
    OMX_IN  OMX_CALLBACKTYPE* pCallBacks);

 

OMX_GetExtensionIndex

除了標準OMX_INDEXTYPE中定義的以外,返回用戶自定義的一些參數(第二個參數)對應的index(第三個參數,用在OMX_SetParameter...裏面),用來configur或者parameter.

這些參數往往被定義在用戶特殊的extension interface裏面

 

#define OMX_GetExtensionIndex(                              /
        hComponent,                                         /
        cParameterName,                                     /
        pIndexType)                                         /
    ((OMX_COMPONENTTYPE*)hComponent)->GetExtensionIndex(    /
        hComponent,                                         /
        cParameterName,                                     /
        pIndexType)                     /* Macro End */

 

 

 

OMX_SetParameter

設定某個參數對應的值

#define OMX_SetParameter(                                   /
        hComponent,                                         /
        nParamIndex,                                        /
        pComponentParameterStructure)                        /
    ((OMX_COMPONENTTYPE*)hComponent)->SetParameter(         /
        hComponent,                                         /
        nParamIndex,                                        /
        pComponentParameterStructure)    /* Macro End */

 

 

 

OMX_SetConfig

設定某個config值

#define OMX_SetConfig(                                      /
        hComponent,                                         /
        nConfigIndex,                                       /
        pComponentConfigStructure)                           /
    ((OMX_COMPONENTTYPE*)hComponent)->SetConfig(            /
        hComponent,                                         /
        nConfigIndex,                                       /
        pComponentConfigStructure)       /* Macro End */

 

注意有時候,需要先停止某個組件(的某些端口),才能設置config 成功

 

OMX_SendCommand

 

一般的命令有:

OMX_CommandStateSet 、OMX_CommandFlush、OMX_CommandPortDisable" 、 "OMX_CommandPortEnable、CommandMarkBuffer

 

#define OMX_SendCommand(                                    /
         hComponent,                                        /
         Cmd,                                               /
         nParam,                                            /
         pCmdData)                                          /
     ((OMX_COMPONENTTYPE*)hComponent)->SendCommand(         /
         hComponent,                                        /
         Cmd,                                               /
         nParam,                                            /
         pCmdData)                          /* Macro End */

 

 例子:OMXSAFE(OMX_SendCommand(vrenderer, OMX_CommandPortEnable, 1, 0)); // 停下1對應的端口

 

OMX_SetupTunnel

將兩個組件連接起來,實際會引起調用每個組件的ComponentTunnelRequest

 

OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel(
    OMX_IN  OMX_HANDLETYPE hOutput,
    OMX_IN  OMX_U32 nPortOutput,
    OMX_IN  OMX_HANDLETYPE hInput,
    OMX_IN  OMX_U32 nPortInput);

 

例子:

OMXSAFE(OMX_SetupTunnel(reader,   0, vdecoder,  0)); // reader的0端口爲出,vdecoder的0端口爲入,連接成一個Tunnel

 

 

準備好後,就可以設置OMX_StateExecuting,來讓這個流程活動起來了。

 

再以後,就可以通過OMX_StateIdle 來停下。

 

OMX_GetState

 

#define OMX_GetState(                                       /
        hComponent,                                         /
        pState)                                             /
    ((OMX_COMPONENTTYPE*)hComponent)->GetState(             /
        hComponent,                                         /
        pState)                         /* Macro End */

 

 一些新補充:

 

1:

OMX_PARAM_PORTDEFINITIONTYPE decOutputPortDef;

   INIT_PARAM(decOutputPortDef);
    decOutputPortDef.nPortIndex = 0;

    err = OMX_GetParameter(pCtx->hReaderComp,
                           OMX_IndexParamPortDefinition,
                           &decOutputPortDef); // 利用IndexParamPortDefinition來得到組件的輸出端口的屬性

 

    videoWidth = decOutputPortDef.format.video.nFrameWidth; 
    videoHeight = decOutputPortDef.format.video.nFrameHeight;

 

2:OMX_BUFFERHEADERTYPE *pOmxBufferHeader ;

// tell decoder output port that it will be using our buffer

        err = OMX_UseBuffer(hDecodeComp,
                            &pOmxBufferHeader,  //out
                            OMX_DECODE_OUTPUT_PORT,
                            NULL,
                            outSize,
                            (NvU8*)pOut);

 

 將分配好的pOut指針和他的大小outSize,配成一個OMX_BUF, 並給pOmxBufferHeader,這樣就通過OMX_UseBuffer,來得到一個以後能給他用的Buffer,指針用我們分配的。

 

3:

 

 OMXErr = OMX_FillThisBuffer(hDecodeComp, pOmxBufferHeader);

 

讓hDecodeComp將pOmxBufferHeader的數據準備好(就是輸出數據),pOmxBufferHeader就是通過UseBuffer來組裝的。

 

通過nFilledLen,可以得到具體數據填充情況。

如果OMX_FillThisBuffer是異步函數的話,那真正的返回是要靠:Callback_FillBufferDone 來設置真正數據ready信號

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