Android OMX

Android OMX

Android OMX

Android Audio 的播放

AwesomePlayer 中 媒体流buffer 中的传递

一 OMXClient

AwesomePlayer 在创建OMXCodec 的时候调用了mClient.interface()。 mClient 类型为: OMXClient.OMXClient 负责OMX的客户端调用。

status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
    mVideoSource = OMXCodec::Create(
            mClient.interface(), mVideoTrack->getFormat(),
            false, // createEncoder
            mVideoTrack,
            NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL);
}

status_t AwesomePlayer::initAudioDecoder() {
    mAudioSource = OMXCodec::Create(
        mClient.interface(), mAudioTrack->getFormat(), 
        false, // createEncoder 
        mAudioTrack);
    }
}

看下OMXClient的头文件:interface函数返回一个 sp 类型的 mOMX。

class OMXClient {
public:
    OMXClient();

    status_t connect();
    void disconnect();

    sp<IOMX> interface() {
        return mOMX;
    }

private:
    sp<IOMX> mOMX;

    OMXClient(const OMXClient &);
    OMXClient &operator=(const OMXClient &);
};

在OMXClient.cpp 文件中是OMXClient 的实现,三个函数,构造函数为空;connect 函数中获取binder系统服务,然后获取到 MediaPlayerService 的binder服务,从MediaPlayerService获取了一个IOMX mOMX = service->getOMX();
看来OMX 也是binder架构的,OMX 为MediaPlayerService 上的一个匿名binder。
那就看看OMX Binder 架构。OMX继承BnOMX,为服务端。

OMXClient::OMXClient() {
}

status_t OMXClient::connect() {
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("media.player"));
    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);

    mOMX = service->getOMX();
 
    if (!mOMX->livesLocally(NULL /* node */, getpid())) {
        ALOGI("Using client-side OMX mux.");
        mOMX = new MuxOMX(mOMX);
    }

    return OK;
}

void OMXClient::disconnect() {
    if (mOMX.get() != NULL) {
        mOMX.clear();
        mOMX = NULL;
    }
}

AwesomePlayer 持有一个OMXClient类型的mClient。interface()返回一个OMX的代理。
看到这里好像完了,等等,下面几行代码好像有些不大一样,通常我们获取到service 以后就拿到了Binder的Bp 代理端,可以直接返回了。有两点值得注意:

1. 为什么下面还要判断livesLocally 呢;

2. 又new 了一个MuxOMX ,MuxOMX 是什么鬼?

二 MuxOMX

看看livesLocally 函数定义. livesLocally 生活在本地,生活服务O2O,美团糯米大战吗,扯远了。判断pid是不是在一个进程,
StagefrightPlayer 和MediaPlayerService 是一个进程,return true, 果然是本地服务。那 mOMX = new MuxOMX(mOMX); 这句代码就没有执行,Android4.0 以后的版本中是可以在java 层中调用codec 的,就不在一个进程了,看来要执行这句代码了。在不在一个进程执行很关键,如果在一个进程中 mOMX = service->getOMX(); 的mOMX 对象为BnOMX 就是OMX类。如果不是在一个进程中mOMX 对象为BpOMX 就要走mOMX = new MuxOMX(mOMX)。

OMX.cpp
bool OMX::livesLocally(node_id node, pid_t pid) {
    return pid == getpid();
}

看第二个问题 MuxOMX 是什么。MuxOMX 构造中赋值为mRemoteOMX。通常我们在binder 的代理端会持有一个Bpbinder 对象,上边已经获取了BpOMX 然后赋值mRemoteOMX,那mLocalOMX 干嘛呢? 晕 mLocalOMX 也是OMX。
MuOMX 函数调用的时候都会通过getOMX 来决定获取的是 mLocalOMX 还是mRemoteOMX. getOMX根据什么判断呢,node 是否在mIsLocalNode 中。在分配node 的时候可以看到,如果是软解码,node 就会加入到mIsLocalNode 容器中。
因此这个问题可以总结下:

1. 如果是软件码,OMX 和程序运行在一个进程

2. 如果是硬解码在StagefrightPlayer 也是运行在一个进程,在APP 通过binder 跨进程调用。

struct MuxOMX : public IOMX {

......
private:
    sp<IOMX> mRemoteOMX;
    sp<IOMX> mLocalOMX;
}

MuxOMX::MuxOMX(const sp<IOMX> &remoteOMX)
    : mRemoteOMX(remoteOMX) {
}

bool MuxOMX::isLocalNode(node_id node) const {
    Mutex::Autolock autoLock(mLock);

    return isLocalNode_l(node);
}

bool MuxOMX::isLocalNode_l(node_id node) const {
    return mIsLocalNode.indexOfKey(node) >= 0;
}

// static
bool MuxOMX::IsSoftwareComponent(const char *name) {
    return !strncasecmp(name, "OMX.google.", 11);
}

const sp<IOMX> &MuxOMX::getOMX(node_id node) const {
    return isLocalNode(node) ? mLocalOMX : mRemoteOMX;
}

status_t MuxOMX::listNodes(List<ComponentInfo> *list) {
    Mutex::Autolock autoLock(mLock);

    if (mLocalOMX == NULL) {
        mLocalOMX = new OMX;
    }

    return mLocalOMX->listNodes(list);
}

status_t MuxOMX::allocateNode(
        const char *name, const sp<IOMXObserver> &observer,
        node_id *node) {
    Mutex::Autolock autoLock(mLock);

    sp<IOMX> omx;

    if (IsSoftwareComponent(name)) {
        if (mLocalOMX == NULL) {
            mLocalOMX = new OMX;
        }
        omx = mLocalOMX;
    } else {
        omx = mRemoteOMX;
    }

    status_t err = omx->allocateNode(name, observer, node);

    if (err != OK) {
        return err;
    }

    if (omx == mLocalOMX) {
        mIsLocalNode.add(*node, true);
    }

    return OK;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HNMGzT9c-1585192476143)(https://www.processon.com/chart_image/581c705ce4b0c6fe57196996.png)]

三 OMX 类

OMX 类负责真正的是解码 编码解码的服务总管。主要是通过OMXMaster 加载解码器;OMXNodeInstance 负责函数调用。

OMXMaster *mMaster;

OMX::OMX()  
    : mMaster(new OMXMaster),  
      mNodeCounter(0) {  
}

1.OMXMaster

在OMX 的构造函数中初始化了mMaster, mMaster 为OMXMaster 类型,在头文件中定义了几个函数,主要用于加载解码器插件,原理是dlopen dlsym, 需要export 的API定义在OMX_Component.h。 addVendorPlugin 加载厂商的硬解码,封装在libstagefrighthw.so 中;addPlugin(new SoftOMXPlugin) 加载软解码。所有的解码插件保存在 List<OMXPluginBase *> mPlugins; 真正的操作封装在OMXNodeInstance类中。

struct OMXMaster : public OMXPluginBase {
   
private:
    List<OMXPluginBase *> mPlugins;
    KeyedVector<String8, OMXPluginBase *> mPluginByComponentName;
    KeyedVector<OMX_COMPONENTTYPE *, OMXPluginBase *> mPluginByInstance;
    void addVendorPlugin();
    void addPlugin(const char *libname);
    void addPlugin(OMXPluginBase *plugin);
    void clearPlugins();
};


OMXMaster::OMXMaster()
    : mVendorLibHandle(NULL) {
    addVendorPlugin();
    addPlugin(new SoftOMXPlugin);
}

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)());
    }
}

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

    mPlugins.push_back(plugin);

    OMX_U32 index = 0;
    ......
}

2. OMXNodeInstance

OMXNodeInstance 是真正的API调用的地方。在OMX中通过 findInstance(node) 获取OMXNodeInstance实例。 在上面的分析中我们一共调用了
allocateNode emptyBuffer fillBuffer 这几个函数
看下这几个函数的实现.

allocateNote
OMXNodeInstance 实例化

在 allocateNote 中,首先new了OMXNodeInstance 实例,然后根据name 通过Master 在List中查找对应的插件,并实例化OMXNodeInstance中需要调用的定义在OMX_Component.h的函数操作。

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

    *node = 0;

    OMXNodeInstance *instance = new OMXNodeInstance(this, observer);

    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();

        return UNKNOWN_ERROR;
    }

    *node = makeNodeID(instance);
    mDispatchers.add(*node, new CallbackDispatcher(instance));

    instance->setHandle(*node, handle);

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

    return OK;
}

可以通过SoftOMXPlugin查看function实例化的调用流程为
OMXMaster::makeComponentInstance ->
SoftOMXPlugin::makeComponentInstance

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;
        }

        AString libName = "libstagefright_soft_";
        libName.append(kComponents[i].mLibNameSuffix);
        libName.append(".so");

        void *libHandle = dlopen(libName.c_str(), RTLD_NOW);

        typedef SoftOMXComponent *(*CreateSoftOMXComponentFunc)(
                const char *, const OMX_CALLBACKTYPE *,
                OMX_PTR, OMX_COMPONENTTYPE **);

        CreateSoftOMXComponentFunc createSoftOMXComponent =
            (CreateSoftOMXComponentFunc)dlsym(
                    libHandle,
                    "_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE"
                    "PvPP17OMX_COMPONENTTYPE");


        sp<SoftOMXComponent> codec =
            (*createSoftOMXComponent)(name, callbacks, appData, component);

        ......
    }

    return OMX_ErrorInvalidComponentName;
}

分配node_id

完成 实例化后调用makeNodeID 分配node_id; 分配node_id 类型为void *;其实是一个int 指针,指示对应的OMXNodeInstance 在mNodeIDToInstance 的位置。

typedef node_id  void * 
OMX::node_id OMX::makeNodeID(OMXNodeInstance *instance) {
    // mLock is already held.

    node_id node = (node_id)++mNodeCounter;
    mNodeIDToInstance.add(node, instance);

    return node;
}

emptyBuffer

OMX 的emptyBuffer 直接通过findInstance调用到了实例对应的OMXNodeInstance 的emptyBuffer.

status_t OMX::emptyBuffer(
        node_id node,
        buffer_id buffer,
        OMX_U32 range_offset, OMX_U32 range_length,
        OMX_U32 flags, OMX_TICKS timestamp) {
    return findInstance(node)->emptyBuffer(
            buffer, range_offset, range_length, flags, timestamp);
}

看下OMXNodeInstance 的emptyBuffer的实现:最终调用到so中的OMX_EmptyThisBuffer

status_t OMXNodeInstance::emptyBuffer(
        OMX::buffer_id buffer,
        OMX_U32 rangeOffset, OMX_U32 rangeLength,
        OMX_U32 flags, OMX_TICKS timestamp) {
    Mutex::Autolock autoLock(mLock);

    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
    header->nFilledLen = rangeLength;
    header->nOffset = rangeOffset;
    header->nFlags = flags;
    header->nTimeStamp = timestamp;

    BufferMeta *buffer_meta =
        static_cast<BufferMeta *>(header->pAppPrivate);
    buffer_meta->CopyToOMX(header);

    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);

    return StatusFromOMXError(err);
}

fillBuffer

和emptyBuffer 类似:

status_t OMXNodeInstance::fillBuffer(OMX::buffer_id buffer) {
    Mutex::Autolock autoLock(mLock);

    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
    header->nFilledLen = 0;
    header->nOffset = 0;
    header->nFlags = 0;

    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);

    return StatusFromOMXError(err);
}

参考:

OpenMax整体框架

AudioPlayback的流程

OMXCodec执行流程细节

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值