Android MediaPlayer框架分析

应用层:从setDataSource说起

  先来看看应用层Mediaplayer的例子:

public class MediaPlayerStudy extends Activity {
    private Button bplay,bpause,bstop;
    private MediaPlayer mp = new MediaPlayer();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        bplay = (Button)findViewById(R.id.play);
        bpause = (Button)findViewById(R.id.pause);
        bstop = (Button)findViewById(R.id.stop);
        bplay.setOnClickListener(new OnClickListener(){
           @Override
           public void onClick(View v) {
                  try {
                     mp.setDataSource("/sdcard/test.mp3");
                     mp.prepare();
                     mp.start();
                  } catch (IllegalArgumentException e) {
                     e.printStackTrace();
                  } catch (IllegalStateException e) {
                     e.printStackTrace();
                  } catch (IOException e) {
                     e.printStackTrace();
                  }
                  mp.setOnCompletionListener(new OnCompletionListener(){
                     @Override
                     public void onCompletion(MediaPlayer mp) {
                         mp.release();
                     }
                  });
           }
        });

        bpause.setOnClickListener(new OnClickListener(){
           @Override
           public void onClick(View v) {
                  if(mp != null){
                     mp.pause();
                  }
           }
        });

        bstop.setOnClickListener(new OnClickListener(){
        @Override
        public void onClick(View v) {
             if(mp != null){
                mp.stop();
             }
        }
        });
    }

    @Override
    protected void onDestroy() {
       if(mp != null)
           mp.release();
       super.onDestroy();
    }
}

mediaserver的启动

  mediaserver在开机时启动,在init.rc文件中有体现:

/system/core/rootdir/init.rc

service media /system/bin/mediaserver
    class main
    user media
    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
    ioprio rt 4

  mediaserver的main函数里初始化了AudioFlinger,MediaPlayerService,ResourceManagerService,CameraService,AudioPolicyService,SoundTriggerHwService和
RadioService等service。
/frameworks/av/media/mediaserver/main_mediaserver.cpp

 ...
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
SoundTriggerHwService::instantiate();
RadioService::instantiate();
...

  这里只涉及MediaPlayerService,看看其instantiate函数实现:

/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

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

  MediaPlayerService::instantiate()主要作用是向ServiceManager注册服务。

MediaPlayer的启动

  MediaPlayer构造函数执行之前加载了libmedia_jni.so,并调用了native函数native_init。

/frameworks/base/media/java/android/media/MediaPlayer.java

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

  进程执行native_init时会切换到JNI环境,执行JNI_OnLoad函数:

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        ALOGE("ERROR: GetEnv failed\n");
        goto bail;
    }
    assert(env != NULL);
    ...
    if (register_android_media_MediaPlayer(env) < 0) {
        ALOGE("ERROR: MediaPlayer native registration failed\n");
        goto bail;
    }
    ...

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

static int register_android_media_MediaPlayer(JNIEnv *env)
{
    return AndroidRuntime::registerNativeMethods(env,
                "android/media/MediaPlayer", gMethods, NELEM(gMethods));
}

  Java层的函数与JNI层的函数对应关系写在gMethods数组中:

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

static JNINativeMethod gMethods[] = {
    ...
    {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
    {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
    ...

  native层fields是个struct fields_t类型的static变量。

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

struct fields_t {
    jfieldID    context;
    jfieldID    surface_texture;

    jmethodID   post_event;

    jmethodID   proxyConfigGetHost;
    jmethodID   proxyConfigGetPort;
    jmethodID   proxyConfigGetExclusionList;
};

  android_media_MediaPlayer_native_init负责将Java层的一些信息保存在JNI层,如Java层的long型(J)的成员mNativeContext保存在fields.context中,函数成员postEventFromNative保存在fields.post_event中( (Ljava/lang/Object;IIILjava/lang/Object;)V”)表示该函数接收五个参数Object,int,int,int,Object,返回值为void )等等。

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

static void
android_media_MediaPlayer_native_init(JNIEnv *env)
{
    jclass clazz;

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

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

    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);

    gPlaybackParamsFields.init(env);
    gSyncParamsFields.init(env);
}

  这样,MediaPlayer.java的静态代码块执行完毕。返回Java层MediaPlayer的构造函数中,开始为MediaPlayer设置了Looper和EventHandler,末尾调用native函数native_setup,并传入该MediaPlayer对象的弱引用。这里传入MediaPlayer对象的弱引用的原因是当这个MediaPlayer在不再被需要时(被置null)能被GC回收。

/frameworks/base/media/java/android/media/MediaPlayer.java

public MediaPlayer() {

        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }

        mTimeProvider = new TimeProvider(this);
        mOpenSubtitleSources = new Vector<InputStream>();
        IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
        mAppOps = IAppOpsService.Stub.asInterface(b);

        /* Native setup requires a weak reference to our object.
         * It's easier to create it here than in C++.
         */
        native_setup(new WeakReference<MediaPlayer>(this));
    }

  同理,native_setup最终会调到JNI层的android_media_MediaPlayer_native_setup函数。

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
    ALOGV("native_setup");
    sp<MediaPlayer> mp = new MediaPlayer();
    if (mp == NULL) {
        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
        return;
    }

    // create new listener and give it to MediaPlayer
    sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
    mp->setListener(listener);

    // Stow our new C++ MediaPlayer in an opaque field in the Java object.
    setMediaPlayer(env, thiz, mp);
}

  android_media_MediaPlayer_native_setup中首先new了一个C++层的MediaPlayer对象。接着new了一个回调用的JNIMediaPlayerListener,weak_thiz传入Java层传下来的MediaPlayer弱引用。GetObjectClass从对象实例thiz中获取class,mclass为android/media/MediaPlayer的全局引用,mObject为MediaPlayer弱引用的全局引用。如果希望创建的对象实例在作用域外也能使用,则需要使用NewGlobalRef接口将其提升为Global Reference——需要注意的是,当Global Reference不再使用后,需要显式的释放,以便通知JVM进行垃圾收集。

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
{

    // Hold onto the MediaPlayer class for use in calling the static method
    // that posts events to the application thread.
    jclass clazz = env->GetObjectClass(thiz);
    if (clazz == NULL) {
        ALOGE("Can't find android/media/MediaPlayer");
        jniThrowException(env, "java/lang/Exception", NULL);
        return;
    }
    mClass = (jclass)env->NewGlobalRef(clazz);

    // We use a weak reference so the MediaPlayer object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    mObject  = env->NewGlobalRef();
}

  setListener将JNIMediaPlayerListener(JNIMediaPlayerListener继承自MediaPlayerListener)保存在成员变量mListener中。这样,C++层的MediaPlayer能够回调JNIMediaPlayerListener的唯一的接口实现notify函数。

/frameworks/av/media/libmedia/mediaplayer.cpp

status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
{
    ALOGV("setListener");
    Mutex::Autolock _l(mLock);
    mListener = listener;
    return NO_ERROR;
}

  JNIMediaPlayerListener::notify在JNI层调用Java层的方法。fields.post_event存储的是Java层的postEventFromNative函数,mclass为android/media/MediaPlayer这个class的全局引用,mObject为Java层MediaPlayer对象的全局引用。调用Java层的静态方法或访问Java层的静态变量时,CallStaticVoidMethod第一个参数为jclass,否则为jobject,因为静态方法或静态变量为类所有,不为特定对象所有。mObject,msg, ext1, ext2, jParcel作为Java层的函数参数传入。

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (obj && obj->dataSize() > 0) {
        jobject jParcel = createJavaParcelObject(env);
        if (jParcel != NULL) {
            Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
            nativeParcel->setData(obj->data(), obj->dataSize());
            env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                    msg, ext1, ext2, jParcel);
            env->DeleteLocalRef(jParcel);
        }
    } else {
        env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                msg, ext1, ext2, NULL);
    }
    if (env->ExceptionCheck()) {
        ALOGW("An exception occurred while notifying an event.");
        LOGW_EX(env);
        env->ExceptionClear();
    }
}

  Java层的postEventFromNative函数中,首先把native_setup传到C++层的MediaPlayer弱引用捞上来,获得对应的MediaPlayer对象。最后,将what, arg1, arg2, obj参数封装成一个Message发送出去。

/frameworks/base/media/java/android/media/MediaPlayer.java

private static void postEventFromNative(Object mediaplayer_ref,
                                            int what, int arg1, int arg2, Object obj)
    {
        MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get();
        if (mp == null) {
            return;
        }

        if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
            // this acquires the wakelock if needed, and sets the client side state
            mp.start();
        }
        if (mp.mEventHandler != null) {
            Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
            mp.mEventHandler.sendMessage(m);
        }
    }

  回到android_media_MediaPlayer_native_setup函数中,最后一步是调用setMediaPlayer。GetLongField获取Java层mNativeContext的值,mNativeContext保存的是C++层MediaPlayer的地址。将最新new的MediaPlayer强引用计数加1,将旧的MediaPlaye强引用计数减1,使旧的MediaPlayer自动释放内存。最后,把新的MediaPlayer的地址保存在mNativeContext中。

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
{
    Mutex::Autolock l(sLock);
    sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);
    if (player.get()) {
        player->incStrong((void*)setMediaPlayer);
    }
    if (old != 0) {
        old->decStrong((void*)setMediaPlayer);
    }
    env->SetLongField(thiz, fields.context, (jlong)player.get());
    return old;
}

  至此,MediaPlayer的启动流程介绍完毕。

MediaPlayer和MediaPlayerService的关系

  从mp.setDataSource(“/sdcard/test.mp3”)出发,说明MediaPlayer和MediaPlayer的关系。
  setDataSource最终会调到native函数android_media_MediaPlayer_setDataSourceAndHeaders。

/frameworks/base/media/java/android/media/MediaPlayer.java

public void setDataSource(String path)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        setDataSource(path, null, null);
    }

  MediaHTTPService.createHttpServiceBinderIfNecessary的作用是:如果path是网络路径(”http://”,”https://”或”widevine://”),则返回一个BpMediaHTTPService。由于我们是用的是本地路径,所以该函数返回null。

/frameworks/base/media/java/android/media/MediaPlayer.java

private void setDataSource(String path, String[] keys, String[] values)
            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
        final Uri uri = Uri.parse(path);
        final String scheme = uri.getScheme();
        if ("file".equals(scheme)) {
            path = uri.getPath();
        } else if (scheme != null) {
            // handle non-file sources
            nativeSetDataSource(
                MediaHTTPService.createHttpServiceBinderIfNecessary(path),
                path,
                keys,
                values);
            return;
        }

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

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

  getMediaPlayer返回Java层mNativeContext保存的C++层MediaPlayer的强指针。GetStringUTFChars将Java的字符串转化为C++的字符串。C++层的MediaPlayer实际上是调用setDataSource(null,”/sdcard/test.mp3”,null)。

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

static void
android_media_MediaPlayer_setDataSourceAndHeaders(
        JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path,
        jobjectArray keys, jobjectArray values) {

    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }

    if (path == NULL) {
        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
        return;
    }

    const char *tmp = env->GetStringUTFChars(path, NULL);
    if (tmp == NULL) {  // Out of memory
        return;
    }
    ALOGV("setDataSource: path %s", tmp);

    String8 pathStr(tmp);
    env->ReleaseStringUTFChars(path, tmp);
    tmp = NULL;

    // We build a KeyedVector out of the key and val arrays
    KeyedVector<String8, String8> headersVector;
    if (!ConvertKeyValueArraysToKeyedVector(
            env, keys, values, &headersVector)) {
        return;
    }

    sp<IMediaHTTPService> httpService;
    if (httpServiceBinderObj != NULL) {
        sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
        httpService = interface_cast<IMediaHTTPService>(binder);
    }

    status_t opStatus =
        mp->setDataSource(
                httpService,
                pathStr,
                headersVector.size() > 0? &headersVector : NULL);

    process_media_player_call(
            env, thiz, opStatus, "java/io/IOException",
            "setDataSource failed." );
}

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
{
    Mutex::Autolock l(sLock);
    MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);
    return sp<MediaPlayer>(p);
}

  MediaPlayer::setDataSource函数中,首先会调用getMediaPlayerService去获得MediaPlayerService的BpMediaPlayerService对象。getMediaPlayerService定义在MediaPlayer父类IMediaDeathNotifier的cpp实现文件中。

/frameworks/base/media/jni/android_media_MediaPlayer.cpp

status_t MediaPlayer::setDataSource(
        const sp<IMediaHTTPService> &httpService,
        const char *url, const KeyedVector<String8, String8> *headers)
{
    ALOGV("setDataSource(%s)", url);
    status_t err = BAD_VALUE;
    if (url != NULL) {
        const sp<IMediaPlayerService>& service(getMediaPlayerService());
        if (service != 0) {
            sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
            if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
                (NO_ERROR != player->setDataSource(httpService, url, headers))) {
                player.clear();
            }
            err = attachNewPlayer(player);
        }
    }
    return err;
}

/frameworks/av/media/libmedia/IMediaDeathNotifier.cpp

IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
            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;
}

  MediaPlayerService::create函数创建了MediaPlayerService::Client的弱引用,并添加到SortedVector< wp >。SortedVector是一个排序Vector,排序方法是按里面元素的数值大小进行排序。MediaPlayerService::Client以进程的PID,connId(每次连上MediaPlayerService该值都会加1),audioSessionId,UID等为标识。MediaPlayerService::create函数返回Client的强引用。MediaPlayerService::Client的作用类似于套接字,MediaPlayer的主要功能函数在MediaPlayerService::Client这端能找到同名函数,MediaPlayer通过Client对象,使调用流程从客户端转移到服务端。

/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
        int audioSessionId)
{
    pid_t pid = IPCThreadState::self()->getCallingPid();
    int32_t connId = android_atomic_inc(&mNextConnId);

    sp<Client> c = new Client(
            this, pid, connId, client, audioSessionId,
            IPCThreadState::self()->getCallingUid());

    ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
         IPCThreadState::self()->getCallingUid());

    wp<Client> w = c;
    {
        Mutex::Autolock lock(mLock);
        mClients.add(w);
    }
    return c;
}

  于是,player初始化为MediaPlayerService::Client的强引用。然后调用MediaPlayerService::Client::setDataSource函数。如果传入的url开头为”http://”,”https://”或”rtsp://”(网络内容),则需要检查网络权限。如果传入的url是数据库内容,使用openContentProviderFile函数打开。应用层传下来的url是本地路径,属于第三种情况。

/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;
        }
        setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
        close(fd);
        return mStatus;
    } else {
        player_type playerType = MediaPlayerFactory::getPlayerType(this, url);
        sp<MediaPlayerBase> p = setDataSource_pre(playerType);
        if (p == NULL) {
            return NO_INIT;
        }

        setDataSource_post(p, p->setDataSource(httpService, url, headers));
        return mStatus;
    }
}

  getPlayerType函数根据视频源获取所需要的播放器。

/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp

player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
                                              const char* url) {
    GET_PLAYER_TYPE_IMPL(client, url);
}

  sFactoryMap类型为KeyedVector< player_type,IFactory*>,player_type是枚举类型,列出了播放器的id;IFactory*对应具体的播放器产品接口实现类。每次要添加播放器时,都要添加播放器id和实现类这对键值对到sFactoryMap中来实现注册。

/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp

#define GET_PLAYER_TYPE_IMPL(a...)                      \
    Mutex::Autolock lock_(&sLock);                      \
                                                        \
    player_type ret = STAGEFRIGHT_PLAYER;               \
    float bestScore = 0.0;                              \
                                                        \
    for (size_t i = 0; i < sFactoryMap.size(); ++i) {   \
                                                        \
        IFactory* v = sFactoryMap.valueAt(i);           \
        float thisScore;                                \
        CHECK(v != NULL);                               \
        thisScore = v->scoreFactory(a, bestScore);      \
        if (thisScore > bestScore) {                    \
            ret = sFactoryMap.keyAt(i);                 \
            bestScore = thisScore;                      \
        }                                               \
    }                                                   \
                                                        \
    if (0.0 == bestScore) {                             \
        ret = getDefaultPlayerType();                   \
    }                                                   \
                                                        \
    return ret;

/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.cpp

  virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                               const char* url,
                               float /*curScore*/) {
        if (legacyDrm() && !strncasecmp("widevine://", url, 11)) {
            return 1.0;
        }
        return 0.0;
    }

/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.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,
};

  MediaPlayerFactory是一个工厂类,MediaPlayerFactory::IFactory是一个抽象基类,同时也是一个接口类。产品接口实现类在MediaPlayerFactory.cpp中,分别是tagefrightPlayerFactory,NuPlayerFactory和TestPlayerFactory。它们均继承自IFactory,并各自实现了scoreFactory和createPlayer方法,scoreFactory定义了规则来帮助选取合适的播放器,createPlayer直接创建播放器的实例。所以,MediaPlayerFactory::getPlayerType是一个工厂方法,只需传入额外的url参数就能选取到合适的播放器。

/frameworks/av/media/libmediaplayerservice/MediaPlayerFactory.h

class MediaPlayerFactory {
  public:
    class IFactory {
      public:
        virtual ~IFactory() { }

        virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                                   const char* /*url*/,
                                   float /*curScore*/) { return 0.0; }

        virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                                   int /*fd*/,
                                   int64_t /*offset*/,
                                   int64_t /*length*/,
                                   float /*curScore*/) { return 0.0; }

        virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                                   const sp<IStreamSource> &/*source*/,
                                   float /*curScore*/) { return 0.0; }

        virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
                                   const sp<DataSource> &/*source*/,
                                   float /*curScore*/) { return 0.0; }

        virtual sp<MediaPlayerBase> createPlayer(pid_t pid) = 0;
    };
    ...

  接着回到MediaPlayerService::Client::setDataSource函数中,createPlayer创建了具体的播放器实例。mp3文件使用的播放器id为STAGEFRIGHT_PLAYER,所以这里直接跳过细节,假设createPlayer(playerType)返回的是StagefrightPlayer对象指针。

/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

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);
    if (p == NULL) {
        return p;
    }

    if (!p->hardwareOutput()) {
        Mutex::Autolock l(mLock);
        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
                mPid, mAudioAttributes);
        static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
    }

    return p;
}

  MediaPlayerService::Client::setDataSource的最后一步是调用setDataSource_post,p->setDataSource(httpService, url, headers)这步是播放器真正解析数据的过程,setDataSource_post函数还将MediaPlayerService的mPlayer成员设为播放器对象指针。StagefrightPlayer的mPlayer指向一个AwesomePlayer对象,AwesomePlayer::setDataSource将url保存在struct Stats类型的成员变量mStats的mURI成员中,这样便完成了播放器数据源的设置。

/frameworks/av/media/libmediaplayerservice/StagefrightPlayer.cpp

StagefrightPlayer::StagefrightPlayer()
    : mPlayer(new AwesomePlayer) {
    ALOGV("StagefrightPlayer");

    mPlayer->setListener(this);
}

/frameworks/av/media/libmediaplayerservice/StagefrightPlayer.cpp

status_t StagefrightPlayer::setDataSource(
        const sp<IMediaHTTPService> &httpService,
        const char *url,
        const KeyedVector<String8, String8> *headers) {
    return mPlayer->setDataSource(httpService, url, headers);
}

/frameworks/av/media/libstagefright/AwesomePlayer.cpp

status_t AwesomePlayer::setDataSource(
        const sp<IMediaHTTPService> &httpService,
        const char *uri,
        const KeyedVector<String8, String8> *headers) {
    Mutex::Autolock autoLock(mLock);
    return setDataSource_l(httpService, uri, headers);
}

/frameworks/av/media/libstagefright/AwesomePlayer.cpp

status_t AwesomePlayer::setDataSource(
        const sp<IMediaHTTPService> &httpService,
        const char *uri,
        const KeyedVector<String8, String8> *headers) {
    Mutex::Autolock autoLock(mLock);
    return setDataSource_l(httpService, uri, headers);
}

status_t AwesomePlayer::setDataSource_l(
        const sp<IMediaHTTPService> &httpService,
        const char *uri,
        const KeyedVector<String8, String8> *headers) {
    reset_l();

    mHTTPService = httpService;
    mUri = uri;

    if (headers) {
        mUriHeaders = *headers;

        ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
        if (index >= 0) {
            // Browser is in "incognito" mode, suppress logging URLs.

            // This isn't something that should be passed to the server.
            mUriHeaders.removeItemsAt(index);

            modifyFlags(INCOGNITO, SET);
        }
    }

    ALOGI("setDataSource_l(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str());

    // The actual work will be done during preparation in the call to
    // ::finishSetDataSource_l to avoid blocking the calling thread in
    // setDataSource for any significant time.

    {
        Mutex::Autolock autoLock(mStatsLock);
        mStats.mFd = -1;
        mStats.mURI = mUri;
    }

    return OK;
}

猜你喜欢

转载自blog.csdn.net/invoker123/article/details/77814663