[Android Video Framework]ACodec加载OMX

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012188065/article/details/86723535

OpenMAX确立了一套标准的接口,上层App直接调用这些接口,底层硬件厂商直接实现这些接口,
从而实现了上层软件开发与底层芯片开发地彻底分离,加速了跨平台的多媒体组件的开发、整合和编程。
Android上的MediaCodec是通过ACodec来加载openmax层,了解OMX加载过程,有助于我们更好的分析问题和解决问题

加载过程还需从ACodec::UninitializedState::onAllocateComponent接口说起。

1、onAllocateComponent

bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
……
    for (size_t matchIndex = 0; matchIndex < matchingCodecs.size();
            ++matchIndex) {
        componentName = matchingCodecs[matchIndex];

    OMXClient client;
    bool trebleFlag;
    if (client.connect(owners[matchIndex].c_str(), &trebleFlag) != OK) {
        mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
        return false;
    }
    omx = client.interface();

        pid_t tid = gettid();
        int prevPriority = androidGetThreadPriority(tid);
        androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
        err = omx->allocateNode(componentName.c_str(), observer, &omxNode);
        androidSetThreadPriority(tid, prevPriority);

        if (err == OK) {
            mCodec->setTrebleFlag(trebleFlag);
            ALOGE("codec %s selected", componentName.c_str());
            break;
        } else {
            ALOGE("Allocating component '%s' failed, try next one.", componentName.c_str());
        }

        omxNode = NULL;
    }

可以简单理解为两步
1、获取OMX句柄
2、分配component

1.1 获取OMX句柄

我们可以将此过程理解为 C/S模型,客户端/服务器模型
运行在mediaserver或者app进程内的 MediaCodec是 client
运行在media.codec进程内的component是 server
MediaCodec通过 OMXClient,经过binder进程间通讯, 向MediaCodecService获取 OMX句柄
如下:

        OMXClient client;
        bool trebleFlag;
        if (client.connect(owners[matchIndex].c_str(), &trebleFlag) != OK) {
            mCodec->signalError(OMX_ErrorUndefined, NO_INIT);
            return false;
        }
        omx = client.interface();

1.1.1 连接server

OMXClient 通过connect接口与 MediaCodecService建立通讯,如下:

status_t OMXClient::connect(const char* name, bool* trebleFlag) {
    if (property_get_bool("persist.media.treble_omx", true)) {
        if (trebleFlag != nullptr) {
            *trebleFlag = true;
        }
        return connectTreble(name);
    }
    if (trebleFlag != nullptr) {
        *trebleFlag = false;
    }
    return connectLegacy();
}

status_t OMXClient::connectLegacy() {
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> codecbinder = sm->getService(String16("media.codec"));
    sp<IMediaCodecService> codecservice = interface_cast<IMediaCodecService>(codecbinder);

    if (codecservice.get() == NULL) {
        ALOGE("Cannot obtain IMediaCodecService");
        return NO_INIT;
    }

    mOMX = codecservice->getOMX();
    if (mOMX.get() == NULL) {
        ALOGE("Cannot obtain mediacodec IOMX");
        return NO_INIT;
    }

    return OK;
}

status_t OMXClient::connectTreble(const char* name) {
    using namespace ::android::hardware::media::omx::V1_0;
    if (name == nullptr) {
        name = "default";
    }
    sp<IOmx> tOmx = IOmx::getService(name);
    if (tOmx.get() == nullptr) {
        ALOGE("Cannot obtain Treble IOmx.");
        return NO_INIT;
    }
    if (!tOmx->isRemote()) {
        ALOGE("Treble IOmx is in passthrough mode.");
        return NO_INIT;
    }
    mOMX = new utils::LWOmx(tOmx);
    ALOGI("Treble IOmx obtained");
    return OK;
}

自Android 8.0起,google引入了 Project Treble,google的原生代码(FrameWork框架部分)编译至system.img镜像,华为、三星等手机制造厂商的vendor定制化代码和feather(HAL驱动模块)编译至vendor.img镜像,可以解耦google开发与手机厂商升级工作,以便实现更快地迭代,而system和vendor镜像之间的通讯是通过一种hidl语言来实现的,本质上仍然是IPC binder的一种,所以8.0上,OMXClinet获取 OMX 接口的方式有两种:
1、从MediaCodecService获取 (media.codec 进程)
2、从 Treble获取 (hw/[email protected] 进程)
本质都是通过binder获取server提供的句柄和接口。
以下我们仍以传统的非Treble的 connectLegacy 方式, 即从MediaCoderService中获取OMX的句柄 mOMX。

我们进一步看下 codecservice->getOMX() 做了什么:

sp<IOMX> MediaCodecService::getOMX() {

    Mutex::Autolock autoLock(mOMXLock);

    if (mOMX.get() == NULL) {
        mOMX = new OMX();
    }

    return mOMX;
}

继续查看OMX类的构造函数

OMX::OMX() : mMaster(new OMXMaster), mParser() {
}

两个作用,
1、创建 OMXMaster
2、创建解析xml文件的parser

进一步查看 OMXMaster的构造函数

OMXMaster::OMXMaster()
    : mVendorLibHandle(NULL) {

    pid_t pid = getpid();
    char filename[20];
    snprintf(filename, sizeof(filename), "/proc/%d/comm", pid);
    int fd = open(filename, O_RDONLY);
    if (fd < 0) {
      ALOGW("couldn't determine process name");
      strlcpy(mProcessName, "<unknown>", sizeof(mProcessName));
    } else {
      ssize_t len = read(fd, mProcessName, sizeof(mProcessName));
      if (len < 2) {
        ALOGW("couldn't determine process name");
        strlcpy(mProcessName, "<unknown>", sizeof(mProcessName));
      } else {
        // the name is newline terminated, so erase the newline
        mProcessName[len - 1] = 0;
      }
      close(fd);
    }

    addVendorPlugin();
    addPlugin(new SoftOMXPlugin);
}

加载vendor和google的component。

扫描二维码关注公众号,回复: 5656703 查看本文章

1.1.1.1 加载vendor的component

addVendorPlugin();
……
void OMXMaster::addVendorPlugin() {
    addPlugin("libstagefrighthw.so");
}

void OMXMaster::addPlugin(const char *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)());
    }
}

加载 libstagefrighthw.so,并获取 createOMXPlugin 函数地址,之后 addPlugin((*createOMXPlugin)());
类似加载google的component, addPlugin(new SoftOMXPlugin);
参考google的 SoftOMXPlugin类,我们在libstagefrighthw.so中至少实现
makeComponentInstance, destroyComponentInstance,enumerateComponents 和 getRolesOfComponent这些接口
具体接口见

1.1.1.2 加载google的component

    addPlugin(new SoftOMXPlugin);
    ……
void OMXMaster::addPlugin(OMXPluginBase *plugin) {
    Mutex::Autolock autoLock(mLock);

    mPlugins.push_back(plugin);

    OMX_U32 index = 0;

    char name[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);
    }

    if (err != OMX_ErrorNoMore) {
        ALOGE("OMX plugin failed w/ error 0x%08x after registering %zu "
             "components", err, mPluginByComponentName.size());
    }
}

枚举所有的 component并和plugin放置于 mPluginByComponentName
至此完成了vendor和google所有的component的加载。
关系如下:
在这里插入图片描述

1.1.2 获取interface

omx = client.interface();

至此 OMXClient通过mOMX 与 MediaCodecService建立了联系,并返回mOMX给 ACodec

1.2 分配Node

err = omx->allocateNode(componentName.c_str(), observer, &omxNode);

从上文可知,omx为MediaCodecService返回来的句柄,我们直接查看MediaCodecService中OMX类的方法

status_t OMX::allocateNode(
        const char *name, const sp<IOMXObserver> &observer,
        sp<IOMXNode> *omxNode) {
    Mutex::Autolock autoLock(mLock);

    omxNode->clear();

    if (mLiveNodes.size() == kMaxNodeInstances) {
        return NO_MEMORY;
    }

    sp<OMXNodeInstance> instance = new OMXNodeInstance(this, observer, name);

    OMX_COMPONENTTYPE *handle;
    OMX_ERRORTYPE err = mMaster->makeComponentInstance(
            name, &OMXNodeInstance::kCallbacks,
            instance.get(), &handle);

    if (err != OMX_ErrorNone) {
        ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err);

        return StatusFromOMXError(err);
    }
    instance->setHandle(handle);

    // Find quirks from mParser
    const auto& codec = mParser.getCodecMap().find(name);
    if (codec == mParser.getCodecMap().cend()) {
        ALOGW("Failed to obtain quirks for omx component '%s' from XML files",
                name);
    } else {
        uint32_t quirks = 0;
        for (const auto& quirk : codec->second.quirkSet) {
            if (quirk == "requires-allocate-on-input-ports") {
                quirks |= OMXNodeInstance::
                        kRequiresAllocateBufferOnInputPorts;
            }
            if (quirk == "requires-allocate-on-output-ports") {
                quirks |= OMXNodeInstance::
                        kRequiresAllocateBufferOnOutputPorts;
            }
        }
        instance->setQuirks(quirks);
    }

    mLiveNodes.add(IInterface::asBinder(observer), instance);
    IInterface::asBinder(observer)->linkToDeath(this);

    *omxNode = instance;

    return OK;
}

主要工作有二:
1、创建OMXNodeInstance
2、分配真正的component,并返回句柄
未完……

猜你喜欢

转载自blog.csdn.net/u012188065/article/details/86723535