您的位置:首页 > 其它

libstagefright 框架设计分析(2): omx 相关

2016-01-17 18:15 441 查看
OMX 框架是android 音视频codec 的入口吧。 说到入口, 首先omx 就是在ACodec 被使用, 而且是以一个client 来使用, 所以omx 会有个service。这个分析就从这里开始好了。

bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
ALOGV("onAllocateComponent");

CHECK(mCodec->mNode == NULL);

OMXClient client;
CHECK_EQ(client.connect(), (status_t)OK);

sp<IOMX> omx = client.interface();
....
mCodec->mQuirks = quirks;
    mCodec->mOMX = omx; // omx client
    mCodec->mNode = node;   // node 很关键
所以在ACodec.cpp 的代码中会发现所以omx相关的操作都是mCodec->mOMX->xxxx, 主要对omx 的操作方法显然就可以从头文件一目了然了。

IOMX.h

#ifndef ANDROID_IOMX_H_

#define ANDROID_IOMX_H_

#include <binder/IInterface.h>
#include <gui/IGraphicBufferProducer.h>
#include <ui/GraphicBuffer.h>
#include <utils/List.h>
#include <utils/String8.h>

#include <OMX_Core.h>
#include <OMX_Video.h>

namespace android {

class IMemory;
class IOMXObserver;
class IOMXRenderer;
class Surface;

class IOMX : public IInterface {
public:
DECLARE_META_INTERFACE(OMX);

typedef uint32_t buffer_id;
typedef uint32_t node_id;

// Given a node_id and the calling process' pid, returns true iff
// the implementation of the OMX interface lives in the same
// process.
virtual bool livesLocally(node_id node, pid_t pid) = 0;

struct ComponentInfo {
String8 mName;
List<String8> mRoles;
};
virtual status_t listNodes(List<ComponentInfo> *list) = 0;

virtual status_t allocateNode(
const char *name, const sp<IOMXObserver> &observer,
node_id *node) = 0;

virtual status_t freeNode(node_id node) = 0;

virtual status_t sendCommand(
node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) = 0;

virtual status_t getParameter(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) = 0;

virtual status_t setParameter(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) = 0;

virtual status_t getConfig(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) = 0;

virtual status_t setConfig(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) = 0;

virtual status_t getState(
node_id node, OMX_STATETYPE* state) = 0;

virtual status_t storeMetaDataInBuffers(
node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0;

virtual status_t prepareForAdaptivePlayback(
node_id node, OMX_U32 portIndex, OMX_BOOL enable,
OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) = 0;

virtual status_t configureVideoTunnelMode(
node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
OMX_U32 audioHwSync, native_handle_t **sidebandHandle) = 0;

virtual status_t enableGraphicBuffers(
node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0;

virtual status_t getGraphicBufferUsage(
node_id node, OMX_U32 port_index, OMX_U32* usage) = 0;

virtual status_t useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer) = 0;

virtual status_t useGraphicBuffer(
node_id node, OMX_U32 port_index,
const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) = 0;

virtual status_t updateGraphicBufferInMeta(
node_id node, OMX_U32 port_index,
const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) = 0;

virtual status_t createInputSurface(
node_id node, OMX_U32 port_index,
sp<IGraphicBufferProducer> *bufferProducer) = 0;

virtual status_t signalEndOfInputStream(node_id node) = 0;

// This API clearly only makes sense if the caller lives in the
// same process as the callee, i.e. is the media_server, as the
// returned "buffer_data" pointer is just that, a pointer into local
// address space.
virtual status_t allocateBuffer(
node_id node, OMX_U32 port_index, size_t size,
buffer_id *buffer, void **buffer_data) = 0;

virtual status_t allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer) = 0;

virtual status_t freeBuffer(
node_id node, OMX_U32 port_index, buffer_id buffer) = 0;

virtual status_t fillBuffer(node_id node, buffer_id buffer) = 0;

virtual status_t emptyBuffer(
node_id node,
buffer_id buffer,
OMX_U32 range_offset, OMX_U32 range_length,
OMX_U32 flags, OMX_TICKS timestamp) = 0;

virtual status_t getExtensionIndex(
node_id node,
const char *parameter_name,
OMX_INDEXTYPE *index) = 0;

enum InternalOptionType {
INTERNAL_OPTION_SUSPEND,  // data is a bool
INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY,  // data is an int64_t
INTERNAL_OPTION_MAX_TIMESTAMP_GAP, // data is int64_t
INTERNAL_OPTION_START_TIME, // data is an int64_t
INTERNAL_OPTION_TIME_LAPSE, // data is an int64_t[2]
};
virtual status_t setInternalOption(
node_id node,
OMX_U32 port_index,
InternalOptionType type,
const void *data,
size_t size) = 0;
};

struct omx_message {
enum {
EVENT,
EMPTY_BUFFER_DONE,
FILL_BUFFER_DONE,

} type;

IOMX::node_id node;

union {
// if type == EVENT
struct {
OMX_EVENTTYPE event;
OMX_U32 data1;
OMX_U32 data2;
} event_data;

// if type == EMPTY_BUFFER_DONE
struct {
IOMX::buffer_id buffer;
} buffer_data;

// if type == FILL_BUFFER_DONE
struct {
IOMX::buffer_id buffer;
OMX_U32 range_offset;
OMX_U32 range_length;
OMX_U32 flags;
OMX_TICKS timestamp;
} extended_buffer_data;

} u;
};

class IOMXObserver : public IInterface {
public:
DECLARE_META_INTERFACE(OMXObserver);

virtual void onMessage(const omx_message &msg) = 0;
};

////////////////////////////////////////////////////////////////////////////////

class BnOMX : public BnInterface<IOMX> {
public:
virtual status_t onTransact(
uint32_t code, const Parcel &data, Parcel *reply,
uint32_t flags = 0);
};

class BnOMXObserver : public BnInterface<IOMXObserver> {
public:
virtual status_t onTransact(
uint32_t code, const Parcel &data, Parcel *reply,
uint32_t flags = 0);
};

struct CodecProfileLevel {
OMX_U32 mProfile;
OMX_U32 mLevel;
};

}  // namespace android

#endif


这里是interface, binder 的client server 就没必要纠结, 我们都知道最后的实现是在server 端。所以就直接分析server 端。

就从上面的ACodec::UninitializedState::onAllocateComponent() 来分析好了, 在这个函数里面有一句代码

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


字面上就知道是要分配一个node, 一个omx node, 因为omx 是一个service, 管理着多个component, 也就是这里的node。

status_t OMX::allocateNode(
const char *name, const sp<IOMXObserver> &observer, node_id *node) {  // 注意参数node, 这个会是ACodec 在OMX service 找到对应component 的id,
Mutex::Autolock autoLock(mLock);

*node = 0;

OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name); // new omx node 的实例

OMX_COMPONENTTYPE *handle;
OMX_ERRORTYPE err = mMaster->makeComponentInstance(    // 这里根据参数name 去找到对应的component, 也就是这里的参handle最后被赋值
name, &OMXNodeInstance::kCallbacks, // callback 函数会在component 中调用
instance, &handle);if (err != OMX_ErrorNone) {
        ALOGE("FAILED to allocate omx component '%s'", name);

        instance->onGetHandleFailed();

        return UNKNOWN_ERROR;
    }

    *node = makeNodeID(instance); // 对应instance 生成一个唯一的node id
    mDispatchers.add(*node, new CallbackDispatcher(instance));

    instance->setHandle(*node, handle);  // hanle, node id, instance 这里扯上关系了, 在OMX 中多个node, 最后也是靠node id 来找到

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

    return OK;
}

============================================================================
OMX_ERRORTYPE OMXMaster::makeComponentInstance(
        const char *name,
        const OMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData,
        OMX_COMPONENTTYPE **component) {
    Mutex::Autolock autoLock(mLock);

    *component = NULL;

    ssize_t index = mPluginByComponentName.indexOfKey(String8(name)); // 这里根据name 找到对应的plugin 的index, 为什么要plugin 呢,
// 因为android 除了原生的,还要支持vendor的, 这个会OMXMaster 实例化的时候加进来

    if (index < 0) {
        return OMX_ErrorInvalidComponentName;
    }

    OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);   // 由上面得到的index 找到plugin 指针,然后再找
    OMX_ERRORTYPE err =
        plugin->makeComponentInstance(name, callbacks, appData, component);  // 注意这个component 参数

 ======================================================================  原生android 的Plugin
OMX_ERRORTYPE SoftOMXPlugin::makeComponentInstance(
        const char *name,
        const OMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData,
        OMX_COMPONENTTYPE **component) {
    ALOGV("makeComponentInstance '%s'", name);

    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);     // component 都是so的形式, 比如aac, 就是libstagefright_soft_aac.so

        if (libHandle == NULL) {
            ALOGE("unable to dlopen %s", libName.c_str());

            return OMX_ErrorComponentNotFound;
        }

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

        CreateSoftOMXComponentFunc createSoftOMXComponent =
            (CreateSoftOMXComponentFunc)dlsym(                  // 这里找到了component 的create 函数, 下面就可以生成component 的实例
                    libHandle,
                    "_Z22createSoftOMXComponentPKcPK16OMX_CALLBACKTYPE"
                    "PvPP17OMX_COMPONENTTYPE");

        if (createSoftOMXComponent == NULL) {
            dlclose(libHandle);
            libHandle = NULL;

            return OMX_ErrorComponentNotFound;
        }

        sp<SoftOMXComponent> codec =
            (*createSoftOMXComponent)(name, callbacks, appData, component); // 比如aac , 这里就会call 到aac 的createSoftOMXComponent 函数,
// 最后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;
    }


就这样, 在ACodec 中, 会根据allocate 回来的handle 和 node id, 最后就可以对所谓的component 操作了, 如下

ACodec->OMX->Component (比如aac,就是SoftAAC2.cpp 的内容),

反向都是Component->OMXNodeInstance->OMX->ACodec
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: