Android多媒体框架--02:从MediaPlayer到Nu

2023-04-16  本文已影响0人  DarcyZhou

1.概述

  Android上经常会使用到MediaPlayer去播放音频和视频。但是从严格意义上来说,MediaPlayer并不是播放器本身,它只是Android框架层众多媒体播放器(包括ROM厂商自定义的播放器)的“壳”。

  MediaPlayer的主要操作(包括但不限于播放、暂停、快进等)都会调用到框架层的播放器,比如常见的NuPlayer播放器。

image.png

2.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.png

3.从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
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
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));
}

  (1)setDataSource()方法中,这里先来看一下getPlayerType()获取的类型。如下,在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()方法

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
上一篇 下一篇

猜你喜欢

热点阅读