ACodec状态机分析

一、引言:
ACodec作为OMX的直接对接上级,其状态机的维护比MediaCodec要复杂一些,ACodec将状态机独立出来,确保与OMX处于同步状态,这篇文章将详细介绍下ACodec的状态机是如何维护的。

二、ACodec的状态机引入:
我们先看下OMX标准头文件(OMX_CORE.h)的状态机:

typedef enum OMX_STATETYPE
{
    
    
    OMX_StateInvalid,      /**< component has detected that it's internal data
                                structures are corrupted to the point that
                                it cannot determine it's state properly */
    OMX_StateLoaded,      /**< component has been loaded but has not completed
                                initialization.  The OMX_SetParameter macro
                                and the OMX_GetParameter macro are the only
                                valid macros allowed to be sent to the
                                component in this state. */
    OMX_StateIdle,        /**< component initialization has been completed
                                successfully and the component is ready to
                                to start. */
    OMX_StateExecuting,   /**< component has accepted the start command and
                                is processing data (if data is available) */
    OMX_StatePause,       /**< component has received pause command */
    OMX_StateWaitForResources, /**< component is waiting for resources, either after
                                preemption or before it gets the resources requested.
                                See specification for complete details. */
    OMX_StateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
    OMX_StateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
    OMX_StateMax = 0X7FFFFFFF
} OMX_STATETYPE;

这几个状态机中最重要的是OMX_StateLoadedOMX_StateIdleOMX_StateExecuting,而ACodec就是根据这几个状态机来对OMX组件进行操控的。
下面看下ACodec的构造函数:

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),
      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),
      mLatency(0),
      mTunneled(false),
      mDescribeColorAspectsIndex((OMX_INDEXTYPE)0),
      mDescribeHDRStaticInfoIndex((OMX_INDEXTYPE)0),
      mStateGeneration(0),
      mVendorExtensionsStatus(kExtensionsUnchecked) {
    
    

    // Mediatek  Android Patch Begin
    sVerboseLog = (bool)property_get_int32("vendor.media.acodec.verbose.log", 0);
    // Mediatek  Android Patch End
    memset(&mLastHDRStaticInfo, 0, sizeof(mLastHDRStaticInfo));

	/* 1.实例化各个状态机 */
    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));
	/* 2.改变状态 */
    changeState(mUninitializedState);
}

1.ACodec的状态机:
ACodec一共维护了9个状态机,分别如下:

    sp<UninitializedState> mUninitializedState;
    sp<LoadedState> mLoadedState;
    sp<LoadedToIdleState> mLoadedToIdleState;
    sp<IdleToExecutingState> mIdleToExecutingState;
    sp<ExecutingState> mExecutingState;
    sp<OutputPortSettingsChangedState> mOutputPortSettingsChangedState;
    sp<ExecutingToIdleState> mExecutingToIdleState;
    sp<IdleToLoadedState> mIdleToLoadedState;
    sp<FlushingState> mFlushingState;
    sp<SkipCutBuffer> mSkipCutBuffer;

mUninitializedState为例,看一下这个类的继承关系:

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 ,类中有两个重要的成员函数onMessageReceivedstateEntered,前者用于处理独立于每个状态的msg,后者则用于处理进入此状态时所做的一些必要的事情,而private中的成员函数则是每个状态所特有的,也从正面反映了每个状态机的特色。

2.BaseState分析:

struct ACodec::BaseState : public AState {
    
    
    explicit BaseState(ACodec *codec, const sp<AState> &parentState = NULL);

protected:
    enum PortMode {
    
    
        KEEP_BUFFERS,
        RESUBMIT_BUFFERS,
        FREE_BUFFERS,
    };

    ACodec *mCodec;

    virtual PortMode getPortMode(OMX_U32 portIndex);

    virtual void stateExited();
    virtual bool onMessageReceived(const sp<AMessage> &msg);

    virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);

    virtual void onOutputBufferDrained(const sp<AMessage> &msg);
    virtual void onInputBufferFilled(const sp<AMessage> &msg);

    void postFillThisBuffer(BufferInfo *info);

private:
    // Handles an OMX message. Returns true iff message was handled.
    bool onOMXMessage(const sp<AMessage> &msg);

    // Handles a list of messages. Returns true iff messages were handled.
    bool onOMXMessageList(const sp<AMessage> &msg);

    // returns true iff this message is for this component and the component is alive
    bool checkOMXMessage(const sp<AMessage> &msg);

    bool onOMXEmptyBufferDone(IOMX::buffer_id bufferID, int fenceFd);

    bool onOMXFillBufferDone(
            IOMX::buffer_id bufferID,
            size_t rangeOffset, size_t rangeLength,
            OMX_U32 flags,
            int64_t timeUs,
            int fenceFd);

    virtual bool onOMXFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano);

    void getMoreInputDataIfPossible();

    DISALLOW_EVIL_CONSTRUCTORS(BaseState);
};

可以看到,ACodec::BaseState是对OMX组件的具体操作,其中onOutputBufferDrainedonInputBufferFilled就是对buffer的操作。也就是说,ACodec的状态机是具备对OMX进行buffer操作的。

3.changeState分析:
所有状态的改变都需要通过changeState来实现,看看这个函数的实现:

void AHierarchicalStateMachine::changeState(const sp<AState> &state) {
    
    
	/* 1.确认设置的状态是否是当前状态 */
    if (state == mState) {
    
    
        // Quick exit for the easy case.
        return;
    }
	
	/* 2.将当前状态推入容器A中 */
    Vector<sp<AState> > A;
    sp<AState> cur = mState;
    for (;;) {
    
    
        A.push(cur);
        if (cur == NULL) {
    
    
            break;
        }
        cur = cur->parentState();
    }
	/* 3.将下一个状态推入容器B中 */
    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();
    }
	/* 4.更新状态 */
    mState = state;

	/* 5.调用上一个状态的退出函数 */
    for (size_t i = 0; i < A.size(); ++i) {
    
    
        A.editItemAt(i)->stateExited();
    }

	/* 6.调用待设置状态的进入函数 */
    for (size_t i = B.size(); i > 0;) {
    
    
        i--;
        B.editItemAt(i)->stateEntered();
    }
}

三、ACodec状态机分析:
ACodec的各个状态机是紧密相连的,为了让他加不至于对下面每个状态机的讲解云里雾里,这里先贴出整个ACodec的状态机图示:
在这里插入图片描述

1.UninitializedState:
a.ACodec的构造:
在前面将ACodec构造的时候,已经看到,在实例化了9个状态之后,最后会调用changeState将当前状态设置为UninitializedState

ACodec::ACodec()...{
    
    
	...
	changeState(mUninitializedState);
}

b.在LoadedState状态时,如果此时调用onShundown时,也会置于这个状态,看一下这个状态的stateEntered实现:

void ACodec::LoadedState::onShutdown(bool keepComponentAllocated) {
    
    
	/* release()函数会调用此处 */
    if (!keepComponentAllocated) {
    
    
        (void)mCodec->mOMXNode->freeNode();

        mCodec->changeState(mCodec->mUninitializedState);
    }
	...
}

2.LoadedState:
a.当MediaCodec在配置codec时,会调用到onAllocateComponent函数,这里会去申请omx组件,申请成功后会将状态改为LoadedState

bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) {
    
    
	...
	sp<CodecObserver> observer = new CodecObserver;
    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);
    ...
    mCodec->mOMX = omx;
    mCodec->mOMXNode = omxNode;
    mCodec->mCallback->onComponentAllocated(mCodec->mComponentName.c_str());
    mCodec->changeState(mCodec->mLoadedState);

    return true;
}

b.进入LoadedToIdleState状态后,会去申请buffer,如果buffer申请失败,会回退到此状态:

void ACodec::LoadedToIdleState::stateEntered() {
    
    
    ALOGV("[%s] Now Loaded->Idle", mCodec->mComponentName.c_str());

    status_t err;
    /* 申请buffer */
    if ((err = allocateBuffers()) != OK) {
    
    
        ALOGE("Failed to allocate buffers after transitioning to IDLE state "
             "(error 0x%08x)",
             err);

        mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));

        mCodec->mOMXNode->sendCommand(
                OMX_CommandStateSet, OMX_StateLoaded);
        if (mCodec->allYourBuffersAreBelongToUs(kPortIndexInput)) {
    
    
            mCodec->freeBuffersOnPort(kPortIndexInput);
        }
        if (mCodec->allYourBuffersAreBelongToUs(kPortIndexOutput)) {
    
    
            mCodec->freeBuffersOnPort(kPortIndexOutput);
        }

        mCodec->changeState(mCodec->mLoadedState);
    }
}

c.codec的release阶段,即IdleToLoadedState收到OMX_EventCmdComplete消息时:


bool ACodec::IdleToLoadedState::onOMXEvent(
        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
    
    
    switch (event) {
    
    
        case OMX_EventCmdComplete:
        {
    
    
            if (data1 != (OMX_U32)OMX_CommandStateSet
                    || data2 != (OMX_U32)OMX_StateLoaded) {
    
    
                ALOGE("Unexpected command completion in IdleToLoadedState: %s(%u) %s(%u)",
                        asString((OMX_COMMANDTYPE)data1), data1,
                        asString((OMX_STATETYPE)data2), data2);
                mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);
                return true;
            }
			
            mCodec->changeState(mCodec->mLoadedState);

            return true;
        }

        default:
            return BaseState::onOMXEvent(event, data1, data2);
    }
}

3.LoadedToIdleState:
LoadedState状态下,调用onStart函数时会去设置OMX状态为OMX_StateIdle,如果设置状态成功,ACodec就会切换至此状态:

void ACodec::LoadedState::onStart() {
    
    
    ALOGV("onStart");

    status_t err = mCodec->mOMXNode->sendCommand(OMX_CommandStateSet, OMX_StateIdle);
    if (err != OK) {
    
    
        mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
    } else {
    
    
        mCodec->changeState(mCodec->mLoadedToIdleState);
    }
}

4.IdleToExecutingState:
LoadedToIdleState状态下,接收到OMX_EventCmdComplete消息时,表明此时OMX底层的状态是切换成功的,同时会向底层发送OMX_StateExecuting的状态设置,同时会将此时的ACodec状态变更成IdleToExecutingState

bool ACodec::LoadedToIdleState::onOMXEvent(
        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
    
    
		switch (event) {
    
    
        	case OMX_EventCmdComplete:
       	 	{
    
    
       	 		status_t err = OK;
            	if (data1 != (OMX_U32)OMX_CommandStateSet
                    || data2 != (OMX_U32)OMX_StateIdle) {
    
    
               		 ALOGE("Unexpected command completion in LoadedToIdleState: %s(%u) %s(%u)",
                        asString((OMX_COMMANDTYPE)data1), data1,
                        asString((OMX_STATETYPE)data2), data2);
                err = FAILED_TRANSACTION;
            	}

	            if (err == OK) {
    
    
	                err = mCodec->mOMXNode->sendCommand(
	                    OMX_CommandStateSet, OMX_StateExecuting);
	            }

            	if (err != OK) {
    
    
	                mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
	            } else {
    
    
	                mCodec->changeState(mCodec->mIdleToExecutingState);
	            }

            	return true;
        }
        ...
}

5.ExecutingState:
IdleToExecutingState状态下,接收到OMX_EventCmdComplete消息时,表明底层OMX此时已处于OMX_StateExecuting状态了,那么ACodec当同步改变状态为ExecutingState

bool ACodec::IdleToExecutingState::onOMXEvent(
        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
    
    
    switch (event) {
    
    
        case OMX_EventCmdComplete:
        {
    
    
            if (data1 != (OMX_U32)OMX_CommandStateSet
                    || data2 != (OMX_U32)OMX_StateExecuting) {
    
    
                ALOGE("Unexpected command completion in IdleToExecutingState: %s(%u) %s(%u)",
                        asString((OMX_COMMANDTYPE)data1), data1,
                        asString((OMX_STATETYPE)data2), data2);
                mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);
                return true;
            }

            mCodec->mExecutingState->resume();
            mCodec->changeState(mCodec->mExecutingState);

            return true;
        }

        default:
            return BaseState::onOMXEvent(event, data1, data2);
    }
}

当ACodec变更为此状态机时,表明此时与OMX在不停地进行buffer操作了。

6.OutputPortSettingsChangedState:
这是一个特殊的状态机,只会与ExecutingState进行相互切换,通常用于输入或者输出port的参数变化,需要重新配置。
ExecutingState的事件接收中,如果收到OMX_EventPortSettingsChanged事件,会将状态切换为OutputPortSettingsChangedState

bool ACodec::ExecutingState::onOMXEvent(
        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
    
    
	    switch (event) {
    
    
        	case OMX_EventPortSettingsChanged:
        	{
    
    
        		...
        		/* 给OMX组件发送OMX_CommandPortDisable指令 */ 
        		if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) {
    
    
                	mCodec->mMetadataBuffersToSubmit = 0;
                	CHECK_EQ(mCodec->mOMXNode->sendCommand(
                            OMX_CommandPortDisable, kPortIndexOutput),
                         (status_t)OK);

                	mCodec->freeOutputBuffersNotOwnedByComponent();

                	mCodec->changeState(mCodec->mOutputPortSettingsChangedState);
            	}
            	...
          	}
          	...
}

上面的代码中,可以看到,当切换到此状态时,会给OMX组件发送OMX_CommandPortDisable指令,而OMX组件执行指令完成后,会回调通知到ACodec:

bool ACodec::OutputPortSettingsChangedState::onOMXEvent(
        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
    
    
		switch (event) {
    
    
        	case OMX_EventCmdComplete:
        	{
    
    
				if (data1 == (OMX_U32)OMX_CommandPortDisable) {
    
    
                if (data2 != (OMX_U32)kPortIndexOutput) {
    
    
                    ALOGW("ignoring EventCmdComplete CommandPortDisable for port %u", data2);
                    return false;
                }

                ALOGV("[%s] Output port now disabled.", mCodec->mComponentName.c_str());

                status_t err = OK;
                if (!mCodec->mBuffers[kPortIndexOutput].isEmpty()) {
    
    
                    ALOGE("disabled port should be empty, but has %zu buffers",
                            mCodec->mBuffers[kPortIndexOutput].size());
                    err = FAILED_TRANSACTION;
                } else {
    
    
                    mCodec->mAllocator[kPortIndexOutput].clear();
                }
				/* OMX组件执行指令完成后将继续发送OMX_CommandPortEnable指令 */
                if (err == OK) {
    
    
                    err = mCodec->mOMXNode->sendCommand(
                            OMX_CommandPortEnable, kPortIndexOutput);
                }

                if (err == OK) {
    
    
                    err = mCodec->allocateBuffersOnPort(kPortIndexOutput);
                    ALOGE_IF(err != OK, "Failed to allocate output port buffers after port "
                            "reconfiguration: (%d)", err);
                    mCodec->mCallback->onOutputBuffersChanged();
                }

                if (err != OK) {
    
    
                    mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
                    ALOGE("Error occurred while disabling the output port");
                }

                return true;
               } else if (data1 == (OMX_U32)OMX_CommandPortEnable) {
    
    
                if (data2 != (OMX_U32)kPortIndexOutput) {
    
    
                    ALOGW("ignoring EventCmdComplete OMX_CommandPortEnable for port %u", data2);
                    return false;
                }

                ALOGV("[%s] Output port now reenabled.", mCodec->mComponentName.c_str());

                if (mCodec->mExecutingState->active()) {
    
    
                    mCodec->mExecutingState->submitOutputBuffers();
                }
				/* 再次失能端口成功将切换至ExecutingState */
                mCodec->changeState(mCodec->mExecutingState);

                return true;
            }

            return false;
        }
        default:
        return BaseState::onOMXEvent(event, data1, data2);
    }
}

可以看到这个状态切换是ACodec自己主动完成的,通过向OMX发送指令-等待回调,在所有的操作都完成后,最终会切换回ExecutingState

7.ExecutingToIdleState:
当应用决定不再需要解码器进行编解码时,此时会调用ACodec的initiateShutdown函数:

void ACodec::initiateShutdown(bool keepComponentAllocated) {
    
    
	/* 发送kWhatShutdown消息 */
    sp<AMessage> msg = new AMessage(kWhatShutdown, this);
    msg->setInt32("keepComponentAllocated", keepComponentAllocated);
    msg->post();
    if (!keepComponentAllocated) {
    
    
        // ensure shutdown completes in 3 seconds
        (new AMessage(kWhatReleaseCodecInstance, this))->post(3000000);
    }
}

ExecutingStateonMessageReceived会接收到此消息:

bool ACodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) {
    
    
    bool handled = false;
    switch (msg->what()) {
    
    
        case kWhatShutdown:
        {
    
    
            int32_t keepComponentAllocated;
            CHECK(msg->findInt32(
                        "keepComponentAllocated", &keepComponentAllocated));

            mCodec->mShutdownInProgress = true;
            mCodec->mExplicitShutdown = true;
            mCodec->mKeepComponentAllocated = keepComponentAllocated;

            mActive = false;
			/* 向OMX发送OMX_StateIdle状态的设置CMD */
            status_t err = mCodec->mOMXNode->sendCommand(
                    OMX_CommandStateSet, OMX_StateIdle);
            if (err != OK) {
    
    
                if (keepComponentAllocated) {
    
    
                    mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);
                }
                // TODO: do some recovery here.
            } else {
    
    
            	/* 设置成功将切换状态 */
                mCodec->changeState(mCodec->mExecutingToIdleState);
            }

            handled = true;
            break;
        }
        ...
}

可以看到,ExecutingState会向底层发送OMX_StateIdle的状态设置,同时会将ACodec的状态切换为ExecutingToIdleState

8.IdleToLoadedState:
OMX_StateIdle状态设置成功会,会回调通知给ExecutingToIdleStateonOMXEvent

bool ACodec::ExecutingToIdleState::onOMXEvent(
        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
    
    
    switch (event) {
    
    
        case OMX_EventCmdComplete:
        {
    
    
            if (data1 != (OMX_U32)OMX_CommandStateSet
                    || data2 != (OMX_U32)OMX_StateIdle) {
    
    
                ALOGE("Unexpected command completion in ExecutingToIdleState: %s(%u) %s(%u)",
                        asString((OMX_COMMANDTYPE)data1), data1,
                        asString((OMX_STATETYPE)data2), data2);
                mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);
                return true;
            }

            mComponentNowIdle = true;
			/* 注意这个函数 */
            changeStateIfWeOwnAllBuffers();

            return true;
        }
        ...
    }
	...
}

跟进看一下changeStateIfWeOwnAllBuffers

void ACodec::ExecutingToIdleState::changeStateIfWeOwnAllBuffers() {
    
    
    if (mComponentNowIdle && mCodec->allYourBuffersAreBelongToUs()) {
    
    
    	/* 向OMX发送OMX_StateLoaded指令 */
        status_t err = mCodec->mOMXNode->sendCommand(
                OMX_CommandStateSet, OMX_StateLoaded);
        if (err == OK) {
    
    
            err = mCodec->freeBuffersOnPort(kPortIndexInput);
            status_t err2 = mCodec->freeBuffersOnPort(kPortIndexOutput);
            if (err == OK) {
    
    
                err = err2;
            }
        }
		...
	}
	...
	/* 状态切换 */
	mCodec->changeState(mCodec->mIdleToLoadedState);
}

当底层OMX状态切换成功后,ACodec又将通过回调切换至`LoadedState状态。

9.FlushingState:
这个状态也只能同ExecutingState相互切换。
ExecutingState接收到kWhatFlush消息时,会进行状态的切换:

        case kWhatFlush:
        {
    
    
            ALOGV("[%s] ExecutingState flushing now "
                 "(codec owns %zu/%zu input, %zu/%zu output).",
                    mCodec->mComponentName.c_str(),
                    mCodec->countBuffersOwnedByComponent(kPortIndexInput),
                    mCodec->mBuffers[kPortIndexInput].size(),
                    mCodec->countBuffersOwnedByComponent(kPortIndexOutput),
                    mCodec->mBuffers[kPortIndexOutput].size());

            mActive = false;
			/* 向OMX底层发送OMX_CommandFlush指令 */
            status_t err = mCodec->mOMXNode->sendCommand(OMX_CommandFlush, OMX_ALL);
            if (err != OK) {
    
    
                mCodec->signalError(OMX_ErrorUndefined, FAILED_TRANSACTION);
            } else {
    
    
            	/* 同时切换状态 */
                mCodec->changeState(mCodec->mFlushingState);
            }

            handled = true;
            break;
        }

当OMX底层完成了OMX_CommandFlush后,会回调通知至ACodec:

bool ACodec::FlushingState::onOMXEvent(
        OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
    
    
	...
	case OMX_EventCmdComplete:
	{
    
    
		...
		changeStateIfWeOwnAllBuffers();
		...
	}
	...
}

跟进到changeStateIfWeOwnAllBuffers(),最终会回到ExecutingState:

void ACodec::FlushingState::changeStateIfWeOwnAllBuffers() {
    
    
	...
	mCodec->changeState(mCodec->mExecutingState);
	...
}

四、总结:
掌握ACodec的状态机,需要从以下几个方面入手:
1.关注ACodec的各个状态机的紧密联系,可以参考上面的总览图;
2.关注每个状态的stateEntered()stateExited()实现;
3.关注ACodec是如何通过OMX的标准接口向OMX组件进行状态设置,OMX是如何通过回调通知至ACodec;

猜你喜欢

转载自blog.csdn.net/achina2011jy/article/details/124595650