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服务启动起来。
   

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐