Android 13 - Media框架(19)- ACodec(一)

这一节我们将会一起了解 ACodec 的设计方式,在看具体的实现细节前我们要先了解它内部的状态转换机制,这也是ACodec的核心难点之一。

1、AHierarchicalStateMachine

ACodec 封装了OMX调用,我们在OpenMax(三)一节中了解到 OMX
有很多状态(Loaded、Idle、Executing),自然 ACodec 也会有很多状态。先来看 ACodec 的头文件:

struct ACodec : public AHierarchicalStateMachine, public CodecBase

可以看到 ACodec 除了继承于 CodecBase 外,还继承于 AHierarchicalStateMachine,翻译过来就是分层状态机,具体为什么叫分层状态机可能是因为在不同的状态(层次)下,每个函数都会对应不同的动作。

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);
};

AHierarchicalStateMachine 只有一个公有的构造函数,和几个访问权限为 protected 的方法:

  • changeState:用于切换状态;
  • handleMessage:用于处理消息;

AHierarchicalStateMachine 中还维护了一个 AState 对象,这个对象就代表着当前状态机处在什么状态下,AState 定义如下:

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);
};

这个类就是不同状态的基类了,所有的状态都需要继承自 AState,实现其 onMessageReceived 方法(注意这里不要和 AHandler 的方法混淆了)。AState 主要有三个方法:

  • stateEntered:进入某个状态需要执行的动作;
  • stateExited:退出某个状态需要执行的动作;
  • onMessageReceived:具体的状态下的事件处理方法;

前面两个方法 AState 给出了默认实现,也就是说如果不覆写,那么进入/退出状态将不不会有任何动作。

了解 AState 之后我们再来看 AHierarchicalStateMachine 给出的 changeState 和 handleMessage 的实现:

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());
}

从以上代码我们可以了解到,状态机处理消息,其实调用的就是 AState 的 onMessageReceived 方法。

再来看状态切换方法 changeState :

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();
    }
}

这里写的比较复杂,目前看来这边属于冗余设计,主要是调用最下面的 stateExitedstateEntered 方法。在我们想要切换状态时,调用状态机的 changeState 方法,传入想要切换的状态的对象,替换掉状态机内 mState 指向内容,即可完成切换。

2、ACodec

当有消息发送给 ACodec 来处理时,ACodec 调用自身的 onMessageReceived 方法,内部调用状态机的 handleMessage 方法,即可调用到不同状态下的实现了

    virtual void onMessageReceived(const sp<AMessage> &msg) {
   
        handleMessage(msg);
    }

请添加图片描述

相关推荐

  1. Android 13 - Media框架(20)- ACodec(二)

    2023-12-09 14:36:05       45 阅读
  2. Android 13 - Media框架(21)- ACodec(三)

    2023-12-09 14:36:05       56 阅读
  3. Android 13 - Media框架(22)- ACodec(四)

    2023-12-09 14:36:05       116 阅读
  4. Android 13 - Media框架(21)- ACodec(三)

    2023-12-09 14:36:05       55 阅读
  5. Android 13 - Media框架(31)- ACodec(七)

    2023-12-09 14:36:05       47 阅读
  6. Android 13 - Media框架(33)- ACodec(九)

    2023-12-09 14:36:05       85 阅读
  7. Android 13 - Media框架(22)- ACodecBufferChannel

    2023-12-09 14:36:05       46 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2023-12-09 14:36:05       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2023-12-09 14:36:05       100 阅读
  3. 在Django里面运行非项目文件

    2023-12-09 14:36:05       82 阅读
  4. Python语言-面向对象

    2023-12-09 14:36:05       91 阅读

热门阅读

  1. Webpack技术入门与实践

    2023-12-09 14:36:05       70 阅读
  2. 第一百九十六回 通过蓝牙发送数据的细节

    2023-12-09 14:36:05       60 阅读
  3. DPDK系列之三十八网卡优化

    2023-12-09 14:36:05       49 阅读
  4. 数据结构和算法专题---7、负载均衡算法与应用

    2023-12-09 14:36:05       63 阅读
  5. 什么是git pr

    2023-12-09 14:36:05       47 阅读
  6. 浅谈低代码

    2023-12-09 14:36:05       62 阅读
  7. yaml工作常用语法总结

    2023-12-09 14:36:05       49 阅读
  8. yarn和npm的区别

    2023-12-09 14:36:05       71 阅读
  9. Mac系统升级node.js版本和npm版本

    2023-12-09 14:36:05       63 阅读