Android MediaPlayer整体架构源码分析 -【MediaCodec编解码器插件模块化注册和创建处理流程】【Part 6】

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

你可能感兴趣的:(MediaPlayer,【音视频】,MediaCodec,ACodec,MediaCodec,init,OMX)