Openmax IL (二)Android多媒體編解碼Component

帶着三個問題學習這個部分: 
問題1:Android中間各類編解碼庫的加載與管理? 
問題1:Android如何肯定使用那個編解碼器而且初始化? 
問題2:Android如何集成一個新的編解碼器,硬件平臺相關/非硬件平臺相關兩種狀況?css

按照OpenMax IL的簡述,編解碼架構中間相當重要的是以下兩點: 
1,各個不一樣功能的conponent 
2,平臺商實現的「media.resouce_manager」,用來管理conponent須要的資源。從而控制component狀態的變化。node

PS: 
本文是基於Android7.0+QCOM8909高通平臺,播放本地視頻的狀況分析代碼,先對架構有一個總體的認識,後面再開始對流媒體以及協議的學習與分析。android

1,編解碼加載與管理流程

1.1,系統相關的uml類圖—看編解碼相關成員模塊


分析類圖: 
其中主要包括個模塊 
1,nuplay 
2,MediaCodec 
3,OMXConponent 
4,FileSouce數組

1.2編解碼庫的加載和初始化管理


二,加載初始化時序圖,以及流程分析bash

一,系統包含的編解碼庫文件的描述文件 
「/etc/media_codecs.xml」 
「/etc/media_codecs_performance.xml」架構

這兩個文件列舉了這個系統支持的全部音視頻編解碼對應的支持格式,僅僅在開機初始化的時候加載一次 
project 編譯文件:app

# media_profiles and media_codecs xmls for msm8909 ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS), true) PRODUCT_COPY_FILES += device/Project/media/media_profiles_8909.xml:system/etc/media_profiles.xml \ device/Project/media/media_codecs_8909.xml:system/etc/media_codecs.xml \ device/Project/media/media_codecs_performance_8909.xml:system/etc/media_codecs_performance.xml endif
  • 1
  • 2
  • 3
  • 4
  • 5

qcom/base.mk編譯文件ide

PRODUCT_COPY_FILES += \    frameworks/av/media/libstagefright/data/media_codecs_google_audio.xml:system/etc/media_codecs_google_audio.xml \ frameworks/av/media/libstagefright/data/media_codecs_google_telephony.xml:system/etc/media_codecs_google_telephony.xml \ frameworks/av/media/libstagefright/data/media_codecs_google_video.xml:system/etc/media_codecs_google_video.xml \ device/qcom/common/media/media_profiles.xml:system/etc/media_profiles.xml \ #覆蓋 device/qcom/common/media/media_codecs.xml:system/etc/media_codecs.xml #覆蓋 
  • 1
  • 2
  • 3
  • 4

相關文件描述函數

//media_codecs.xml(media_codecs_8909.xml)
<CodecList> <Include href="media_codecs_google_audio.xml" /> <Include href="media_codecs_google_telephony.xml" /> <Settings> <Setting name="max-video-encoder-input-buffers" value="9" /> </Settings> <Encoders> <!-- Video Hardware --> <MediaCodec name="OMX.qcom.video.encoder.avc" type="video/avc" > <Quirk name="requires-allocate-on-input-ports" /> <Quirk name="requires-allocate-on-output-ports" /> <Quirk name="requires-loaded-to-idle-after-allocation" /> <Limit name="size" min="96x64" max="1280x720" /> <Limit name="alignment" value="2x2" /> <Limit name="block-size" value="16x16" /> <Limit name="blocks-per-second" min="1" max="108000" /> <Limit name="bitrate" range="1-14000000" /> <Limit name="concurrent-instances" max="8" /> <Feature name="intra-refresh" /> </MediaCodec> </Encoders> <Decoders> <!-- Audio Software --> <MediaCodec name="OMX.qti.audio.decoder.flac" type="audio/flac" > <Limit name="concurrent-instances" max="10" /> </MediaCodec> <!-- Video Hardware --> <MediaCodec name="OMX.qcom.video.decoder.avc" type="video/avc" > <Quirk name="requires-allocate-on-input-ports" /> <Quirk name="requires-allocate-on-output-ports" /> <Quirk name="defers-output-buffer-allocation" /> <Limit name="size" min="64x64" max="1920x1088" /> <Limit name="alignment" value="2x2" /> <Limit name="block-size" value="16x16" /> <Limit name="blocks-per-second" min="1" max="244800" /> <Limit name="bitrate" range="1-20000000" /> <Feature name="adaptive-playback" /> <Limit name="concurrent-instances" max="8" /> </MediaCodec> </Decoders> <Include href="media_codecs_google_video.xml" /> </CodecList> // media_codecs_performance.xml (media_codecs_performance_8909.xml) <MediaCodecs> <Encoders> <MediaCodec name="OMX.qcom.video.encoder.avc" type="video/avc" update="true"> <Limit name="measured-frame-rate-320x240" range="183-183" /> <Limit name="measured-frame-rate-720x480" range="56-56" /> <Limit name="measured-frame-rate-1280x720" range="25-25" /> </MediaCodec> <!--還有不少MediaCodec成員--> </Encoders> <Decoders> <MediaCodec name="OMX.qcom.video.decoder.avc" type="video/avc" update="true"> <Limit name="measured-frame-rate-320x240" range="457-457" /> <Limit name="measured-frame-rate-720x480" range="274-274" /> <Limit name="measured-frame-rate-1280x720" range="168-168" /> <Limit name="measured-frame-rate-1920x1088" range="54-54" /> </MediaCodec> </Decoders> // media_codecs_google_audio.xml //media_codecs_google_telephony.xml //media_codecs_google_video.xml //media_codecs_performance.xml //media_profiles.xml 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

二,初始化加載流程如分析 
上圖: 
廠商和google支持的compont初始化加載時序圖post

從上面的交互能夠看出,MediaCodecList初始化的時候: 
1,實質就是經過MediaPlayerService,MediaCodecService去支配依次建立OMX實例(交互10),OMXMaster實例(交互11),從而初始化MediaCodecList::mOMX成員。而OMXMaster構造的時候,實質是去加載,遍歷vendor和google的OMXPlugin,加載各個component。 
這部分重點函數在交互12:addPlugin()

//OMXMaster.c OMXMaster::OMXMaster() : mVendorLibHandle(NULL) { //省略不重要代碼 addVendorPlugin(); addPlugin(new SoftOMXPlugin);//Soft就是google支持的軟解 } //看看加載廠商支持的,就一句話 void OMXMaster::addVendorPlugin() { addPlugin("libstagefrighthw.so"); } // void OMXMaster::addPlugin(const char *libname) { mVendorLibHandle = dlopen(libname, RTLD_NOW); typedef OMXPluginBase *(*CreateOMXPluginFunc)(); //這裏映射hardware/qcom/media/libstagefrighthw/QComOMXPlugin.cpp //實質是建立一個廠商實現的OMXPluginBase子類,廠商硬解,實例化 CreateOMXPluginFunc createOMXPlugin = (CreateOMXPluginFunc)dlsym( mVendorLibHandle, "createOMXPlugin"); if (!createOMXPlugin) createOMXPlugin = (CreateOMXPluginFunc)dlsym( mVendorLibHandle, "_ZN7android15createOMXPluginEv"); if (createOMXPlugin) { addPlugin((*createOMXPlugin)());//經過vendor庫文件函數映射,建立OMXPluginBase,仍是調到這個接口 } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

看了上面的代碼,咱們再來分析addPlugin

void OMXMaster::addPlugin(OMXPluginBase *plugin) {
    Mutex::Autolock autoLock(mLock);
    mPlugins.push_back(plugin);//將全部的plugin保存
    OMX_U32 index = 0; char name[128]; OMX_ERRORTYPE err; //調用plugin接口,實質是枚舉出plugin支持的全部的component,稍後在具體分析 while ((err = plugin->enumerateComponents( name, sizeof(name), index++)) == OMX_ErrorNone) { String8 name8(name); //... // KeyedVector<String8, OMXPluginBase *> mPluginByComponentName; mPluginByComponentName.add(name8, plugin); } // ... }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

mPluginByComponentName,這個數組包含系統全部的編解碼庫的信息。關於plugin->enumerateComponents,咱們具體狀況具體分析,加入是google軟解,SoftOMXPlugin,查閱代碼SoftOMXPlugin.cpp,發現就是根據index返回compont:

OMX_ERRORTYPE SoftOMXPlugin::enumerateComponents(
        OMX_STRING name,
        size_t /* size */,
        OMX_U32 index) {
    //... strcpy(name, kComponents[index].mName); return OMX_ErrorNone; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

那看Component是啥?就是一個數組!列舉了全部的軟解component信息,相似於這樣的:

static const struct { const char *mName;//名字,要和xml文件中間一致的! const char *mLibNameSuffix;//軟解庫文件後綴 const char *mRole; //角色,編解碼?音視頻? } kComponents[] = { { "OMX.google.aac.decoder", "aacdec", "audio_decoder.aac" }, { "OMX.google.aac.encoder", "aacenc", "audio_encoder.aac" }, //全部軟解支持的都在這裏 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

那若是是平臺商的硬解碼呢?以MSM8909爲例: 
在平臺實現的OMXPluginBase子類,枚舉component函數實際是映射到libOmxCore.so中間的方法:

mComponentNameEnum =
            (ComponentNameEnumFunc)dlsym(mLibHandle, "OMX_ComponentNameEnum");
  • 1
  • 2

查閱hardware/qcom/media/mm-core/src/common/qc_omx_core.c這隻文件發現:

typedef struct _omx_core_cb_type { char* name;// Component name ,對應在xml文件中間有值 create_qc_omx_component fn_ptr;// create instance fn ptr void* inst[OMX_COMP_MAX_INST];// Instance handle void* so_lib_handle;// So Library handle char* so_lib_name;// so directory char* roles[OMX_CORE_MAX_CMP_ROLES];// roles played }omx_core_cb_type; //對應初始化 omx_core_cb_type core[] = { { "OMX.qcom.video.decoder.avc", NULL, // Create instance function // Unique instance handle { NULL }, NULL, // Shared object library handle "libOmxVdec.so", { "video_decoder.avc" } }, //... }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

2,加載完component,而後加載解析各個xml文件,根據xml文件描述,主要是初始化MediaCodecList:: mCodecInfos (MediaCodecInfo類型的Vector)。 
注意:經過研究全部的xml文件結構以及解析流程,一個Audio Encoder/Decoder只會有一個」type「標籤,而video能夠有多個,這個就是支持的mineType。

總結一下: 
1,初始化工做的大體流程,能夠理解爲OMXClient和OMXMaster的交互,OMXMaster管理全部的conponent信息,提供接口給client,用來對component的操做: 
OMXClient類圖主要成員函數以及變量

2,至於IOMX這個角色是幹嗎的,具體咱們在後面分析,劇透,這個就是控制編解碼流程,經過ACodec->MuxOMX->OMX->ComponentInstance ->OMX Core ->Concrate component 這條控制線,進行編解碼流程控制。

3,這個流程分析,若是咱們要集成一個軟/硬 編解碼庫,咱們的工做有以下,固然這三點還不夠,還須要作什麼還要往下看:

  1. 添加信息到xml文件
  2. 根據軟硬解碼類型,添加到數組core/kComponent
  3. 同時集成相關的編解碼庫文件到系統

1.3,如何匹配而且初始化一個編解碼庫


初始化一個編解碼庫文件,在以前的文章中間已經有分析到,若是是一個視頻文件,先經過MediaExtractor解封裝,得到到一個MineType,這個就是咱們決定要用何種編解碼的重要依據,也是惟一依據。下面開始分析。

首先,上初始化時序圖:

這裏寫圖片描述

在nuplayer::instantiateDecoder調用的時候,mineType是已知的,這個是查找解碼componnent的惟一依據。 
按照nuplayer::decoder->MediaCodec->ACodec的調用封裝順序分析 
交互5:nuplayer::decoder::onConfig中間作的主要工做以下:

1,初始化一個MediaCodec,實質是實例化一個ACodec而且至於ACodec::UninitializedState狀態。 
2 ,MediaCodec 經過交互11(initiateAllocateComponent)觸發ACodec的系列操做,去根據mineType,最終是構建一個OMXNodeInstance,這是控制OMX core的接口。那這部分的重點,就是看OMXNodeInstance究竟是封裝了什麼東西,以及後面的交互33-42的控制component流程能夠體現其做用。下面重點分析這個實例化流程,學習OMXNodeInstance在Android Openmax中間的關鍵做用。

相關調用參數說明: 
交互18: 主要是傳入mineTpe,返回一組知足的matchingCodecs,隨後在其中遍歷,根據遍歷成功的第一個,allocatenode。

MediaCodecList::findMatchingCodecs( mime.c_str(), encoder, // createEncoder 0, // flags &matchingCodecs);
  • 1
  • 2
  • 3
  • 4
  • 5

交互21:OMX::allocateNode傳入參數主要是爲CodecName,返回一個node_id

status_t OMX::allocateNode(
        const char *name, const sp<IOMXObserver> &observer, sp<IBinder> *nodeBinder, node_id *node) { Mutex::Autolock autoLock(mLock); *node = 0; if (nodeBinder != NULL) { *nodeBinder = NULL; } if (mNodeIDToInstance.size() == kMaxNodeInstances) { // all possible node IDs are in use return NO_MEMORY; }//系統支持的node instance是有上限的 OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name); //建立一個實例,第三個參數是codec name OMX_COMPONENTTYPE *handle; //得到一個handle,這個繼續跟代碼 OMX_ERRORTYPE err = mMaster->makeComponentInstance( name, &OMXNodeInstance::kCallbacks, instance, &handle); //... *node = makeNodeID_l(instance);//得到node_id mDispatchers.add(*node, new CallbackDispatcher(instance)); instance->setHandle(*node, handle);//設置操做句柄 mLiveNodes.add(IInterface::asBinder(observer), instance); IInterface::asBinder(observer)->linkToDeath(this); return OK; } //下面看OMXMaster::makeComponentInstance,實質是根據名字找到對應的OMXPluginBase,而後調用OMXPluginBase::makeComponentInstance,以AAC軟件爲例。則是調用以下: /* @name:"OMX.google.mp3.decoder" */ OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance( const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) { for (size_t i = 0; i < kNumComponents; ++i) { if (strcmp(name, kComponents[i].mName)) { continue; } //1,遍歷kComponent,找到這個解碼庫名字對應信息,找到繼續下走,不然查找下一個。 AString libName = "libstagefright_soft_"; libName.append(kComponents[i].mLibNameSuffix); libName.append(".so"); //2,解碼庫名字對應信息,合成一個解碼庫的名字,這裏解碼庫後綴"aacdec",那麼編解碼庫就是libstagefright_soft_aacdec void *libHandle = dlopen(libName.c_str(), RTLD_NOW); if (libHandle == NULL) { ALOGE("unable to dlopen %s: %s", libName.c_str(), dlerror()); return OMX_ErrorComponentNotFound; } //3,讀解碼庫,libstagefright_soft_aacdec,映射出其中名字爲「createSoftOMXComponent」的建立方法 typedef SoftOMXComponent *(*CreateSoftOMXComponentFunc)( const char *, const OMX_CALLBACKTYPE *, OMX_PTR, OMX_COMPONENTTYPE **); CreateSoftOMXComponentFunc createSoftOMXComponent = (CreateSoftOMXComponentFunc)dlsym( libHandle, "_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE" "PvPP17OMX_COMPONENTTYPE"); if (createSoftOMXComponent == NULL) { dlclose(libHandle); libHandle = NULL; return OMX_ErrorComponentNotFound; } //4,執行「createSoftOMXComponent」的建立方法,建立一個SoftOMXComponent,關注下component賦值 sp<SoftOMXComponent> codec = (*createSoftOMXComponent)(name, callbacks, appData, component); if (codec == NULL) { dlclose(libHandle); libHandle = NULL; return OMX_ErrorInsufficientResources; } OMX_ERRORTYPE err = codec->initCheck(); if (err != OMX_ErrorNone) { dlclose(libHandle); libHandle = NULL; return err; } codec->incStrong(this); codec->setLibHandle(libHandle); return OMX_ErrorNone; } return OMX_ErrorInvalidComponentName; } //5,查閱這個AAC解碼庫,找到建立codec對應的方法,其實就是實例化一個SoftAAC2,關注component賦值 android::SoftOMXComponent *createSoftOMXComponent( const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) { return new android::SoftAAC2(name, callbacks, appData, component); } //6,追查component賦值,發現其賦值是調用的基類的賦值方法繼承關係爲:SoftAAC2 : public SimpleSoftOMXComponent:SoftOMXComponent,那麼其賦值爲: SoftOMXComponent::SoftOMXComponent( const char *name, const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData, OMX_COMPONENTTYPE **component) : mName(name), mCallbacks(callbacks), mComponent(new OMX_COMPONENTTYPE), mLibHandle(NULL) { //可見,就是建立一個OMX_COMPONENTTYPE,賦值後,傳給component mComponent->nSize = sizeof(*mComponent); mComponent->nVersion.s.nVersionMajor = 1; mComponent->nVersion.s.nVersionMinor = 0; mComponent->nVersion.s.nRevision = 0; mComponent->nVersion.s.nStep = 0; mComponent->pComponentPrivate = this;//重點 mComponent->pApplicationPrivate = appData; mComponent->GetComponentVersion = NULL; mComponent->SendCommand = SendCommandWrapper; mComponent->GetParameter = GetParameterWrapper; mComponent->SetParameter = SetParameterWrapper; mComponent->GetConfig = GetConfigWrapper; mComponent->SetConfig = SetConfigWrapper; mComponent->GetExtensionIndex = GetExtensionIndexWrapper; mComponent->GetState = GetStateWrapper; mComponent->ComponentTunnelRequest = NULL; mComponent->UseBuffer = UseBufferWrapper; mComponent->AllocateBuffer = AllocateBufferWrapper; mComponent->FreeBuffer = FreeBufferWrapper; //以此爲例,查看這裏封裝的什麼 mComponent->EmptyThisBuffer = EmptyThisBufferWrapper; mComponent->FillThisBuffer = FillThisBufferWrapper; mComponent->SetCallbacks = NULL; mComponent->ComponentDeInit = NULL; mComponent->UseEGLImage = NULL; mComponent->ComponentRoleEnum = NULL; *component = mComponent; } // static OMX_ERRORTYPE SoftOMXComponent::EmptyThisBufferWrapper( OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE *buffer) { SoftOMXComponent *me = (SoftOMXComponent *) ((OMX_COMPONENTTYPE *)component)->pComponentPrivate; //基類無此方法實現,查看子類,看下面 return me->emptyThisBuffer(buffer); } OMX_ERRORTYPE SimpleSoftOMXComponent::emptyThisBuffer( OMX_BUFFERHEADERTYPE *buffer) { sp<AMessage> msg = new AMessage(kWhatEmptyThisBuffer, mHandler); msg->setPointer("header", buffer); msg->post(); return OMX_ErrorNone; } //根據這個kWhatEmptyThisBuffer消息查看,其中會發現不少SimpleSoftOMXComponent也沒有實現的方法,這個時候,就須要查看SoftAAC2中間的具體實現了。 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176

從上面的代碼分析來看從makeComponentInstance初始化一個component,實質是將SoftOMXComponent與具體的解碼庫結合。每一個解碼庫,都必須實現一個SimpleSoftOMXComponent接口,如SoftAAC2,這個類是和具體的解碼庫關聯的接口文件,那麼集成一個解碼庫,還須要實現一個SimpleSoftOMXComponent子類,建立要點:

  1. 實現一個createSoftOMXComponent,用於初始化
  2. 實現一個SimpleSoftOMXComponent子類,調用libstagefright_soft_xxx 中間的編解碼方法,實現編解碼流程,具體接口參考SimpleSoftOMXComponent

固然若是是視頻的解碼庫,那麼就須要去查閱SoftVideoDecoderOMXComponent的封裝與實現

能夠看下OMX_CALLBACKTYPE和OMX_COMPONENTTYPE在OMX中間的聲明與定義。

1.4 從控制Conponent分析OMXNodeInstance到底封裝了什麼?

在ACodec經過OMX建立 OMXNodeInstance實例的時候,關注這個成員:

// static OMX_CALLBACKTYPE OMXNodeInstance::kCallbacks = { &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone };
  • 1
  • 2
  • 3
  • 4

這個OMX_CALLBACKTYPE最終是賦值給哪裏查看SoftOMXComponent的三個相關方法。以下:

void SoftOMXComponent::notify( OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2, OMX_PTR data) { (*mCallbacks->EventHandler)( mComponent, mComponent->pApplicationPrivate, event, data1, data2, data); } void SoftOMXComponent::notifyEmptyBufferDone(OMX_BUFFERHEADERTYPE *header) { (*mCallbacks->EmptyBufferDone)( mComponent, mComponent->pApplicationPrivate, header); } void SoftOMXComponent::notifyFillBufferDone(OMX_BUFFERHEADERTYPE *header) { (*mCallbacks->FillBufferDone)( mComponent, mComponent->pApplicationPrivate, header); }
相關文章
相關標籤/搜索