android 在java api中播放一个音乐文件:
MediaPlayer player = new MediaPlayer();
try {
player.setDataSource("/storage/emulated/0/test.aac");
player.prepare();
} catch (IOException e) {
e.printStackTrace();
}
player.start();
上面调用如此简单,framework层里面可是做了非常多的工作,追一下源码。基于android 10,api-29.本篇仅仅为了分析从MediaPlayer.java 到NuPlayer的关联过程,主要跟踪setDataSource 和prepare两个函数,至于后续NuPlayer如何解复用,解码,渲染,已经其中涉及到的音视频数据流转,控制,驱动线程模型,不涉及。大图:
上图的文字模式:
mediaplayer
|------MediaPlayer.java
| \base\media\java\android\media
| |--static {
| | System.loadLibrary("media_jni");
| | native_init();
| | }
| |--MediaPlyer()
| | |--Looper.myLooper()//创建了looper线程
| | | |--new EventHandler(this, looper)
| | |--mTimeProvider = new TimeProvider(this);
| | |--mOpenSubtitleSources = new Vector<InputStream>();
| | |--native_setup(new WeakReference<MediaPlayer>(this))
| | |--baseRegisterPlayer()
| |--setDataSource()
| | |--nativeSetDataSource(
| | | IBinder httpServiceBinder, String path, String[] keys, String[] values)
| | |--native void _setDataSource(FileDescriptor fd, long offset, long length)
| |--prepare()
|-----android_media_MediaPlayer.cpp
| \base\media\jni
| |--android_media_MediaPlayer_native_init()
| |--android_media_MediaPlayer_native_setup()
| | |--sp<MediaPlayer> mp = new MediaPlayer();
| | |--sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
| | |--setMediaPlayer(env, thiz, mp);
| |--android_media_MediaPlayer_setDataSourceFD()
| | |--mp->setDataSource(fd, offset, length)
| |--android_media_MediaPlayer_prepare()
| |--mp->prepare()
|------mediaplayer.cpp
| \av\media\libmedia
| |--MediaPlayer()
| |--setDataSource()
| | |--sp<IMediaPlayer> player(service->create(this, mAudioSessionId)
| | |--attachNewPlayer()
| | | sp<IMediaPlayer> mPlayer
| | |--player->setDataSource
| |--prepare()
| | |--prepareAsync_l()
| | | |--mPlayer->setParameter
| | | |--mPlayer->prepareAsync()
|------IMediaPlayerService.cpp
| \av\media\libmedia
| |--BpMediaPlayerService
| | |--create()
| |--BnMediaPlayerService::onTransact()
|------MediaPlayerService.cpp
\av\media\libmediaplayerservice
|--create()
| |--return new Client()
| | |--MediaPlayerService::Client
| | |--setDataSource
| | | |--setDataSource_pre
| | | |--MediaPlayerFactory::getPlayerType(this, url);
| | | |这里,通过url来匹配合适的player类型
| | | |宏定义:GET_PLAYER_TYPE_IMPL
| | | |其原理是 遍历 sFactoryMap ,(MediaPlayerService构造函数中就对其进行了初始,注册了几个内置的Factory到该表中)
| | | |调用每一个factory的虚函数scoreFactory(), 表明这个factory对当前url的匹配分数,
| | | |选取分数最高的一个factory,也就是最匹配的factory。
| | | |所以这里注册的NuplayerFactory,可以很容易的替换成其他Factory,框架很灵活。
| | | |--setDataSource_pre(player_type playerType)
| | | |--mPlayer = createPlayer()
| | | |--MediaPlayerFactory::createPlayer(playerType, mListener, mPid);
| | | MediaPlayerFactory中的静态方法,创建Plyer,
| | | 其内部通过传入的playerType类型,从sFactoryMap表中取对应的factory,
| | | 比如之前注册的NuplayerFactory,来创建player
| | |--sp<MediaPlayerBase> mPlayer;
| | |--sp<MediaPlayerService> mService;
| | |--sp<IMediaPlayerClient> mClient;
| |--在MediaPlayerService中crate 的实际上是一个client,客户端 并且MediaPlayerService会把这个client加到
| SortedVector< wp<Client> > mClients;有序向量中记录 这个 client 自身就是一个 BnMediaPlayer,
| 所以由 mediaplayer.cpp 中的 mPlayer的操作直接调用到这个client里面的实现
|--MediaPlayerService()构造函数
|--MediaPlayerFactory::registerBuiltinFactories();
|注册内置的 player工厂
| new NuPlayerFactory();
| new TestPlayerFactory();
| 这里将这这两个Factory注册进去,加入到对象 MediaPlayerFactory 中的KeyedVector<player_type, IFactory*> sFactoryMap
| 我们可以在这里添加自己的Player, 在factory匹配分数的时候对 自定义的类型给出一个高的匹配分数,实现自定义的player,
| 用以对某些特定格式使用自定义的player代替默认的Nuplayer
|--instantiate() //在av/media/mediaserver/main_mediaserver.cpp 生成可执行文件,被.rc启动脚本记录,系统启动的时候会将这个程序运行,把media.player服务运行起来。
defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService())
T1:player 耦合点 --MediaPlayerFactory::getPlayerType(this, url);
这里,通过url来匹配合适的player类型 宏定义:GET_PLAYER_TYPE_IMPL
其原理是 遍历 sFactoryMap ,(MediaPlayerService构造函数中就对其进行了初始化,注册了几个内置的Factory到该表中,目前只有一个Nuplayer可注册)
调用每一个factory的虚函数scoreFactory(), 表明这个factory对当前url的匹配分数,
选取分数最高的一个factory,也就是最匹配的factory。
所以这里注册的NuplayerFactory,可以很容易的替换成其他Factory,框架很灵活,哪一天google对这个Nuplayer不满意了,可能就再整一个新的player在这里注册进去。
T2:主要文件
------MediaPlayer.java \base\media\java\android\media java的class
------android_media_MediaPlayer.cpp \base\media\jni java 对应的jni转
------mediaplayer.cpp \av\media\libmedia 没什么实在作用,一层包装
------IMediaPlayerService.cpp \av\media\libmedia android典型的 binder 实现的服务,Bp+Bn,跨进程的方法调用,弱化进程概念,代之以组件的思想
------MediaPlayerService.cpp \av\media\libmediaplayerservice Bn,真正的MediaPlayer工作的地方
------main_mediaserver.cpp av\media\mediaserver 这里有main入口函数,这个会生成可执行程序mediaserver,列在系统的启动脚本.rc文件中,系统启动的时候会调用该可执行程序,把mediaPlayerserver服务启动起来。