Stagefright多媒体架构中的A31的OMX插件和Codec组件

来源:互联网 发布:债券代持 知乎 编辑:程序博客网 时间:2024/06/07 05:36
Android4.2.2下Stagefright多媒体架构中的A31的OMX插件和Codec组件
2014-05-23      0 个评论    来源:Android4.2.2下Stagefright多媒体架构中的A31的OMX插件和Codec组件  
收藏    我要投稿

本文均属自己阅读源码的点滴总结,转账请注明出处谢谢。

欢迎和大家交流。qq:1037701636 email: gzzaigcn2012@gmail.com

在前面的博文中提到,AwesomePlayer::onPrepareAsyncEvent()开始进行Codec解码器组件的获取以及创建,这里和大家分享。

1.以解码器实例作为切入点

?
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
status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
    ATRACE_CALL();
......
    ALOGV("initVideoDecoder flags=0x%x", flags);
    mVideoSource = OMXCodec::Create(
            mClient.interface(), mVideoTrack->getFormat(),//提取视频流的格式, mClient:BpOMX
            false,// createEncoder
            mVideoTrack,
            NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);//创建一个解码器mVideoSource
 
    if(mVideoSource != NULL) {
        int64_t durationUs;
        if(mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
            Mutex::Autolock autoLock(mMiscStateLock);
            if(mDurationUs < 0|| durationUs > mDurationUs) {
                mDurationUs = durationUs;
            }
        }
 
        status_t err = mVideoSource->start();//启动解码器OMXCodec
 
        if(err != OK) {
            ALOGE("failed to start video source");
            mVideoSource.clear();
            returnerr;
        }
    }
......
}

这里不得不先说明以下几个成员变量的相关内容,方便后续的分析:

a. mClinet:OMXClient(继承于)类对象。做为AwesomePlayer的成员变量,在这里能找到他的一些踪迹。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
AwesomePlayer::AwesomePlayer()
    : mQueueStarted(false),
      mUIDValid(false),
      mTimeSource(NULL),
      mVideoRenderingStarted(false),
      mVideoRendererIsPreview(false),
      mAudioPlayer(NULL),
      mDisplayWidth(0),
      mDisplayHeight(0),
      mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
      mFlags(0),
      mExtractorFlags(0),
      mVideoBuffer(NULL),
      mDecryptHandle(NULL),
      mLastVideoTimeUs(-1),
      mTextDriver(NULL) {
    CHECK_EQ(mClient.connect(), (status_t)OK);//OMXClient,connect后维护一个mOMX:BpOMX

看到这里进行了connect的处理,我们来看看其所完成的工作:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
status_t OMXClient::connect() {
    sp<iservicemanager> sm = defaultServiceManager();
    sp<ibinder> binder = sm->getService(String16("media.player"));
    sp<imediaplayerservice> service = interface_cast<imediaplayerservice>(binder);//获取MPS服务BpMediaPlayerService
 
    CHECK(service.get() != NULL);
 
    mOMX = service->getOMX();//获取一个omx在本地的接口传给videosource, BpOMX
    CHECK(mOMX.get() != NULL);
 
    if(!mOMX->livesLocally(NULL /* node */, getpid())) {
        ALOGI("Using client-side OMX mux.");
        mOMX = newMuxOMX(mOMX);
    }
 
    returnOK;
}</imediaplayerservice></imediaplayerservice></ibinder></iservicemanager>

这里进行线程间的Binder驱动处理。获取一个OMX组件的接口到mOMX。我们不得不去看MediaPlayService端的getOMX的实现:

?
1
2
3
4
5
6
7
8
9
10
sp<iomx> MediaPlayerService::getOMX() {
    Mutex::Autolock autoLock(mLock);
 
    if(mOMX.get() == NULL) {
        mOMX = newOMX;//新建一个本地匿名的OMX
    }
 
    returnmOMX;
}
</iomx>

新构建了一个OMX组件类,该类继承了BnOMX。使得Binder驱动返回后最终创建的是一个BpOMX这么个匿名驱动。

返回BpOMX后在OMXClient侧创建一个MuxOMX类mOMX,其作为OMXClient的成员变量而存在。

分析可知mClient.interace即是connect创建的mOMX组件。

b.

setVideoSource(extractor->getTrack(i));//设置视频源mVideoTrack ;

setAudioSource(extractor->getTrack(i));//设置音频源mAudioTrack;

mVideoTrack和mAudioTrack的做为创建的AwesomePlay的成员函数,其类型为MPEG4Source,继承了MediaSource。

那么mVideoTrack->getFormat(),是获取对应视频信息源的格式。

2.OMXCodec的创建

所有的解码器无论是软解还是硬解,都是挂载OMX下面,作为其的一个Component来使用。下面来看一个Codec的创建过程。

?
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
sp<mediasource> OMXCodec::Create(
        constsp<iomx> &omx,
        constsp<metadata> &meta, bool createEncoder,
        constsp<mediasource> &source,
        constchar *matchComponentName,
        uint32_t flags,
        constsp &nativeWindow) {
    int32_t requiresSecureBuffers;
    if(source->getFormat()->findInt32(
                kKeyRequiresSecureBuffers,
                &requiresSecureBuffers)
            && requiresSecureBuffers) {
        flags |= kIgnoreCodecSpecificData;
        flags |= kUseSecureInputBuffers;
    }
 
    constchar *mime;
    bool success = meta->findCString(kKeyMIMEType, &mime);
    CHECK(success);
 
    Vector<codecnameandquirks> matchingCodecs;
    findMatchingCodecs(
            mime, createEncoder, matchComponentName, flags, &matchingCodecs);//寻找可用的解码器如OMX.allwinner.video.decoder.avc
 
    if(matchingCodecs.isEmpty()) {
        ALOGV("No matching codecs! (mime: %s, createEncoder: %s, "
                "matchComponentName: %s, flags: 0x%x)",
                mime, createEncoder ? "true": "false", matchComponentName, flags);
        returnNULL;
    }
 
    sp<omxcodecobserver> observer = newOMXCodecObserver;
    IOMX::node_id node = 0;
 
    for(size_t i = 0; i < matchingCodecs.size(); ++i) {
        constchar *componentNameBase = matchingCodecs[i].mName.string();//OMX组件的名字
        uint32_t quirks = matchingCodecs[i].mQuirks;
        constchar *componentName = componentNameBase;
 
        AString tmp;
        if(flags & kUseSecureInputBuffers) {
            tmp = componentNameBase;
            tmp.append(".secure");
 
            componentName = tmp.c_str();
        }
 
        if(createEncoder) {//软解码器createEncoder = 1;
            sp<mediasource> softwareCodec =
                InstantiateSoftwareEncoder(componentName, source, meta);
 
            if(softwareCodec != NULL) {
                ALOGV("Successfully allocated software codec '%s'", componentName);
 
                returnsoftwareCodec;
            }
        }
 
        ALOGV("Attempting to allocate OMX node '%s'", componentName);
 
        if(!createEncoder
                && (quirks & kOutputBuffersAreUnreadable)
                && (flags & kClientNeedsFramebuffer)) {
            if(strncmp(componentName, "OMX.SEC.",8)) {
                // For OMX.SEC.* decoders we can enable a special mode that
                // gives the client access to the framebuffer contents.
 
                ALOGW("Component '%s' does not give the client access to "
                     "the framebuffer contents. Skipping.",
                     componentName);
 
                continue;
            }
        }
 
        status_t err = omx->allocateNode(componentName, observer, &node);//请求mediaplayerservice创建一个节点,真正的解码器所在
        if(err == OK) {
            ALOGV("Successfully allocated OMX node '%s'", componentName);
 
            sp<omxcodec> codec = newOMXCodec(
                    omx, node, quirks, flags,
                    createEncoder, mime, componentName,
                    source, nativeWindow);//创建一个本地OMXCodec解码器
 
            observer->setCodec(codec);//将解码器交给observer
 
            err = codec->configureCodec(meta);
 
            if(err == OK) {
                if(!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {
                    codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;
                }
 
                returncodec;
            }
 
            ALOGV("Failed to configure codec '%s'", componentName);
        }
    }
 
    returnNULL;
}</omxcodec></mediasource></omxcodecobserver></codecnameandquirks></anativewindow></mediasource></metadata></iomx></mediasource>

2.1 查找平台支持的解码器

bool success = meta->findCString(kKeyMIMEType, &mime);首先对传入的视频源track进行mime的提取。然后是继续一个解码器的查找,为当前视频源的解码所用:

findMatchingCodecs();//寻找可用的解码器如OMX.allwinner.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
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
voidOMXCodec::findMatchingCodecs(
        constchar *mime,
        bool createEncoder, constchar *matchComponentName,
        uint32_t flags,
        Vector<codecnameandquirks> *matchingCodecs) {
    matchingCodecs->clear();
 
    constMediaCodecList *list = MediaCodecList::getInstance();
    if(list == NULL) {
        return;
    }
 
    size_t index = 0;
    for(;;) {
        ssize_t matchIndex =
            list->findCodecByType(mime, createEncoder, index);
 
        if(matchIndex < 0) {
            break;
        }
 
        index = matchIndex + 1;
 
        constchar *componentName = list->getCodecName(matchIndex);//获取解码器的名字
 
        // If a specific codec is requested, skip the non-matching ones.
        if(matchComponentName && strcmp(componentName, matchComponentName)) {
            continue;
        }
 
        // When requesting software-only codecs, only push software codecs
        // When requesting hardware-only codecs, only push hardware codecs
        // When there is request neither for software-only nor for
        // hardware-only codecs, push all codecs
        if(((flags & kSoftwareCodecsOnly) &&   IsSoftwareCodec(componentName)) ||
            ((flags & kHardwareCodecsOnly) &&  !IsSoftwareCodec(componentName)) ||
            (!(flags & (kSoftwareCodecsOnly | kHardwareCodecsOnly)))) {
 
            ssize_t index = matchingCodecs->add();
            CodecNameAndQuirks *entry = &matchingCodecs->editItemAt(index);
            entry->mName = String8(componentName);
            entry->mQuirks = getComponentQuirks(list, matchIndex);
 
            ALOGV("matching '%s' quirks 0x%08x",
                  entry->mName.string(), entry->mQuirks);
        }
    }
 
    if(flags & kPreferSoftwareCodecs) {
        matchingCodecs->sort(CompareSoftwareCodecsFirst);
    }
}</codecnameandquirks>

在这里很熟悉的看到一个单列模式的创建MediaCodecList,一个多媒体解码器列表的创建。在这里我们很有必要看一下他的构造过程,因为这里体现出android4.2.2的编解码器维护和之前2.3等的不同。也是他更接近移动互联的表现之一。

2.2 MediaCodecList的构建

?
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
constMediaCodecList *MediaCodecList::getInstance() {
    Mutex::Autolock autoLock(sInitMutex);
 
    if(sCodecList == NULL) {
        sCodecList = newMediaCodecList;
    }
 
    returnsCodecList->initCheck() == OK ? sCodecList : NULL;
}
 
MediaCodecList::MediaCodecList()//单列模式的创建,解析xml完成当前mCodecInfos的维护,支持的编解码器
    : mInitCheck(NO_INIT) {
    FILE *file = fopen("/etc/media_codecs.xml","r");
 
    if(file == NULL) {
        ALOGW("unable to open media codecs configuration xml file.");
        return;
    }
 
    parseXMLFile(file);//解析xml文件提取其中支持的codec
 
    if(mInitCheck == OK) {
        // These are currently still used by the video editing suite.
/*
            <mediacodec name="OMX.allwinner.video.decoder.avc" type="video/avc">
           <mediacodec name="OMX.allwinner.video.decoder.mpeg2" type="video/mpeg2">
 
        */
        addMediaCodec(true/* encoder */,"AACEncoder","audio/mp4a-latm");//硬解码器
 
        addMediaCodec(
                false/* encoder */,"OMX.google.raw.decoder","audio/raw");//软解码器
    }
 
#if0
    for(size_t i = 0; i < mCodecInfos.size(); ++i) {
        constCodecInfo &info = mCodecInfos.itemAt(i);
 
        AString line = info.mName;
        line.append(" supports ");
        for(size_t j = 0; j < mTypes.size(); ++j) {
            uint32_t value = mTypes.valueAt(j);
 
            if(info.mTypes & (1ul << value)) {
                line.append(mTypes.keyAt(j));
                line.append(" ");
            }
        }
 
        ALOGI("%s", line.c_str());
    }
#endif
 
    fclose(file);
    file = NULL;
}
</mediacodec></mediacodec>

MediaCodecList的特点在于它对一个/etc/media_codecs.xml进行了解析,很容易看到xml让人感觉到了互联网的特色所在。我们来看看在全志A31下的这个配置文件部分内容,显然放在最前面的是全志自己的软硬件解码器:

?
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
<mediacodecs>
 93    <decoders>
 94        <mediacodec name="OMX.allwinner.video.decoder.avc"type="video/avc">
 95        <mediacodec name="OMX.allwinner.video.decoder.mpeg2"type="video/mpeg2">
 96        <mediacodec name="OMX.google.mpeg4.decoder"type="video/mp4v-es">
 97        <mediacodec name="OMX.google.h263.decoder"type="video/3gpp">
 98        <mediacodec name="OMX.google.vpx.decoder"type="video/x-vnd.on2.vp8">
 99
100        <mediacodec name="OMX.google.mp3.decoder"type="audio/mpeg">
101        <mediacodec name="OMX.google.amrnb.decoder"type="audio/3gpp">
102        <mediacodec name="OMX.google.amrwb.decoder"type="audio/amr-wb">
103        <mediacodec name="OMX.google.aac.decoder"type="audio/mp4a-latm">
104        <mediacodec name="OMX.google.g711.alaw.decoder"type="audio/g711-alaw">
105        <mediacodec name="OMX.google.g711.mlaw.decoder"type="audio/g711-mlaw">
106        <mediacodec name="OMX.google.vorbis.decoder"type="audio/vorbis">
107        <mediacodec name="OMX.google.raw.decoder"type="audio/raw">
108
109    </mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></decoders>
110
111    <encoders>
112        <mediacodec name="OMX.allwinner.video.encoder.avc"type="video/avc">
113
114        <mediacodec name="OMX.google.h263.encoder"type="video/3gpp">
115        <mediacodec name="OMX.google.mpeg4.encoder"type="video/mp4v-es">
116        <mediacodec name="OMX.google.amrnb.encoder"type="audio/3gpp">
117        <mediacodec name="OMX.google.amrwb.encoder"type="audio/amr-wb">
118        <mediacodec name="OMX.google.aac.encoder"type="audio/mp4a-latm">
119        <mediacodec name="OMX.google.flac.encoder"type="audio/flac">
120    </mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></mediacodec></encoders>
121</mediacodecs>

而这个文件的解析通过parseXMLFile来完成,最终解码器属性维护在了mCodecInfos,这其中xml文件的解析过程不是很熟悉,但核心是提取name和type这两个字段后进行addMediaCodec的操作。
当然,我们也可以通过手动addMediaCodec来完成添加,其中ture代表的是编码器,反之则为解码器。

通过以上的手段,最终我们获取到了硬件平台所支持的所有编解码器的类型,也就是OMX下的各种Component组件。

2.3

有了这个所谓的编解码器list,一切的变得更加的轻松,分别经过如下处理:

?
1
ssize_t matchIndex = list->findCodecByType(mime, createEncoder, index);
?
1
constchar *componentName = list->getCodecName(matchIndex);//获取解码器的名字

componentName将成为后续的进一步处理的关键

3. 创建一个属于OMX解码器的Node节点

?
1
status_t err = omx->allocateNode(componentName, observer, &node);//请求mediaplayerservice创建一个节点,真正的解码器所在

这里的omx在传入时已经分析过,变量类型为一个匿名Binder服务类BpOMX.回到在MediaPlayService的BnOMX处,估计核心的创建解码器等还是要交给MPS来完成的。

?
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
status_t OMX::allocateNode(
        constchar *name, constsp<iomxobserver> &observer, node_id *node) {
    Mutex::Autolock autoLock(mLock);
 
    *node = 0;
 
    OMXNodeInstance *instance = newOMXNodeInstance(this, observer);//新建一个OMXNodeInstance实例
 
    OMX_COMPONENTTYPE *handle;
    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
            name, &OMXNodeInstance::kCallbacks,
            instance, &handle);//创建一个组件,并获取其操作句柄
 
    if(err != OMX_ErrorNone) {
        ALOGV("FAILED to allocate omx component '%s'", name);
 
        instance->onGetHandleFailed();
 
        returnUNKNOWN_ERROR;
    }
 
    *node = makeNodeID(instance);
    mDispatchers.add(*node,newCallbackDispatcher(instance));
 
    instance->setHandle(*node, handle);
 
    mLiveNodes.add(observer->asBinder(), instance);
    observer->asBinder()->linkToDeath(this);
 
    returnOK;
}
</iomxobserver>

3.1 新建一个真正的OMXNodeInstance实例

3.2 mMaster->makeComponentInstance()真正获取一个多下一层解码器的控制权
这里要和大家分析mMaster这个变量:

在获取BpOMX时,在MPS侧的getOMX里实现了new OMX:

?
1
2
3
4
OMX::OMX()
    : mMaster(newOMXMaster),//新建一个mMaster
      mNodeCounter(0) {
}

这里看到MPS中的mOMX成员的子成员mMaster。

?
1
2
3
4
5
OMXMaster::OMXMaster()
    : mVendorLibHandle(NULL) {
    addVendorPlugin();//插入设备厂商的编解码器插件libstagefrighthw
    addPlugin(newSoftOMXPlugin);
}

看到这里我会觉得OMXMaster是所有底层编解码的管理者吧。因此组件的创建等都需要通过他来完成。

4.OMXMaster管理者的角色扮演

?
1
2
3
voidOMXMaster::addVendorPlugin() {
    addPlugin("libstagefrighthw.so");//厂商的硬件编解码器
}

看到这里添加了所谓的设备厂商的插件,看到其是添加了一个libstagefrighthw.so库。我们看看他是如何对这个so文件做处理的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
voidOMXMaster::addPlugin(constchar *libname) {
    mVendorLibHandle = dlopen(libname, RTLD_NOW);
 
    if(mVendorLibHandle == NULL) {
        return;
    }
 
    typedef OMXPluginBase *(*CreateOMXPluginFunc)();
    CreateOMXPluginFunc createOMXPlugin =
        (CreateOMXPluginFunc)dlsym(
                mVendorLibHandle,"createOMXPlugin");
    if(!createOMXPlugin)
        createOMXPlugin = (CreateOMXPluginFunc)dlsym(
                mVendorLibHandle,"_ZN7android15createOMXPluginEv");
 
    if(createOMXPlugin) {
        addPlugin((*createOMXPlugin)());//将当前的lib插件加入到Component中去
    }
}

这里做了典型的lib库的操作,dlopen加载库,dlsym获取库中的操作函数handle。*createOMXPLugin()是调用这个so库中的函数,这个函数返回的是一个OMXPluginBase*的类型。

到这里,我觉得和有必要和大家分析下OMX下的插件的基本结构了,因为只有满足这个规定的结构,才能成为一个合理的OMX下的插件。而

5. 神奇的libstagefighthw.so

这个被称之为平台厂商所设计的组件插件。在A31里面我们可以看到他的源码:/home/A31_Android4.2.2/android/hardware/aw/libstagefrighthw

我来看看之前调用该库里面的函数createOMXPlugin,获取其入口地址后,直接调用后是创建了属于AW的一个OMX插件

?
1
2
3
4
extern"C"OMXPluginBase* createOMXPlugin()
{
    returnnew AwOMXPlugin;//创建一个解码器插件
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
AwOMXPlugin::AwOMXPlugin()
    : mLibHandle(dlopen("libOmxCore.so", RTLD_NOW)),
      mInit(NULL),
      mDeinit(NULL),
      mComponentNameEnum(NULL),
      mGetHandle(NULL),
      mFreeHandle(NULL),
      mGetRolesOfComponentHandle(NULL)
{
    if(mLibHandle != NULL)
    {
        mInit                      = (InitFunc)dlsym(mLibHandle, "OMX_Init");
        mDeinit                    = (DeinitFunc)dlsym(mLibHandle, "OMX_Deinit");
        mComponentNameEnum         = (ComponentNameEnumFunc)dlsym(mLibHandle, "OMX_ComponentNameEnum");
        mGetHandle                 = (GetHandleFunc)dlsym(mLibHandle, "OMX_GetHandle");
        mFreeHandle                = (FreeHandleFunc)dlsym(mLibHandle, "OMX_FreeHandle");
        mGetRolesOfComponentHandle = (GetRolesOfComponentFunc)dlsym(mLibHandle, "OMX_GetRolesOfComponent");
 
        (*mInit)();
    }
}

AwOMXPlugin类继承了OMXPluginBase类,实现了其相关接口

这里又打开了一个OmxCore这个lib,依次获取了以上几个函数的接口,将会被AwOMXPlugin来进一步使用。我们看到mInit()函数的执行,其他类似的函数源码位于:/home/A31_Android4.2.2/android/hardware/aw/omxcore/src/aw_omx_core.c

6. OMX Plugin的维护

回到4中的处理流程,继续分析OMXMaster::addPluginOMXPluginBase *plugin()函数的实现。

?
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
voidOMXMaster::addPlugin(OMXPluginBase *plugin) {
    Mutex::Autolock autoLock(mLock);
 
    mPlugins.push_back(plugin);
 
    OMX_U32 index = 0;
 
    charname[128];
    OMX_ERRORTYPE err;
    while((err = plugin->enumerateComponents(
                    name, sizeof(name), index++)) == OMX_ErrorNone) {
        String8 name8(name);
 
        if(mPluginByComponentName.indexOfKey(name8) >= 0) {
            ALOGE("A component of name '%s' already exists, ignoring this one.",
                 name8.string());
 
            continue;
        }
 
        mPluginByComponentName.add(name8, plugin);//增加stragefright里面的插件
    }
 
    if(err != OMX_ErrorNoMore) {
        ALOGE("OMX plugin failed w/ error 0x%08x after registering %d "
             "components", err, mPluginByComponentName.size());
    }
}

我们可以看到先查找当前的这个插件支持的组件,我们来看其在AwOMXPlugin中的实现。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OMX_ERRORTYPE AwOMXPlugin::enumerateComponents(OMX_STRING name, size_t size, OMX_U32 index)
{
    if(mLibHandle == NULL)
    {
        returnOMX_ErrorUndefined;
    }
 
    OMX_ERRORTYPE res = (*mComponentNameEnum)(name, size, index);
 
    if(res != OMX_ErrorNone)
    {
        returnres;
    }
 
    returnOMX_ErrorNone;
}

看到这里调用的是libOMXCore.so库里面的内容:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_ComponentNameEnum(OMX_OUT OMX_STRING componentName, OMX_IN OMX_U32 nameLen, OMX_IN OMX_U32 index)
{
    OMX_ERRORTYPE eRet = OMX_ErrorNone;
    ALOGV("OMXCORE API - OMX_ComponentNameEnum %x %d %d\n",(unsigned) componentName, (unsigned)nameLen, (unsigned)index);
    if(index < SIZE_OF_CORE)
    {
        strlcpy(componentName, core[index].name, nameLen);
    }
    else
    {
        eRet = OMX_ErrorNoMore;
    }
 
    returneRet;
}

这里有一个Core的全局变量,其具体的结构如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
omx_core_cb_type core[] =
{
    {
        "OMX.allwinner.video.decoder.avc",
        NULL,// Create instance function
        // Unique instance handle
        {
            NULL,
            NULL,
            NULL,
            NULL
        },
        NULL,  // Shared object library handle
        "libOmxVdec.so",
        {
            "video_decoder.avc"
        }
    },
....
}

通过以上函数的层层分析,提取到了core中的编解码器name以及对应的Lib库。

最终是获取了各个name之后,通过mPluginByComponentName.add(name8, plugin),添加不同name的编解码器component到mPluginByComponentName变量中,而这个变量的所有权归mMaster维护。

到这里我们基本分析完了OMX插件和codec的提取。还没有完成针对特定的视频源,构建出专门的组件。这样我们得回归到3中创建一个属于OMX解码器的Node节点处。

7.OMXMaster::makeComponentInstance的处理

?
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
OMX_ERRORTYPE OMXMaster::makeComponentInstance(
        constchar *name,
        constOMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData,
        OMX_COMPONENTTYPE **component) {
    Mutex::Autolock autoLock(mLock);
 
    *component = NULL;
 
    ssize_t index = mPluginByComponentName.indexOfKey(String8(name));//根据传入的解码器的名字,获取组件索引
 
    if(index < 0) {
        returnOMX_ErrorInvalidComponentName;
    }
 
    OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);
    OMX_ERRORTYPE err =
        plugin->makeComponentInstance(name, callbacks, appData, component);//创建硬件,完成初始化,返回handle到component
 
    if(err != OMX_ErrorNone) {
        returnerr;
    }
 
    mPluginByInstance.add(*component, plugin);//将插件维护起来
 
    returnerr;
}

这个name是之前我们查找到平台支持的codec后(通过解析media_codec.xml获得)后,再根据这个name,找到这个index值,定位到这个解码器所在的插件plugin.这里比如name是OMX.allwinner.video.decoder.avc,这个获取的组件就是libStragefighthw.so这个插件AwOXPlugin

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OMX_ERRORTYPE AwOMXPlugin::makeComponentInstance(constchar* name, constOMX_CALLBACKTYPE* callbacks, OMX_PTR appData, OMX_COMPONENTTYPE** component)
{
    ALOGV("step 1.");
    if(mLibHandle == NULL)
    {
        returnOMX_ErrorUndefined;
    }
 
    ALOGV("step 2.");
 
    return(*mGetHandle)(reinterpret_cast<omx_handletype *="">(component),
                         const_cast<char*="">(name),
                         appData,
                         const_cast<omx_callbacktype *="">(callbacks));
}
</omx_callbacktype></char></omx_handletype>

这里的创建的一个组件,变成了handle,可见是获取对这个组件的操作权。而mGetHandle对应的是OMX_GetHandle其位于libOmxCore.so库之中。

?
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
OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(OMX_OUT OMX_HANDLETYPE* handle, OMX_IN OMX_STRING componentName, OMX_IN OMX_PTR appData, OMX_IN OMX_CALLBACKTYPE* callBacks)
{
     OMX_ERRORTYPE  eRet = OMX_ErrorNone;
     intcmp_index = -1;
     inthnd_index = -1;
 
     create_aw_omx_component fn_ptr = NULL;
 
     ALOGV("OMXCORE API :  Get Handle %x %s %x\n",(unsigned) handle, componentName, (unsigned) appData);
 
     if(handle)
     {
          cmp_index = get_cmp_index(componentName);
 
          if(cmp_index >= 0)
          {
               ALOGV("getting fn pointer\n");
 
               // dynamically load the so
 
               // ALOGV("core[cmp_index].fn_ptr: %x", core[cmp_index].fn_ptr);
 
               fn_ptr = omx_core_load_cmp_library(cmp_index);                   
           
               if(fn_ptr)
               {
                    // Construct the component requested
                    // Function returns the opaque handle
 
                    void* pThis = (*fn_ptr)();
                    if(pThis)
                    {
                         void*hComp = NULL;
                         hComp = aw_omx_create_component_wrapper((OMX_PTR)pThis);
                         if((eRet = aw_omx_component_init(hComp, componentName)) != OMX_ErrorNone)
                         {
                              ALOGE("Component not created succesfully\n");
                              returneRet;
                         }
 
                         aw_omx_component_set_callbacks(hComp, callBacks, appData);
                          
                         hnd_index = set_comp_handle(componentName, hComp);
                         if(hnd_index >= 0)
                         {
                              *handle = (OMX_HANDLETYPE) hComp;
                         }
                         else
                         {
                              ALOGE("OMX_GetHandle:NO free slot available to store Component Handle\n");
                              returnOMX_ErrorInsufficientResources;
                         }
 
   .......
 
     returneRet;
}

7.1 get_cmp_index()根据传入的组件name获取其在core中的索引

7.2 omx_core_load_cmp_library

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
staticcreate_aw_omx_component omx_core_load_cmp_library(intidx)
{
     create_aw_omx_component fn_ptr = NULL;
 
     pthread_mutex_lock(&g_mutex_core_info);
 
 
     if(core[idx].so_lib_handle == NULL)
     {
          ALOGV("Dynamically Loading the library : %s\n",core[idx].so_lib_name);
 
          core[idx].so_lib_handle = dlopen(core[idx].so_lib_name, RTLD_NOW);
     }
 
     if(core[idx].so_lib_handle)
     {
          if(core[idx].fn_ptr == NULL)
          {
               core[idx].fn_ptr = dlsym(core[idx].so_lib_handle, "get_omx_component_factory_fn");
 
  .....

假设这里获取的是 "OMX.allwinner.video.decoder.avc"对应的组件,则其操作的lib库为"libOmxVdec.so"。完成加载,获取库的handle。此外这里返回的是一个函数get_omx_component_factory_fn的地址,用于后续的对这个解码库的操作。

7.3 接着看 void* pThis = (*fn_ptr)();
就是调用7.2中返回的get_omx_component_factory_fn函数入口。

?
1
2
3
4
void*get_omx_component_factory_fn(void)
{
    return(newomx_vdec);
}

这里看到是新建了一个omx_vdec对象,如下所示:

?
1
2
3
4
5
classomx_vdec: publicaw_omx_component
{
public:
    omx_vdec();          // constructor
    virtual ~omx_vdec();  // destructor

后续内容的主要是涉及相关OMX组件构造的标准构造,自己也要学习后才能消化,先和大家分享到这里,最终会提炼出一个大的框架和模块间的处理图,方便更好的理解这个OMX组件的构建过程。

来图了,重新整理画了一个简单的流程图,内部含有A31的编解码器插件:

0 0
原创粉丝点击