关注公众号免费阅读全文,进入音视频开发技术分享群!

这一节我们将会一起了解 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);
}

ACodec 中有如下状态,均以内部类的方式实现:

    struct BaseState;
struct UninitializedState;
struct LoadedState;
struct LoadedToIdleState;
struct IdleToExecutingState;
struct ExecutingState;
struct OutputPortSettingsChangedState;
struct ExecutingToIdleState;
struct IdleToLoadedState;
struct FlushingState;
struct DeathNotifier;

BaseState 是其他状态的基类,其继承于 AState,因此我们大概可以猜到,ACodec 切换状态时调用 changeState 时,传入的参数就是这些状态类对象,最后 ACodec 的消息也由这些状态类来最终执行。

BaseState 持有一个 ACodec 对象指针,使得它与相关的派生类状态可以操作 ACodec;BaseState 还定义有一些 protected 方法,这些方法是一些默认实现可供子类使用,如果需要自定义子类也可以覆写这些方法;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); void maybePostExtraOutputMetadataBufferRequest() {
if (!mPendingExtraOutputMetadataBufferRequest) {
(new AMessage(kWhatSubmitExtraOutputMetadataBuffer, mCodec))->post();
mPendingExtraOutputMetadataBufferRequest = true;
}
} 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(); bool mPendingExtraOutputMetadataBufferRequest; DISALLOW_EVIL_CONSTRUCTORS(BaseState);
};

Android 13 - Media框架(19)- ACodec(一)的更多相关文章

  1. 简析Android 兼容性测试框架CTS使用

    一.什么是兼容性测试? 1)为用户提供最好的用户体验,让更多高质量的APP可以顺利的运行在此平台上 2)让程序员能为此平台写更多的高质量的应用程序 3)可以更好的利用Android应用市场 二.CTS ...

  2. 15类Android通用流行框架

    15类Android通用流行框架 Android流行框架 缓存 DiskLruCache Java实现基于LRU的磁盘缓存 图片加载 Android Universal Image Loader 一个 ...

  3. android开源项目框架大全:

    android开源项目框架大全: 1.多页切换TabHost9 高仿网易云音乐客户端的Home页面切换Tabhost 高仿网易云音乐客户端的Home页面切换Tabhost,并且三角形是透明的,实现方式 ...

  4. 各种Android UI开源框架 开源库

    各种Android UI开源框架 开源库 转 https://blog.csdn.net/zhangdi_gdk2016/article/details/84643668 自己总结的Android开源 ...

  5. 25类Android常用开源框架

    1.图片加载,缓存,处理 框架名称 功能描述 Android Universal Image Loader 一个强大的加载,缓存,展示图片的库,已过时 Picasso 一个强大的图片下载与缓存的库 F ...

  6. [Android]Android端ORM框架——RapidORM(v2.0)

    以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5626716.html [Android]Android端ORM ...

  7. 15 个 Android 通用流行框架大全(转)

    1. 缓存 DiskLruCache    Java实现基于LRU的磁盘缓存 2.图片加载 Android Universal Image Loader 一个强大的加载,缓存,展示图片的库 Picas ...

  8. Android 通用流行框架

    原文出处: http://android.jobbole.com/83028/ 1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Andro ...

  9. 经受时间沉淀的15 个 Android 通用流行框架大全

    1. 缓存 名称描述 DiskLruCache: Java实现基于LRU的磁盘缓存 2.图片加载 名称描述 Android    Universal Image Loader 一个强大的加载,缓存,展 ...

  10. Android通用流行框架大全

    1. 缓存 名称 描述 DiskLruCache Java实现基于LRU的磁盘缓存 2.图片加载 名称 描述 Android Universal Image Loader 一个强大的加载,缓存,展示图 ...

随机推荐

  1. 树模型-C4.5

    C4.5: ID3的改进版本 首先,C4.5和ID3一样都是多叉树,重点是连续特征处理+特征选择的方式不同. ID3算法存在的不足, 在C4.5里面有了改进 有那些改进 不能处理连续特征的问题 C4. ...

  2. .NET 9 预览版 3 发布

    我们很高兴地宣布发布 .NET 9 预览版 3,其中包含 .NET 库.运行时和 SDK 的新功能和改进.此预览版带来了旨在提高性能.提高开发人员工作效率以及向 .NET 生态系统引入新功能的增强功能 ...

  3. 【7】SpringBoot是什么?SpringBoot的优缺点有哪些?

    随着动态语言的流行(Ruby.Groovy.Scala.Node.js),Java 的开发显得格外的笨重,繁多的配置.低下的开发效率.复杂的部署流程以及第三方技术集成难度大. 在上述环境下,Sprin ...

  4. mysql 必知必会整理—表[十一]

    前言 简单整理一下表和视图. 正文 MySQL不仅用于表数据操纵,而且还可以用来执行数据库和表的所有操作,包括表本身的创建和处理. 一般有两种创建表的方法: 使用具有交互式创建和管理表的工具 表也可以 ...

  5. sql 语句系列(月份的第一天和最后一天)[八百章之第二十章]

    前言 插播一个,从给定日期值里面提取年月日时分秒. 之所以写这个是因为使用频率太高. mysql: select DATE_FORMAT(CURRENT_TIMESTAMP,'%k') hr, DAT ...

  6. 重新整理数据结构与算法(c#)—— 平衡二叉树[二十三]

    前言 因为有些树是这样子的: 这样子的树有个坏处就是查询效率低,因为左边只有一层,而右边有3层,这就说明如果查找一个数字大于根元素的数字,那么查询判断就更多. 解决方法就是降低两边的层数差距: 变成这 ...

  7. Python中2种常用数据可视化库:Bokeh和Altair

    本文分享自华为云社区<探究数据可视化:Bokeh vs. Altair>,作者:柠檬味拥抱. 在数据科学和数据分析领域,数据可视化是一种强大的工具,可以帮助我们更好地理解数据.发现模式和趋 ...

  8. 简单的UrlDns链分析

    URLDNS链学习 首先我们先理解一下序列化与反序列化,我先贴出三段代码,大家可以尝试先体验一下. 首先我们先构造一个Person类,其实跟这条链没什么关系,主要涉及序列化 点击查看代码 // 引入 ...

  9. Hadoop HDFS 3.2的部署

    之前写过HDFS 2.6的部署,最近项目中尝试使用最新的HDFS 3.2.1做离线存储,部署方式略有不同,所以这里再简单写一下,这里只涉及到存储因此不再配置yarn,只配置HDFS最基本的服务Name ...

  10. 代理网关设计与实现(基于NETTY)

    ​简介:本文重点在代理网关本身的设计与实现,而非代理资源的管理与维护. ​ 作者 | 新然 来源 | 阿里技术公众号 一 问题背景 平台端购置一批裸代理,来做广告异地展现审核.从外部购置的代理,使用方 ...