Android 9.0 multimedia框架(一)加载media extractor组件

Extractor概念

Extractor在multimedia框架扮演着解析器的角色,用于解析文件的封装。extractor会把视频文件解析成音频流和视频流,把音频文件解析成音频流。

关键类说明

  1. NuMediaExtractor:在NuMediaExtractor中,会去保存RemoteMediaExtractor的远程代理对象,也就是binder client。它其实就是针对MediaExtractor的再一次封装,比如它在调用RemoteMediaExtractor获取文件格式的时候,获取得到的是MetaData,然后它会对MetaData进行处理,转化成AMessage,然后再送给调用者。这个类一般是调用SoundPool解析音频文件的时候才会用到的。使用MediaPlayer播放音频文件是不会走这个类的。

  2. RemoteMediaExtractor:binder server。RemoteMediaExtractor跟RemoteDataSource的作用是相似的,它也是将MediaExtractor保存为私有变量中,它的binder client通过它可以访问到MediaExtractor,间接解析多媒体文件。

  3. MediaExtractorFactory:工具类,里面都是static函数。用于加载extractor组件,创建idatasource等

  4. MediaExtractor:extractor组件需继承它。在9.0的版本中,它只是一个类而已,通过其他binder服务来调用它,间接binder化。通过它可以获得解析器的音频轨或者视频轨的信息。

  5. ExtractorPlugin:解析器组件。每一个extractor so都对应一个组件,这个组件会保存so库的句柄,路径及库中定义的解析器信息。

  6. FileSource:根据构造时传递的文件描述符或者文件路径对多媒体文件进行读取等操作。

  7. RemoteDataSource:binder server。在加载解析器的过程中,FileSource被保存位RemoteDataSource的本地对象,供代理进行文件读取的操作。所以,通过RemoteDataSource这个binder服务,extractor可以跨进程访问文件数据。

  8. CallbackDataSource:顾名思义就是用于回调DataSource,在加载extractor过程中,它保存了RemoteDataSource的远程对象在自己的私有变量sp mIDataSource中,通过mIDataSource,CallbackDataSource跨进程操作FileSource,从而访问多媒体文件。

  9. TinyCacheSource:从字面上理解就是:小型缓冲数据源。它保存了CallbackDataSource的对象,通过CallbackDataSource访问多媒体文件。

流程图

因为我们的分析是从SoundPool 的decode开始引入的,所以流程图从decode开始

在这里插入图片描述
上面的时序图,体现了SoundPool解析ogg等多媒体文件时,加载extractor的过程。主要包含几个过程:
1、创建FileSource,然后为FileSource创建binder server: RemoteDataSource,目的是为了提供IDataSource的接口,这样就可以跨进程访问FileSource
2、创建TinyCacheSource,封装IDataSource接口,供media.extractor可以使用
3、UpdateExtractors,遍历system/lib(lib64)/extractors、vendor/lib(lib64)/extractors和RegisterExtractorsInApk,最终会保存到MediaExtractorFactory的gPlugins成员变量中
4、sniff过程,将之前创建的TinyCacheSource传递给所有的extractor,调用每一个的sniff函数评分,最后确定一个extractor来解析此文件
5、创建RemoteMediaExtractor,封装IMediaExtractor接口,方便后续解码使用

通过时序图最后我们发现registerMediaExtractor所有的extractor都会保存在sExtractors这个动态数组中,那么我们可以通过dumpsys media.extractor 命令快速查看
在这里插入图片描述

DataSource

通过DataSource可以获取到文件名及文件路径等信息,在SoundPool设置数据源的时候会传入一个fd趣创建FileSource(FileSource是DataSource一个子类)。我们看下DataSource的一个相关类的框架

在这里插入图片描述
RemoteDataSource 属于binder Server,CallbackDataSource拥有IDataSource binder接口;TinyCacheSource的mSource就是CallbackDataSource,并且TinyCacheSource的toString()就是调用mSource的toString()。所以,只要调用TinyCacheSource的toString就可以获得FileSource保存的文件路径名。在 new TinyCacheSource 创建出来的对象作为localSource参数传递给了MediaExtractorFactory::CreateFromService,然后经过一系列内部调用在调用(*it)->def.sniff的时候把刚才传递进来的localSource作为参数传递进去。这里的sniff就是每一个extractor的静态函数

UpdateExtractors

在调用MediaExtractorFactory::UpdateExtractors时会去遍历system/lib(lib64)/extractors/ 、vendor/lib(lib64)/extractors/下的所有so库,调用dlopen,对每一个存在GETEXTRACTORDEF符号的库的信息保存到ExtractorPlugin中(当然这里会判断是否已经注册了),最后把这个信息列表保存到gPlugins。如果newUpdateApkPath != nullptr,会去找对应的apk,并看对应的是否有extractor.so库,有的话也会将信息保存到列表中

IMediaExtractor

获取到IMediaExtractor就可以访问binder server RemoteMediaExtractor。RemoteMediaExtractor里面保存有MediaExtractor,一个MediaExtractor对应一个RemoteMediaExtractor。这里的MediaExtractor是个功能基类,谷歌自带的或者自己实现的解析器都需要继承它。比如系统中的解析器有:MP3Extractor、MPEG2TSExtractor.cpp、AACExtractor.cpp、FLACExtractor.cpp等等。
从时序图中可以看出,在MediaExtractorFactory::sniff中,会取出gPlugins保存的每一个extractor库,然后调用它们的sniff函数。例如MP3Extractor中的sniff函数会去判断这个数据源是不是属于MP3格式的,如果是则会设置confidence的分数。MediaExtractorFactory::sniff会返回confidence值最大的那个extractor的CreatorFunc。CreatorFunc是每一个extractor 库需要创建的一个static函数,用于构造extractor。

在MediaExtractorFactory的CreateFromService函数中,会用到这个extractor对象,会将这个创建好的MediaExtractor、属于它的FileSource以及ExtractorPlugin都传给RemoteMediaExtractor,构造出一个RemoteMediaExtractor对象。

因为MediaExtractor仅仅是一个本地类,无法提供跨进程访问接口,所以需要一个binder server为它提供接口,这个server就是RemoteMediaExtractor。
RemoteMediaExtractor::RemoteMediaExtractor( MediaExtractor *extractor, const sp<DataSource> &source, const sp<RefBase> &plugin) :mExtractor(extractor), mSource(source), mExtractorPlugin(plugin)
RemoteMediaExtractor就是MediaExtractor的wrapper(封装),只要获得IMediaExtractor,就可以跨进程访问MediaExtractor,比如MP3Extractor。最后就是调用registerMediaExtractor把IMediaExtractor保存到ExtractorInstance里面,方便后面使用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值