重庆网站平台建设,公司组织架构图怎么设计,南京做网站的额,网站路径这一节开始我们就来学习 ACodec 的实现 1、创建 ACodec
ACodec 是在 MediaCodec 中创建的#xff0c;这里先贴出创建部分的代码#xff1a; mCodec mGetCodecBase(name, owner);if (mCodec NULL) {ALOGE(Getting codec base with name %s (owner%s) failed, n… 这一节开始我们就来学习 ACodec 的实现 1、创建 ACodec
ACodec 是在 MediaCodec 中创建的这里先贴出创建部分的代码 mCodec mGetCodecBase(name, owner);if (mCodec NULL) {ALOGE(Getting codec base with name %s (owner%s) failed, name.c_str(), owner);return NAME_NOT_FOUND;}if (mDomain DOMAIN_VIDEO) {// video codec needs dedicated looperif (mCodecLooper NULL) {status_t err OK;mCodecLooper new ALooper;mCodecLooper-setName(CodecLooper);err mCodecLooper-start(false, false, ANDROID_PRIORITY_AUDIO);if (OK ! err) {ALOGE(Codec Looper failed to start);return err;}}mCodecLooper-registerHandler(mCodec);} else {mLooper-registerHandler(mCodec);}从前面的学习我们可以知道MediaCodec 使用的是异步消息处理的机制创建MediaCodec 时需要传入一个 ALooper 对象用于处理发送给 MediaCodec 的消息。同样的 ACodec 也是用的异步消息处理机制它也需要一个 ALooper这个 ALooper 应该由上一级 MediaCodec 传递从上面的代码我们可以知道如果创建的是音频解码器那么 ACodec 将会复用 MediaCodec 的 ALooper也就是它们的消息处理会在相同线程当中如果是视频解码器那么 MediaCodec 会创建一个专门的 ALooper 给 ACodec 使用ACodec 和 MediaCodec 的消息处理在不同线程中。
ACodec::ACodec(): mSampleRate(0),mNodeGeneration(0),mUsingNativeWindow(false),mNativeWindowUsageBits(0),mLastNativeWindowDataSpace(HAL_DATASPACE_UNKNOWN),mIsVideo(false),mIsImage(false),mIsEncoder(false),mFatalError(false),mShutdownInProgress(false),mExplicitShutdown(false),mIsLegacyVP9Decoder(false),mIsStreamCorruptFree(false),mIsLowLatency(false),mEncoderDelay(0),mEncoderPadding(0),mRotationDegrees(0),mChannelMaskPresent(false),mChannelMask(0),mDequeueCounter(0),mMetadataBuffersToSubmit(0),mNumUndequeuedBuffers(0),mRepeatFrameDelayUs(-1LL),mMaxPtsGapUs(0LL),mMaxFps(-1),mFps(-1.0),mCaptureFps(-1.0),mCreateInputBuffersSuspended(false),mTunneled(false),mDescribeColorAspectsIndex((OMX_INDEXTYPE)0),mDescribeHDRStaticInfoIndex((OMX_INDEXTYPE)0),mDescribeHDR10PlusInfoIndex((OMX_INDEXTYPE)0),mStateGeneration(0),mVendorExtensionsStatus(kExtensionsUnchecked) {memset(mLastHDRStaticInfo, 0, sizeof(mLastHDRStaticInfo));mUninitializedState new UninitializedState(this);mLoadedState new LoadedState(this);mLoadedToIdleState new LoadedToIdleState(this);mIdleToExecutingState new IdleToExecutingState(this);mExecutingState new ExecutingState(this);mOutputPortSettingsChangedState new OutputPortSettingsChangedState(this);mExecutingToIdleState new ExecutingToIdleState(this);mIdleToLoadedState new IdleToLoadedState(this);mFlushingState new FlushingState(this);mPortEOS[kPortIndexInput] mPortEOS[kPortIndexOutput] false;mInputEOSResult OK;mPortMode[kPortIndexInput] IOMX::kPortModePresetByteBuffer;mPortMode[kPortIndexOutput] IOMX::kPortModePresetByteBuffer;memset(mLastNativeWindowCrop, 0, sizeof(mLastNativeWindowCrop));changeState(mUninitializedState);
}ACodec 的构造函数主要是初始化了成员对象实例化了各个状态对象并且将状态切换到了 UninitializedState这时候我们就要去查看它的 stateEntered 方法
void ACodec::UninitializedState::stateEntered() {ALOGV(Now uninitialized);if (mDeathNotifier ! NULL) {if (mCodec-mOMXNode ! NULL) {auto tOmxNode mCodec-mOMXNode-getHalInterfaceIOmxNode();if (tOmxNode) {tOmxNode-unlinkToDeath(mDeathNotifier);}}mDeathNotifier.clear();}mCodec-mUsingNativeWindow false;mCodec-mNativeWindow.clear();mCodec-mNativeWindowUsageBits 0;mCodec-mOMX.clear();mCodec-mOMXNode.clear();mCodec-mFlags 0;mCodec-mPortMode[kPortIndexInput] IOMX::kPortModePresetByteBuffer;mCodec-mPortMode[kPortIndexOutput] IOMX::kPortModePresetByteBuffer;mCodec-mConverter[0].clear();mCodec-mConverter[1].clear();mCodec-mComponentName.clear();
}UninitializedState::stateEntered 主要是将与 OMX 组件相关的成员对象重置初始化。
2、initiateAllocateComponent
创建 MediaCodec 时ACodec 也就被创建了随后就会调用 initiateAllocateComponent 方法创建 OMX 组件ACodec 创建之后处在 UninitializedState所以消息最终在该状态中被处理
bool ACodec::UninitializedState::onAllocateComponent(const spAMessage msg) {ALOGV(onAllocateComponent);CHECK(mCodec-mOMXNode NULL);mCodec-mFatalError false;// 创建 Callback 消息并且设置好 notifyspAMessage notify new AMessage(kWhatOMXMessageList, mCodec);// notify 的 generation 为 nodegeneration 1这是因为进入 loaded 状态后mNodeGeneration 会 1notify-setInt32(generation, mCodec-mNodeGeneration 1);// 需要检查 codecInfo 才能创建 OMXNodespRefBase obj;CHECK(msg-findObject(codecInfo, obj));spMediaCodecInfo 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));// 创建 callback 对象spCodecObserver observer new CodecObserver(notify);spIOMX omx;spIOMXNode omxNode;status_t err NAME_NOT_FOUND;// 创建 OMXClientOMXClient client;// 获取 IOmx 服务if (client.connect(owner.c_str()) ! OK) {mCodec-signalError(OMX_ErrorUndefined, NO_INIT);return false;}// 将获取到的 IOmx 服务代理封装为 Legacy 模式omx client.interface();pid_t tid gettid();int prevPriority androidGetThreadPriority(tid);androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);// 创建 IOmxNode 服务代理并且封装为 IOMXNodeerr omx-allocateNode(componentName.c_str(), observer, omxNode);androidSetThreadPriority(tid, prevPriority);mDeathNotifier new DeathNotifier(new AMessage(kWhatOMXDied, mCodec));auto tOmxNode omxNode-getHalInterfaceIOmxNode();if (tOmxNode !tOmxNode-linkToDeath(mDeathNotifier, 0)) {mDeathNotifier.clear();}// 记录新的状态下的 ACodec 状态mCodec-mNodeGeneration;mCodec-mComponentName componentName;mCodec-mRenderTracker.setComponentName(componentName);mCodec-mFlags 0;// 记录是否创建的是 secure 组件if (componentName.endsWith(.secure)) {mCodec-mFlags | kFlagIsSecure;mCodec-mFlags | kFlagIsGrallocUsageProtected;mCodec-mFlags | kFlagPushBlankBuffersToNativeWindowOnShutdown;}mCodec-mOMX omx;mCodec-mOMXNode omxNode;// 调用 callback 通知 MediaCodec 完成阻塞调用mCodec-mCallback-onComponentAllocated(mCodec-mComponentName.c_str());// 切换状态到 LoadedStatemCodec-changeState(mCodec-mLoadedState);return true;
}这里涉及的内容比较多
创建 notify 对象并且传入到 CodecObserver 对象中CodecObserver 会把 OMX 发送回来的消息重新封装再通过 notify message 转发给 ACodec最后在不同状态中处理。这里有个是 mNodeGeneration 用于检查 OMX 消息及时性的但是实际并未启用。这里有一点需要注意这些 State 状态类都是 ACodec 的内部类C11之后内部类可以访问外部类的私有成员以及私有方法所以虽然这些类并不是 ACodec 的友元但是同样是可以调用 ACodec 所有方法的。创建 OMXNode 之前会先检查从 MediaCodec 层获取到的 MediaCodecInfo如果没有这个信息将会报错这里算是一个双重检查防止强行越过 MediaCodecList 的检查调用 OMXClient 的方法获取 IOmx 的代理并用该代理创建 IOmxNode 代理传入参数为组件名称如果组件名称以 secure 结尾那么说明需要创建安全组件并且记录到 ACodec mFlags 成员中调用 onComponentAllocated 通知 MediaCodec 完成阻塞调用切换状态到 LoadedState
在看 LoadedState 的 stateEntered 方法之前我们要先看下 BaseState 给出的 stateExited 方法这里用到了 mStateGeneration用来记录 ACodec 当前的状态变化在处理消息时如果传来的消息 generation 不等于当前的generation说明状态机发生错误这和之前看到的部分是不一样的具体什么情况会出现不一样我们后续再做了解。
void ACodec::BaseState::stateExited() {mCodec-mStateGeneration;
}从上面的代码我们可以知道每次状态切换mStateGeneration数都会加 1 。
接下来看 LoadedState 的 stateEntered
void ACodec::LoadedState::stateEntered() {ALOGV([%s] Now Loaded, mCodec-mComponentName.c_str());mCodec-mPortEOS[kPortIndexInput] mCodec-mPortEOS[kPortIndexOutput] false;mCodec-mInputEOSResult OK;mCodec-mDequeueCounter 0;mCodec-mMetadataBuffersToSubmit 0;mCodec-mRepeatFrameDelayUs -1LL;mCodec-mInputFormat.clear();mCodec-mOutputFormat.clear();mCodec-mBaseOutputFormat.clear();mCodec-mGraphicBufferSource.clear();if (mCodec-mShutdownInProgress) {bool keepComponentAllocated mCodec-mKeepComponentAllocated;mCodec-mShutdownInProgress false;mCodec-mKeepComponentAllocated false;onShutdown(keepComponentAllocated);}mCodec-mExplicitShutdown false;mCodec-processDeferredMessages();
}LoadedState::stateEntered 会对编解码过程中记录信息的成员变量进行重置后面是关于 shutdown 的处理流程这里暂时不看。
到这里我们先做一个小结MediaCodec 创建完成后ACodec 最终会进入到 LoadedState这个状态代表了内部的 OMX 组件已经创建完成UninitializedState 则表示OMX组件还未创建或者是已经销毁的状态。
3、initiateConfigureComponent
组件创建完成后就要开始配置组件了这时候状态在 LoadedState所以我们去这个状态下找对应的处理
bool ACodec::LoadedState::onConfigureComponent(const spAMessage msg) {ALOGV(onConfigureComponent);CHECK(mCodec-mOMXNode ! NULL);status_t err OK;// 检查 mime type调用 configureCodec 方法AString mime;if (!msg-findString(mime, mime)) {err BAD_VALUE;} else {err mCodec-configureCodec(mime.c_str(), msg);}if (err ! OK) {ALOGE([%s] configureCodec returning error %d,mCodec-mComponentName.c_str(), err);mCodec-signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));return false;}// 调用 CallbackmCodec-mCallback-onComponentConfigured(mCodec-mInputFormat, mCodec-mOutputFormat);return true;
}onConfigureComponent 会先去检查 mime type如果没有将会返回error如果有则会再调用 ACodec 的 configureCodec 方法做组件的配置这个方法会比较复杂我们留到下一节来讲最后会调用 callback 完成 MediaCodec 阻塞调用同时把 input format 和 output format 回传给 MediaCodec需要注意的是这里的 output format 并不一定是准确的可能是 omx 设定的默认值在decoder解出相关序列信息之后会把真正的 output format 再回传回来。