承接上一章节分析:Android MediaPlayer整体架构源码分析 -【MediaCodec编解码器插件模块化注册和创建处理流程】【Part 1】 本系列文章分析的安卓源码版本:【Android 10.0 版本】
推荐涉及到的知识点:
Binder机制实现原理:Android C++底层Binder通信机制原理分析总结【通俗易懂】 ALooper机制实现原理:Android native层媒体通信架构AHandler/ALooper机制实现源码分析 Binder异常关闭监听:Android native层DeathRecipient对关联进程(如相关Service服务进程)异常关闭通知事件的监听实现源码分析
【本章节小节序号将重新开始】
MediaCodec类声明和构造函数,见第1小节分析
codec->init(componentName, true) 实现分析,见第2小节分析
1、new MediaCodec(looper, pid, uid)实现分析:
创建MediaCodec对象。
MediaCodec类声明【省略其他代码】
可以看到它实现了AHandler消息循环机制。
// [frameworks/av/media/libstagefright/include/media/stagefright/MediaCodec.h]
struct MediaCodec : public AHandler {}
MediaCodec类构造函数实现
主要就是初始化默认值处理。
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
MediaCodec::MediaCodec(const sp<ALooper> &looper, pid_t pid, uid_t uid)
// 未初始化状态
: mState(UNINITIALIZED),
// 是否执行了stopped/released处理流程
mReleasedByResourceManager(false),
mLooper(looper),
// CodecBase基类对象,后续会在init中创建,注意它主要有两个实现者即ACodec和CCodec类,MediaFilter目前不分析
mCodec(NULL),
// 响应消息应答ID对象,实际就是ALooper分析章节中的AReplyToken应答对象
mReplyID(0),
// 事件bit位标记,可表示多种不同事件
mFlags(0),
// 目前该值弃用状态,始终都是OK
mStickyError(OK),
// 软渲染器,也就是视频播放时当mFlags设置了kFlagUsesSoftwareRenderer标志位时才会加载使用这种方式渲染
mSoftRenderer(NULL),
// 媒体统计项数据(KV键值对值),主要可以用来debug数据等
mAnalyticsItem(NULL),
// 是否为视频
mIsVideo(false),
// 视频宽高值
mVideoWidth(0),
mVideoHeight(0),
// 视频帧旋转角度
mRotationDegrees(0),
// 出队列输入事件超时代数值【关于代数值作用(多媒体框架层分析过)基本都是类似的,
// 即将会在处理该事件前判断是否应该继续处理】
mDequeueInputTimeoutGeneration(0),
// 出队列输入事件消息应答AReplyToken对象
mDequeueInputReplyID(0),
// 出队列输出事件操作代数值
mDequeueOutputTimeoutGeneration(0),
// 出队列输出事件消息应答AReplyToken对象
mDequeueOutputReplyID(0),
// 是否有输入Surface,默认false
mHaveInputSurface(false),
// 是否有将要执行的输入buffer,默认false
mHavePendingInputBuffers(false),
// 是否有CPU提高请求
mCpuBoostRequested(false),
// 未知延迟计数值,实际上就是解码数据匹配不上或无效等将会递增该值
mLatencyUnknown(0) {
// kNoUid为-1
// 初始化调用进程用户ID
if (uid == kNoUid) {
mUid = IPCThreadState::self()->getCallingUid();
} else {
mUid = uid;
}
// 系统资源管理客户端实现,实际是个Bn实现端,实际作用就是管理当前MediaCodec编解码器资源是否应该被回收,
// 这个跟系统资源策略有关。
// 见1.1小节分析
mResourceManagerClient = new ResourceManagerClient(this);
// 系统资源管理服务代理实现
// 见1.2小节分析
mResourceManagerService = new ResourceManagerServiceProxy(pid, mUid);
// 初始化媒体统计数据项(KV键值对值),主要可以用来debug数据等(关于这种数据的分析此前很多章节中已分析过)
// 见1.3小节分析
initAnalyticsItem();
}
1.1、ResourceManagerClient类声明和构造函数:
系统资源管理客户端实现,实际是个Bn实现端,实际作用就是管理当前MediaCodec编解码器资源是否应该被回收,这个跟系统资源策略有关。
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
struct ResourceManagerClient : public BnResourceManagerClient {
// 构造方法体内空实现
explicit ResourceManagerClient(MediaCodec* codec) : mMediaCodec(codec) {}
1.2、ResourceManagerServiceProxy类声明和构造函数:
系统资源管理服务代理实现
ResourceManagerServiceProxy类声明:【省略其他代码】
是MediaCodec类的内部类,根据父类继承DeathRecipient类,可知其实现了监听对端Binder死亡通知功能。
// [frameworks/av/media/libstagefright/include/media/stagefright/MediaCodec.h]
struct ResourceManagerServiceProxy : public IBinder::DeathRecipient {}
ResourceManagerServiceProxy类构造函数:
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(
pid_t pid, uid_t uid)
: mPid(pid), mUid(uid) {
if (mPid == MediaCodec::kNoPid) {
mPid = IPCThreadState::self()->getCallingPid();
}
}
1.3、initAnalyticsItem()实现分析:
初始化媒体统计数据项(KV键值对值),主要可以用来debug数据等(关于这种数据的分析此前很多章节中已分析过)
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
void MediaCodec::initAnalyticsItem() {
// 统计数据项对象未初始化则创建它
// key为kCodecKeyName:"codec"
// 备注:关于它的创建和使用,此处不详细分析了,简单的理解就是相当于一个map,缓存KV值
if (mAnalyticsItem == NULL) {
mAnalyticsItem = MediaAnalyticsItem::create(kCodecKeyName);
}
// mLatencyHist 表示延迟统计(数据)直方图(柱状图)
// setup是初始化该柱状图相关的默认值,也就是设置柱状图的默认形状,
// 如柱(桶)的个数,及其宽度和(桶)柱状下限值。
// 这三个值依次为:20,2000,2000。
// mLatencyHist对应实现类声明和构造函数实现,见1.3.1小节分析
// setup实现,见1.3.2小节分析
mLatencyHist.setup(kLatencyHistBuckets, kLatencyHistWidth, kLatencyHistFloor);
// 加锁代码块
{
Mutex::Autolock al(mRecentLock);
// 最近延迟统计柱状图中的帧数
// kRecentLatencyFrames:默认300帧高度并且都赋值为无效帧状态,300 frames = 5 sec @ 60fps or ~12 sec @ 24fps
for (int i = 0; i<kRecentLatencyFrames; i++) {
mRecentSamples[i] = kRecentSampleInvalid;
}
mRecentHead = 0;
}
}
1.3.1、mLatencyHist对应实现类即Histogram类声明和构造函数实现
是MediaCodec类的内部类,看声明可知,构造参数是默认空实现,并初始化各个柱状图相关参数。
// [frameworks/av/media/libstagefright/include/media/stagefright/MediaCodec.h]
class Histogram {
public:
Histogram() : mFloor(0), mWidth(0), mBelow(0), mAbove(0),
mMin(INT64_MAX), mMax(INT64_MIN), mSum(0), mCount(0),
mBucketCount(0), mBuckets(NULL) {};
~Histogram() { clear(); };
void clear() { if (mBuckets != NULL) free(mBuckets); mBuckets = NULL; };
bool setup(int nbuckets, int64_t width, int64_t floor = 0);
void insert(int64_t sample);
int64_t getMin() const { return mMin; }
int64_t getMax() const { return mMax; }
int64_t getCount() const { return mCount; }
int64_t getSum() const { return mSum; }
int64_t getAvg() const { return mSum / (mCount == 0 ? 1 : mCount); }
std::string emit();
private:
int64_t mFloor, mCeiling, mWidth;
int64_t mBelow, mAbove;
int64_t mMin, mMax, mSum, mCount;
int mBucketCount;
int64_t *mBuckets;
};
Histogram mLatencyHist;
1.3.2、mLatencyHist.setup() 实现分析:
是初始化该柱状图相关的默认值,也就是设置柱状图的默认形状,如柱(桶)的个数,及其宽度和(桶)柱状下限值
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
bool MediaCodec::Histogram::setup(int nbuckets, int64_t width, int64_t floor)
{
if (nbuckets <= 0 || width <= 0) {
return false;
}
// get histogram buckets
if (nbuckets == mBucketCount && mBuckets != NULL) {
// 若是和此前同个数相同时,则直接使用已存在的buffer内存
// reuse our existing buffer
memset(mBuckets, 0, sizeof(*mBuckets) * mBucketCount);
} else {
// 不相等时,获取一个新的预置零缓冲区
// get a new pre-zeroed buffer
int64_t *newbuckets = (int64_t *)calloc(nbuckets, sizeof (*mBuckets));
if (newbuckets == NULL) {
goto bad;
}
// 释放旧内存,缓存新buffer
if (mBuckets != NULL)
free(mBuckets);
mBuckets = newbuckets;
}
mWidth = width;
mFloor = floor;
// (桶)柱状上限值
mCeiling = floor + nbuckets * width;
// 柱状个数
mBucketCount = nbuckets;
// 最小最大初始化这些值。
mMin = INT64_MAX;
mMax = INT64_MIN;
mSum = 0;
mCount = 0;
mBelow = mAbove = 0;
return true;
bad:
if (mBuckets != NULL) {
free(mBuckets);
mBuckets = NULL;
}
return false;
}
2、codec->init(componentName, true) 实现分析:
执行编解码器MediaCodec的初始化方法,检查是否初始化成功。参数nameIsType在方法声明时默认值为false。
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
status_t MediaCodec::init(const AString &name, bool nameIsType) {
// 资源管理器服务初始化
// 见2.1小节分析
mResourceManagerService->init();
// 缓存初始化参数即具体插件编解码器组件名
// save init parameters for reset
mInitName = name;
// 此处英文注释大致意思就是:
// 当前视频解码器插件没有从OMX_FillThisBuffer处快速返回,而这违背了OMX实现标准,
// 因此为了弥补该问题,我们需要新增一个额外的ALooper来释放主事件队列。
// Current video decoders do not return from OMX_FillThisBuffer
// quickly, violating the OpenMAX specs, until that is remedied
// we need to invest in an extra looper to free the main event
// queue.
// 此为前面流程中分析的MediaCodecInfo媒体编解码器信息对象,此处先清除释放此前缓存的对象。
// 该方法为sp智能指针方法,清除内部实际对象指针。
mCodecInfo.clear();
// 判断是否是安全编解码器
// 备注:所有的安全编辑解码器都是组件名以".secure"结尾的。
bool secureCodec = false;
AString tmp = name;
if (tmp.endsWith(".secure")) {
secureCodec = true;
// 然后去掉这个字符串
tmp.erase(tmp.size() - 7, 7);
}
// 此处英文注释大致意思就是:
// 确保若组件名包含qcom或qti的字符串时,当这些组件在media_codecs.xml音视频配置文件中不存在
// 并且MediaCodecList也不能通过findCodecByName查找到这些组件情况下,在这种情况我们不能返回错误。
//make sure if the component name contains qcom/qti, we don't return error
//as these components are not present in media_codecs.xml and MediaCodecList won't find
//these component by findCodecByName
//Video and Flac decoder are present in list so exclude them.
if ((!(name.find("qcom", 0) > 0 || name.find("qti", 0) > 0 || name.find("filter", 0) > 0)
|| name.find("video", 0) > 0 || name.find("flac", 0) > 0 || name.find("c2.qti", 0) >= 0)
&& !(name.find("tme",0) > 0)) {
// 此处的进入条件是:当组件名不包含qcom/qti/filter这三个字符串,或者组件名包含video/flac/"c2.qti"这三个中任意一个字符串时,
// 此处再判断组件名不能包含"tme"字符串,若满足以上条件则进入执行。
// 举例:OMX.qcom.video.decoder.avc 该组件名时满足条件
// 获取MediaCodecList编解码器列表处理对象单列,见前面流程中分析
const sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
if (mcl == NULL) {
mCodec = NULL; // remove the codec.
return NO_INIT; // if called from Java should raise IOException
}
// 然后将name和tmp两个值for循环处理
for (const AString &codecName : { name, tmp }) {
// 指定(插件编解码器)组件名查询系统中可用组件列表的索引,见前面流程中分析
ssize_t codecIdx = mcl->findCodecByName(codecName.c_str());
if (codecIdx < 0) {
// 小于0-未找到,继续下一个
continue;
}
// 获取该索引对应的(编解码器插件)媒体编解码器信息对象实例并缓存,见前面流程中分析
mCodecInfo = mcl->getCodecInfo(codecIdx);
Vector<AString> mediaTypes;
// 获取该编解码器支持的媒体类型(即mime格式)列表信息,见前面流程中分析
// 也就是说一个编/解码器可能支持多种媒体类型编码或解码
mCodecInfo->getSupportedMediaTypes(&mediaTypes);
// 循环判断是否有video媒体格式,若有则表明当前(编码器或解码器)组件为视频处理组件
for (size_t i = 0; i < mediaTypes.size(); i++) {
if (mediaTypes[i].startsWith("video/")) {
mIsVideo = true;
break;
}
}
break;
}
// 获取编解码器组件失败,返回对应错误码
if (mCodecInfo == nullptr) {
ALOGE("component not found");
return NAME_NOT_FOUND;
}
}
// owner默认值
const char *owner = "default";
// 获取编解码器归属者名(会修改掉默认值),见前面流程相关分析
if (mCodecInfo !=NULL)
owner = mCodecInfo->getOwnerName();
// 创建获取下一层(Base)编解码器
// 见2.2小节分析
mCodec = GetCodecBase(name, owner);
if (mCodec == NULL) {
return NAME_NOT_FOUND;
}
if (mIsVideo) {
// 视频编/解码器组件时
// 正如上面英文注释的原因,在视频Codec时需创建专用ALooper来进行消息事件传递处理
// video codec needs dedicated looper
if (mCodecLooper == NULL) {
mCodecLooper = new ALooper;
mCodecLooper->setName("CodecLooper");
mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
}
// mCodecLooper消息循环线程的接收消息事件处理者为mCodec对象实现
mCodecLooper->registerHandler(mCodec);
} else {
// 若是音频编/解码器则不需要新创建ALooper,直接使用mLooper来注册消息循环处理者mCodec对象即可,
// mLooper即第一章开头的create创建MediaCodec方法createByType传入MediaCodec构造函数的looper参数。
mLooper->registerHandler(mCodec);
}
// 再次注册当前MediaCodec对象
mLooper->registerHandler(this);
// 注意:由上可知,若为音频编/解码器时mLooper消息循环线程的消息事件将会有两个AHandler实现
// 【即MediaCodec和mCodec对象】来接受它们自身发送对应的消息事件,
// 也就是说这两个AHandler接受到的消息处理的线程都是同一个线程中同步完成的。
// (向ACodec等)设置监听回调消息事件。传入创建的匿名CodecCallback对象指针,并创建接收消息【kWhatCodecNotify】的通知事件
// 见2.3小节分析
mCodec->setCallback(
std::unique_ptr<CodecBase::CodecCallback>(
new CodecCallback(new AMessage(kWhatCodecNotify, this))));
// 获取buffer通道对象
// 见2.4小节分析
mBufferChannel = mCodec->getBufferChannel();
// 向该buffer通道对象设置回调监听类,并接收【kWhatCodecNotify】事件消息的通知处理
// 见2.5小节分析
mBufferChannel->setCallback(
std::unique_ptr<CodecBase::BufferCallback>(
new BufferCallback(new AMessage(kWhatCodecNotify, this))));
// 创建 【kWhatInit】 事件消息
sp<AMessage> msg = new AMessage(kWhatInit, this);
// 编解码器信息对象
msg->setObject("codecInfo", mCodecInfo);
// name may be different from mCodecInfo->getCodecName() if we stripped
// ".secure"
// 编解码器组件名
msg->setString("name", name);
// 该值在两个MediaCodec的create方法中值不同
msg->setInt32("nameIsType", nameIsType);
// 构造函数中创建媒体统计数据项(KV值)对象
// 备注:其实该对象主要是给java层MediaCodec.java类来使用获取这些信息的。
if (mAnalyticsItem != NULL) {
// 缓存这些值
mAnalyticsItem->setCString(kCodecCodec, name.c_str());
mAnalyticsItem->setCString(kCodecMode, mIsVideo ? kCodecModeVideo : kCodecModeAudio);
}
if (mIsVideo) {
// 视频时
// 此处是检查监听电池状态的消息事件kWhatCheckBatteryStats接收处理
// 见2.6小节分析
mBatteryChecker = new BatteryChecker(new AMessage(kWhatCheckBatteryStats, this));
}
status_t err;
// 媒体资源类型信息对象集合,也就是记录当前组件的两个类型信息:编解码类型及子类型
Vector<MediaResource> resources;
// 是否为安全编解码器,一般情况下为false即非安全编解码器
MediaResource::Type type =
secureCodec ? MediaResource::kSecureCodec : MediaResource::kNonSecureCodec;
// 子类型即当前组件为视频还是音频编解码器
MediaResource::SubType subtype =
mIsVideo ? MediaResource::kVideoCodec : MediaResource::kAudioCodec;
// MediaResource类的第三个参数为value,此次传入1,该值应该是表示当前需要创建这种类型资源的个数吧,
// 该类实现比较简单就是存储这三个值,因此不再分析。
// 放入列表中
resources.push_back(MediaResource(type, subtype, 1));
// kMaxRetry:值为2,即最大尝试处理次数。从下面for循环判断可知,该循环可执行总次数为3次。
// 循环处理:尝试从资源管理服务那里检查是否应该能够创建该媒体资源类型
for (int i = 0; i <= kMaxRetry; ++i) {
if (i > 0) {
// 非第一次循环时进入
// 注释:第一次不要尝试回收资源。
// 警告:也就是说,第一次若上面的 kWhatInit 事件消息处理失败后,第二次循环开始将会执行该资源回收处理。
// Don't try to reclaim resource for the first time.
// 回收资源处理,回收成功返回true,否则失败为false。
// 警告:其实通过2.7的分析概述,我们应该正确理解该功能实现原理,它不是说的回收当前正在请求的请求端资源,
// 而是说,当前该类型媒体资源已经不够用了,那么需要回收的是系统中其他client正在使用的该类型资源。
// 见2.7小节分析
if (!mResourceManagerService->reclaimResource(resources)) {
// 若回收资源失败,则将不会继续创建编解码器,也就预示着本次音视频功能失败。
break;
}
}
sp<AMessage> response;
// 立即发送AMessage消息事件并等待应答信息,该消息为【kWhatInit】 事件消息
// 见2.8小节分析
err = PostAndAwaitResponse(msg, &response);
// 检查资源错误类型,即判断错误码是否为无内存错误,
// 若为true则继续尝试创建,若是其它错误则直接结束创建
// 见2.9小节分析
if (!isResourceError(err)) {
break;
}
}
// 返回执行结果错误码
return err;
}
2.1、mResourceManagerService->init()实现分析:
资源管理器服务初始化
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
void MediaCodec::ResourceManagerServiceProxy::init() {
// Binder机制实现,从服务注册管理中心获取已注册名为"media.resource_manager"的Binder服务对象,
// 并将其使用interface_cast转换为Bp代理端BpResourceManagerService对象,
// 那么根据Binder实现机制,其Bn实现端即为BnResourceManagerService的子类ResourceManagerService类【在ResourceManagerService.cpp】中
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.resource_manager"));
mService = interface_cast<IResourceManagerService>(binder);
if (mService == NULL) {
ALOGE("Failed to get ResourceManagerService");
return;
}
// 此处让ResourceManagerServiceProxy实现监听该Binder服务的死亡通知事件。
IInterface::asBinder(mService)->linkToDeath(this);
}
2.2、GetCodecBase(name, owner)实现分析:
创建获取下一层(Base)编解码器,参数为组件名和组件owner归属名,由该系列内容第5部分章节分析可知,该值一般情况下为 “codec2::software"或默认为"default”,也可能为null。因此在下面的处理中,一般情况下将会执行CreateCCodec()或AVFactory::get()->createACodec()来创建。注意CodecBase编解码器基类主要有两个实现者即ACodec和CCodec类,MediaFilter暂不分析,因此它将会创建这两种不同实现对象实例来完成不同编解码器的功能。它们的主要区别,如下简单的分析
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
//static
sp<CodecBase> MediaCodec::GetCodecBase(const AString &name, const char *owner) {
if (owner) {
// 此部分以编解码器归属者信息来创建
if (strcmp(owner, "default") == 0) {
return AVFactory::get()->createACodec();
} else if (strncmp(owner, "codec2", 6) == 0) {
// 若是软编解码器实现将会走此处
return CreateCCodec();
}
}
// 此部分以编解码器组件名前缀匹配来创建,字符串前缀匹配不区分大小写
if (name.startsWithIgnoreCase("c2.")) {
// 一般也会执行此处
return CreateCCodec();
} else if (name.startsWithIgnoreCase("omx.")) {
// 比较常见的是这种方式。
// at this time only ACodec specifies a mime type.
return AVFactory::get()->createACodec();
} else if (name.startsWithIgnoreCase("android.filter.qti")) {
return AVFactory::get()->createMediaFilter();
} else if (name.startsWithIgnoreCase("android.filter")) {
return new MediaFilter;
} else {
return NULL;
}
}
基于上面的分析,其实这两种实现的主要功能大致一致的,因此目前暂时只分析ACodec的创建(后续有时间再详细分析CCodec实现吧 TODO),即AVFactory::get()->createACodec()实现,而关于AVFactory的实现原理,此系列文章的早前章节中已分析过了,它是通过私有库so库【libavenhancements.so】来加载的,可以让vendor厂商自定义实现,另外它也有默认实现在AVFactory.cpp中,即若so库未提供则加载默认实现,不过该私有库的该方法默认应该也是直接返回ACodec的对象的,正如AVFactory.cpp的实现:
// [frameworks/av/media/libextensions/stagefright/AVFactory.cpp]
sp<ACodec> AVFactory::createACodec() {
return new ACodec;
}
ACodec类声明和构造函数实现
ACodec类声明【省略其他代码】
其实通过其父类AHierarchicalStateMachine名就大致可知晓,ACodec其实是实现了(层级)状态机实现机制的功能。
关于状态机实现机制可自行先了解下它的实现原理,此处不再阐述。
// [frameworks/av/media/libstagefright/include/media/stagefright/ACodec.h]
struct ACodec : public AHierarchicalStateMachine, public CodecBase {}
// [frameworks/av/media/libstagefright/include/media/stagefright/AHierarchicalStateMachine.h]
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);
};
// [frameworks/av/media/libstagefright/include/media/stagefright/AHierarchicalStateMachine.h]
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);
};
// [frameworks/av/media/libstagefright/include/media/stagefright/CodecBase.h]
struct CodecBase : public AHandler, /* static */ ColorUtils {}
// [frameworks/av/media/libstagefright/foundation/include/media/stagefright/foundation/ColorUtils.h]
// 该类其主要定义色彩空间类型值等
struct ColorUtils {}
ACodec类构造函数实现
// [frameworks/av/media/libstagefright/ACodec.cpp]
ACodec::ACodec()
// 采样率
: mSampleRate(0),
// 节点代数值
mNodeGeneration(0),
// 是否使用native window来渲染,默认false
mUsingNativeWindow(false),
// native window使用位标记类型
mNativeWindowUsageBits(0),
// 最后一次native window数据空间枚举类型,其实就是对应于比如BT709、BT601等色彩空间即色域空间,
// 它们的区别主要是色度坐标值不一样,不同的协议需要使用不同的RGB->YCbCr参数来转换:
// 且不同的协议或者色域, RGB->XYZ、RGB->Lab的转换公式也不一样(色坐标的差别会影响转换的公式)。
// 该枚举类型主要定义在:system/core/libsystem/include/system/graphics-base-v1.0.h
mLastNativeWindowDataSpace(HAL_DATASPACE_UNKNOWN),
mIsVideo(false),
mIsImage(false),
mIsEncoder(false),
// 是否为致命错误
mFatalError(false),
// 是否在执行流程中处理shutwdown请求
mShutdownInProgress(false),
// 是否为显式shutdown处理
mExplicitShutdown(false),
// 是否为遗留(旧版本)的VP9解码器
mIsLegacyVP9Decoder(false),
// 编码器延迟时长
mEncoderDelay(0),
// 编码器padding时长【待确定作用】
mEncoderPadding(0),
// 视频旋转角度,安卓摄像头录像的视频默认有旋转角度(90度)
mRotationDegrees(0),
// 通道掩码是否存在
mChannelMaskPresent(false),
// 通道掩码即也是bit位标记法,其实就是此前章节分析的声道类型
mChannelMask(0),
// 出队列buffer计数
mDequeueCounter(0),
// 需要提交的媒体元buffer数据个数
mMetadataBuffersToSubmit(0),
// 未出队列的buffer个数
mNumUndequeuedBuffers(0),
// 重复帧延迟时长
mRepeatFrameDelayUs(-1LL),
// 最大PTS(显示时间)间隔时长
mMaxPtsGapUs(0LL),
// 最大PTS(显示时间)时长
mMaxFps(-1),
// 帧率
mFps(-1.0),
// 时间流逝fps帧率
mCaptureFps(-1.0),
// 创建输入buffer是否已被挂起
mCreateInputBuffersSuspended(false),
// 隧道化视频播放模式
mTunneled(false),
// 描述色彩宽高比枚举类型索引,默认为0(无效值)
mDescribeColorAspectsIndex((OMX_INDEXTYPE)0),
// 描述高动态范围图像静态信息媒体类型索引
mDescribeHDRStaticInfoIndex((OMX_INDEXTYPE)0),
// 描述高动态范围图像增强信息媒体类型索引
mDescribeHDR10PlusInfoIndex((OMX_INDEXTYPE)0),
// 状态机状态代数值
mStateGeneration(0),
// 视频扩展状态枚举类型
mVendorExtensionsStatus(kExtensionsUnchecked) {
// 初始化对象中的内存,其实就是将所有内存清除并置为0
// mLastHDRStaticInfo对应类声明实现,见2.2.1小节分析
memset(&mLastHDRStaticInfo, 0, sizeof(mLastHDRStaticInfo));
// 以下即为状态机不同状态功能实现对象初始化
// 不同状态功能实现,本系列内容只举例对UninitializedState的初始化过程进行详细分析,其它状态实现都类似的。
// UninitializedState的初始化过程分析,见2.2.2小节分析
// 备注:关于状态机设计模式的实现原理,本系列内容分析就不再详细阐述了,
// 原理很简单,就是各种状态实现扭转,可自行先百度了解下。
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);
// 输入输出buffer对应端口索引的端口EOS状态
// 其是bool数组来表示,kPortIndexInput为0,kPortIndexOutput为1
mPortEOS[kPortIndexInput] = mPortEOS[kPortIndexOutput] = false;
// 输入buffer的EOS结果状态码,默认为OK正常状态
mInputEOSResult = OK;
// 输入输出buffer对应端口索引的端口预设模式,也就是buffer存储方式,此处都设置为字节buffer类型
// mPortMode为IOMX::PortMode枚举类型数组
mPortMode[kPortIndexInput] = IOMX::kPortModePresetByteBuffer;
mPortMode[kPortIndexOutput] = IOMX::kPortModePresetByteBuffer;
// 初始化mLastNativeWindowCrop所有内存为0
// mLastNativeWindowCrop:表示最后一个native window的尺寸剪切大小值
// mLastNativeWindowCrop对应类声明实现,见2.2.3小节分析
memset(&mLastNativeWindowCrop, 0, sizeof(mLastNativeWindowCrop));
// 状态机从第一个未初始化状态实现mUninitializedState开始工作
// 见2.2.4小节分析
changeState(mUninitializedState);
}
2.2.1、mLastHDRStaticInfo对应类声明实现:
最近(新)的高动态范围图像静态信息,实际就是HDR标准的静态元数据描述信息,该信息是提供画面质量等
// [frameworks/native/headers/media_plugin/media/hardware/VideoAPI.h]
// HDR Static Metadata Descriptor as defined by CTA-861-3.
struct __attribute__ ((__packed__)) HDRStaticInfo {
// id参数
// Static_Metadata_Descriptor_ID
enum ID : uint8_t {
kType1 = 0, // Static Metadata Type 1
} mID;
// 每个基元(原)色的信息
struct __attribute__ ((__packed__)) Primaries1 {
// values are in units of 0.00002
uint16_t x;
uint16_t y;
};
// RGB(W)基元色组成类型信息
// Static Metadata Descriptor Type 1
struct __attribute__ ((__packed__)) Type1 {
Primaries1 mR; // display primary 0
Primaries1 mG; // display primary 1
Primaries1 mB; // display primary 2
Primaries1 mW; // white point
// 最大展示亮度值
uint16_t mMaxDisplayLuminance; // in cd/m^2
// 最小显示亮度值
uint16_t mMinDisplayLuminance; // in 0.0001 cd/m^2
// 最大容量亮度等级
uint16_t mMaxContentLightLevel; // in cd/m^2
// 最大帧平均亮度等级
uint16_t mMaxFrameAverageLightLevel; // in cd/m^2
};
// 共同体/联合体
union {
Type1 sType1;
};
};
2.2.2、UninitializedState的初始化过程分析:
未初始化状态类实现
UninitializedState类声明【省略其他代码】
UninitializedState和BaseState都是ACodec内部类
// [frameworks/av/media/libstagefright/ACodec.cpp]
struct ACodec::UninitializedState : public ACodec::BaseState {}
// [frameworks/av/media/libstagefright/ACodec.cpp]
// 状态机状态类实现的基类,AState类见上面已有声明,注意第二个参数默认为null
struct ACodec::BaseState : public AState {
explicit BaseState(ACodec *codec, const sp<AState> &parentState = NULL);
}
UninitializedState类构造函数实现
// [frameworks/av/media/libstagefright/ACodec.cpp]
ACodec::UninitializedState::UninitializedState(ACodec *codec)
: BaseState(codec) {
}
// [frameworks/av/media/libstagefright/ACodec.cpp]
ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
: AState(parentState),
mCodec(codec) {
}
// [frameworks/av/media/libstagefright/AHierarchicalStateMachine.cpp]
AState::AState(const sp<AState> &parentState)
: mParentState(parentState) {
}
2.2.3、mLastNativeWindowCrop对应类即android_native_rect_t类声明实现:
缓存最后一个native window的尺寸剪切大小值,即记录左上右下矩形坐标系值。
// [frameworks/native/libs/nativebase/include/nativebase/nativebase.h]
typedef struct android_native_rect_t
{
int32_t left;
int32_t top;
int32_t right;
int32_t bottom;
} android_native_rect_t;
2.2.4、changeState(mUninitializedState)实现分析:
状态机从第一个未初始化状态实现mUninitializedState开始工作
// [frameworks/av/media/libstagefright/AHierarchicalStateMachine.cpp]
void AHierarchicalStateMachine::changeState(const sp<AState> &state) {
// 判断当前状态机的状态实现是否和此前是同一个,若相同状态则直接退出不再重复执行,第一次执行时mState为空。
if (state == mState) {
// Quick exit for the easy case.
return;
}
// 此前缓存的旧状态链实现类集合,第一次执行时mState为空
// 备注:其实此处处理的当前状态实现类的父状态实现类等都取出来缓存在一起,
// 但是根据我们前面的分析可以看出,在ACodec这个状态机中,所有实现状态类都没有父类状态的。
// 因此该集合中只会有自身State实现类
Vector<sp<AState> > A;
sp<AState> cur = mState;
for (;;) {
A.push(cur);
if (cur == NULL) {
break;
}
// 始终为空
cur = cur->parentState();
}
// 新状态链实现类集合,如上分析只会缓存自身State实现
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();
}
// 依次按从父实现到子实现链条来执行新状态链的状态进入方法
// 备注:其实只有当前新状态自身,无父状态实现。
// stateEntered()状态进入实现,见下面的分析
for (size_t i = B.size(); i > 0;) {
i--;
B.editItemAt(i)->stateEntered();
}
}
stateEntered()状态进入实现分析:
// [frameworks/av/media/libstagefright/ACodec.cpp]
void ACodec::UninitializedState::stateEntered() {
ALOGV("Now uninitialized");
// mDeathNotifier看名称就知道它的作用,即实现了Binder服务死亡通知监听事件。
// DeathNotifier类实现很简单,见下面的分析。
// 此处处理为取消该监听功能,并清除该监听对象。当然第一次执行该变量为null。
// 关于此处的实现就不再分析了,可参考开头推荐相关文章。
if (mDeathNotifier != NULL) {
if (mCodec->mOMXNode != NULL) {
auto tOmxNode = mCodec->mOMXNode->getHalInterface<IOmxNode>();
if (tOmxNode) {
tOmxNode->unlinkToDeath(mDeathNotifier);
}
}
mDeathNotifier.clear();
}
// 下面就是初始化清除这些类变量值
mCodec->mUsingNativeWindow = false;
mCodec->mNativeWindow.clear();
mCodec->mNativeWindowUsageBits = 0;
// IOMX接口类
mCodec->mOMX.clear();
// IOMXNode接口节点类
mCodec->mOMXNode.clear();
mCodec->mFlags = 0;
mCodec->mPortMode[kPortIndexInput] = IOMX::kPortModePresetByteBuffer;
mCodec->mPortMode[kPortIndexOutput] = IOMX::kPortModePresetByteBuffer;
// mConverter为buffer数据转换对象的数组
// DataConverter类后续流程会分析到
mCodec->mConverter[0].clear();
mCodec->mConverter[1].clear();
// 清除组件名
mCodec->mComponentName.clear();
}
DeathNotifier类实现:
ACodec类的一个内部类,同时使用两种方式来实现的Binder服务死亡通知监听事件。也就是IBinder和HIDL两种Binder机制实现方式的死亡通知监听实现,同时监听这两种方式实现的Binder服务。通过注入的AMessage消息机制来完成死亡通知事件接收处理。
// [frameworks/av/media/libstagefright/ACodec.cpp]
struct ACodec::DeathNotifier :
public IBinder::DeathRecipient,
public ::android::hardware::hidl_death_recipient {
explicit DeathNotifier(const sp<AMessage> ¬ify)
: mNotify(notify) {
}
virtual void binderDied(const wp<IBinder> &) {
mNotify->post();
}
virtual void serviceDied(
uint64_t /* cookie */,
const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
mNotify->post();
}
protected:
virtual ~DeathNotifier() {}
private:
sp<AMessage> mNotify;
DISALLOW_EVIL_CONSTRUCTORS(DeathNotifier);
};
2.3、mCodec->setCallback(std::unique_ptrCodecBase::CodecCallback(new CodecCallback(new AMessage(kWhatCodecNotify, this)))):
设置监听回调消息事件。传入创建的匿名CodecCallback对象指针,并创建接收消息【kWhatCodecNotify】的通知事件。
如此前阐述,目前只分析ACodec实现。关于参数AMessage就不再分析了。
先分析CodecCallback实现,也就是编解码器通知消息事件的回调类【回调给MediaCodec】,为CodecBase的内部类声明,但其实现是在MediaCodec中,因为不同类都可以自定义实现该回调类功能。
CodecCallback类及其CodecBase::CodecCallback父类声明:父类为接口定义,子类是自定义实现类。
【因为比较重要此处将它所有的声明都附上了,根据英文注释其实就很好理解其提供的功能了】
// [frameworks/av/media/libstagefright/include/media/stagefright/CodecBase.h]
// 该类接口定义实现编解码器事件回调通知MediaCodec
// 所有方法必须不阻塞执行。
/**
* This interface defines events firing from CodecBase back to MediaCodec.
* All methods must not block.
*/
class CodecCallback {
public:
virtual ~CodecCallback() = default;
// 编解码器输出发生EOS时通知MediaCodec,若不是OK也不是ERROR_END_OF_STREAM错误,
// 那么此时EOS通知的错误就比这两个错误类发生时间更早
/**
* Notify MediaCodec for seeing an output EOS.
*
* @param err the underlying cause of the EOS. If the value is neither
* OK nor ERROR_END_OF_STREAM, the EOS is declared
* prematurely for that error.
*/
virtual void onEos(status_t err) = 0;
// 编解码器开始(工作)操作完成通知
/**
* Notify MediaCodec that start operation is complete.
*/
virtual void onStartCompleted() = 0;
// Codec停止工作完成通知
/**
* Notify MediaCodec that stop operation is complete.
*/
virtual void onStopCompleted() = 0;
// Codec释放release完成通知
/**
* Notify MediaCodec that release operation is complete.
*/
virtual void onReleaseCompleted() = 0;
// Codec刷新(缓冲区等)工作完成通知
/**
* Notify MediaCodec that flush operation is complete.
*/
virtual void onFlushCompleted() = 0;
// Codec错误发生通知
/**
* Notify MediaCodec that an error is occurred.
*
* @param err an error code for the occurred error.
* @param actionCode an action code for severity of the error.
*/
virtual void onError(status_t err, enum ActionCode actionCode) = 0;
// 底层(插件编解码器)组件分配(创建)完成通知,并回调该组件名
/**
* Notify MediaCodec that the underlying component is allocated.
*
* @param componentName the unique name of the component specified in
* MediaCodecList.
*/
virtual void onComponentAllocated(const char *componentName) = 0;
// 底层(插件编解码器)组件配置工作完成通知,并回调输入输出(编解码)格式信息【KV键值对】
/**
* Notify MediaCodec that the underlying component is configured.
*
* @param inputFormat an input format at configure time.
* @param outputFormat an output format at configure time.
*/
virtual void onComponentConfigured(
const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) = 0;
// 创建输入Surface完成通知
/**
* Notify MediaCodec that the input surface is created.
*
* @param inputFormat an input format at surface creation. Formats
* could change from the previous state as a result
* of creating a surface.
* @param outputFormat an output format at surface creation.
* @param inputSurface the created surface.
*/
virtual void onInputSurfaceCreated(
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat,
const sp<BufferProducerWrapper> &inputSurface) = 0;
// 输入Surface创建失败通知
/**
* Notify MediaCodec that the input surface creation is failed.
*
* @param err an error code of the cause.
*/
virtual void onInputSurfaceCreationFailed(status_t err) = 0;
// 该组件接收提供的输入Surface完成通知
/**
* Notify MediaCodec that the component accepted the provided input
* surface.
*
* @param inputFormat an input format at surface assignment. Formats
* could change from the previous state as a result
* of assigning a surface.
* @param outputFormat an output format at surface assignment.
*/
virtual void onInputSurfaceAccepted(
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat) = 0;
// 该组件拒绝接收提供的输入Surface失败通知
/**
* Notify MediaCodec that the component declined the provided input
* surface.
*
* @param err an error code of the cause.
*/
virtual void onInputSurfaceDeclined(status_t err) = 0;
// 通知请求输入EOS事件(该事件被发送给输入Surface处理错误时发生的)
/**
* Noitfy MediaCodec that the requested input EOS is sent to the input
* surface.
*
* @param err an error code returned from the surface. If there is no
* input surface, the value is INVALID_OPERATION.
*/
virtual void onSignaledInputEOS(status_t err) = 0;
// 通知输出帧已被渲染(或渲染完成)事件,并回调这些已渲染完成的帧数据列表
/**
* Notify MediaCodec that output frames are rendered with information on
* those frames.
*
* @param done a list of rendered frames.
*/
virtual void onOutputFramesRendered(const std::list<RenderedFrameInfo> &done) = 0;
// 通知输出buffer已改变事件
/**
* Notify MediaCodec that output buffers are changed.
*/
virtual void onOutputBuffersChanged() = 0;
};
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
class CodecCallback : public CodecBase::CodecCallback {
public:
// 可以看出多了一个显式构造函数,并传入一个通知事件消息用于回调这些事件
explicit CodecCallback(const sp<AMessage> ¬ify);
virtual ~CodecCallback() = default;
virtual void onEos(status_t err) override;
virtual void onStartCompleted() override;
virtual void onStopCompleted() override;
virtual void onReleaseCompleted() override;
virtual void onFlushCompleted() override;
virtual void onError(status_t err, enum ActionCode actionCode) override;
virtual void onComponentAllocated(const char *componentName) override;
virtual void onComponentConfigured(
const sp<AMessage> &inputFormat, const sp<AMessage> &outputFormat) override;
virtual void onInputSurfaceCreated(
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat,
const sp<BufferProducerWrapper> &inputSurface) override;
virtual void onInputSurfaceCreationFailed(status_t err) override;
virtual void onInputSurfaceAccepted(
const sp<AMessage> &inputFormat,
const sp<AMessage> &outputFormat) override;
virtual void onInputSurfaceDeclined(status_t err) override;
virtual void onSignaledInputEOS(status_t err) override;
virtual void onOutputFramesRendered(const std::list<FrameRenderTracker::Info> &done) override;
virtual void onOutputBuffersChanged() override;
private:
const sp<AMessage> mNotify;
};
CodecCallback类构造函数:
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
CodecCallback::CodecCallback(const sp<AMessage> ¬ify) : mNotify(notify) {}
mCodec->setCallback() 方法实现分析:
可以看到其实父类默认实现的内联函数,并缓存该回调对象
// [frameworks/av/media/libstagefright/include/media/stagefright/CodecBase.h]
struct CodecBase : public AHandler, /* static */ ColorUtils {
inline void setCallback(std::unique_ptr<CodecCallback> &&callback) {
mCallback = std::move(callback);
}
}
2.4、 mCodec->getBufferChannel()实现分析:
获取buffer通道对象
// [frameworks/av/media/libstagefright/ACodec.cpp]
std::shared_ptr<BufferChannelBase> ACodec::getBufferChannel() {
if (!mBufferChannel) {
// 第一次执行为空时创建新的buffer通道对象,传入两个AMessage的通知事件消息对象用来接收这两个消息事件
// ACodecBufferChannel类声明和构造函数实现,见下面的分析
mBufferChannel = std::make_shared<ACodecBufferChannel>(
// 【kWhatInputBufferFilled】即输入buffer填充事件通知消息
new AMessage(kWhatInputBufferFilled, this),
// 【kWhatOutputBufferDrained】即输出buffer消耗(即使用)事件通知消息
new AMessage(kWhatOutputBufferDrained, this));
}
return mBufferChannel;
}
ACodecBufferChannel类声明和构造函数实现
ACodecBufferChannel类声明:【省略其他代码】
该类的作用简单来说,就是管理MediaCodec和CodecBase(如ACodec)对象之间的buffer传递的一个通道。该通道支持并发请求。
// [frameworks/av/media/libstagefright/include/ACodecBufferChannel.h]
/**
* BufferChannelBase implementation for ACodec.
*/
class ACodecBufferChannel : public BufferChannelBase {}
// [frameworks/av/media/libstagefright/include/media/stagefright/CodecBase.h]
/**
* A channel between MediaCodec and CodecBase object which manages buffer
* passing. Only MediaCodec is expected to call these methods, and
* underlying CodecBase implementation should define its own interface
* separately for itself.
*
* Concurrency assumptions:
*
* 1) Clients may access the object at multiple threads concurrently.
* 2) All methods do not call underlying CodecBase object while holding a lock.
* 3) Code inside critical section executes within 1ms.
*/
class BufferChannelBase {}
ACodecBufferChannel类构造函数实现:
缓存两个AMessage的通知事件消息对象,用于后续通知接收消息方
// [frameworks/av/media/libstagefright/ACodecBufferChannel.cpp]
ACodecBufferChannel::ACodecBufferChannel(
const sp<AMessage> &inputBufferFilled, const sp<AMessage> &outputBufferDrained)
: mInputBufferFilled(inputBufferFilled),
mOutputBufferDrained(outputBufferDrained),
/// 堆序列号
mHeapSeqNum(-1) {
}
2.5、mBufferChannel->setCallback(std::unique_ptrCodecBase::BufferCallback(new BufferCallback(new AMessage(kWhatCodecNotify, this))))实现分析:
向该buffer通道对象设置回调监听类
BufferCallback类及其CodecBase::BufferCallback父类声明:【其实从这里可以看到实现原理都是和前一个Callback回调类类似的】
// [frameworks/av/media/libstagefright/include/media/stagefright/CodecBase.h]
/**
* This interface defines events firing from BufferChannelBase back to MediaCodec.
* All methods must not block.
*/
class BufferCallback {
public:
virtual ~BufferCallback() = default;
// 当有可使用的输入buffer时回调该方法,通过buffer索引来定位可使用buffer。此处不全部翻译了,可自行看下英文注释。
/**
* Notify MediaCodec that an input buffer is available with given index.
* When BufferChannelBase::getInputBufferArray() is not called,
* BufferChannelBase may report different buffers with the same index if
* MediaCodec already queued/discarded the buffer. After calling
* BufferChannelBase::getInputBufferArray(), the buffer and index match the
* returned array.
*/
virtual void onInputBufferAvailable(
size_t index, const sp<MediaCodecBuffer> &buffer) = 0;
// 当有可使用的输出buffer时回调该方法,通过buffer索引来定位可使用buffer。此处不全部翻译了,可自行看下英文注释。
/**
* Notify MediaCodec that an output buffer is available with given index.
* When BufferChannelBase::getOutputBufferArray() is not called,
* BufferChannelBase may report different buffers with the same index if
* MediaCodec already queued/discarded the buffer. After calling
* BufferChannelBase::getOutputBufferArray(), the buffer and index match the
* returned array.
*/
virtual void onOutputBufferAvailable(
size_t index, const sp<MediaCodecBuffer> &buffer) = 0;
};
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
class BufferCallback : public CodecBase::BufferCallback {
public:
explicit BufferCallback(const sp<AMessage> ¬ify);
virtual ~BufferCallback() = default;
virtual void onInputBufferAvailable(
size_t index, const sp<MediaCodecBuffer> &buffer) override;
virtual void onOutputBufferAvailable(
size_t index, const sp<MediaCodecBuffer> &buffer) override;
private:
const sp<AMessage> mNotify;
};
BufferCallback类构造函数实现:
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
BufferCallback::BufferCallback(const sp<AMessage> ¬ify)
: mNotify(notify) {}
mBufferChannel->setCallback()实现分析:
其为父类实现的内联函数。
// [frameworks/av/media/libstagefright/include/media/stagefright/CodecBase.h]
class BufferChannelBase {
inline void setCallback(std::unique_ptr<CodecBase::BufferCallback> &&callback) {
mCallback = std::move(callback);
}
}
2.6、new BatteryChecker(new AMessage(kWhatCheckBatteryStats, this))实现分析:
此处是检查监听电池状态的消息事件kWhatCheckBatteryStats接收处理
BatteryChecker类声明:【省略其他代码】
主要此处第二个参数timeout(单位为us即毫秒)为默认值即超时时长为3秒
// [frameworks/av/media/libstagefright/include/media/stagefright/BatteryChecker.h]
struct BatteryChecker : public RefBase {
BatteryChecker(const sp<AMessage> &msg, int64_t timeout = 3000000ll);
}
BatteryChecker类构造函数实现:
初始化值
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
BatteryChecker::BatteryChecker(const sp<AMessage> &msg, int64_t timeoutUs)
: mTimeoutUs(timeoutUs)
, mLastActivityTimeUs(-1ll)
, mBatteryStatNotified(false)
, mBatteryCheckerGeneration(0)
, mIsExecuting(false)
, mBatteryCheckerMsg(msg) {}
2.7、mResourceManagerService->reclaimResource(resources)实现分析:
回收资源处理。
该服务在前面流程中已分析过,其实现为ResourceManagerServiceProxy,如下
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
const Vector<MediaResource> &resources) {
Mutex::Autolock _l(mLock);
if (mService == NULL) {
return false;
}
// Binder调用Bn实现端对应方法
return mService->reclaimResource(mPid, resources);
}
注意:Bn实现端的对应实现此系列文章就暂不详细分析了,我们只需要知道前面创建了两个和资源管理有关的类对象:
mResourceManagerClient 和 mResourceManagerService。
我们只需要理解其大致工作原理即可,mResourceManagerService管理服务就是系统用来管理不同媒体类型资源Client客户端的申请该类型媒体资源处理过程,mResourceManagerService该服务提供了对资源类型及客户端client操作添加、移除、回收等功能,即mResourceManagerClient资源管理客户端可以通过mResourceManagerService该服务来添加自身媒体类型到系统该服务中,而该服务内部在reclaimResource()方法实现中将会根据不同媒体类型来获取对应类型资源使用的总数即client端个数,并且判断当前请求释放该媒体资源的进程号优先级是否存在比其他client中的一个client所属线程优先级高,若有比当前请求线程优先级低的client则表示可以释放该client正在使用的媒体资源,然后给到当前高优先级线程来使用,否则若不存在则将该方法返回false,也就是说当前系统对于该媒体类型的资源已经使用完了,因此若释放其它正在占用的client也失败了,那么最终将导致此次编解码器不能创建。
因此若有低优先级client,并且是释放所有比请求进程优先级低的client,即是个集合集体释放资源,那么将会执行这些低优先级client即mResourceManagerClient的reclaimResource()方法,但注意若该方法直接结果有一个client失败,那么也将不能创建此次需要的编解码器。
该服务内部维护和使用一个名为【mMap】全局变量来存储所有client通过addResouce()注册的信息。
【关于媒体资源管理服务的具体实现,以后有时间再详细分析吧】
服务对应实现文件在【frameworks/av/services/mediasourcemanager/ResourceManagerService.cpp】
注意该方法处理是在MediaCodec处理流程中是第二次循环才执行的。
2.8、PostAndAwaitResponse(msg, &response)实现分析:
立即发送AMessage消息事件并等待应答信息。
由于该部分内容篇幅过长,因此放入另一章节分析,请查看:
Android MediaPlayer整体架构源码分析 -【MediaCodec编解码器插件模块化注册和创建处理流程】【Part 7】
2.9、isResourceError(err)实现分析:
检查资源错误类型,即判断错误码是否为无内存错误
// [frameworks/av/media/libstagefright/MediaCodec.cpp]
static bool isResourceError(status_t err) {
return (err == NO_MEMORY);
}
本章节分析结束