郑州做网站公司汉狮价格,购物网站建设策划书,网站建设和成本,互联网项目为了了解 ACodec 是如何与 OpenMAX 组件进行 buffer 流转的#xff0c;我们有必要先来学习 OMXNodeInstance#xff0c;在前面的章节中#xff0c;我们已经了解了 media.codec 进程包含的内容#xff0c;以及 OpenMAX 框架中的一些内容。这一节我们将来学习 OMXNode 与 med… 为了了解 ACodec 是如何与 OpenMAX 组件进行 buffer 流转的我们有必要先来学习 OMXNodeInstance在前面的章节中我们已经了解了 media.codec 进程包含的内容以及 OpenMAX 框架中的一些内容。这一节我们将来学习 OMXNode 与 media.codec 进程之间的关系了解OMXNode是如何创建、使用、销毁的。 1、创建 OMXNodeInstance
我们回到 Omx.cpp 来看 allocateNode 方法
Returnvoid Omx::allocateNode(const hidl_string name,const spIOmxObserver observer,allocateNode_cb _hidl_cb) {using ::android::IOMXNode;using ::android::IOMXObserver;spOMXNodeInstance instance;{// 检查是否到达了 OMXNode 实例最大个数Mutex::Autolock autoLock(mLock);if (mLiveNodes.size() kMaxNodeInstances) {_hidl_cb(toStatus(NO_MEMORY), nullptr);return Void();}// 创建 OMXNodeInstance 实例传入参数为 IOmx 服务IOmxObserver以及组件名称instance new OMXNodeInstance(this, new LWOmxObserver(observer), name.c_str());// 调用 OMXStore 的方法创建 OMX_COMPONENTTYPE 对象OMX_COMPONENTTYPE *handle;OMX_ERRORTYPE err mStore-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();}// 将创建的 OMX_COMPONENTTYPE 对象与 OMXNodeInstance 进行绑定instance-setHandle(handle);// 获取 quirks 信息// Find quirks from mParserconst 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;}}// 如果有 quirks 信息则设置instance-setQuirks(quirks);}// 将 IOmxObersver 和 OMXNodeInstance 以键值的形式存储mLiveNodes.add(observer.get(), instance);// 将 OMXNodeInstance 和 IOmxObersver 以键值的形式存储mNode2Observer.add(instance.get(), observer.get());}observer-linkToDeath(this, 0);// 返回 OMXNodeInstance 给 ACodec_hidl_cb(toStatus(OK), new TWOmxNode(instance));return Void();
}allocateNode 方法中的内容还是比较清晰简洁的主要做了如下几件事情
检查 OMXNode 实例个数是否达到上限创建 OMXNodeInstance 实例传入参数为 IOmx 服务IOmxObserver以及组件名称将创建的 OMX_COMPONENTTYPE 对象与 OMXNodeInstance 进行绑定获取 quirks 并给 OMXNodeInstance 设置相关信息将 IOmxObersver 和 OMXNodeInstance 以键值的形式双向绑定存储返回 OMXNodeInstance 返回给 ACodec。
以上是代码的解释接下来是我们对这段代码的理解
OMX_COMPONENTTYPE 是由 OMXStore 创建这个指针由 OMXStore 来管理所以最终也由 OMXStore 来释放OMX_COMPONENTTYPE 和 OMXNodeInstance 进行了绑定OMXNodeInstance帮我们进行OMX组件方法的封装之后上层调用 OMXNodeInstance 的方法OMXNodeInstance 最终调用到组件的接口OMXNodeInstance 的引用计数为2mLiveNodes 中存有一个计数上层ACodec存有一个计数mNode2Observer 中存储的是指针所以不会有计数增加。
2、OMXNodeInstance 构造函数
OMXNodeInstance::OMXNodeInstance(Omx *owner, const spIOMXObserver 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);
}OMXNodeInstance 的构造函数主要就初始化了几个数组这个数组中都是由两个元素索引0表示input port索引 1 表示 output port以下是一些数组的意义
mNumPortBuffersport 中buffer的数量mMetadataTypemeta data 的类型这个用于确定有surface的情况下ouput buffer的类型以及input为camera或者是graphic录屏的情况下 input buffer的类型mPortMode端口模式mSecureBufferTypesecure buffer 的类型mGraphicBufferEnabled是否使用graphic buffer
看过前面章节的小伙伴应该大致可以揣摩出使用的枚举类型的意义。
void OMXNodeInstance::setHandle(OMX_HANDLETYPE handle) {CLOG_LIFE(allocateNode, handle%p, handle);CHECK(mHandle NULL);mHandle handle;if (handle ! NULL) {mDispatcher new CallbackDispatcher(this);}
}setHandle方法可以把创建的OMX组件和OMXNodeInstance实例进行绑定同时会创建一个CallbackDispatcher对象。
3、CallbackDispatcher
CallbackDispatcher 从名字上来看是回调的调度者它的作用是开启一个线程所有由OMX组件发上来的消息或者事件都会进入到该线程的队列当中按照顺序一个一个通过 IOmxObserver 发回到 ACodec 层。
OMX callback 会把事件或者消息封装成为 omx_message再通过IOmxObserver发送具体如何封装的以及ACodec如何解封装参考OnEvent、OnEmptyBufferDone、OnFillBufferDone这三个方法的实现。
具体 CallbackDispatcher 和 CallbackDispatcherThread 是如何实现的我们这里不做过多的了解。
4、销毁 OMXNodeInstance
我们常常只关注对象是如何创建的其实销毁的过程也很重要这里我们就一起来了解OMXNode是如何被销毁的。
目光回到 ACodec 中来当我们调用了 initiateShutdown 去释放组件时ACodec 会调用 IOMXNode 的 freeNode 方法 case ACodec::kWhatReleaseCodecInstance:{ALOGI([%s] forcing the release of codec,mCodec-mComponentName.c_str());status_t err mCodec-mOMXNode-freeNode();ALOGE_IF([%s] failed to release codec instance: err%d,mCodec-mComponentName.c_str(), err);mCodec-mCallback-onReleaseCompleted();mCodec-changeState(mCodec-mUninitializedState);break;}最终调用到 OMXNodeInstance 的 freeNode 方法中
status_t OMXNodeInstance::freeNode() {CLOG_LIFE(freeNode, handle%p, mHandle);static int32_t kMaxNumIterations 10;// Transition the node from its current state all the way down// to Loaded.// This ensures that all active buffers are properly freed even// for components that dont do this themselves on a call to// FreeHandle.// The code below may trigger some more events to be dispatched// by the OMX component - we want to ignore them as our client// does not expect them.bool expected false;if (!mDying.compare_exchange_strong(expected, true)) {// exit if we have already freed the node or doing so right now.// NOTE: this ensures that the block below executes at most once.ALOGV(Already dying);return OK;}// 获取 OMX 组件当前的状态OMX_STATETYPE state;CHECK_EQ(OMX_GetState(mHandle, state), OMX_ErrorNone);switch (state) {case OMX_StateExecuting:{// 将OMX状态置为 IdleALOGV(forcing Executing-Idle);sendCommand(OMX_CommandStateSet, OMX_StateIdle);OMX_ERRORTYPE err;int32_t iteration 0;// 阻塞等待while ((err OMX_GetState(mHandle, state)) OMX_ErrorNone state ! OMX_StateIdle state ! OMX_StateInvalid) {if (iteration kMaxNumIterations) {CLOGW(failed to enter Idle state (now %s(%d), aborting.,asString(state), state);state OMX_StateInvalid;break;}usleep(100000);}CHECK_EQ(err, OMX_ErrorNone);if (state OMX_StateInvalid) {break;}FALLTHROUGH_INTENDED;}case OMX_StateIdle:{// 将 OMX 组件状态设置为 LoadedALOGV(forcing Idle-Loaded);sendCommand(OMX_CommandStateSet, OMX_StateLoaded);// 销毁所有 bufferfreeActiveBuffers();OMX_ERRORTYPE err;int32_t iteration 0;// 阻塞等待while ((err OMX_GetState(mHandle, state)) OMX_ErrorNone state ! OMX_StateLoaded state ! OMX_StateInvalid) {if (iteration kMaxNumIterations) {CLOGW(failed to enter Loaded state (now %s(%d), aborting.,asString(state), state);state OMX_StateInvalid;break;}ALOGV(waiting for Loaded state...);usleep(100000);}CHECK_EQ(err, OMX_ErrorNone);FALLTHROUGH_INTENDED;}case OMX_StateLoaded:{// 销毁所有 bufferfreeActiveBuffers();FALLTHROUGH_INTENDED;}case OMX_StateInvalid:break;default:LOG_ALWAYS_FATAL(unknown state %s(%#x)., asString(state), state);break;}Mutex::Autolock _l(mLock);// 调用 OMXNodeInstance 的另一个 freeNode 方法传入参数为自身status_t err mOwner-freeNode(this);// 关闭 Dispatcher 线程销毁相关内容 mDispatcher.clear();mOMXBufferSource.clear();mHandle NULL;CLOG_IF_ERROR(freeNode, err, );free(mName);mName NULL;ALOGV(OMXNodeInstance going away.);return err;
}获取 OMX 组件当前的状态按照状态依次设定 OMX_StateIdle、OMX_StateLoaded并且调用 freeActiveBuffers 释放所有的 buffer这里的buffer指的是什么我们后面再看调用 IOmx 的 freeNode 方法传入参数为自身关闭 Dispatcher 线程
这里比较令人疑惑的可能就是第二点了我们刚刚调用的 OMXNode freeNode 干了什么为什么又要调用一个freeNode呢
其实从上面的代码我们可以看出来OMXNodeInstance 的 freeNode 方法是用于关闭或者销毁 OMX 组件所使用的一些资源但是这时候 OMX 组件还是存在没有被销毁的。之所以把销毁资源的方法放在 OMXNodeInstance 中是为了保证 API 调用逻辑的统一所有的关于组件的操作方法都放在 OMXNode 当中。
当OMX组件的资源全部释放完成下一步就是要销毁OMX组件了调用的方法就是 IOmx 的 freeNode 方法
status_t Omx::freeNode(spOMXNodeInstance const instance) {if (instance NULL) {return OK;}{Mutex::Autolock autoLock(mLock);// 获取OMXNode指针ssize_t observerIndex mNode2Observer.indexOfKey(instance.get());if (observerIndex 0) {wpIBase observer mNode2Observer.valueAt(observerIndex);ssize_t nodeIndex mLiveNodes.indexOfKey(observer);// 移除引用计数移除指针if (nodeIndex 0) {mNode2Observer.removeItemsAt(observerIndex);mLiveNodes.removeItemsAt(nodeIndex);spIBase sObserver observer.promote();if (sObserver ! nullptr) {sObserver-unlinkToDeath(this);}} else {LOG(WARNING) Inconsistent observer record;}}}OMX_ERRORTYPE err OMX_ErrorNone;if (instance-handle() ! NULL) {// 调用destroyComponentInstance销毁OMX组件err mStore-destroyComponentInstance(static_castOMX_COMPONENTTYPE*(instance-handle()));}return StatusFromOMXError(err);
}移除两个keyedVector 中的键值减少OMXNode引用计数减少IOmxObserver 的引用计数释放资源调用destroyComponentInstance销毁OMX组件最终创建的组件还是由 OMXStore 来销毁
Omx::freeNode 执行完成OMX组件被销毁这时候 OMXNodeInstance 有没有被销毁呢答案是没有的退出 Omx::freeNode 时OMXNodeInstance 的引用计数为 1通过 binder 被 ACodec 持有当 ACodec 销毁时OMXNodeInstance 自然就销毁了。
把之前的一幅图改改来表示 OMXNodeInsatnce、OMX_HANDLE、IOmx、OMXStore 之间的关系