Android多媒体框架--02:从MediaPlayer到Nu
1.概述
Android上经常会使用到MediaPlayer去播放音频和视频。但是从严格意义上来说,MediaPlayer并不是播放器本身,它只是Android框架层众多媒体播放器(包括ROM厂商自定义的播放器)的“壳”。
MediaPlayer的主要操作(包括但不限于播放、暂停、快进等)都会调用到框架层的播放器,比如常见的NuPlayer播放器。
image.png2.MediaPlayer播放视频
MediaPlayer的使用很简单,如果是想要在一个SurfaceView上播放assets下的video.mp4视频,以下简单的代码就能实现视频画面的显示:
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surface);
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
MediaPlayer player = new MediaPlayer();
player.setDisplay(holder); //设置画面显示在哪
try {
player.setDataSource(getAssets().openFd("video.mp4"));//设置视频源
player.prepare(); //准备视频数据
} catch (IOException e) {
e.printStackTrace();
}
player.start(); //开始播放
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
MediaPlayer的API和用法比较简单,只要熟悉掌握下面的状态图就能很方便的使用。主要涉及的状态有setDataSource、prepare、start、pause、stop、reset、release。
image.png3.从MediaPlayer到NuPlayer
3.1 整体架构
应用里面调了MediaPlayer的方法,其实底层都会通过IPC机制调到MediaPlayerService。其实不仅是MediaPlayer,android.media包下的媒体播放接口像AudioTrack、SoundPool、MediaCodec都是会调到MediaPlayerService去做具体的编解码操作的,安卓的媒体播放是个典型的C/S架构。
image.png其实android.media.MediaPlayer这个java类只是native层的一个代理,具体的实现都是通过jni调用到libmedia_jni.so里面的c/c++代码。比如设置音视频数据的setDataSource()方法有如下调用关系:
==> android.media.MediaPlayer
==> android_media_MediaPlayer.cpp
==> mediaplayer.cpp
- mediaplayer.cpp
status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
{
ALOGV("setDataSource(IDataSource)");
status_t err = UNKNOWN_ERROR;
const sp<IMediaPlayerService> service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(source))) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
MediaPlayerService会创建一个Client返回给客户端,客户端这个Client调用到MediaPlayerService的功能了。Client是MediaPlayerService的一个内部类,它继承了BnMediaPlayerService,而BnMediaPlayer又继承了BnInterface<IMediaPlayer>。
3.2 NuPlayer创建
image.png- MediaPlayerService.cpp
status_t MediaPlayerService::Client::setDataSource(
const sp<IDataSource> &source) {
sp<DataSource> dataSource = DataSource::CreateFromIDataSource(source);
player_type playerType = MediaPlayerFactory::getPlayerType(this, dataSource); // 对已经注册的播放器进行打分,创建得分最高的播放器(NU_PLAYER)
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
}
// now set data source
return mStatus = setDataSource_post(p, p->setDataSource(dataSource));
}
- MediaPlayerFactory::getPlayerType:该函数涉及Android底层媒体播放器的评分机制。通过评分,获得一个最优的播放器类型。一般情况下,函数调用返回的是NuPlayer对应的播放器类型NU_PLAYER。
- setDataSource_pre:该函数的作用是根据前面获得的播放器类型创建播放器对象。
- setDataSource_post:将媒体资源设置给播放器,这才是真正的setDataSource操作。
(1)setDataSource()方法中,这里先来看一下getPlayerType()获取的类型。如下,在MediaPlayerInterface.h中枚举所有的播放器类型。
- MediaPlayerInterface.h
enum player_type {
STAGEFRIGHT_PLAYER = 3,
NU_PLAYER = 4,
// Test players are available only in the 'test' and 'eng' builds.
// The shared library with the test player is passed passed as an
// argument to the 'test:' url in the setDataSource call.
TEST_PLAYER = 5,
};
目前只注册了NU_PLAYER和TEST_PLAYER两种播放器。 STAGEFRIGHT_PLAYER实际上指的是AwesomePlayer,在早期的安卓系统使用AwesomePlayer去播放本地视频,用NuPlayer去播放流媒体。后来因为某些原因所以逐渐用弃用了AwesomePlayer,统一使用NuPlayer去播放。在某些过度版本的安卓系统开发者选项里面还可以选择NuPlayer代替AwesomePlayer,到后期都不用选了,只有一个NuPlayer可以用。
用于创建两种播放器的NuPlayerFactory和TestPlayerFactory,在如下代码中注册的:
void MediaPlayerFactory::registerBuiltinFactories() {
Mutex::Autolock lock_(&sLock);
if (sInitComplete)
return;
IFactory* factory = new NuPlayerFactory();
if (registerFactory_l(factory, NU_PLAYER) != OK)
delete factory;
factory = new TestPlayerFactory();
if (registerFactory_l(factory, TEST_PLAYER) != OK)
delete factory;
sInitComplete = true;
}
(2)紧接着执行了setDataSource_pre()方法
- MediaPlayerService.cpp
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
player_type playerType)
{
...
sp<MediaPlayerBase> p = createPlayer(playerType); // 根据类型创建player
if (p == NULL) {
return p;
}
...
}
---------------------
sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
sp<MediaPlayerBase> p = mPlayer;
...
p = MediaPlayerFactory::createPlayer(playerType, this, notify, mPid);
...
return p;
}
--------------------
virtual sp<MediaPlayerBase> createPlayer(pid_t pid) {
ALOGV(" create NuPlayer");
return new NuPlayerDriver(pid);
}
--------------------
mPlayer(AVNuFactory::get()->createNuPlayer(pid)),
--------------------
sp<NuPlayer> AVNuFactory::createNuPlayer(pid_t pid) {
return new NuPlayer(pid);
}
NuPlayerFactory创建出来的是NuPlayerDriver,不过NuPlayerDriver内部也是封装了NuPlayer。对应上述代码中的mPlayer,后续的start(),stop(),setDataSource()等都是通过该对象进行操作。
3.3 播放器工厂
默认情况下,只有NuPlayerFactory和TestPlayerFactory两种播放器的工厂,ROM厂商也可以根据标准进行自定义。播放器工厂的类图如下:
image.png