承接上一章节分析: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