zoukankan      html  css  js  c++  java
  • [hanchao3c]Android的MediaPlayer架构介绍 + 补充

    难得一见的好文章,转了:

    http://doc.chinaunix.net/android/200904/164098.shtml

    感谢hanchao3c!


    ==============================================================================

    【内容导航】

    • 第1页:第一部分 MediaPlayer概述
    • 第2页:第二部分 MediaPlayer的接口与架构
    • 第3页:第三部分 MediaPlayer的主要实现分析

      本文主要介绍的是Android中很重要也最为复杂的媒体播放器(MediaPlayer)部分的架构。对于Android这样一个完整又相对复杂的系统,一个MediaPlayer功能的实现不在其具体的功能,而是具体功能如何适应Android系统Android MediaPlayer的主要具体实现在OpenCorePlayer中,这部分不是本文的关注点。本文关注的是MediaPlayer系统的架构,其他的一些Android的应用程序也使用类似的架构。

           对于开源事业在中国的发展,hanchao3c认为应该共享的不仅仅是代码,文档、设计思想、理念甚至对于技术的理解都应该得到充分的共享。Android为中国人进入大规模的开源项目提了很好的机遇,对于走在技术前沿的人们,不应将技术视为私有财产,而应该将自己理解更好地奉献给大众,提高大众的学习速度,从中也可以得到反馈,从而促进自己的进步。仅以此文奉献给所有关系技术的朋友,希望可以抛砖引玉,促进我们共同的技术进步!

    第一部分 MediaPlayer概述

            Android
    MediaPlayer包含了Audiovideo的播放功能,在Android的界面上,MusicVideo两个应用程序都是调用MediaPlayer实现的。

            MediaPlayer
    底层是基于OpenCore(PacketVideo)的库实现的,为了构建一个MediaPlayer程序,上层还包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制。

    以开源的Android为例MediaPlayer的代码主要在以下的目录中:
    JAVA程序的路径:
    packages/apps/Music/src/com/android/music/



    JAVA类的路径:
    frameworks/base/media/java/android/media/MediaPlayer.java

    JAVA本地调用部分(JNI):
    frameworks/base/media/jni/android_media_MediaPlayer.cpp
    这部分内容编译成为目标是libmedia_jni.so

    主要的头文件在以下的目录中:
    frameworks/base/include/media/

    多媒体底层库在以下的目录中:
    frameworks/base/media/libmedia/ 
    这部分的内容被编译成库libmedia.so

    多媒体服务部分:
    frameworks/base/media/libmediaplayerservice/
    文件为mediaplayerservice.h和mediaplayerservice.cpp
    这部分内容被编译成库libmediaplayerservice.so

    基于OpenCore的多媒体播放器部分 
    external/opencore/
    这部分内容被编译成库libopencoreplayer.so

            从程序规模上来看,libopencoreplayer.so是主要的实现部分,而其他的库基本上都是在其上建立的封装和为建立进程间通讯的机制。



    第二部分 MediaPlayer的接口与架构

    2.1 整体框架图
            MediaPlayer的各个库之间的结构比较复杂,可以用下图的表示

        在各个库中,libmedia.so位于核心的位置,它对上层的提供的接口主要是MediaPlayer类,类libmedia_jni.so通过调用MediaPlayer类提供对JAVA的接口,并且实现了android.media.MediaPlayer类。
    libmediaplayerservice.soMedia的服务器,它通过继承libmedia.so的类实现服务器的功能,而libmedia.so中的另外一部分内容则通过进程间通讯和libmediaplayerservice.so进行通讯。libmediaplayerservice.so的真正功能通过调用OpenCore Player来完成。

        MediaPlayer
    部分的头文件在frameworks/base/include/media/目录中,这个目录是和libmedia.so库源文件的目录frameworks/base/media/libmedia/相对应的。主要的头文件有以下几个:


    IMediaPlayerClient.h
    mediaplayer.h 
    IMediaPlayer.h
    IMediaPlayerService.h
    MediaPlayerInterface.h


        在这些头文件mediaplayer.h提供了对上层的接口,而其他的几个头文件都是提供一些接口类(即包含了纯虚函数的类),这些接口类必须被实现类继承才能够使用。
        整个MediaPlayer库和调用的关系如下图所示:

            整个MediaPlayer在运行的时候,可以大致上分成ClientServer两个部分,它们分别在两个进程中运行,它们之间使用Binder机制实现IPC通讯。从框架结构上来看,IMediaPlayerService.hIMediaPlayerClient.hMediaPlayer.h三个类定义了MeidaPlayer的接口和架构,MediaPlayerService.cppmediaplayer.coo两个文件用于MeidaPlayer架构的实现,MeidaPlayer的具体功能在PVPlayer(库libopencoreplayer.so)中的实现。

    2.2 头文件IMediaPlayerClient.h    
            IMediaPlayerClient.h
    用于描述一个MediaPlayer客户端的接口,描述如下所示:
    class IMediaPlayerClient: public IInterface
    {
    public:
        DECLARE_META_INTERFACE(MediaPlayerClient);
        virtual void notify(int msg, int ext1, int ext2) = 0;
    };


    class BnMediaPlayerClient: public BnInterface<IMediaPlayerClient>
    {
    public:

        virtual status_t  onTransact( uint32_t code,

                                      const Parcel& data,

                                      Parcel* reply,

                                      uint32_t flags = 0);

    };
            在定义中,IMediaPlayerClient类继承IInterface,并定义了一个MediaPlayer客户端的接口,BnMediaPlayerClient继承了BnInterface<IMediaPlayerClient>这是为基于Android的基础类Binder机制实现在进程通讯而构建的。事实上根据BnInterface类模版的定义BnInterface<IMediaPlayerClient>类相当于双继承了BnInterfaceImediaPlayerClient。这是Android一种常用的定义方式。

    2.3 头文件mediaplayer.h
            mediaplayer.h
    是对外的接口类它最主要是定义了一个MediaPlayer
    class MediaPlayer : public BnMediaPlayerClient
    {
    public:

        MediaPlayer();

        ~MediaPlayer();

        void onFirstRef();

        void disconnect();

        status_t    setDataSource(const char *url);
        status_t    setDataSource(int fd, int64_t offset, int64_t length);
        status_t    setVideoSurface(const sp<Surface>& surface);
        status_t    setListener(const sp<MediaPlayerListener>& listener);
        status_t    prepare();
        status_t    prepareAsync();
        status_t    start();
        status_t    stop();
        status_t    pause();
        bool        isPlaying();
        status_t    getVideoWidth(int *w);
        status_t    getVideoHeight(int *h);
        status_t    seekTo(int msec);
        status_t    getCurrentPosition(int *msec);
        status_t    getDuration(int *msec);
        status_t    reset();
        status_t    setAudioStreamType(int type);
        status_t    setLooping(int loop);
        status_t    setVolume(float leftVolume, float rightVolume);
        void    notify(int msg, int ext1, int ext2);
        static    sp<IMemory>    decode(const char* url, uint32_t *pSampleRate, int* pNumChannels);
        static    sp<IMemory>    decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels);
    //……
    }

        从接口中可以看出MediaPlayer类刚好实现了一个MediaPlayer的基本操作,例如播放(start)、停止(stop)、暂停(pause)等。
        另外的一个类DeathNotifierMediaPlayer类中定义,它继承了IBinder类中的DeathRecipient类:
    class DeathNotifier: public IBinder:: DeathRecipient
    {
    public:
        DeathNotifier() {}
        virtual ~DeathNotifier();
        virtual void binderDied(const wp<IBinder>& who);
    };
            事实上,MediaPlayer类正是间接地继承了IBinder,而MediaPlayer:: DeathNotifier类继承了IBinder:: DeathRecipient,这都是为了实现进程间通讯而构建的。

    2.4 头文件IMediaPlayer.h
            IMediaPlayer.h
    主要的的内容是一个实现MediaPlayer功能的接口,它的主要定义如下所示:
    class IMediaPlayer: public IInterface
    {
    public:
        DECLARE_META_INTERFACE(MediaPlayer);
        virtual void    disconnect() = 0;
        virtual status_t    setVideoSurface(const sp<ISurface>& surface) = 0;
        virtual status_t    prepareAsync() = 0;
        virtual status_t    start() = 0;
        virtual status_t    stop() = 0;
        virtual status_t    pause() = 0;
        virtual status_t    isPlaying(bool* state) = 0;
        virtual status_t    getVideoSize(int* w, int* h) = 0;
        virtual status_t    seekTo(int msec) = 0;
        virtual status_t    getCurrentPosition(int* msec) = 0;
        virtual status_t    getDuration(int* msec) = 0;
        virtual status_t    reset() = 0;
        virtual status_t    setAudioStreamType(int type) = 0;
        virtual status_t    setLooping(int loop) = 0;
        virtual status_t    setVolume(float leftVolume, float rightVolume) = 0;
    };
    class BnMediaPlayer: public BnInterface<IMediaPlayer>
    {
    public:
        virtual status_t    onTransact( uint32_t code,
                                        const Parcel& data,    

                                        Parcel* reply,

                                        uint32_t flags = 0);
    };

            IMediaPlayer类中,主要定义MediaPlayer的功能接口,这个类必须被继承才能够使用。值得注意的是,这些接口和MediaPlayer类的接口有些类似,但是它们并没有直接的关系。事实上,在MediaPlayer类的各种实现中,一般都会通过调用IMediaPlayer类的实现类来完成。


    2.5 头文件IMediaPlayerService.h
            IMediaPlayerService.h用于描述一个MediaPlayer的服务,定义方式如下所示:
    class IMediaPlayerService: public IInterface
    {
    public:
        DECLARE_META_INTERFACE(MediaPlayerService);

        virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) = 0;

        virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;

        virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels) = 0;

        virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels) = 0;
    };
    class BnMediaPlayerService: public BnInterface<IMediaPlayerService>
    {
    public:
        virtual status_t    onTransact( uint32_t code,
                                        const Parcel& data,
                                        Parcel* reply,
                                        uint32_t flags = 0);
    };


        由于具有纯虚函数,IMediaPlayerService 以及BnMediaPlayerService必须被继承实现才能够使用,在IMediaPlayerService定义的createdecode等接口,事实上是必须被继承者实现的内容。注意,create的返回值的类型是sp<IMediaPlayer>,这个IMediaPlayer正是提供实现功能的接口。



    第三部分 MediaPlayer的主要实现分析

    3.1 JAVA程序部分
        在packages/apps/Music/src/com/android/music/目录的MediaPlaybackService.java文件中,包含了对MediaPlayer的调用。
        在MediaPlaybackService.java中包含对包的引用:
    import android.media.MediaPlayer;
        在MediaPlaybackService类的内部,定义了MultiPlayer类:
    private class MultiPlayer {
        private MediaPlayer mMediaPlayer = new MediaPlayer();
    }

        MultiPlayer
    类中使用了MediaPlayer类,其中有一些对这个MediaPlayer的调用,调用的过程如下所示:
        mMediaPlayer.reset();
        mMediaPlayer.setDataSource(path);
        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

        resetsetDataSourcesetAudioStreamType等接口就是通过JAVA本地调用(JNI)来实现的。

    3.2 MediaPlayer的JAVA本地调用部分
        MediaPlayer
    JAVA本地调用部分在目录frameworks/base/media/jni/android_media_MediaPlayer.cpp中的文件中实现。
        android_media_MediaPlayer.cpp之中定义了一个JNINativeMethodJAVA本地调用方法)类型的数组gMethods,如下所示:
    static JNINativeMethod gMethods[] = {

    {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource},


    {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},

        {"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},
        {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo},
        {"_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},
        {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
        {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
        {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},
        {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
        {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
    }
            JNINativeMethod的第一个成员是一个字符串,表示了JAVA本地调用方法的名称,这个名称是在JAVA程序中调用的名称;第二个成员也是一个字符串,表示JAVA本地调用方法的参数和返回值;第三个成员是JAVA本地调用方法对应的C语言函数。
        其中android_media_MediaPlayer_reset函数的实现如下所示:
    static void android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
    {
        sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
        if (mp == NULL ) {
            jniThrowException(env, "java/lang/IllegalStateException", NULL);
            return;
        }
        process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
    }

        在android_media_MediaPlayer_reset的调用中,得到一个MediaPlayer指针,通过对它的调用实现实际的功能。
            register_android_media_MediaPlayer用于将gMethods注册为的类"android/media/MediaPlayer",其实现如下所示。
    static int register_android_media_MediaPlayer(JNIEnv *env)
    {
        jclass clazz;
        clazz = env->FindClass("android/media/MediaPlayer");
    // ......
        return AndroidRuntime::registerNativeMethods(env, "android/media/MediaPlayer", gMethods, NELEM(gMethods));
    }


        "android/media/MediaPlayer"
    对应JAVA的类android.media.MediaPlayer
     

    3.3 mediaplayer的核心库libmedia.so
        libs/media/mediaplayer.cpp
    文件用于实现mediaplayer.h提供的接口,其中一个重要的片段如下所示:
    const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
    {
        Mutex::Autolock _l(mServiceLock);
        if (mMediaPlayerService.get() == 0) {
            sp<IServiceManager> sm = defaultServiceManager();
            sp<IBinder> binder;
        do {
            binder = sm->getService(String16("media.player"));
            if (binder != 0)
            break;
            LOGW("MediaPlayerService not published, waiting...");
            usleep(500000); // 0.5 s
            } while(true);
            if (mDeathNotifier == NULL) {
            mDeathNotifier = new DeathNotifier();
        }
            binder->linkToDeath(mDeathNotifier);
            mMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
        }
        LOGE_IF(mMediaPlayerService==0, "no MediaPlayerService!?");
        return mMediaPlayerService;
    }

          其中最重要的一点是binder = sm->getService(String16("media.player"));这个调用用来得到一个名称为"media.player"的服务,这个调用返回值的类型为IBinder,根据实现将其转换成类型IMediaPlayerService使用。
           一个具体的函数setDataSource如下所示:
    status_t MediaPlayer::setDataSource(const char *url)
    {
        LOGV("setDataSource(%s)", url);
        status_t err = UNKNOWN_ERROR;
        if (url != NULL) {
            const sp<IMediaPlayerService>& service(getMediaPlayerService());
            if (service != 0) {
                sp<IMediaPlayer> player(service->create(getpid(), this, url));
                err = setDataSource(player);
            }
        }
        return err;
    }
        在函数setDataSource函数中,调用getMediaPlayerService得到了一个IMediaPlayerService,又从IMediaPlayerService中得到了IMediaPlayer类型的指针,通过这个指针进行着具体的操作。
        其他一些函数的实现也与setDataSource类似。
            libmedia.so中的其他一些文件与头文件的名称相同,它们是:
    libs/media/IMediaPlayerClient.cpp
    libs/media/IMediaPlayer.cpp
    libs/media/IMediaPlayerService.cpp 
         为了实现Binder的具体功能,在这些类中还需要实现一个BpXXX的类,例如IMediaPlayerClient.cpp的实现如下所示:l
    class BpMediaPlayerClient: public BpInterface<IMediaPlayerClient>
    {
    public:
        BpMediaPlayerClient(const sp<IBinder>& impl)
        : BpInterface<IMediaPlayerClient>(impl){}
        virtual void notify(int msg, int ext1, int ext2)
        {
            Parcel data, reply;
            data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());
            data.writeInt32(msg);
            data.writeInt32(ext1);
            data.writeInt32(ext2);
            remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
        }
    };

            还需要实现定义宏IMPLEMENT_META_INTERFACE,这个宏将被展开,生成几个函数:
    IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient");
            以上的实现都是基于Binder框架的实现方式,只需要按照模版实现即可。其中BpXXX的类为代理类(proxy),BnXXX的类为本地类(native)。代理类的transact函数和本地类的onTransact函数实现对应的通讯。

    3.4 media服务libmediaservice.so
        frameworks/base/media\libmediaplayerservice
    目录中的MediaPlayerService.hMediaPlayerService.cpp用于实现一个
    servers/media/的服务,MediaPlayerService是继承BnMediaPlayerService的实现,在这个类的内部又定义了类ClientMediaPlayerService::Client继承了BnMediaPlayer
    class MediaPlayerService : public BnMediaPlayerService
    {
        class Client : public BnMediaPlayer
    }
        MediaPlayerService中具有如下一个静态函数instantiate
    void MediaPlayerService::instantiate() {
        defaultServiceManager()->addService(
        String16("media.player"), new MediaPlayerService());
    }
        在instantiate函数中,调用IServiceManager的一个函数addService,向其中增加了一个名为"media.player"的服务。
        这个名为"media.player"的服务和mediaplayer.cpp中调用getService中得到的使用一样名称。因此,在这里调用addService增加服务在mediaplayer.cpp中可以按照名称"media.player"来使用。这就是使用Binder实现进程间通讯的(IPC)的作用,事实上这个MediaPlayerService类是在服务中运行的,而mediaplayer.cpp调用的功能在应用中运行,二者并不是一个进程。但是在mediaplayer.cpp却像一个进程的调用一样调用MediaPlayerService的功能。
        MediaPlayerService.cpp中的createPlayer函数如下所示:
    static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
        notify_callback_f notifyFunc)
    {
        sp<MediaPlayerBase> p;
        switch (playerType) {
            case PV_PLAYER:
                LOGV(" create PVPlayer");
                p = new PVPlayer();
                break;
            case SONIVOX_PLAYER:
                LOGV(" create MidiFile");
                p = new MidiFile();
                break;
            case VORBIS_PLAYER:
                LOGV(" create VorbisPlayer");
                p = new VorbisPlayer();
                break;
        }
    //……
        return p;
    }

        在这里根据playerType的类型建立不同的播放器:对于大多数情况,类型将是PV_PLAYER,这时会调用了new PVPlayer()建立一个PVPlayer,然后将其指针转换成MediaPlayerBase来使用;对于Mini文件的情况,类型为SONIVOX_PLAYER,将会建立一个MidiFile;对于Ogg Vorbis格式的情况,将会建立一个VorbisPlayer
         (OGG Vobis是一种音频压缩格式,与MP3等的音乐格式类似,它具有完全免费、开放和没有专利限制的特点。)
        值得注意的是PVPlayerMidiFileVorbisPlayer三个类都是继承MediaPlayerInterface得到的,而MediaPlayerInterface又是继承MediaPlayerBase得到的,因此三者具有相同接口类型。只有建立的时候会调用各自的构造函数,在建立之后,将只通过MediaPlayerBase接口来MediaPlayerBase控制它们。
        frameworks/base/media/libmediaplayerservice目录中,MidiFile.hMidiFile.cpp的实现MidiFileVorbisPlayer.hVorbisPlayer.cpp实现一个VorbisPlayer

    3.5 OpenCorePlayer的实现libopencoreplayer.so 
           OpenCore Playerexternal/opencore/中实现,这个实现是一个基于OpenCorePlayer的实现。具体实现的文件为playerdriver.cpp。其中实现了两个类:PlayerDriverPVPlayerPVPlayer通过调用PlayerDriver的函数实现具体的功能。










    补充:

    一 、类图扩充


    图1

            Binder代理,本地接口
            类图中加入了Bp<Interface>的代理类:BpMediaPlayer,BpMediaPlayerService。这些类和相应的Bn<Interface>互相配对,Bp<Interface>客户端代理接口,而Bn<Interface>实现服务端本地接口。
    拿BxMediaPlayer来举例:BpMediaPlayer继承BpInterface<IMediaPlayer>,并重载实现IMediaPlayer接口的所有方法,这些方法包括start(), stop(),pause()等等。在这些重载方法中,实现client<->server的服务协议,利用remote()->transact()发送请求ID(enum结构),请求附带数据并获得调用结果(reply)。然后由宏IMPLEMENT_META_INTERFACE(MediaPlayer,"android.hardware.IMediaPlayer”) 将BpMediaPlayer和静态方法IMediaPlayer::asInterface(constsp<IBinder>& obj)相关联。你在代码里看不到有代码去实例化BpMediaPlayer,其实是在asInterface里做的,并且由interface_cast模板函数实现:

    Template<typename INTERFACE>
    inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
    {
        return INTERFACE::asInterface(obj);
    }
    	
    具体的interface_cast的用法,可以在BpMediaPlayerService::create()里看到:
    virtual sp<IMediaPlayer> create(pid_t pid, constsp<IMediaPlayerClient>& client, const char* url
    {
            Parcel data, reply;
            data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
            data.writeInt32(pid);
            data.writeStrongBinder(client->asBinder());
            data.writeCString(url);
            remote()->transact(CREATE_URL,data, &reply);
            returninterface_cast<IMediaPlayer>(reply.readStrongBinder());
    }


            该create函数,实际是mediaplayer client实例在请求MediaPlayerService获取一个MediaPlayer服务接口时,BpMediaPlayerService代理返回的interface_cast过后得到的BpMediaPlayer实例。
            因此,如果某个service需要走IPC层(也就是服务提供者和请求者不在同一个进程里),那么这个服务需要暴露的IXXXXInterface必然被BpXX/BnXX两个类实现(继承),Bp用在客户端,Bn用在服务端。客户端获取服务接口类的类型虽然是IXXXX,但实际上利用C++的多态机制,得到的是BpXX的类型。

            各个类之间关系

            MediaPlayer(MediaPlayerClient)对象从MediaPlayerService获取的player,实际上是BpMediaPlayer实例,并保存在它的mPlayer成员变量中。对应的在MediaPlayerService实例中,MediaPlayerClient申请,并创建的player对象会被放入clients成员向量中,该向量实际上是BnMediaPlayer的对象容器。每个client对象都有自己的mPlayer成员变量,保存的则是OpenCORE创建的PVPlayer对象。这里有两个mPlayer成员变量,各自代表不同类型,不要混淆。

    二、通过MediaPlayer获得service player时序图
            以setDataSource接口为例:

    图2
            使用MediaPlayer的App,可以通过setDataSource来获得(创建)一个player对象,并保存在mPlayer成员中。大概的时序:MediaPlayer首先创建一个service代理对象BpMediaPlayerService,通过该代理对象的create()方法去call IPC,对MediaPlayerService发出创建player的请求。BnMediaPlayerService则在获取IPC的调用请求后,直接调用MediaPlayerService的create方法,分配一个Client对象,然后通过IPC返回该client对象的asBinder()的返回结果。BpMediaPlayerService在得到BnMediaPlayerService返回的client->asBinder()的reply后,会利用readStrongBinder()去读出IBinder对象,将其作为参数调用interface_cast创建一个BpMediaPlayer。(IBinder对象内部到底记录了些什么,目前还没研究:))得到了BpMediaPlayer的MediaPlayer对象,将其保存入mPlayer,之后App就可以调用其完成一些列操作。

    三、使用serviceplayer时序图

    图3



            以上的时序图,描述的是之前获得的mPlayer的使用时序。这个时序比较简单,这里不做详细说明,需要注意的是图最右侧,Client对象实际要通过创建和调用OpenCORE里的PVPlayer来最终实现多媒体播放功能。
    图4



    Meet so Meet. C plusplus I-PLUS....
  • 相关阅读:
    linux sysfs (2)
    微软——助您启动云的力量网络虚拟盛会
    Windows Azure入门教学系列 全面更新啦!
    与Advanced Telemetry创始人兼 CTO, Tom Naylor的访谈
    Windows Azure AppFabric概述
    Windows Azure Extra Small Instances Public Beta版本发布
    DataMarket 一月内容更新
    和Steve, Wade 一起学习如何使用Windows Azure Startup Tasks
    现实世界的Windows Azure:与eCraft的 Nicklas Andersson(CTO),Peter Löfgren(项目经理)以及Jörgen Westerling(CCO)的访谈
    正确使用Windows Azure 中的VM Role
  • 原文地址:https://www.cnblogs.com/iplus/p/4467429.html
Copyright © 2011-2022 走看看