MediaCodec 系列文章:
- 【Android 10 源码】深入理解 MediaCodec 硬解码初始化
- 【Android 10 源码】深入理解 Omx 初始化
- 【Android 10 源码】深入理解 codecservice 启动
- 【Android 10 源码】深入理解 software Codec2 服务启动
- 【Android 10 源码】深入理解构建 MediaCodec 列表:buildMediaCodecList
- 【Android 10 源码】深入理解 MediaCodec 组件分配
- 【Android 10 源码】深入理解 MediaCodec configure
组件分配的起点位于 native MediaCodec 的 init 流程。init() 函数中构建 kWhatInit 消息后等待处理结束,消息是由 MediaCodec 本身处理的。
frameworks/av/media/libstagefright/MediaCodec.cpp
status_t MediaCodec::init(const AString &name) {
......
sp<AMessage> msg = new AMessage(kWhatInit, this);
msg->setObject("codecInfo", mCodecInfo);
// name may be different from mCodecInfo->getCodecName() if we stripped
// ".secure"
msg->setString("name", name);
......
for (int i = 0; i <= kMaxRetry; ++i) {
......
sp<AMessage> response;
err = PostAndAwaitResponse(msg, &response);
if (!isResourceError(err)) {
break;
}
}
return err;
}
- 调用 setState(…) 将状态更改为 INITIALIZING;
- 从 msg 入参中重新构建消息,并调用 ACodec initiateAllocateComponent(…) 分配组件。
frameworks/av/media/libstagefright/MediaCodec.cpp
void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
......
case kWhatInit:
{
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
if (mState != UNINITIALIZED) {
PostReplyWithError(replyID, INVALID_OPERATION);
break;
}
mReplyID = replyID;
setState(INITIALIZING);
sp<RefBase> codecInfo;
CHECK(msg->findObject("codecInfo", &codecInfo));
AString name;
CHECK(msg->findString("name", &name));
sp<AMessage> format = new AMessage;
format->setObject("codecInfo", codecInfo);
format->setString("componentName", name);
mCodec->initiateAllocateComponent(format);
break;
}
......
}
}
ACodec::initiateAllocateComponent(…) 中将消息真正发出,消息 what 标志设置为 kWhatAllocateComponent。处理者设置为 this 意味着就是 ACodec 自己。
frameworks/av/media/libstagefright/ACodec.cpp
void ACodec::initiateAllocateComponent(const sp<AMessage> &msg) {
msg->setWhat(kWhatAllocateComponent);
msg->setTarget(this);
msg->post();
}
由于 MediaCodec 初始化期间构造了 ACodec,ACodec 此时的状态设置为 mUninitializedState,也就是未初始化(调用 changeState(…) 实现)。changeState(…) 实现在 AHierarchicalStateMachine.cpp 中,ACodec 继承了 AHierarchicalStateMachine。
frameworks/av/media/libstagefright/include/media/stagefright/ACodec.h
struct ACodec : public AHierarchicalStateMachine, public CodecBase {
......
}
AState 结构体定义了纯虚函数 onMessageReceived(…) 这肯定是和消息处理相关的,后面揭晓答案。
AHierarchicalStateMachine 结构体里定义了 changeState(…) 方法;另外还有 handleMessage(…) 虚函数,和消息处理相关。
frameworks/av/media/libstagefright/include/media/stagefright/AHierarchicalStateMachine.h
#ifndef A_HIERARCHICAL_STATE_MACHINE_H_
#define A_HIERARCHICAL_STATE_MACHINE_H_
#include <media/stagefright/foundation/AHandler.h>
namespace android {
struct AState : public RefBase {
AState(const sp<AState> &parentState = NULL);
sp<AState> parentState();
protected:
virtual ~AState();
virtual void stateEntered();
virtual void stateExited();
virtual bool onMessageReceived(const sp<AMessage> &msg) = 0;
private:
friend struct AHierarchicalStateMachine;
sp<AState> mParentState;
DISALLOW_EVIL_CONSTRUCTORS(AState);
};
struct AHierarchicalStateMachine {
AHierarchicalStateMachine();
protected:
virtual ~AHierarchicalStateMachine();
virtual void handleMessage(const sp<AMessage> &msg);
// Only to be called in response to a message.
void changeState(const sp<AState> &state);
private:
sp<AState> mState;
DISALLOW_EVIL_CONSTRUCTORS(AHierarchicalStateMachine);
};
} // namespace android
#endif // A_HIERARCHICAL_STATE_MACHINE_H_
现在来摸清楚 changeState(…) 改变状态都干了什么?
注意 AState 构造器中初始化了 mParentState,并且 parentState() 方法返回就是 mParentState。AHierarchicalStateMachine::changeState(const sp &state) 入参是一个指向 AState 的指针,所有前面提到的 ACodec 九种状态当然就需要全部继承自 AState。
AHierarchicalStateMachine::changeState(…) 实现:
- 如果设置状态和当前保存在 mState 中的状态一样,直接返回;
- 将旧的 State 链 push 到容器中;
- 将新的 State 链 push 到容器中;
- 去掉两个容器中相同的 top;
- 旧的 State 链调用 stateExited();
- 新的 State 链调用 stateEntered()。
AHierarchicalStateMachine::handleMessage(…) 实际调用了 State 链去处理消息,如果 onMessageReceived(…) 不能返回 true,就沿着父 State 链上升,直到可以处理消息返回 true。
frameworks/av/media/libstagefright/AHierarchicalStateMachine.cpp
namespace android {
AState::AState(const sp<AState> &parentState)
: mParentState(parentState) {
}
......
sp<AState> AState::parentState() {
return mParentState;
}
......
void AHierarchicalStateMachine::handleMessage(const sp<AMessage> &msg) {
sp<AState> save = mState;
sp<AState> cur = mState;
while (cur != NULL && !cur->onMessageReceived(msg)) {
// If you claim not to have handled the message you shouldn't
// have called setState...
CHECK(save == mState);
cur = cur->parentState();
}
if (cur != NULL) {
return;
}
ALOGW("Warning message %s unhandled in root state.",
msg->debugString().c_str());
}
void AHierarchicalStateMachine::changeState(const sp<AState> &state) {
if (state == mState) {
// Quick exit for the easy case.
return;
}
Vector<sp<AState> > A;
sp<AState> cur = mState;
for (;;) {
A.push(cur);
if (cur == NULL) {
break;
}
cur = cur->parentState();
}
Vector<sp<AState> > B;
cur = state;
for (;;) {
B.push(cur);
if (cur == NULL) {
break;
}
cur = cur->parentState();
}
// Remove the common tail.
while (A.size() > 0 && B.size() > 0 && A.top() == B.top()) {
A.pop();
B.pop();
}
mState = state;
for (size_t i = 0; i < A.size(); ++i) {
A.editItemAt(i)->stateExited();
}
for (size_t i = B.size(); i > 0;) {
i--;
B.editItemAt(i)->stateEntered();
}
}
} // namespace android
UninitializedState 继承自 ACodec::BaseState,看来 BaseState 可能继承自 AState。
frameworks/av/media/libstagefright/ACodec.cpp
struct ACodec::UninitializedState : public ACodec::BaseState {
explicit UninitializedState(ACodec *codec);
protected:
virtual bool onMessageReceived(const sp<AMessage> &msg);
virtual void stateEntered();
private:
void onSetup(const sp<AMessage> &msg);
bool onAllocateComponent(const sp<AMessage> &msg);
sp<DeathNotifier> mDeathNotifier;
DISALLOW_EVIL_CONSTRUCTORS(UninitializedState);
};
BaseState 的确继承自 AState。
frameworks/av/media/libstagefright/ACodec.cpp
struct ACodec::BaseState : public AState {
......
}
回到主线,kWhatAllocateComponent 这个标志的 message 必定是发给了 ACodec 去处理, ACodec 将 onMessageReceived(…) 定义为一个虚函数,其实现内部则调用了 handleMessage(…) ,如此消息处理就明确了,最终落在了 BaseState 的子类实现上,就是前面提到的九种状态之一。
frameworks/av/media/libstagefright/include/media/stagefright/ACodec.h
struct ACodec : public AHierarchicalStateMachine, public CodecBase {
......
// AHierarchicalStateMachine implements the message handling
virtual void onMessageReceived(const sp<AMessage> &msg) {
handleMessage(msg);
}
......
}
由于 ACodec 此时的状态设置为 mUninitializedState,所以消息处理就落在它的头上。注意它的 onMessageReceived(…) 返回了 true,意味着仅仅由它处理消息,消息不再上升。kWhatAllocateComponent 这个消息仅仅调用了 onAllocateComponent(…) 做进一步处理。
frameworks/av/media/libstagefright/ACodec.cpp
bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
bool handled = false;
switch (msg->what()) {
......
case ACodec::kWhatAllocateComponent:
{
onAllocateComponent(msg);
handled = true;
break;
}
......
default:
return BaseState::onMessageReceived(msg);
}
return handled;
}
mCodec 指向 ACodec,ACodec 对象是在 ACodec 无参构造器中传给 UninitializedState 构造器的,实际上九种状态都将 ACodec 对象作为实参传入进行了构造工作。
- 构建 kWhatOMXMessageList message,将 generation 的值设为 1,因为 ACodec 之前在无参构造器中将 mNodeGeneration 字段初始化 0;
- 从入参 msg 消息中获取 MediaCodecInfo、owner(属主)和 componentName(组件名称);
- 创建 CodecObserver 对象;
- 调用 OMXClient connect(…) 方法连接;
- 调用 OMXClient interface() 获取 OMX 代理对象;
- 修改当前线程优先级为 ANDROID_PRIORITY_FOREGROUND,接着调用 OMX allocateNode(…) 分配 omx 节点,还原线程优先级;
- 调用 OMXNode getHalInterface(…) 获取 hal 接口,并设置“死亡通知” DeathNotifier;
- mNodeGeneration 自增加 1;
- 给 mCodec 指向的 ACodec 对象设置 mComponentName、mOMX 等字段的值;
- 调用 changeState(…) 将 ACodec 对象的状态更改为加载状态(mLoadedState)。
frameworks/av/media/libstagefright/ACodec.cpp
bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
ALOGV("onAllocateComponent");
CHECK(mCodec->mOMXNode == NULL);
sp<AMessage> notify = new AMessage(kWhatOMXMessageList, mCodec);
notify->setInt32("generation", mCodec->mNodeGeneration + 1);
sp<RefBase> obj;
CHECK(msg->findObject("codecInfo", &obj));
sp<MediaCodecInfo> info = (MediaCodecInfo *)obj.get();
if (info == nullptr) {
ALOGE("Unexpected nullptr for codec information");
mCodec->signalError(OMX_ErrorUndefined, UNKNOWN_ERROR);
return false;
}
AString owner = (info->getOwnerName() == nullptr) ? "default" : info->getOwnerName();
AString componentName;
CHECK(msg->findString("componentName", &componentName));
sp<CodecObserver> observer = new CodecObserver(notify);
sp<IOMX> omx;
sp<IOMXNode> omxNode;
status_t err = NAME_NOT_FOUND;
OMXClient client;
if (client.connect(owner.c_str()) != 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) {
ALOGE("Unable to instantiate codec '%s' with err %#x.", componentName.c_str(), err);
mCodec->signalError((OMX_ERRORTYPE)err, makeNoSideEffectStatus(err));
return false;
}
mDeathNotifier = new DeathNotifier(new AMessage(kWhatOMXDied, mCodec));
auto tOmxNode = omxNode->getHalInterface<IOmxNode>();
if (tOmxNode && !tOmxNode->linkToDeath(mDeathNotifier, 0)) {
mDeathNotifier.clear();
}
++mCodec->mNodeGeneration;
mCodec->mComponentName = componentName;
mCodec->mRenderTracker.setComponentName(componentName);
mCodec->mFlags = 0;
if (componentName.endsWith(".secure")) {
mCodec->mFlags |= kFlagIsSecure;
mCodec->mFlags |= kFlagIsGrallocUsageProtected;
mCodec->mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown;
}
mCodec->mOMX = omx;
mCodec->mOMXNode = omxNode;
mCodec->mCallback->onComponentAllocated(mCodec->mComponentName.c_str());
mCodec->changeState(mCodec->mLoadedState);
return true;
}
CodecObserver 的创建非常简单,仅仅给 mNotify 字段进行了赋值而已。
frameworks/av/media/libstagefright/ACodec.cpp
struct CodecObserver : public BnOMXObserver {
explicit CodecObserver(const sp<AMessage> &msg) : mNotify(msg) {}
......
private:
const sp<AMessage> mNotify;
DISALLOW_EVIL_CONSTRUCTORS(CodecObserver);
};
OMXClient::connect(const char* name) 内部首先调用 IOmx::getService(…) 获取 Omx 服务的代理,然后将这个代理对象传入 LWOmx 构造器初始化了 LWOmx 对象。
frameworks/av/media/libstagefright/OMXClient.cpp
namespace android {
OMXClient::OMXClient() {
}
status_t OMXClient::connect() {
return connect("default");
}
status_t OMXClient::connect(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 IOmx service.");
return NO_INIT;
}
if (!tOmx->isRemote()) {
ALOGE("IOmx service running in passthrough mode.");
return NO_INIT;
}
mOMX = new utils::LWOmx(tOmx);
ALOGI("IOmx service obtained");
return OK;
}
void OMXClient::disconnect() {
mOMX.clear();
}
sp<IOMX> OMXClient::interface() {
return mOMX;
}
} // namespace android
用于转换的包装器类。LW = Legacy Wrapper, 它将 Treble 对象包装在 Legacy 对象中。
结合上面的代码,不难看出调用 OMXClient interface() 获取 OMX 代理对象实际上是一个包装对象 LWOmx(确切的说是结构体)。
frameworks/av/media/libmedia/include/media/omx/1.0/WOmx.h
/**
* Wrapper classes for conversion
* ==============================
*
* Naming convention:
* - LW = Legacy Wrapper --- It wraps a Treble object inside a legacy object.
* - TW = Treble Wrapper --- It wraps a legacy object inside a Treble object.
*/
struct LWOmx : public IOMX {
sp<IOmx> mBase;
LWOmx(sp<IOmx> const& base);
status_t listNodes(List<IOMX::ComponentInfo>* list) override;
status_t allocateNode(
char const* name,
sp<IOMXObserver> const& observer,
sp<IOMXNode>* omxNode) override;
status_t createInputSurface(
sp<::android::IGraphicBufferProducer>* bufferProducer,
sp<::android::IGraphicBufferSource>* bufferSource) override;
};
调用 OMX allocateNode(…) 分配 omx 节点,实际是调用 LWOmx allocateNode(…) 分配 omx 节点。
mBase 指向 Omx 服务的代理对象,所以实际还是调用了 Omx 服务的 allocateNode(…)。我们看到返回指向 IOmxNode 的指针,实际指向 LWOmxNode 对象。
frameworks/av/media/libmedia/omx/1.0/WOmx.cpp
status_t LWOmx::allocateNode(
char const* name,
sp<IOMXObserver> const& observer,
sp<IOMXNode>* omxNode) {
status_t fnStatus;
status_t transStatus = toStatusT(mBase->allocateNode(
name, new TWOmxObserver(observer),
[&fnStatus, omxNode](Status status, sp<IOmxNode> const& node) {
fnStatus = toStatusT(status);
*omxNode = new LWOmxNode(node);
}));
return transStatus == NO_ERROR ? fnStatus : transStatus;
}
- 如果 mLiveNodes 容器的 size 已经达到了 2^16,返回 NO_MEMORY;
- 新建 OMXNodeInstance 对象;
- 调用 OMXMaster makeComponentInstance(…) 真正的创建组件实例;
- 从 mParser 中查找 quirk,调用 OMXNodeInstance setQuirks(…) 设置 quirk;
- mLiveNodes 容器和 mNode2Observer 容器中添加新条目;
- hal 返回 OK 状态和 TWOmxNode 对象。
frameworks/av/media/libstagefright/omx/1.0/Omx.cpp
Return<void> Omx::allocateNode(
const hidl_string& name,
const sp<IOmxObserver>& observer,
allocateNode_cb _hidl_cb) {
using ::android::IOMXNode;
using ::android::IOMXObserver;
sp<OMXNodeInstance> instance;
{
Mutex::Autolock autoLock(mLock);
if (mLiveNodes.size() == kMaxNodeInstances) {
_hidl_cb(toStatus(NO_MEMORY), nullptr);
return Void();
}
instance = new OMXNodeInstance(
this, new LWOmxObserver(observer), name.c_str());
OMX_COMPONENTTYPE *handle;
OMX_ERRORTYPE err = mMaster->makeComponentInstance(
name.c_str(), &OMXNodeInstance::kCallbacks,
instance.get(), &handle);
if (err != OMX_ErrorNone) {
LOG(ERROR) << "Failed to allocate omx component "
"'" << name.c_str() << "' "
" err=" << asString(err) <<
"(0x" << std::hex << unsigned(err) << ")";
_hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);
return Void();
}
instance->setHandle(handle);
// Find quirks from mParser
const auto& codec = mParser.getCodecMap().find(name.c_str());
if (codec == mParser.getCodecMap().cend()) {
LOG(WARNING) << "Failed to obtain quirks for omx component "
"'" << name.c_str() << "' "
"from XML files";
} else {
uint32_t quirks = 0;
for (const auto& quirk : codec->second.quirkSet) {
if (quirk == "quirk::requires-allocate-on-input-ports") {
quirks |= OMXNodeInstance::
kRequiresAllocateBufferOnInputPorts;
}
if (quirk == "quirk::requires-allocate-on-output-ports") {
quirks |= OMXNodeInstance::
kRequiresAllocateBufferOnOutputPorts;
}
}
instance->setQuirks(quirks);
}
mLiveNodes.add(observer.get(), instance);
mNode2Observer.add(instance.get(), observer.get());
}
observer->linkToDeath(this, 0);
_hidl_cb(toStatus(OK), new TWOmxNode(instance));
return Void();
}
先来分析新建 OMXNodeInstance 对象。给一系列字段进行了初始化,赋初值。
frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp
OMXNodeInstance::OMXNodeInstance(
Omx *owner, const sp<IOMXObserver> &observer, const char *name)
: mOwner(owner),
mHandle(NULL),
mObserver(observer),
mDying(false),
mSailed(false),
mQueriedProhibitedExtensions(false),
mQuirks(0),
mBufferIDCount(0),
mRestorePtsFailed(false),
mMaxTimestampGapUs(0LL),
mPrevOriginalTimeUs(-1LL),
mPrevModifiedTimeUs(-1LL)
{
mName = ADebug::GetDebugName(name);
DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug");
ALOGV("debug level for %s is %d", name, DEBUG);
DEBUG_BUMP = DEBUG;
mNumPortBuffers[0] = 0;
mNumPortBuffers[1] = 0;
mDebugLevelBumpPendingBuffers[0] = 0;
mDebugLevelBumpPendingBuffers[1] = 0;
mMetadataType[0] = kMetadataBufferTypeInvalid;
mMetadataType[1] = kMetadataBufferTypeInvalid;
mPortMode[0] = IOMX::kPortModePresetByteBuffer;
mPortMode[1] = IOMX::kPortModePresetByteBuffer;
mSecureBufferType[0] = kSecureBufferTypeUnknown;
mSecureBufferType[1] = kSecureBufferTypeUnknown;
mGraphicBufferEnabled[0] = false;
mGraphicBufferEnabled[1] = false;
mIsSecure = AString(name).endsWith(".secure");
mLegacyAdaptiveExperiment = ADebug::isExperimentEnabled("legacy-adaptive");
}
再来调用 OMXMaster makeComponentInstance(…) 真正的创建组件实例。以 rk3399 android10 平台为例,mine 类型为 video/avc,此处打印如下 Log:
OMXMaster: makeComponentInstance(OMX.rk.video_decoder.avc) in android.hardwar process
首先从 mPluginByComponentName 中查找插件,这里必然是 RK OMX Plugin。然后调用插件中的 makeComponentInstance(…) 实现。
frameworks/av/media/libstagefright/omx/OMXMaster.cpp
OMX_ERRORTYPE OMXMaster::makeComponentInstance(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component) {
ALOGI("makeComponentInstance(%s) in %s process", name, mProcessName);
Mutex::Autolock autoLock(mLock);
*component = NULL;
ssize_t index = mPluginByComponentName.indexOfKey(String8(name));
if (index < 0) {
return OMX_ErrorInvalidComponentName;
}
OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);
OMX_ERRORTYPE err =
plugin->makeComponentInstance(name, callbacks, appData, component);
if (err != OMX_ErrorNone) {
return err;
}
mPluginByInstance.add(*component, plugin);
return err;
}
此处主要会调用 libOMX_Core.so 中的 RKOMX_GetHandle(…) 方法。
hardware/rockchip/librkvpu/libstagefrighthw/RKOMXPlugin.cpp
OMX_ERRORTYPE RKOMXPlugin::makeComponentInstance(
const char *name,
const OMX_CALLBACKTYPE *callbacks,
OMX_PTR appData,
OMX_COMPONENTTYPE **component) {
for (OMX_U32 i = 0; i < mCores.size(); i++) {
if (mCores[i] != NULL) {
if (mCores[i]->mLibHandle == NULL) {
continue;
}
OMX_ERRORTYPE omx_res = (*(mCores[i]->mGetHandle))(
reinterpret_cast<OMX_HANDLETYPE *>(component),
const_cast<char *>(name),
appData, const_cast<OMX_CALLBACKTYPE *>(callbacks));
if(omx_res == OMX_ErrorNone) {
Mutex::Autolock autoLock(mMutex);
RKOMXComponent comp;
comp.mComponent = *component;
comp.mCore = mCores[i];
mComponents.push_back(comp);
return OMX_ErrorNone;
} else if (omx_res == OMX_ErrorInsufficientResources) {
return omx_res;
}
}
}
return OMX_ErrorInvalidComponentName;
}
- 检查入参是否存在 NULL,如果存在直接退出;
- 从 gComponentList 列表中查找组件名称为 OMX.rk.video_decoder.avc 的组件,然后根据找到的条目给 ROCKCHIP_OMX_COMPONENT 结构各字段赋值;
- 调用 Rockchip_OMX_ComponentLoad(…) 进行组件加载;
- 调用 ROCKCHIP_OMX_COMPONENT 结构内的 pOMXComponent 字段 SetCallbacks(…) 方法,pOMXComponent 指向 OMX_HANDLETYPE 结构,这个结构体定义了组件句柄,组件句柄用于访问组件的所有公共方法,还包含指向组件私有数据区域的指针;
- 调用 Rockchip_OMX_Check_Resource(…) 检查资源;
- 修改 gLoadComponentList 全局变量,如果 gLoadComponentList 为 NULL,直接将第一步分配的 ROCKCHIP_OMX_COMPONENT 结构赋给它,否则将ROCKCHIP_OMX_COMPONENT 结构挂在以 gLoadComponentList 为头的单链表尾部;
hardware/rockchip/omx_il/core/Rockchip_OMX_Core.c
OMX_API OMX_ERRORTYPE OMX_APIENTRY RKOMX_GetHandle(
OMX_OUT OMX_HANDLETYPE *pHandle,
OMX_IN OMX_STRING cComponentName,
OMX_IN OMX_PTR pAppData,
OMX_IN OMX_CALLBACKTYPE *pCallBacks)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
ROCKCHIP_OMX_COMPONENT *loadComponent;
ROCKCHIP_OMX_COMPONENT *currentComponent;
unsigned int i = 0;
FunctionIn();
if (gInitialized != 1) {
ret = OMX_ErrorNotReady;
goto EXIT;
}
if ((pHandle == NULL) || (cComponentName == NULL) || (pCallBacks == NULL)) {
ret = OMX_ErrorBadParameter;
goto EXIT;
}
omx_trace("ComponentName : %s", cComponentName);
for (i = 0; i < gComponentNum; i++) {
if (Rockchip_OSAL_Strcmp(cComponentName, gComponentList[i].component.componentName) == 0) {
loadComponent = Rockchip_OSAL_Malloc(sizeof(ROCKCHIP_OMX_COMPONENT));
Rockchip_OSAL_Memset(loadComponent, 0, sizeof(ROCKCHIP_OMX_COMPONENT));
Rockchip_OSAL_Strcpy(loadComponent->libName, gComponentList[i].libName);
Rockchip_OSAL_Strcpy(loadComponent->componentName, gComponentList[i].component.componentName);
ret = Rockchip_OMX_ComponentLoad(loadComponent);
if (ret != OMX_ErrorNone) {
Rockchip_OSAL_Free(loadComponent);
omx_err("OMX_Error, Line:%d", __LINE__);
goto EXIT;
}
ret = loadComponent->pOMXComponent->SetCallbacks(loadComponent->pOMXComponent, pCallBacks, pAppData);
if (ret != OMX_ErrorNone) {
Rockchip_OMX_ComponentUnload(loadComponent);
Rockchip_OSAL_Free(loadComponent);
omx_err("OMX_Error 0x%x, Line:%d", ret, __LINE__);
goto EXIT;
}
ret = Rockchip_OMX_Check_Resource(loadComponent->pOMXComponent);
if (ret != OMX_ErrorNone) {
Rockchip_OMX_ComponentUnload(loadComponent);
Rockchip_OSAL_Free(loadComponent);
omx_err("OMX_Error 0x%x, Line:%d", ret, __LINE__);
goto EXIT;
}
Rockchip_OSAL_MutexLock(ghLoadComponentListMutex);
if (gLoadComponentList == NULL) {
gLoadComponentList = loadComponent;
} else {
currentComponent = gLoadComponentList;
while (currentComponent->nextOMXComp != NULL) {
currentComponent = currentComponent->nextOMXComp;
}
currentComponent->nextOMXComp = loadComponent;
}
Rockchip_OSAL_MutexUnlock(ghLoadComponentListMutex);
*pHandle = loadComponent->pOMXComponent;
ret = OMX_ErrorNone;
omx_trace("Rockchip_OMX_GetHandle : %s", "OMX_ErrorNone");
goto EXIT;
}
}
ret = OMX_ErrorComponentNotFound;
EXIT:
FunctionOut();
return ret;
}
- 由于整体流程在分析硬解码所以打开的 so 库实际是 libomxvpu_dec.so,获取到 Rockchip_OMX_ComponentConstructor 函数符号;
- 调用 Rockchip_OSAL_Malloc(…) 给 OMX_COMPONENTTYPE 结构分配内存,然后调用 libomxvpu_dec.so 中的 Rockchip_OMX_ComponentConstructor(…) 组件构造方法;
- 调用 Rockchip_OMX_ComponentAPICheck(…) 检查 OMX_COMPONENTTYPE 结构中的方法是否为 NULL;
- 给入参 rockchip_component 其他字段赋值。
hardware/rockchip/omx_il/core/Rockchip_OMX_Component_Register.c
OMX_ERRORTYPE Rockchip_OMX_ComponentLoad(ROCKCHIP_OMX_COMPONENT *rockchip_component)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
OMX_HANDLETYPE libHandle;
OMX_COMPONENTTYPE *pOMXComponent;
FunctionIn();
OMX_ERRORTYPE (*Rockchip_OMX_ComponentConstructor)(OMX_HANDLETYPE hComponent, OMX_STRING componentName);
libHandle = Rockchip_OSAL_dlopen((OMX_STRING)rockchip_component->libName, RTLD_NOW);
if (!libHandle) {
ret = OMX_ErrorInvalidComponentName;
omx_err("OMX_ErrorInvalidComponentName, Line:%d", __LINE__);
goto EXIT;
}
Rockchip_OMX_ComponentConstructor = Rockchip_OSAL_dlsym(libHandle, "Rockchip_OMX_ComponentConstructor");
if (!Rockchip_OMX_ComponentConstructor) {
Rockchip_OSAL_dlclose(libHandle);
ret = OMX_ErrorInvalidComponent;
omx_err("OMX_ErrorInvalidComponent, Line:%d", __LINE__);
goto EXIT;
}
pOMXComponent = (OMX_COMPONENTTYPE *)Rockchip_OSAL_Malloc(sizeof(OMX_COMPONENTTYPE));
INIT_SET_SIZE_VERSION(pOMXComponent, OMX_COMPONENTTYPE);
ret = (*Rockchip_OMX_ComponentConstructor)((OMX_HANDLETYPE)pOMXComponent, (OMX_STRING)rockchip_component->componentName);
if (ret != OMX_ErrorNone) {
Rockchip_OSAL_Free(pOMXComponent);
Rockchip_OSAL_dlclose(libHandle);
ret = OMX_ErrorInvalidComponent;
omx_err("OMX_ErrorInvalidComponent, Line:%d", __LINE__);
goto EXIT;
} else {
if (Rockchip_OMX_ComponentAPICheck(pOMXComponent) != OMX_ErrorNone) {
if (NULL != pOMXComponent->ComponentDeInit)
pOMXComponent->ComponentDeInit(pOMXComponent);
Rockchip_OSAL_Free(pOMXComponent);
Rockchip_OSAL_dlclose(libHandle);
ret = OMX_ErrorInvalidComponent;
omx_err("OMX_ErrorInvalidComponent, Line:%d", __LINE__);
goto EXIT;
}
rockchip_component->libHandle = libHandle;
rockchip_component->pOMXComponent = pOMXComponent;
rockchip_component->rkversion = OMX_COMPILE_INFO;
ret = OMX_ErrorNone;
}
EXIT:
FunctionOut();
return ret;
}
这个组件构造方法非常长。
- 检查入参 hComponent 或 componentName 是否为 NULL;
- 调用 Rockchip_OMX_Check_SizeVersion(…) 检查结构体大小和版本是否正常;
- 调用 Rockchip_OMX_BaseComponent_Constructor(…) 构造 ROCKCHIP_OMX_BASECOMPONENT 结构;
- 调用 Rockchip_OMX_Port_Constructor(…) 构造 Input 和 Output port;
- 调用 Rockchip_OSAL_Malloc(…) 给 RKVPU_OMX_VIDEODEC_COMPONENT 结构分配内存;
- 调用 Rockchip_OSAL_SharedMemory_Open() 开启共享内存;
- pVideoDec 指向 RKVPU_OMX_VIDEODEC_COMPONENT 结构,对它进行各种字段赋值;
- pRockchipComponent 指向 ROCKCHIP_OMX_BASECOMPONENT 结构,对它进行各种字段赋值;
- pOMXComponent 指向 OMX_COMPONENTTYPE 对它的进行各种字段赋值。
hardware/rockchip/omx_il/component/video/dec/Rkvpu_OMX_Vdec.c
OMX_ERRORTYPE Rockchip_OMX_ComponentConstructor(OMX_HANDLETYPE hComponent, OMX_STRING componentName)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
OMX_COMPONENTTYPE *pOMXComponent = NULL;
ROCKCHIP_OMX_BASECOMPONENT *pRockchipComponent = NULL;
ROCKCHIP_OMX_BASEPORT *pRockchipPort = NULL;
RKVPU_OMX_VIDEODEC_COMPONENT *pVideoDec = NULL;
FunctionIn();
if ((hComponent == NULL) || (componentName == NULL)) {
ret = OMX_ErrorBadParameter;
omx_err("OMX_ErrorBadParameter, Line:%d", __LINE__);
goto EXIT;
}
pOMXComponent = (OMX_COMPONENTTYPE *)hComponent;
ret = Rockchip_OMX_Check_SizeVersion(pOMXComponent, sizeof(OMX_COMPONENTTYPE));
if (ret != OMX_ErrorNone) {
omx_err("OMX_Error, Line:%d", __LINE__);
goto EXIT;
}
ret = Rockchip_OMX_BaseComponent_Constructor(pOMXComponent);
if (ret != OMX_ErrorNone) {
omx_err("OMX_Error, Line:%d", __LINE__);
goto EXIT;
}
ret = Rockchip_OMX_Port_Constructor(pOMXComponent);
if (ret != OMX_ErrorNone) {
Rockchip_OMX_BaseComponent_Destructor(pOMXComponent);
omx_err("OMX_Error, Line:%d", __LINE__);
goto EXIT;
}
pRockchipComponent = (ROCKCHIP_OMX_BASECOMPONENT *)pOMXComponent->pComponentPrivate;
pVideoDec = Rockchip_OSAL_Malloc(sizeof(RKVPU_OMX_VIDEODEC_COMPONENT));
if (pVideoDec == NULL) {
Rockchip_OMX_BaseComponent_Destructor(pOMXComponent);
ret = OMX_ErrorInsufficientResources;
omx_err("OMX_ErrorInsufficientResources, Line:%d", __LINE__);
goto EXIT;
}
Rockchip_OSAL_Memset(pVideoDec, 0, sizeof(RKVPU_OMX_VIDEODEC_COMPONENT));
pVideoDec->hSharedMemory = Rockchip_OSAL_SharedMemory_Open();
if (pVideoDec->hSharedMemory == NULL) {
omx_err("Rockchip_OSAL_SharedMemory_Open open fail");
}
pRockchipComponent->componentName = (OMX_STRING)Rockchip_OSAL_Malloc(MAX_OMX_COMPONENT_NAME_SIZE);
if (pRockchipComponent->componentName == NULL) {
Rockchip_OMX_ComponentDeInit(hComponent);
ret = OMX_ErrorInsufficientResources;
omx_err("OMX_ErrorInsufficientResources, Line:%d", __LINE__);
goto EXIT;
}
Rockchip_OSAL_Memset(pRockchipComponent->componentName, 0, MAX_OMX_COMPONENT_NAME_SIZE);
pVideoDec->nDpbSize = 0;
pRockchipComponent->hComponentHandle = (OMX_HANDLETYPE)pVideoDec;
pRockchipComponent->bSaveFlagEOS = OMX_FALSE;
pRockchipComponent->nRkFlags = 0;
pRockchipComponent->bBehaviorEOS = OMX_FALSE;
pVideoDec->bDecSendEOS = OMX_FALSE;
pVideoDec->bPvr_Flag = OMX_FALSE;
pVideoDec->bFastMode = OMX_FALSE;
pVideoDec->fp_in = NULL;
pVideoDec->fp_out = NULL;
pVideoDec->b4K_flags = OMX_FALSE;
pVideoDec->codecProfile = 0;
pVideoDec->power_fd = -1;
pVideoDec->bIsPowerControl = OMX_FALSE;
pVideoDec->bIsHevc = 0;
pVideoDec->bIs10bit = OMX_FALSE;
pRockchipComponent->bMultiThreadProcess = OMX_TRUE;
pRockchipComponent->codecType = HW_VIDEO_DEC_CODEC;
/* for debug */
pVideoDec->bPrintFps = OMX_FALSE;
pVideoDec->bPrintBufferPosition = OMX_FALSE;
pVideoDec->bGtsMediaTest = OMX_FALSE;
pVideoDec->nVdecDebug = 0;
pVideoDec->bFirstFrame = OMX_TRUE;
pVideoDec->vpumem_handle = NULL;
/* Set componentVersion */
pRockchipComponent->componentVersion.s.nVersionMajor = VERSIONMAJOR_NUMBER;
pRockchipComponent->componentVersion.s.nVersionMinor = VERSIONMINOR_NUMBER;
pRockchipComponent->componentVersion.s.nRevision = REVISION_NUMBER;
pRockchipComponent->componentVersion.s.nStep = STEP_NUMBER;
/* Set specVersion */
pRockchipComponent->specVersion.s.nVersionMajor = VERSIONMAJOR_NUMBER;
pRockchipComponent->specVersion.s.nVersionMinor = VERSIONMINOR_NUMBER;
pRockchipComponent->specVersion.s.nRevision = REVISION_NUMBER;
pRockchipComponent->specVersion.s.nStep = STEP_NUMBER;
/* Input port */
pRockchipPort = &pRockchipComponent->pRockchipPort[INPUT_PORT_INDEX];
pRockchipPort->portDefinition.nBufferCountActual = MAX_VIDEO_INPUTBUFFER_NUM;
pRockchipPort->portDefinition.nBufferCountMin = MAX_VIDEO_INPUTBUFFER_NUM;
pRockchipPort->portDefinition.nBufferSize = 0;
pRockchipPort->portDefinition.eDomain = OMX_PortDomainVideo;
pRockchipPort->portDefinition.format.video.nFrameWidth = DEFAULT_FRAME_WIDTH;
pRockchipPort->portDefinition.format.video.nFrameHeight = DEFAULT_FRAME_HEIGHT;
pRockchipPort->portDefinition.format.video.nStride = 0; /*DEFAULT_FRAME_WIDTH;*/
pRockchipPort->portDefinition.format.video.nSliceHeight = 0;
pRockchipPort->portDefinition.nBufferSize = DEFAULT_VIDEO_INPUT_BUFFER_SIZE;
pRockchipPort->portDefinition.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
pRockchipPort->portDefinition.format.video.cMIMEType = Rockchip_OSAL_Malloc(MAX_OMX_MIMETYPE_SIZE);
Rockchip_OSAL_Memset(pRockchipPort->portDefinition.format.video.cMIMEType, 0, MAX_OMX_MIMETYPE_SIZE);
pRockchipPort->portDefinition.format.video.pNativeRender = 0;
pRockchipPort->portDefinition.format.video.bFlagErrorConcealment = OMX_FALSE;
pRockchipPort->portDefinition.format.video.eColorFormat = OMX_COLOR_FormatUnused;
pRockchipPort->portDefinition.bEnabled = OMX_TRUE;
pRockchipPort->portWayType = WAY2_PORT;
/* Output port */
pRockchipPort = &pRockchipComponent->pRockchipPort[OUTPUT_PORT_INDEX];
pRockchipPort->portDefinition.nBufferCountActual = MAX_VIDEO_OUTPUTBUFFER_NUM;
pRockchipPort->portDefinition.nBufferCountMin = MAX_VIDEO_OUTPUTBUFFER_NUM;
pRockchipPort->portDefinition.nBufferSize = DEFAULT_VIDEO_OUTPUT_BUFFER_SIZE;
pRockchipPort->portDefinition.eDomain = OMX_PortDomainVideo;
pRockchipPort->portDefinition.format.video.nFrameWidth = DEFAULT_FRAME_WIDTH;
pRockchipPort->portDefinition.format.video.nFrameHeight = DEFAULT_FRAME_HEIGHT;
pRockchipPort->portDefinition.format.video.nStride = 0; /*DEFAULT_FRAME_WIDTH;*/
pRockchipPort->portDefinition.format.video.nSliceHeight = 0;
pRockchipPort->portDefinition.nBufferSize = DEFAULT_VIDEO_OUTPUT_BUFFER_SIZE;
pRockchipPort->portDefinition.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
pRockchipPort->portDefinition.format.video.cMIMEType = Rockchip_OSAL_Malloc(MAX_OMX_MIMETYPE_SIZE);
Rockchip_OSAL_Strcpy(pRockchipPort->portDefinition.format.video.cMIMEType, "raw/video");
pRockchipPort->portDefinition.format.video.pNativeRender = 0;
pRockchipPort->portDefinition.format.video.bFlagErrorConcealment = OMX_FALSE;
pRockchipPort->portDefinition.format.video.eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar;
pRockchipPort->portDefinition.bEnabled = OMX_TRUE;
pRockchipPort->portWayType = WAY2_PORT;
pRockchipPort->portDefinition.eDomain = OMX_PortDomainVideo;
pRockchipPort->bufferProcessType = BUFFER_COPY | BUFFER_ANBSHARE;
pRockchipPort->processData.extInfo = (OMX_PTR)Rockchip_OSAL_Malloc(sizeof(DECODE_CODEC_EXTRA_BUFFERINFO));
Rockchip_OSAL_Memset(((char *)pRockchipPort->processData.extInfo), 0, sizeof(DECODE_CODEC_EXTRA_BUFFERINFO));
{
DECODE_CODEC_EXTRA_BUFFERINFO *pBufferInfo = NULL;
pBufferInfo = (DECODE_CODEC_EXTRA_BUFFERINFO *)(pRockchipPort->processData.extInfo);
}
pOMXComponent->UseBuffer = &Rkvpu_OMX_UseBuffer;
pOMXComponent->AllocateBuffer = &Rkvpu_OMX_AllocateBuffer;
pOMXComponent->FreeBuffer = &Rkvpu_OMX_FreeBuffer;
pOMXComponent->ComponentTunnelRequest = &Rkvpu_OMX_ComponentTunnelRequest;
pOMXComponent->GetParameter = &Rkvpu_OMX_GetParameter;
pOMXComponent->SetParameter = &Rkvpu_OMX_SetParameter;
pOMXComponent->GetConfig = &Rkvpu_OMX_GetConfig;
pOMXComponent->SetConfig = &Rkvpu_OMX_SetConfig;
pOMXComponent->GetExtensionIndex = &Rkvpu_OMX_GetExtensionIndex;
pOMXComponent->ComponentRoleEnum = &Rkvpu_OMX_ComponentRoleEnum;
pOMXComponent->ComponentDeInit = &Rockchip_OMX_ComponentDeInit;
pRockchipComponent->rockchip_codec_componentInit = &Rkvpu_Dec_ComponentInit;
pRockchipComponent->rockchip_codec_componentTerminate = &Rkvpu_Dec_Terminate;
pRockchipComponent->rockchip_AllocateTunnelBuffer = &Rkvpu_OMX_AllocateTunnelBuffer;
pRockchipComponent->rockchip_FreeTunnelBuffer = &Rkvpu_OMX_FreeTunnelBuffer;
pRockchipComponent->rockchip_BufferProcessCreate = &Rkvpu_OMX_BufferProcess_Create;
pRockchipComponent->rockchip_BufferProcessTerminate = &Rkvpu_OMX_BufferProcess_Terminate;
pRockchipComponent->rockchip_BufferFlush = &Rkvpu_OMX_BufferFlush;
pRockchipPort = &pRockchipComponent->pRockchipPort[INPUT_PORT_INDEX];
if (!strcmp(componentName, RK_OMX_COMPONENT_H264_DEC)) {
Rockchip_OSAL_Memset(pRockchipPort->portDefinition.format.video.cMIMEType, 0, MAX_OMX_MIMETYPE_SIZE);
Rockchip_OSAL_Strcpy(pRockchipPort->portDefinition.format.video.cMIMEType, "video/avc");
pVideoDec->codecId = OMX_VIDEO_CodingAVC;
pRockchipPort->portDefinition.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC;
}
......
{
int gpu_fd = -1;
gpu_fd = open("/dev/pvrsrvkm", O_RDWR, 0);
if (gpu_fd > 0) {
pVideoDec->bPvr_Flag = OMX_TRUE;
close(gpu_fd);
}
}
strcpy(pRockchipComponent->componentName, componentName);
Rkvpu_OMX_DebugSwitchfromPropget(pRockchipComponent);
pRockchipComponent->currentState = OMX_StateLoaded;
EXIT:
FunctionOut();
return ret;
}
Rockchip_OMX_Check_SizeVersion(…) 实现在 Rockchip_OMX_Basecomponent.c 中,首先从结构体头部取出 32 位长度做比较,然后再去检查版本是否匹配。
hardware/rockchip/omx_il/component/common/Rockchip_OMX_Basecomponent.c
OMX_ERRORTYPE Rockchip_OMX_Check_SizeVersion(OMX_PTR header, OMX_U32 size)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
OMX_VERSIONTYPE* version = NULL;
if (header == NULL) {
ret = OMX_ErrorBadParameter;
goto EXIT;
}
version = (OMX_VERSIONTYPE*)((char*)header + sizeof(OMX_U32));
if (*((OMX_U32*)header) != size) {
ret = OMX_ErrorBadParameter;
goto EXIT;
}
if (version->s.nVersionMajor != VERSIONMAJOR_NUMBER ||
version->s.nVersionMinor != VERSIONMINOR_NUMBER) {
ret = OMX_ErrorVersionMismatch;
goto EXIT;
}
ret = OMX_ErrorNone;
EXIT:
return ret;
}
Rockchip_OMX_BaseComponent_Constructor(…) 方法内部分配了 ROCKCHIP_OMX_BASECOMPONENT 结构内存,并调用 Rockchip_OSAL_Memset(…) 对结构体进行清零,然后对其进行了初始化。注意 pOMXComponent->SetCallbacks 赋值为 Rockchip_OMX_SetCallbacks 函数的地址,后面分析会用到。
hardware/rockchip/omx_il/component/common/Rockchip_OMX_Basecomponent.c
OMX_ERRORTYPE Rockchip_OMX_BaseComponent_Constructor(
OMX_IN OMX_HANDLETYPE hComponent)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
OMX_COMPONENTTYPE *pOMXComponent;
ROCKCHIP_OMX_BASECOMPONENT *pRockchipComponent = NULL;
FunctionIn();
if (hComponent == NULL) {
ret = OMX_ErrorBadParameter;
omx_err("OMX_ErrorBadParameter, Line:%d", __LINE__);
goto EXIT;
}
pOMXComponent = (OMX_COMPONENTTYPE *)hComponent;
pRockchipComponent = Rockchip_OSAL_Malloc(sizeof(ROCKCHIP_OMX_BASECOMPONENT));
if (pRockchipComponent == NULL) {
ret = OMX_ErrorInsufficientResources;
omx_err("OMX_ErrorInsufficientResources, Line:%d", __LINE__);
goto EXIT;
}
Rockchip_OSAL_Memset(pRockchipComponent, 0, sizeof(ROCKCHIP_OMX_BASECOMPONENT));
pRockchipComponent->rkversion = OMX_COMPILE_INFO;
pOMXComponent->pComponentPrivate = (OMX_PTR)pRockchipComponent;
ret = Rockchip_OSAL_SemaphoreCreate(&pRockchipComponent->msgSemaphoreHandle);
if (ret != OMX_ErrorNone) {
ret = OMX_ErrorInsufficientResources;
omx_err("OMX_ErrorInsufficientResources, Line:%d", __LINE__);
goto EXIT;
}
ret = Rockchip_OSAL_MutexCreate(&pRockchipComponent->compMutex);
if (ret != OMX_ErrorNone) {
ret = OMX_ErrorInsufficientResources;
omx_err("OMX_ErrorInsufficientResources, Line:%d", __LINE__);
goto EXIT;
}
ret = Rockchip_OSAL_SignalCreate(&pRockchipComponent->abendStateEvent);
if (ret != OMX_ErrorNone) {
ret = OMX_ErrorInsufficientResources;
omx_err("OMX_ErrorInsufficientResources, Line:%d", __LINE__);
goto EXIT;
}
pRockchipComponent->bExitMessageHandlerThread = OMX_FALSE;
Rockchip_OSAL_QueueCreate(&pRockchipComponent->messageQ, MAX_QUEUE_ELEMENTS);
ret = Rockchip_OSAL_ThreadCreate(&pRockchipComponent->hMessageHandler,
Rockchip_OMX_MessageHandlerThread,
pOMXComponent,
"omx_msg_hdl");
if (ret != OMX_ErrorNone) {
ret = OMX_ErrorInsufficientResources;
omx_err("OMX_ErrorInsufficientResources, Line:%d", __LINE__);
goto EXIT;
}
pRockchipComponent->bMultiThreadProcess = OMX_FALSE;
pOMXComponent->GetComponentVersion = &Rockchip_OMX_GetComponentVersion;
pOMXComponent->SendCommand = &Rockchip_OMX_SendCommand;
pOMXComponent->GetState = &Rockchip_OMX_GetState;
pOMXComponent->SetCallbacks = &Rockchip_OMX_SetCallbacks;
pOMXComponent->UseEGLImage = &Rockchip_OMX_UseEGLImage;
EXIT:
FunctionOut();
return ret;
}
调用 Rockchip_OMX_Port_Constructor(…) 构造 Input 和 Output port,可以看到主要对 ROCKCHIP_OMX_BASEPORT 结构进行了内存分配,ALL_PORT_NUM = 2,所以一共分配了两个元素。然后对 Input 和 Output port 进行了初始化。INPUT_PORT_INDEX 定义为 0,而 OUTPUT_PORT_INDEX 定义为 1。
hardware/rockchip/omx_il/component/common/Rockchip_OMX_Baseport.c
OMX_ERRORTYPE Rockchip_OMX_Port_Constructor(OMX_HANDLETYPE hComponent)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
OMX_COMPONENTTYPE *pOMXComponent = NULL;
ROCKCHIP_OMX_BASECOMPONENT *pRockchipComponent = NULL;
ROCKCHIP_OMX_BASEPORT *pRockchipPort = NULL;
ROCKCHIP_OMX_BASEPORT *pRockchipInputPort = NULL;
ROCKCHIP_OMX_BASEPORT *pRockchipOutputPort = NULL;
FunctionIn();
if (hComponent == NULL) {
ret = OMX_ErrorBadParameter;
omx_err("OMX_ErrorBadParameter, Line:%d", __LINE__);
goto EXIT;
}
pOMXComponent = (OMX_COMPONENTTYPE *)hComponent;
ret = Rockchip_OMX_Check_SizeVersion(pOMXComponent, sizeof(OMX_COMPONENTTYPE));
if (ret != OMX_ErrorNone) {
goto EXIT;
}
if (pOMXComponent->pComponentPrivate == NULL) {
ret = OMX_ErrorBadParameter;
omx_err("OMX_ErrorBadParameter, Line:%d", __LINE__);
goto EXIT;
}
pRockchipComponent = (ROCKCHIP_OMX_BASECOMPONENT *)pOMXComponent->pComponentPrivate;
INIT_SET_SIZE_VERSION(&pRockchipComponent->portParam, OMX_PORT_PARAM_TYPE);
pRockchipComponent->portParam.nPorts = ALL_PORT_NUM;
pRockchipComponent->portParam.nStartPortNumber = INPUT_PORT_INDEX;
pRockchipPort = Rockchip_OSAL_Malloc(sizeof(ROCKCHIP_OMX_BASEPORT) * ALL_PORT_NUM);
if (pRockchipPort == NULL) {
......
}
Rockchip_OSAL_Memset(pRockchipPort, 0, sizeof(ROCKCHIP_OMX_BASEPORT) * ALL_PORT_NUM);
pRockchipComponent->pRockchipPort = pRockchipPort;
/* Input Port */
pRockchipInputPort = &pRockchipPort[INPUT_PORT_INDEX];
Rockchip_OSAL_QueueCreate(&pRockchipInputPort->bufferQ, MAX_QUEUE_ELEMENTS);
Rockchip_OSAL_QueueCreate(&pRockchipInputPort->securebufferQ, MAX_QUEUE_ELEMENTS);
pRockchipInputPort->extendBufferHeader = Rockchip_OSAL_Malloc(sizeof(ROCKCHIP_OMX_BUFFERHEADERTYPE) * MAX_BUFFER_NUM);
if (pRockchipInputPort->extendBufferHeader == NULL) {
......
}
Rockchip_OSAL_Memset(pRockchipInputPort->extendBufferHeader, 0, sizeof(ROCKCHIP_OMX_BUFFERHEADERTYPE) * MAX_BUFFER_NUM);
pRockchipInputPort->bufferStateAllocate = Rockchip_OSAL_Malloc(sizeof(OMX_U32) * MAX_BUFFER_NUM);
if (pRockchipInputPort->bufferStateAllocate == NULL) {
......
}
Rockchip_OSAL_Memset(pRockchipInputPort->bufferStateAllocate, 0, sizeof(OMX_U32) * MAX_BUFFER_NUM);
pRockchipInputPort->bufferSemID = NULL;
pRockchipInputPort->assignedBufferNum = 0;
pRockchipInputPort->portState = OMX_StateMax;
pRockchipInputPort->bIsPortFlushed = OMX_FALSE;
pRockchipInputPort->bIsPortDisabled = OMX_FALSE;
pRockchipInputPort->tunneledComponent = NULL;
pRockchipInputPort->tunneledPort = 0;
pRockchipInputPort->tunnelBufferNum = 0;
pRockchipInputPort->bufferSupplier = OMX_BufferSupplyUnspecified;
pRockchipInputPort->tunnelFlags = 0;
ret = Rockchip_OSAL_SemaphoreCreate(&pRockchipInputPort->loadedResource);
if (ret != OMX_ErrorNone) {
......
}
ret = Rockchip_OSAL_SemaphoreCreate(&pRockchipInputPort->unloadedResource);
if (ret != OMX_ErrorNone) {
......
}
INIT_SET_SIZE_VERSION(&pRockchipInputPort->portDefinition, OMX_PARAM_PORTDEFINITIONTYPE);
pRockchipInputPort->portDefinition.nPortIndex = INPUT_PORT_INDEX;
pRockchipInputPort->portDefinition.eDir = OMX_DirInput;
pRockchipInputPort->portDefinition.nBufferCountActual = 0;
pRockchipInputPort->portDefinition.nBufferCountMin = 0;
pRockchipInputPort->portDefinition.nBufferSize = 0;
pRockchipInputPort->portDefinition.bEnabled = OMX_FALSE;
pRockchipInputPort->portDefinition.bPopulated = OMX_FALSE;
pRockchipInputPort->portDefinition.eDomain = OMX_PortDomainMax;
pRockchipInputPort->portDefinition.bBuffersContiguous = OMX_FALSE;
pRockchipInputPort->portDefinition.nBufferAlignment = 0;
pRockchipInputPort->markType.hMarkTargetComponent = NULL;
pRockchipInputPort->markType.pMarkData = NULL;
pRockchipInputPort->exceptionFlag = GENERAL_STATE;
/* Output Port */
pRockchipOutputPort = &pRockchipPort[OUTPUT_PORT_INDEX];
Rockchip_OSAL_QueueCreate(&pRockchipOutputPort->bufferQ, MAX_QUEUE_ELEMENTS); /* For in case of "Output Buffer Share", MAX ELEMENTS(DPB + EDPB) */
pRockchipOutputPort->extendBufferHeader = Rockchip_OSAL_Malloc(sizeof(ROCKCHIP_OMX_BUFFERHEADERTYPE) * MAX_BUFFER_NUM);
if (pRockchipOutputPort->extendBufferHeader == NULL) {
......
}
Rockchip_OSAL_Memset(pRockchipOutputPort->extendBufferHeader, 0, sizeof(ROCKCHIP_OMX_BUFFERHEADERTYPE) * MAX_BUFFER_NUM);
pRockchipOutputPort->bufferStateAllocate = Rockchip_OSAL_Malloc(sizeof(OMX_U32) * MAX_BUFFER_NUM);
if (pRockchipOutputPort->bufferStateAllocate == NULL) {
......
}
Rockchip_OSAL_Memset(pRockchipOutputPort->bufferStateAllocate, 0, sizeof(OMX_U32) * MAX_BUFFER_NUM);
pRockchipOutputPort->bufferSemID = NULL;
pRockchipOutputPort->assignedBufferNum = 0;
pRockchipOutputPort->portState = OMX_StateMax;
pRockchipOutputPort->bIsPortFlushed = OMX_FALSE;
pRockchipOutputPort->bIsPortDisabled = OMX_FALSE;
pRockchipOutputPort->tunneledComponent = NULL;
pRockchipOutputPort->tunneledPort = 0;
pRockchipOutputPort->tunnelBufferNum = 0;
pRockchipOutputPort->bufferSupplier = OMX_BufferSupplyUnspecified;
pRockchipOutputPort->tunnelFlags = 0;
ret = Rockchip_OSAL_SemaphoreCreate(&pRockchipOutputPort->loadedResource);
if (ret != OMX_ErrorNone) {
......
}
ret = Rockchip_OSAL_SignalCreate(&pRockchipOutputPort->unloadedResource);
if (ret != OMX_ErrorNone) {
......
}
INIT_SET_SIZE_VERSION(&pRockchipOutputPort->portDefinition, OMX_PARAM_PORTDEFINITIONTYPE);
pRockchipOutputPort->portDefinition.nPortIndex = OUTPUT_PORT_INDEX;
pRockchipOutputPort->portDefinition.eDir = OMX_DirOutput;
pRockchipOutputPort->portDefinition.nBufferCountActual = 0;
pRockchipOutputPort->portDefinition.nBufferCountMin = 0;
pRockchipOutputPort->portDefinition.nBufferSize = 0;
pRockchipOutputPort->portDefinition.bEnabled = OMX_FALSE;
pRockchipOutputPort->portDefinition.bPopulated = OMX_FALSE;
pRockchipOutputPort->portDefinition.eDomain = OMX_PortDomainMax;
pRockchipOutputPort->portDefinition.bBuffersContiguous = OMX_FALSE;
pRockchipOutputPort->portDefinition.nBufferAlignment = 0;
pRockchipOutputPort->markType.hMarkTargetComponent = NULL;
pRockchipOutputPort->markType.pMarkData = NULL;
pRockchipOutputPort->exceptionFlag = GENERAL_STATE;
pRockchipComponent->checkTimeStamp.needSetStartTimeStamp = OMX_FALSE;
pRockchipComponent->checkTimeStamp.needCheckStartTimeStamp = OMX_FALSE;
pRockchipComponent->checkTimeStamp.startTimeStamp = 0;
pRockchipComponent->checkTimeStamp.nStartFlags = 0x0;
pOMXComponent->EmptyThisBuffer = &Rockchip_OMX_EmptyThisBuffer;
pOMXComponent->FillThisBuffer = &Rockchip_OMX_FillThisBuffer;
ret = OMX_ErrorNone;
EXIT:
FunctionOut();
return ret;
}
最后来分析一波 Rockchip_OSAL_SharedMemory_Open(),调用 access(…) 检查是否可以打开 /dev/dri/card0 设备,否则打开 /dev/ion 设备。可以看到前一种属于 DRM,而后一种属于 ION。
hardware/rockchip/omx_il/osal/Rockchip_OSAL_SharedMemory.c
OMX_HANDLETYPE Rockchip_OSAL_SharedMemory_Open()
{
ROCKCHIP_SHARED_MEMORY *pHandle = NULL;
int IONClient = 0;
pHandle = (ROCKCHIP_SHARED_MEMORY *)malloc(sizeof(ROCKCHIP_SHARED_MEMORY));
Rockchip_OSAL_Memset(pHandle, 0, sizeof(ROCKCHIP_SHARED_MEMORY));
if (pHandle == NULL)
goto EXIT;
if (!access("/dev/dri/card0", F_OK)) {
IONClient = open("/dev/dri/card0", O_RDWR);
mem_type = MEMORY_TYPE_DRM;
} else {
IONClient = open("/dev/ion", O_RDWR);
mem_type = MEMORY_TYPE_ION;
}
if (IONClient <= 0) {
omx_err("ion_client_create Error: %d", IONClient);
Rockchip_OSAL_Free((void *)pHandle);
pHandle = NULL;
goto EXIT;
}
pHandle->fd = IONClient;
Rockchip_OSAL_MutexCreate(&pHandle->hSMMutex);
EXIT:
return (OMX_HANDLETYPE)pHandle;
}
回到 Rockchip_OMX_ComponentLoad(…) 函数, Rockchip_OMX_ComponentAPICheck(…) 实现非常简单,检查 OMX_COMPONENTTYPE 一系列字段是否赋值,只要有一个为 NULL,就返回 OMX_ErrorInvalidComponent 错误。
hardware/rockchip/omx_il/core/Rockchip_OMX_Component_Register.c
OMX_ERRORTYPE Rockchip_OMX_ComponentAPICheck(OMX_COMPONENTTYPE *component)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
if ((NULL == component->GetComponentVersion) ||
(NULL == component->SendCommand) ||
(NULL == component->GetParameter) ||
(NULL == component->SetParameter) ||
(NULL == component->GetConfig) ||
(NULL == component->SetConfig) ||
(NULL == component->GetExtensionIndex) ||
(NULL == component->GetState) ||
(NULL == component->ComponentTunnelRequest) ||
(NULL == component->UseBuffer) ||
(NULL == component->AllocateBuffer) ||
(NULL == component->FreeBuffer) ||
(NULL == component->EmptyThisBuffer) ||
(NULL == component->FillThisBuffer) ||
(NULL == component->SetCallbacks) ||
(NULL == component->ComponentDeInit) ||
(NULL == component->UseEGLImage) ||
(NULL == component->ComponentRoleEnum))
ret = OMX_ErrorInvalidComponent;
else
ret = OMX_ErrorNone;
return ret;
}
回到 RKOMX_GetHandle(…) 方法,现在来分析调用 ROCKCHIP_OMX_COMPONENT 结构内的 pOMXComponent 字段 SetCallbacks(…) 方法,由上面的分析可以得出实际会调到 Rockchip_OMX_Basecomponent.c 中的 Rockchip_OMX_SetCallbacks 函数。
只是做了一些参数检查,然后给 ROCKCHIP_OMX_BASECOMPONENT pCallbacks 和 callbackData 字段进行了赋值。
hardware/rockchip/omx_il/component/common/Rockchip_OMX_Basecomponent.c
OMX_ERRORTYPE Rockchip_OMX_SetCallbacks (
OMX_IN OMX_HANDLETYPE hComponent,
OMX_IN OMX_CALLBACKTYPE* pCallbacks,
OMX_IN OMX_PTR pAppData)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
OMX_COMPONENTTYPE *pOMXComponent = NULL;
ROCKCHIP_OMX_BASECOMPONENT *pRockchipComponent = NULL;
FunctionIn();
if (hComponent == NULL) {
ret = OMX_ErrorBadParameter;
omx_err("OMX_ErrorBadParameter :%d", __LINE__);
goto EXIT;
}
pOMXComponent = (OMX_COMPONENTTYPE *)hComponent;
ret = Rockchip_OMX_Check_SizeVersion(pOMXComponent, sizeof(OMX_COMPONENTTYPE));
if (ret != OMX_ErrorNone) {
omx_err("OMX_ErrorNone :%d", __LINE__);
goto EXIT;
}
if (pOMXComponent->pComponentPrivate == NULL) {
omx_err("OMX_ErrorBadParameter :%d", __LINE__);
ret = OMX_ErrorBadParameter;
goto EXIT;
}
pRockchipComponent = (ROCKCHIP_OMX_BASECOMPONENT *)pOMXComponent->pComponentPrivate;
if (pCallbacks == NULL) {
omx_err("OMX_ErrorBadParameter :%d", __LINE__);
ret = OMX_ErrorBadParameter;
goto EXIT;
}
if (pRockchipComponent->currentState == OMX_StateInvalid) {
omx_err("OMX_ErrorInvalidState :%d", __LINE__);
ret = OMX_ErrorInvalidState;
goto EXIT;
}
if (pRockchipComponent->currentState != OMX_StateLoaded) {
omx_err("OMX_StateLoaded :%d", __LINE__);
ret = OMX_ErrorIncorrectStateOperation;
goto EXIT;
}
pRockchipComponent->pCallbacks = pCallbacks;
pRockchipComponent->callbackData = pAppData;
ret = OMX_ErrorNone;
EXIT:
FunctionOut();
return ret;
}
最后
以上就是殷勤裙子最近收集整理的关于【Android 10 源码】深入理解 MediaCodec 组件分配的全部内容,更多相关【Android内容请搜索靠谱客的其他文章。
发表评论 取消回复