MediaPlayer

frameworks\base\media\java\android\media\MediaPlayer.java

首先明确一点:MediaPlayer只是向java层暴露了具体播放的接口,其具体实现都是通过JNI接口调用c++代码实现的;

先看一个简单的接口 :start(); 他调用了native层的 _start() 方法

    public void start() throws IllegalStateException {
        //FIXME use lambda to pass startImpl to superclass
        final int delay = getStartDelayMs();
        if (delay == 0) {
            startImpl();
        } else {
            new Thread() {
                public void run() {
                    try {
                        Thread.sleep(delay);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    baseSetStartDelayMs(0);
                    try {
                        startImpl();
                    } catch (IllegalStateException e) {
                        // fail silently for a state exception when it is happening after
                        // a delayed start, as the player state could have changed between the
                        // call to start() and the execution of startImpl()
                    }
                }
            }.start();
        }
    }
private void startImpl() {
        baseStart(0); // unknown device at this point
        stayAwake(true);
        tryToEnableNativeRoutingCallback();
        _start();
    }

private native void _start() throws IllegalStateException;

JNI也是用Native语言编写的,它属于Native层。但是为了便于学习和分析,我们将与JNI相关的代码划 分到JNI层,JNI层是Native层的一部分。

JNI是 Java Native Interface的缩写,通过JNI可以让Java方法与Native方法相互调用,其中Native方法一般是用 C/C++编写的。因此,JNI就是连接Java层和Native层的桥梁。要使用JNI需要先加载JNI库,在 MediaPlayer.java中有如下代码

static {
        System.loadLibrary("media_jni");
        native_init();
    }

在静态代码块中加载JNI库,并调用native_init方法。这里加载的名为”media_jni”的 JIN 库指的是 libmedia.so。

MediaPlayer 的 JNI 层的代码在 frameworks/base/media/jni/android_media_MediaPlayer.cpp中。我们需要通过JNI调用Native方法,那么就应该有一个结构来保存Java层Native方法与JNI层方法的对应关系,这个结构就是 android_media_MediaPlayer.cpp中定义的JNINativeMethod数组,代码如下所示

static const JNINativeMethod gMethods[] = {
    {
        "nativeSetDataSource",
        "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
        "[Ljava/lang/String;)V",
        (void *)android_media_MediaPlayer_setDataSourceAndHeaders
    },

    {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
    {"_setDataSource",      "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
    {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer_setVideoSurface},
    {"_prepare",            "()V",                              (void *)android_media_MediaPlayer_prepare},
    {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer_prepareAsync},
    {"_start",              "()V",                              (void *)android_media_MediaPlayer_start},
    {"_stop",               "()V",                              (void *)android_media_MediaPlayer_stop},
    {"getVideoWidth",       "()I",                              (void *)android_media_MediaPlayer_getVideoWidth},
    {"getVideoHeight",      "()I",                              (void *)android_media_MediaPlayer_getVideoHeight},
    {"native_getMetrics",   "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer_native_getMetrics},
    {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams},
    {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams},
    {"setSyncParams",     "(Landroid/media/SyncParams;)V",  (void *)android_media_MediaPlayer_setSyncParams},
    {"getSyncParams",     "()Landroid/media/SyncParams;",   (void *)android_media_MediaPlayer_getSyncParams},
    {"_seekTo",             "(JI)V",                            (void *)android_media_MediaPlayer_seekTo},
    {"_notifyAt",           "(J)V",                             (void *)android_media_MediaPlayer_notifyAt},
    {"_pause",              "()V",                              (void *)android_media_MediaPlayer_pause},
    {"isPlaying",           "()Z",                              (void *)android_media_MediaPlayer_isPlaying},
    {"getCurrentPosition",  "()I",                              (void *)android_media_MediaPlayer_getCurrentPosition},
    {"getDuration",         "()I",                              (void *)android_media_MediaPlayer_getDuration},
    {"_release",            "()V",                              (void *)android_media_MediaPlayer_release},
    {"_reset",              "()V",                              (void *)android_media_MediaPlayer_reset},
    {"_setAudioStreamType", "(I)V",                             (void *)android_media_MediaPlayer_setAudioStreamType},
    {"_getAudioStreamType", "()I",                              (void *)android_media_MediaPlayer_getAudioStreamType},
    {"setParameter",        "(ILandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_setParameter},
    {"setLooping",          "(Z)V",                             (void *)android_media_MediaPlayer_setLooping},
    {"isLooping",           "()Z",                              (void *)android_media_MediaPlayer_isLooping},
    {"_setVolume",          "(FF)V",                            (void *)android_media_MediaPlayer_setVolume},
    {"native_invoke",       "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
    {"native_setMetadataFilter", "(Landroid/os/Parcel;)I",      (void *)android_media_MediaPlayer_setMetadataFilter},
    {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_getMetadata},
    {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
    {"native_setup",        "(Ljava/lang/Object;Landroid/os/Parcel;)V",(void *)android_media_MediaPlayer_native_setup},
    {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},
    {"getAudioSessionId",   "()I",                              (void *)android_media_MediaPlayer_get_audio_session_id},
    {"native_setAudioSessionId",   "(I)V",                      (void *)android_media_MediaPlayer_set_audio_session_id},
    {"_setAuxEffectSendLevel", "(F)V",                          (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
    {"attachAuxEffect",     "(I)V",                             (void *)android_media_MediaPlayer_attachAuxEffect},
    {"native_pullBatteryData", "(Landroid/os/Parcel;)I",        (void *)android_media_MediaPlayer_pullBatteryData},
    {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I",  (void *)android_media_MediaPlayer_setRetransmitEndpoint},
    {"setNextMediaPlayer",  "(Landroid/media/MediaPlayer;)V",   (void *)android_media_MediaPlayer_setNextMediaPlayer},
    {"native_applyVolumeShaper",
                            "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
                                                                (void *)android_media_MediaPlayer_applyVolumeShaper},
    {"native_getVolumeShaperState",
                            "(I)Landroid/media/VolumeShaper$State;",
                                                                (void *)android_media_MediaPlayer_getVolumeShaperState},
    // Modular DRM
    { "_prepareDrm", "([B[B)V",                                 (void *)android_media_MediaPlayer_prepareDrm },
    { "_releaseDrm", "()V",                                     (void *)android_media_MediaPlayer_releaseDrm },

    // AudioRouting
    {"native_setOutputDevice", "(I)Z",                          (void *)android_media_MediaPlayer_setOutputDevice},
    {"native_getRoutedDeviceId", "()I",                         (void *)android_media_MediaPlayer_getRoutedDeviceId},
    {"native_enableDeviceCallback", "(Z)V",                     (void *)android_media_MediaPlayer_enableDeviceCallback},
};

从上面来看,JNINativeMethod数组有3个参数。

• 第一个参数,比如”_prepare”,它是Java 层Native 方法的名称。在Java层调用Native方法,交由JNI层来 实现。

• 第二个参数是 Java 层 Native 方法的参数和返回值。其中()中的字符代表参数,后面的字母则代表 返回值。

• 第三个参数是Java层Native方法对应的JNI层的方法,比如_prepare方法对应JNI层的方法为 android_media_MediaPlayer_prepare。通过JNI层的方法就可以调用Native层相应的方法

前面在MediaPlayer.java的静态代码块中调用了native_init方法,这个方法是一个Native方法,查询 JNINativeMethod数组,它对应的是android_media_MediaPlayer_native_init方法,如下所示:

// This function gets some field IDs, which in turn causes class initialization.

// It is called from a static block in MediaPlayer, which won't run until the
// first time an instance of this class is used.

static void
android_media_MediaPlayer_native_init(JNIEnv *env)
{
    jclass clazz;
    //JNI层调用Java层,获取MediaPlayer对象
    clazz = env->FindClass("android/media/MediaPlayer");
    if (clazz == NULL) {
        return;
    }

    fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
    if (fields.context == NULL) {
        return;
    }
    //获取Java层的postEventFromNative方法
    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    if (fields.post_event == NULL) {
        return;
    }

    fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J");
    if (fields.surface_texture == NULL) {
        return;
    }

    env->DeleteLocalRef(clazz);

    clazz = env->FindClass("android/net/ProxyInfo");
    if (clazz == NULL) {
        return;
    }

    fields.proxyConfigGetHost =
        env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;");

    fields.proxyConfigGetPort =
        env->GetMethodID(clazz, "getPort", "()I");

    fields.proxyConfigGetExclusionList =
        env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");

    env->DeleteLocalRef(clazz);

    // Modular DRM
    FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
    if (clazz) {
        GET_METHOD_ID(gStateExceptionFields.init, clazz, "<init>", "(ILjava/lang/String;)V");
        gStateExceptionFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz));

        env->DeleteLocalRef(clazz);
    } else {
        ALOGE("JNI android_media_MediaPlayer_native_init couldn't "
              "get clazz android/media/MediaDrm$MediaDrmStateException");
    }

    gPlaybackParamsFields.init(env);
    gSyncParamsFields.init(env);
    gVolumeShaperFields.init(env);
}</jclass></init>

Native层可以通过JNI层来调用Java层代码。

static void android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{
    ALOGV("start");
    sp<mediaplayer> mp = getMediaPlayer(env, thiz);//&#x5F97;&#x5230;MediaPlayer&#x7684;&#x5F3A;&#x6307;&#x9488;
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }
    //&#x901A;&#x8FC7; JNI &#x5C42;&#x7684;android_media_MediaPlayer_start&#x65B9;&#x6CD5;&#x8C03;&#x7528;&#x4E86; Native &#x5C42;&#x7684; start&#x65B9;&#x6CD5;
    process_media_player_call( env, thiz, mp->start(), NULL, NULL );
}</mediaplayer>

MediaPlayer

MediaPlayer的Native层整体是一个C/S(Client/Server)架构,Client端和Server端运行在两个进程中,它们之间通过Binder机制来进行通信。Client端MediaPlayer对应的动态库是libmedia.so,Server端 MediaPlayerService对应的动态库为libmediaservice.so

1.Client端分析

MediaPlayer Client 端的功能实现定义的头文件为 mediaplayer.h,相应的源文件为

frameworks\av\media\libmedia\mediaplayer.cpp

我们 接着来查看mediaplayer.cpp的prepare方法,如下所示 调用了prepareAsync_l方法

// TODO: In case of error, prepareAsync provides the caller with 2 error codes,
// one defined in the Android framework and one provided by the implementation
// that generated the error. The sync version of prepare returns only 1 error
// code.

status_t MediaPlayer::prepare()
{
    ALOGV("prepare");
    Mutex::Autolock _l(mLock);
    mLockThreadId = getThreadId();
    if (mPrepareSync) {
        mLockThreadId = 0;
        return -EALREADY;
    }
    mPrepareSync = true;
    status_t ret = prepareAsync_l();
    if (ret != NO_ERROR) {
        mLockThreadId = 0;
        return ret;
    }

    if (mPrepareSync) {
        mSignal.wait(mLock);  // wait for prepare done
        mPrepareSync = false;
    }
    ALOGV("prepare complete - status=%d", mPrepareStatus);
    mLockThreadId = 0;
    return mPrepareStatus;
}
// must call with lock held
status_t MediaPlayer::prepareAsync_l()
{
    if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
        if (mAudioAttributesParcel != NULL) {
            mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
        } else {
            mPlayer->setAudioStreamType(mStreamType);
        }
        mCurrentState = MEDIA_PLAYER_PREPARING;
        return mPlayer->prepareAsync();
    }
    ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
    return INVALID_OPERATION;
}

调用了mPlayer的prepareAsync方法,那么mPlayer指的是什么呢?我们带着这个问题 来查看mediaplayer.cpp的setDataSource方法

status_t MediaPlayer::setDataSource(const sp<idatasource> &source)
{
    ALOGV("setDataSource(IDataSource)");
    status_t err = UNKNOWN_ERROR;
    //&#x901A;&#x8FC7;getMediaPlayerService&#x65B9;&#x6CD5;&#x5F97;&#x5230;IMediaPlayerService&#x6307;&#x9488;
    //IMediaPlayerService&#x6307;&#x9488;&#x6307;&#x5411;&#x7684;&#x5C31;&#x662F;MediaPlayer&#x7684;Service&#x7AEF;&#xFF1A;MediaPlayerService
    const sp<imediaplayerservice> service(getMediaPlayerService());
    if (service != 0) {
    //&#x901A;&#x8FC7;IMediaPlayerService&#x7684;create&#x65B9;&#x6CD5;&#x5F97;&#x5230;
    //IMediaPlayer&#x6307;&#x9488;&#x3002;&#x901A;&#x8FC7;IMediaPlayer&#x6307;&#x9488;&#x5C31;&#x53EF;&#x4EE5;&#x8C03;&#x7528;MediaPlayerService&#x6240;&#x63D0;&#x4F9B;&#x7684;&#x5404;&#x79CD;&#x529F;&#x80FD;
        sp<imediaplayer> player(service->create(this, mAudioSessionId, mAttributionSource));
        if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
            (NO_ERROR != player->setDataSource(source))) {
            player.clear();
        }
        err = attachNewPlayer(player);
    }
    return err;
}</imediaplayer></imediaplayerservice></idatasource>
status_t MediaPlayer::attachNewPlayer(const sp<imediaplayer>& player)
{
    status_t err = UNKNOWN_ERROR;
    sp<imediaplayer> p;
    { // scope for the lock
        Mutex::Autolock _l(mLock);

        if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
                (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
            ALOGE("attachNewPlayer called in state %d", mCurrentState);
            return INVALID_OPERATION;
        }

        clear_l();
        p = mPlayer;
        mPlayer = player;
        if (player != 0) {
            mCurrentState = MEDIA_PLAYER_INITIALIZED;
            err = NO_ERROR;
        } else {
            ALOGE("Unable to create media player");
        }
    }

    if (p != 0) {
        p->disconnect();
    }

    return err;
}</imediaplayer></imediaplayer>

attachNewPlayer方法将player赋值给mPlayer。因此,前面遗留下的问题得到了解决:mPlayer指的就是 IMediaPlayer指针,调用mPlayer的prepareAsync方法其实就是调用MediaPlayerService的prepareAsync方法。

2.Server端分析

在多媒体架构中除了C/S架构中的Client和Server,还有一个全局的ServiceManager,它用来管理系统中 的各种Service。Client、Server和ServiceManager的关系如图所示。

MediaPlayer

1.首先Server进程会注册一些Service到ServiceManager中
2.Client要使用某个Service,则需要先到ServiceManager查询Service的相关信息
3.然后Client根据Service的相关信息与Service所在的Server进程建立通信通路,这样Client就可以使用Service了。

Android的多媒体服务是由一个叫作 MediaServer的服务进程提供的,它是一个可执行程序,在Android系统启动时,MediaServer也会被启动。

frameworks\av\media\mediaserver\main_mediaserver.cpp

int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);

    sp<processstate> proc(ProcessState::self());
    //&#x5F97;&#x5230;IServiceManager&#x6307;&#x9488;&#xFF0C;&#x8FD9;&#x6837;&#x6211;&#x4EEC;&#x5C31;&#x53EF;&#x4EE5;&#x4E0E;&#x53E6;&#x4E00;&#x4E2A;&#x8FDB;&#x7A0B;&#x7684;ServiceManager&#x8FDB;&#x884C;&#x901A;&#x4FE1;&#x3002;
    sp<iservicemanager> sm(defaultServiceManager());
    ALOGI("ServiceManager: %p", sm.get());
    //&#x6CE8;&#x518C;&#x670D;&#x52A1;
    MediaPlayerService::instantiate();
    ResourceManagerService::instantiate();
    registerExtensions();
    ::android::hardware::configureRpcThreadpool(16, false);
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    ::android::hardware::joinRpcThreadpool();
}</iservicemanager></processstate>

frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp

向 ServiceManager 添加一个名为media.player 的 MediaPlayerService 服务。这样 MediaPlayerService 就被添加到 ServiceManager中,MediaPlayer 就可以通过 字符串”media.player”来查询 MediaPlayerService。

void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService());
}

MediaPlayer是在setDataSource的getMediaPlayerService方法中查询MediaPlayerService的

frameworks\av\media\libmedia\IMediaDeathNotifier.cpp

// establish binder interface to MediaPlayerService
/*static*/const sp<imediaplayerservice>
IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
        //&#x5F97;&#x5230; IServiceManager &#x6307;&#x9488;
        sp<iservicemanager> sm = defaultServiceManager();
        sp<ibinder> binder;
        do {
        //&#x67E5;&#x8BE2;&#x540D;&#x79F0;&#x4E3A;"media.player"&#x7684;&#x670D;&#x52A1;&#x3002;&#x8FD9;&#x6837;MediaPlayer&#x5C31;&#x83B7;&#x53D6;&#x4E86;MediaPlayerService&#x7684;&#x4FE1;&#x606F;&#xFF0C;
        //&#x901A;&#x8FC7;&#x8FD9;&#x4E9B;&#x4FE1;&#x606F;&#x5C31;&#x53EF;&#x4EE5;&#x4E0E;&#x5728;MediaServer&#x8FDB;&#x7A0B;&#x4E2D;&#x7684;MediaPlayerService&#x8FDB;&#x884C;&#x901A;&#x4FE1;&#x4E86;
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            ALOGW("Media player service not published, waiting...");
            usleep(500000); // 0.5 s
        } while (true);

        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();
        }
        binder->linkToDeath(sDeathNotifier);
        sMediaPlayerService = interface_cast<imediaplayerservice>(binder);
    }
    ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
    return sMediaPlayerService;
}</imediaplayerservice></ibinder></iservicemanager></imediaplayerservice>

当我们调用MediaPlayer的setDataSource方法时,会调用MediaPlayerService 的setDataSource方法: frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

status_t MediaPlayerService::Client::setDataSource(
        const sp<imediahttpservice> &httpService,
        const char *url,
        const KeyedVector<string8, string8> *headers)
{
    ALOGV("setDataSource(%s)", url);
    if (url == NULL)
        return UNKNOWN_ERROR;

    if ((strncmp(url, "http://", 7) == 0) ||
        (strncmp(url, "https://", 8) == 0) ||
        (strncmp(url, "rtsp://", 7) == 0)) {
        if (!checkPermission("android.permission.INTERNET")) {
            return PERMISSION_DENIED;
        }
    }

    if (strncmp(url, "content://", 10) == 0) {
        // get a filedescriptor for the content Uri and
        // pass it to the setDataSource(fd) method

        String16 url16(url);
        int fd = android::openContentProviderFile(url16);
        if (fd < 0)
        {
            ALOGE("Couldn't open fd for %s", url);
            return UNKNOWN_ERROR;
        }
        status_t status = setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
        close(fd);
        return mStatus = status;
    } else {
        //&#x83B7;&#x53D6;&#x64AD;&#x653E;&#x5668;&#x7684;&#x7C7B;&#x578B;playerType
        player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
        sp<mediaplayerbase> p = setDataSource_pre(playerType);
        if (p == NULL) {
            return NO_INIT;
        }

        return mStatus =
                setDataSource_post(
                p, p->setDataSource(httpService, url, headers));
    }
}</mediaplayerbase></string8,></imediahttpservice>
sp<mediaplayerbase> MediaPlayerService::Client::setDataSource_pre(
        player_type playerType)
{
    ALOGV("player type = %d", playerType);

    // create the right type of player
    sp<mediaplayerbase> p = createPlayer(playerType);
}</mediaplayerbase></mediaplayerbase>
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, mListener,
            VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mAttributionSource.pid)));
    }

    if (p != NULL) {
        p->setUID(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAttributionSource.uid)));
    }

    return p;
}</mediaplayerbase></mediaplayerbase>

frameworks\av\media\libmediaplayerservice\MediaPlayerFactory.cpp

sp<mediaplayerbase> MediaPlayerFactory::createPlayer(
        player_type playerType,
        const sp<mediaplayerbase::listener> &listener,
        pid_t pid) {
    sp<mediaplayerbase> p;
    IFactory* factory;
    status_t init_result;
    Mutex::Autolock lock_(&sLock);

    if (sFactoryMap.indexOfKey(playerType) < 0) {
        ALOGE("Failed to create player object of type %d, no registered"
              " factory", playerType);
        return p;
    }

    factory = sFactoryMap.valueFor(playerType);
    CHECK(NULL != factory);
    p = factory->createPlayer(pid);

    if (p == NULL) {
        ALOGE("Failed to create player object of type %d, create failed",
               playerType);
        return p;
    }

    init_result = p->initCheck();
    if (init_result == NO_ERROR) {
        p->setNotifyCallback(listener);
    } else {
        ALOGE("Failed to create player object of type %d, initCheck failed"
              " (res = %d)", playerType, init_result);
        p.clear();
    }

    return p;
}</mediaplayerbase></mediaplayerbase::listener></mediaplayerbase>

在Android 6.0中, MediaPlayerFactory 中有 3 个播放器 Factory,分别是 StagefrightPlayerFactory、NuPlayerFactory和 TestPlayerFactory。其中,StagefrightPlayerFactory用于创建Stagefright框架。Stagefright 框架在 Android 2.0 中被引入系统以替代庞大复杂的 OpenCore 框架。但是由于Stagefright 存在严重漏洞,并被黑客所利用,因 此在 Android 7.0 以后中,谷歌去掉了StagefrightPlayerFactory,也就是Stagefright框架。默认的播放器使用谷歌自己研发的NuPlayer框架。NuPlayerFactory的createPlayer方法如下所示

virtual sp<mediaplayerbase> createPlayer(pid_t pid) {
        ALOGV(" create NuPlayer");
        return new NuPlayerDriver(pid);
    }</mediaplayerbase>

MediaPlayer

Original: https://blog.csdn.net/xiaowang_lj/article/details/127816926
Author: 菜鸟xiaowang
Title: MediaPlayer

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/654210/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球