MediaPlayer
3.3、setDataSource设置播放资源
在整个应用程序的进程中,Mediaplayer.cpp 中 setDataSource会从service manager中获得mediaPlayerService 服务,然后通过服务来创建player,这个player就是播放器的真实实例,同时也使MediaPlayer和MediaPlayerService建立了联系。通过 getMediaPlayerService 得到的BpMediaPlayerService类型的service,和mediaPlayerService进程中的BnMediaPlayerService 相对应负责binder通讯。
在create函数中创建了一个MediaPlayerService::Client的实例,是MediaPlayerService的内部类,也就是说MediaPlayerService会为每个client应用进程创建一个相应的MediaPlayerService::Client的实例,来实现播放以及播放过程的控制,向MediaPlayer发事件通知。到这里,在Server端的对象就创建完成了。
然后在MediaPlayer.cpp中就得到了一个sever端的player实例,它和本地其他类的实例没什么用法上的区别,而实际上则是通过binder机制运行在另外一个进程中的。获得此实例后继续player->setDataSource操作。
总结:Java应用程序中使用MediaPlayer.java的setDataSource()会传递到Native层中MediaPlayer.cpp的setDataSource()去执行,而MediaPlayer.cpp又会把这个方法交给MediaPlayerservice去执行。MediaPlayerService则是使用NuPlayer实现的,最后, setDataSource还是交给了NuPlayer去执行了。这个过程把MediaPlayer和MediaPlayerService之间的联系建立起来,同时又把MediaPlayerService和NuPlayer的关系建立了起来。
NuPlayer
NuPlayer由NuPlayerDriver封装,利用了底层的ALooper/AHandler机制来异步地处理请求,ALooper保存消息请求,然后在AHandler中处理。另外,NuPlayer中利用到了Acodec。
1、整体框架图
其中的几个部分:
NuPlayer::Source 解析模块(parser,功能类似FFmpeg的avformat)。其接口与MediaExtractor和
MediaSource组合的接口差不多,同时提供了用于快速定位的seekTo接口。
NuPlayer::Decoder 解码模块(decoder,功能类似FFmpeg的avcodec),封装了用于AVC、AAC解码的接口,
通过ACodec实现解码(包含OMX硬解码和软解码)。
NuPlayer::Render 渲染模块(render,功能类似声卡驱动和显卡驱动),主要用于音视频渲染和同步,与
NativeWindow有关。
NuPlayer 是播放框架中连接Source、Decoder、Renderer的纽带
NuPlayerDriver 作为NuPlayer类的封装,直接调用NuPlayer。
2、ALooper/AHandler机制
NuPlayer本身继承自AHandler类,而ALooper对象保存在NuPlayerDriver中。ALooper/AHandler机制是一种消息循环处理方式,通常有三个主要部分:消息(message,通常包含Handler)、消息队列(queue)、消息处理线程(looperthread)。此机制会将变量封装到一个消息AMessage结构体中,然后放到队列中去,后台专门有一个线程会从这个队列中取出消息然后通过函数onMessageReceived执行。
2.1、AHandler
是消息处理类的父类,基本上只有一个onMessageReceived用于子类继承,deliverMessage用于给类AMessage使用,setID用于给友元类ALooperRoster使用(消息的发送和取出都是调用辅助类ALooperRoster完成的)。
2.2、AMessage
其是消息的载体,在使用AMessage时只需要指定消息类别和要处理该消息的AHandler即可,可以通过构造函数创建,也可以单独调用setWhat和setTarget接口来设置。AMessage构造完成之后,可以调用setXXX设置对应的参数,通过findXXX获取传递的参数。最后通过post即可将消息投递到AHandler的消息队列中。
2.3、ALooper及后台线程
是消息处理循环,其调用逻辑是先创建一个ALooper对象,然后调用setName和start接口,之后调用registerHandler设置一个AHandler,这样就完成了初始化。在析构之前需要调用stop接口。
2.4、例子
2.5、总结
总的来说整个消息的处理过程就是:在ALoop中的ALooper::start接口会启动一个线程LooperThread,并调用ALooper::loop函数来完成消息的实际执行。而消息是由AMessage通过调用ALooper::post接口,将AMessage添加到消息队列中的。ALooper中存在的后台线程线程LooperThread维护着这个消息队列,线程函数不断从这个队列中取出消息执行。其流程如下图所示: