欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

MediaPlayer(二)--MediaPlayer基本框架

程序员文章站 2024-03-22 23:39:58
...

Android FFmpeg专题结构

MediaPlayer涉及的的文件路径

这里参考的是android8.1 的代码
JAVA类的路径:
frameworks/base/media/java/android/media/MediaPlayer.java

JNI路径:
frameworks/base/media/jni/android_media_MediaPlayer.cpp
编译为 libmedia_jni.so

native 层的接口
frameworks/av/media/libmedia
编译为 libmedia.so

native层服务:
frameworks/av/media/libmediaplayerservice/
编译为 libmediaplayerservice.so

#MediePlayer框架
MediaPlayer(二)--MediaPlayer基本框架

MediaPlayer是给应用层提供的接口,通过jni调用native层,native层又采用C/S框架,通过binder调用到service端, servcie端最终调用到本地播放器NuPlayer。
Binder是android普遍采用的架构,这里应该主要也是为了对资源和client进行统一管理。不过笔者不太明白为什么不跟其他模块一样在java层使用binder通讯呢
NuPlayer是andriod原生的播放器,芯片厂家一般会替换成自己的播放器。MediaPlayerService实际上持有的是MediaPlayerFactory, NuPlayer通过MediaPlayerFactory创建出来的,是典型的工厂设计模式
MediaPlayer(二)--MediaPlayer基本框架

IFactory为MediaPlayerFactory的内部类,芯片厂家只要创建自己的factory和player就能替换掉android原生的nuplayer

#Nuplayer的注册创建过程
MediaPlayerService 在构造函数中会去创建各个Player Factory, 并保存到sFactoryMap 中, 后续创建播放器会通过对应的type去获取到对应的factory。

MediaPlayerService::MediaPlayerService()
{
    ALOGV("MediaPlayerService created");
    mNextConnId = 1;

    MediaPlayerFactory::registerBuiltinFactories();
}

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;
#ifdef USE_FFPLAYER
    factory = new FFPlayerFactory();
    if (registerFactory_l(factory,FF_PLAYER) != OK)
        delete factory;
#endif

    sInitComplete = true;
}
status_t MediaPlayerFactory::registerFactory_l(IFactory* factory,
                                               player_type type) {
    if (NULL == factory) {
        ALOGE("Failed to register MediaPlayerFactory of type %d, factory is"
              " NULL.", type);
        return BAD_VALUE;
    }

    if (sFactoryMap.indexOfKey(type) >= 0) {
        ALOGE("Failed to register MediaPlayerFactory of type %d, type is"
              " already registered.", type);
        return ALREADY_EXISTS;
    }

    if (sFactoryMap.add(type, factory) < 0) {
        ALOGE("Failed to register MediaPlayerFactory of type %d, failed to add"
              " to map.", type);
        return UNKNOWN_ERROR;
    }

    return OK;
}

播放器实例会在上层调用setDataSource时调用到createPlayer创建,MediaPlayerFactory会根据playerType,调用对应的factory去创建player

sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
    // determine if we have the right player type
    sp<MediaPlayerBase> p = getPlayer();
    if ((p != NULL) && (p->playerType() != playerType)) {
        ALOGV("delete player");
        p.clear();
    }
    if (p == NULL) {
        p = MediaPlayerFactory::createPlayer(playerType, this, notify, mPid);
    }

    if (p != NULL) {
        p->setUID(mUid);
    }

    return p;
}

openCore,StageFright, NuPlayer的关系

如果接触Android比较早的人,可能有听过openCore,StageFright。 这几个层次是并列的,都属于android底层播放器的实现框架。
Android上的MediaPlayer播放底层框架已经经历了多次变动,从最早先的OpenCore到后来的StageFright再到现在的NuPlayer,这些框架在演进过程中一般都是先两种框架并存,然后再在某个版本中将其移除,早先Android中使用的是Stagefright + NuPlayer并存的方式,其中前者负责播放本地的媒体文件,后者用于播放网络流媒体文件,但是在后来的Android L开始NuPlayer渐渐开始替代了Stagefright,目前本地播放已经切换到NuPlayer上了,在Android N AOPS 源代码中已经移除了Stagefright。

MediaCodec 、OpenMAX、ACodec关系

OpenMAX确立了一套标准的接口,用于编解码,上层App直接调用这些接口,底层硬件厂商直接实现这些接口,从而实现了上层软件开发与底层芯片开发地彻底分离,加速了跨平台的多媒体组件的开发、整合和编程。
Android上的MediaCodec是通过ACodec来加载openmax层

StageFright 直接通过OpenMAX进行编辑码,NuPlayer是通过ACodec进行编解码

参考
https://blog.csdn.net/zds05/article/details/52837998
https://blog.csdn.net/u012188065/article/details/86723535

相关标签: 播放器