編輯:關於Android編程
之所以單獨把這塊內容提煉出來,在於其具備的一定的層次性,結構上具備統一性,API函數的設計需要實現OMX架構獨有的接口。
1. 在上一博文Android4.2.2下Stagefright多媒體架構中的A31的OMX插件和Codec組件 中我們提到,通過Binder架構,在MPS的線程上創建完一個實際的編解碼器節點後,獲取到了一個node:node_id。如下所示將會根據相關的節點信息,創建一個MPS側的OMXCodec結構體,作為類似本地的一個編解碼器。
..... spcodec = new OMXCodec( omx, node, quirks, flags, createEncoder, mime, componentName, source, nativeWindow);//創建一個本地OMXCodec解碼器,node成為後續的操作的關鍵IOMX::node_id //omx為Master observer->setCodec(codec);//將解碼器交給observer err = codec->configureCodec(meta);//根據數據源配置本地的這個解碼器 ........
在configureCodec對這個解碼器的配置中,我們可以看到一些對之前分配的解碼器節點的控制操作。我們以它其中的一個函數調用為例,進行控制流的層層分析:
setVideoOutputFormat(mMIME, meta);//設置視頻輸出格式
mOMX->getParameter(mNode, OMX_IndexParamPortDefinition, &def, sizeof(def))
這裡看到mOMX是在創建AwesomePlayer時獲取的一個匿名的BpOMX對象。最終的實現在MediaPlayerService中的中的OMX對象來實現getParameter。
2.OMX對象下的操作。
status_t OMX::getParameter( node_id node, OMX_INDEXTYPE index, void *params, size_t size) { return findInstance(node)->getParameter( index, params, size); }
findInstance(node)這裡就是根據這個node_id來獲取之前注冊的一個OMXNodeInstance對象實例:
OMXNodeInstance *OMX::findInstance(node_id node) { Mutex::Autolock autoLock(mLock); ssize_t index = mNodeIDToInstance.indexOfKey(node); return index < 0 ? NULL : mNodeIDToInstance.valueAt(index); }
最終就變成了如下的調用:
status_t OMXNodeInstance::setParameter( OMX_INDEXTYPE index, const void *params, size_t size) { Mutex::Autolock autoLock(mLock); OMX_ERRORTYPE err = OMX_SetParameter( mHandle, index, const_cast(params)); return StatusFromOMXError(err); }
3.OMX_XXX的實現
#define OMX_GetParameter( \ hComponent, \ nParamIndex, \ ComponentParameterStructure) \ ((OMX_COMPONENTTYPE*)hComponent)->GetParameter( \ hComponent, \ nParamIndex, \ ComponentParameterStructure) /* Macro End */
OMX_SetParameter等宏函數是OMX_CORE的核心所在,也是原來OpenOMx裡的OMX IL層的體現。來看mHandle的類型,作為一個OMXNodeInstance對象的成員變量,他維護著之前makeComponentInstance返回的一個對底層編解碼組件庫的句柄。這裡看上去就是一個OMX節點實例,一個句柄可操作最下層的解碼組件。可以看到handle轉為OMX_COMPONENTTYPE類型。裡看看其的結構體類型:
typedef struct OMX_COMPONENTTYPE { OMX_U32 nSize; OMX_VERSIONTYPE nVersion; OMX_COMPONENTNAMETYPE eCompName; OMX_PTR pComponentPrivate; OMX_ERRORTYPE (*GetParameter)( OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_INDEXTYPE nIndex, OMX_IN OMX_PTR ComponentParameterStructure);...............
這個handle的獲取是在之前創建解碼器節點時完成的,通過需要創建的解碼器的name,通過OMX插件庫,再進入到libOmxCore.so(OMX IL固有結構)調用OMX_GetHandle來獲取對應組件name下的平台解碼庫libOmxVdec.so,或者libOmxVenc.so等。這個handle通過以下完成初始化:
void* aw_omx_create_component_wrapper(OMX_PTR obj_ptr) { aw_omx_component *pThis = (aw_omx_component *)obj_ptr;//omx_vdec對象 OMX_COMPONENTTYPE* component = &(pThis->m_cmp);//對m_cmp進行初始化 memset(&pThis->m_cmp,0,sizeof(OMX_COMPONENTTYPE)); component->nSize = sizeof(OMX_COMPONENTTYPE); component->nVersion.nVersion = OMX_SPEC_VERSION; component->pApplicationPrivate = 0; component->pComponentPrivate = obj_ptr;//保存著omx_vdec這個對象 component->AllocateBuffer = &aw_omx_component_allocate_buffer; component->FreeBuffer = &aw_omx_component_free_buffer; component->GetParameter = &aw_omx_component_get_parameter; component->SetParameter = &aw_omx_component_set_parameter; component->SendCommand = &aw_omx_component_send_command; component->FillThisBuffer = &aw_omx_component_fill_this_buffer; component->EmptyThisBuffer = &aw_omx_component_empty_this_buffer; component->GetState = &aw_omx_component_get_state; component->GetComponentVersion = &aw_omx_component_get_version; component->GetConfig = &aw_omx_component_get_config; component->SetConfig = &aw_omx_component_set_config; component->GetExtensionIndex = &aw_omx_component_get_extension_index; component->ComponentTunnelRequest = &aw_omx_component_tunnel_request; component->UseBuffer = &aw_omx_component_use_buffer; component->SetCallbacks = &aw_omx_component_set_callbacks; component->UseEGLImage = &aw_omx_component_use_EGL_image; component->ComponentRoleEnum = &aw_omx_component_role_enum; component->ComponentDeInit = &aw_omx_component_deinit; return (void *)component; }
通過以上的賦值操作,我們關注這個component->pComponentPrivate = obj_ptr,他是將硬件平台的解碼器實例維護到handle結構體中,因為最終的操作肯定都要回到最底層的解碼器控制。這也就是OMX IL的架構給予了開發者的方便性和規劃化。通過這個我們就可以總結出需要以下幾個文件來銜接更底層的編解碼器:
xxx_omx_core.c和omx_core_cmp.c兩個源文件來完成。前者提供向上的接口用於創建編解碼器實例,後者提供例如上述的xxx_omx_component_api接口的實現,而實際其實現是調用的是編解碼的相關API來處理:
OMX_ERRORTYPE aw_omx_component_get_parameter(OMX_IN OMX_HANDLETYPE hComp, OMX_IN OMX_INDEXTYPE paramIndex, OMX_INOUT OMX_PTR paramData) { OMX_ERRORTYPE eRet = OMX_ErrorBadParameter; aw_omx_component *pThis = (hComp)? (aw_omx_component *)(((OMX_COMPONENTTYPE *)hComp)->pComponentPrivate):NULL; DEBUG_PRINT("OMXCORE: aw_omx_component_get_parameter %x, %x , %d\n",(unsigned)hComp,(unsigned)paramData,paramIndex); if(pThis) { eRet = pThis->get_parameter(hComp,paramIndex,paramData); } return eRet; }
這裡的pThis技術當前最底層的解碼器組件的控制入口。即所謂的aw_omx_component的派生類對象。這樣也就是說明了我們自己要構建的編解碼需要實aw_omx_component的相關接口函數,可以看到這裡我們最底層的解碼器組件就是對這些函數的實現,加快了自定義一個新的組件類型,以下是幾個接口的定義和實現:
OMX_ERRORTYPE omx_vdec::set_parameter(OMX_IN OMX_HANDLETYPE hComp, OMX_IN OMX_INDEXTYPE paramIndex, OMX_IN OMX_PTR paramData)
OMX_ERRORTYPE omx_vdec::get_parameter(OMX_IN OMX_HANDLETYPE hComp, OMX_IN OMX_INDEXTYPE paramIndex, OMX_INOUT OMX_PTR paramData)
到這裡我們基本走通了從OMXCodec到對最底層的編解碼器組件的控制,層次分明,接口規范帶給我們的是快速開發,我們需要做的核心是在自己的編解碼器組件中實現相關的業務,而這和自身的硬件平台具有緊密性。
4.總結新建一個屬於stagefright下OMX的編解碼組件需要做的事情
我們所要做的核心工作就在libOmxCore.so和libOmxVdec.so這兩個庫文件的設計。但都需要符合OMX的協議即可。
分析了那麼多的控制流,也已經有了所謂的OMXCodec,那麼後續主要內容將是數據流的處理。
概述本篇博文主要介紹的是Android中的Java服務。這部分服務大部分都有一個Manager類,其實就是一個RPC調用,用戶通過調用xxxManager的方法,實際上被
APP中可能會遇到一種需求,就是將當前所在位置的坐標傳到服務器上,今天我提供三種途徑去獲取經緯度坐標信息,第一種是通過Android API來實現,第二種通過百度地圖AP
很多項目需要用到彈幕效果,尤其是在播放視頻的時候需要一起顯示別人發的彈幕,也包括自己的發的。今天就試著寫了一下這個效果。 思路就是將從右往左的動畫效果,字體內容
好久沒有更新博客,寫這篇技術時,感覺很多東西生疏了好多。於是心有感慨:我們做技術的,要是長時間不搞技術,那就是被技術搞!所以攻守之間,大家謹慎思量。冬天已過,放假出去玩耍