精华内容
下载资源
问答
  • Android MediaPlayer

    2017-07-30 22:19:14
    Android MediaPlayer
  • android mediaPlayer

    2009-12-01 23:10:47
    android mediaPlayer android mediaPlayer
  • Android mediaplayer

    千次阅读 2012-10-19 09:48:50
    Android mediaplayer 文主要介绍的是Android中很重要也最为复杂的媒体播放器(MediaPlayer)部分的架构。对于Android这样一个完整又相对复杂的系统,一个MediaPlayer功能的实现不在其具体的功能,而是具体功能如何...
    
    

    Android mediaplayer

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

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

    第一部分 MediaPlayer概述
    Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用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的各个库之间的结构比较复杂,可以用下图的表示

     

    MediaPlayer的各个库之间的结构

    在各个库中,libmedia.so位于核心的位置,它对上层的提供的接口主要是MediaPlayer类,类libmedia_jni.so通过调用 MediaPlayer类提供对JAVA的接口,并且实现了android.media.MediaPlayer类。
    libmediaplayerservice.so是Media的服务器,它通过继承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库和调用的关系

    整个MediaPlayer在运行的时候,可以大致上分成Client和Server两个部分,它们分别在两个进程中运行,它们之间使用Binder机制实现IPC通讯。从框架结构上来看,IMediaPlayerService.h、IMediaPlayerClient.h和 MediaPlayer.h三个类定义了MeidaPlayer的接口和架构,MediaPlayerService.cpp和 mediaplayer.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
    {
    public:
    virtual status_t onTransact( uint32_t code,
    const Parcel& data,
    Parcel* reply,
    uint32_t flags = 0);
    };
    在定义中,IMediaPlayerClient类继承IInterface,并定义了一个MediaPlayer客户端的接口,BnMediaPlayerClient继承了BnInterface,这是为基于Android的基础类Binder机制实现在进程通讯而构建的。事实上,根据BnInterface类模版的定义BnInterface类相当于双继承了BnInterface和 ImediaPlayerClient。这是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);
    status_t setListener(const sp& 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 decode(const char* url, uint32_t *pSampleRate, int* pNumChannels);
    static sp decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels);
    //……
    }
    从接口中可以看出MediaPlayer类刚好实现了一个MediaPlayer的基本操作,例如播放(start)、停止(stop)、暂停(pause)等。
    另外的一个类DeathNotifier在MediaPlayer类中定义,它继承了IBinder类中的DeathRecipient类:
    class DeathNotifier: public IBinder:: DeathRecipient
    {
    public:
    DeathNotifier() {}
    virtual ~DeathNotifier();
    virtual void binderDied(const wp& 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& 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
    {
    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 create(pid_t pid, const sp& client, const char* url) = 0;
    virtual sp create(pid_t pid, const sp& client, int fd, int64_t offset, int64_t length) = 0;
    virtual sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels) = 0;
    virtual sp decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels) = 0;
    };
    class BnMediaPlayerService: public BnInterface
    {
    public:
    virtual status_t onTransact( uint32_t code,
    const Parcel& data,
    Parcel* reply,
    uint32_t flags = 0);
    };

    由于具有纯虚函数,IMediaPlayerService 以及BnMediaPlayerService必须被继承实现才能够使用,在IMediaPlayerService定义的create和decode等接口,事实上是必须被继承者实现的内容。注意,create的返回值的类型是sp,这个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);
    reset、setDataSource和setAudioStreamType等接口就是通过JAVA本地调用(JNI)来实现的。

    3.2 MediaPlayer的JAVA本地调用部分
    MediaPlayer的JAVA本地调用部分在目录frameworks/base/media/jni/的android_media_MediaPlayer.cpp中的文件中实现。
    android_media_MediaPlayer.cpp之中定义了一个JNINativeMethod(JAVA本地调用方法)类型的数组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 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& MediaPlayer::getMediaPlayerService()
    {
    Mutex::Autolock _l(mServiceLock);
    if (mMediaPlayerService.get() == 0) {
    sp sm = defaultServiceManager();
    sp 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(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& service(getMediaPlayerService());
    if (service != 0) {
    sp 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
    {
    public:
    BpMediaPlayerClient(const sp& impl)
    : BpInterface(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.h和MediaPlayerService.cpp用于实现一个
    servers/media/的服务,MediaPlayerService是继承BnMediaPlayerService的实现,在这个类的内部又定义了类Client,MediaPlayerService::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 createPlayer(player_type playerType, void* cookie,
    notify_callback_f notifyFunc)
    {
    sp 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等的音乐格式类似,它具有完全免费、开放和没有专利限制的特点。)
    值得注意的是PVPlayer、MidiFile和VorbisPlayer三个类都是继承MediaPlayerInterface得到的,而 MediaPlayerInterface又是继承MediaPlayerBase得到的,因此三者具有相同接口类型。只有建立的时候会调用各自的构造函数,在建立之后,将只通过MediaPlayerBase接口来MediaPlayerBase控制它们。
    在frameworks/base/media/libmediaplayerservice目录中,MidiFile.h和MidiFile.cpp的实现MidiFile,VorbisPlayer.h和VorbisPlayer.cpp实现一个VorbisPlayer。

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

    展开全文
  • android mediaplayer

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

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

    第一部分 MediaPlayer概述 
    Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用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的各个库之间的结构比较复杂,可以用下图的表示 

     

    MediaPlayer的各个库之间的结构 

    在各个库中,libmedia.so位于核心的位置,它对上层的提供的接口主要是MediaPlayer类,类libmedia_jni.so通过调用 MediaPlayer类提供对JAVA的接口,并且实现了android.media.MediaPlayer类。 
    libmediaplayerservice.so是Media的服务器,它通过继承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库和调用的关系 

    整个MediaPlayer在运行的时候,可以大致上分成Client和Server两个部分,它们分别在两个进程中运行,它们之间使用Binder机制实现IPC通讯。从框架结构上来看,IMediaPlayerService.h、IMediaPlayerClient.h和 MediaPlayer.h三个类定义了MeidaPlayer的接口和架构,MediaPlayerService.cpp和 mediaplayer.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 

    public: 
    virtual status_t onTransact( uint32_t code, 
    const Parcel& data, 
    Parcel* reply, 
    uint32_t flags = 0); 
    }; 
    在定义中,IMediaPlayerClient类继承IInterface,并定义了一个MediaPlayer客户端的接口,BnMediaPlayerClient继承了BnInterface,这是为基于Android的基础类Binder机制实现在进程通讯而构建的。事实上,根据BnInterface类模版的定义BnInterface类相当于双继承了BnInterface和 ImediaPlayerClient。这是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); 
    status_t setListener(const sp& 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 decode(const char* url, uint32_t *pSampleRate, int* pNumChannels); 
    static sp decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels); 
    //…… 

    从接口中可以看出MediaPlayer类刚好实现了一个MediaPlayer的基本操作,例如播放(start)、停止(stop)、暂停(pause)等。 
    另外的一个类DeathNotifier在MediaPlayer类中定义,它继承了IBinder类中的DeathRecipient类: 
    class DeathNotifier: public IBinder:: DeathRecipient 

    public: 
    DeathNotifier() {} 
    virtual ~DeathNotifier(); 
    virtual void binderDied(const wp& 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& 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 

    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 create(pid_t pid, const sp& client, const char* url) = 0; 
    virtual sp create(pid_t pid, const sp& client, int fd, int64_t offset, int64_t length) = 0; 
    virtual sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels) = 0; 
    virtual sp decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels) = 0; 
    }; 
    class BnMediaPlayerService: public BnInterface 

    public: 
    virtual status_t onTransact( uint32_t code, 
    const Parcel& data, 
    Parcel* reply, 
    uint32_t flags = 0); 
    }; 

    由于具有纯虚函数,IMediaPlayerService 以及BnMediaPlayerService必须被继承实现才能够使用,在IMediaPlayerService定义的create和decode等接口,事实上是必须被继承者实现的内容。注意,create的返回值的类型是sp,这个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); 
    reset、setDataSource和setAudioStreamType等接口就是通过JAVA本地调用(JNI)来实现的。 

    3.2 MediaPlayer的JAVA本地调用部分 
    MediaPlayer的JAVA本地调用部分在目录frameworks/base/media/jni/的android_media_MediaPlayer.cpp中的文件中实现。 
    android_media_MediaPlayer.cpp之中定义了一个JNINativeMethod(JAVA本地调用方法)类型的数组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 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& MediaPlayer::getMediaPlayerService() 

    Mutex::Autolock _l(mServiceLock); 
    if (mMediaPlayerService.get() == 0) { 
    sp sm = defaultServiceManager(); 
    sp 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(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& service(getMediaPlayerService()); 
    if (service != 0) { 
    sp 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 

    public: 
    BpMediaPlayerClient(const sp& impl) 
    : BpInterface(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.h和MediaPlayerService.cpp用于实现一个 
    servers/media/的服务,MediaPlayerService是继承BnMediaPlayerService的实现,在这个类的内部又定义了类Client,MediaPlayerService::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 createPlayer(player_type playerType, void* cookie, 
    notify_callback_f notifyFunc) 

    sp 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等的音乐格式类似,它具有完全免费、开放和没有专利限制的特点。) 
    值得注意的是PVPlayer、MidiFile和VorbisPlayer三个类都是继承MediaPlayerInterface得到的,而 MediaPlayerInterface又是继承MediaPlayerBase得到的,因此三者具有相同接口类型。只有建立的时候会调用各自的构造函数,在建立之后,将只通过MediaPlayerBase接口来MediaPlayerBase控制它们。 
    在frameworks/base/media/libmediaplayerservice目录中,MidiFile.h和MidiFile.cpp的实现MidiFile,VorbisPlayer.h和VorbisPlayer.cpp实现一个VorbisPlayer。 

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

    展开全文
  • Android Mediaplayer

    2018-09-11 15:22:31
    frameworks/base/media/java/android/media/MediaPlayer.java JAVA本地调用部分(JNI): frameworks/base/media/jni/android_media_MediaPlayer.cpp 这部分内容编译成为目标是libmedia_jni.so。 主要的头文件在...

    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/av/media/libmedia/
    这部分的内容被编译成库libmedia.so。

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

    int main(int argc __unused, char** argv)
    {
        ...
        InitializeIcuOrDie();  
        //获得ProcessState实例对象
        sp<ProcessState> proc(ProcessState::self());
        //获取ServiceManager实例对象 
        sp<IServiceManager> sm = defaultServiceManager();
        AudioFlinger::instantiate();
    
        MediaPlayerService::instantiate();
        ResourceManagerService::instantiate();
        CameraService::instantiate();
        AudioPolicyService::instantiate();
        SoundTriggerHwService::instantiate();
        RadioService::instantiate();
        registerExtensions();
    
        ProcessState::self()->startThreadPool();
    
        IPCThreadState::self()->joinThreadPool();
     }
    void MediaPlayerService::instantiate() {
        defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService());
    }

    defaultServiceManager

    获取Service Manager远程接口的函数是defaultServiceManager.
    gDefaultServiceManager是单例模式,调用defaultServiceManager函数时,如果gDefaultServiceManager已经创建,
    则直接返回,否则通过interface_cast(ProcessState::self()->getContextObject(NULL))来创建一个,
    并保存在gDefaultServiceManager全局变量中.

    getService接口来获得.Service Manager远程接口是一个特殊的Binder引用,它的引用句柄一定是0。

    ProcessState::ProcessState()
        : mDriverFD(open_driver()) 
        , mVMStart(MAP_FAILED)
        , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
        , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
        , mExecutingThreadsCount(0)
        , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
        , mManagesContexts(false)
        , mBinderContextCheckFunc(NULL)
        , mBinderContextUserData(NULL)
        , mThreadPoolStarted(false)
        , mThreadPoolSeq(1)
    {
        if (mDriverFD >= 0) {
            //采用内存映射函数mmap,给binder分配一块虚拟地址空间,用来接收事务
            mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
            if (mVMStart == MAP_FAILED) {
                close(mDriverFD); //没有足够空间分配给/dev/binder,则关闭驱动
                mDriverFD = -1;
            }
        }
    }

    ProcessState的单例模式的惟一性,因此一个进程只打开binder设备一次,其中ProcessState的成员变量mDriverFD记录binder驱动的fd,用于访问binder设备。

    BINDER_VM_SIZE = (1*1024*1024) - (4096 *2), binder分配的默认内存大小为1M-8k。

    DEFAULT_MAX_BINDER_THREADS = 15,binder默认的最大可并发访问的线程数为16。

    sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
    {
        //获取handle=0的IBinder
        return getStrongProxyForHandle(0);  
    }
    

    interface_cast

    template<typename INTERFACE>
    inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
    {
        return INTERFACE::asInterface(obj);
    }

    对于asInterface()函数,也是通过模板函数来定义的,通过下面两个代码完成的:

    //位于IServiceManager.h文件
    DECLARE_META_INTERFACE(IServiceManager)
    //位于IServiceManager.cpp文件
    IMPLEMENT_META_INTERFACE(ServiceManager,"android.os.IServiceManager")

    IServiceManager::asInterface() 等价于 new BpServiceManager()

    交互

    如果我们要使用MediaPlayerService服务,那么MediaPlayerService客户端就需要与MediaPlayerService
    (即BnMediaPlayerService)交互。交互的过程需要建立一个循环,然后读写Binder设备。注意,
    在BnMediaPlayerService中并没有打开Binder设备和建立一个循环监听,这里实际上是借用ProcessState来完成了MediaPlayerService的一些功能.

    IPCThreadState::self()->joinThreadPool,也就是说,主线程和工作线程都会执行joinThreadPool;
    在该函数中通过talkWithDriver函数操作Binder驱动程序,executeCommand函数来执行命令。
    查看executeCommand的代码可以得知,实际上会根据不同的命令进行不同的解析,
    但是最终的解析还是调用BBinder::transact函数,而transact又调用了自己的BBinder::onTransact函数。
    这里的BnMediaPlayerService继承自BBinder,所以会调用到它自己的BnMediaPlayerService::onTransact函数。

    客户端

    libs/media/mediaplayer.cpp

    class MediaPlayer : public BnMediaPlayerClient,
                        public virtual IMediaDeathNotifier
    const sp<IMediaPlayerService>& service(getMediaPlayerService());  
            if (service != 0) {  
                sp<IMediaPlayer> player(service->create(getpid(), this, url));  
                err = setDataSource(player);  
    展开全文
  • android MediaPlayer

    千次阅读 2014-05-03 13:04:03
    Playback control of audio/video files and streams is managed as a state machine. The following diagram shows the life cycle and the states of a MediaPlayer object driven by the supported playback cont

    Playback control of audio/video files and streams is managed as a state machine. The following diagram shows

     the life cycle and the states of a MediaPlayer object driven by the supported playback control operations. The ovals

     represent the states a MediaPlayer object may reside in. The arcs represent the playback control operations that

     drive the object state transition. There are two types of arcs. The arcs with a single arrow head represent

     synchronous method calls, while those with a double arrow head represent asynchronous method calls.


    (此图为播放控制的生命周期状态图,椭圆形代表MediaPlayer对象所能驻留的状态,单个箭头代表同步方法调用,双


    个箭头代表异步方法调用)如图所示包含如下所述状态:


    When a MediaPlayer object is just created using new or after reset() is called, it is in the Idle state; and after

     release() is called, it is in the End state. Between these two states is the life cycle of the MediaPlayer object.


    (当一个MediaPlayer对象被new初始化,或者调用reset()时处于Idle状态,调用release()后处于End状态,在这两


    种状态之间则处于MediaPlayer对象的生命周期)


    There is a subtle but important difference between a newly constructed MediaPlayer object and the

     MediaPlayer object after reset() is called. It is a programming error to invoke methods such as

     getCurrentPosition(), getDuration(), getVideoHeight(), getVideoWidth(), setAudioStreamType(int),

     setLooping(boolean), setVolume(float, float), pause(), start(), stop(), seekTo(int), prepare() or prepareAsync()

     in the Idle state for both cases. If any of these methods is called right after a MediaPlayer object is constructed,

     the user supplied callback method OnErrorListener.onError() won't be called by the internal player engine and

     the object state remains unchanged; but if these methods are called right after reset(), the user supplied

     callback method OnErrorListener.onError() will be invoked by the internal player engine and the object will be

     transfered to the Error state.


    (新创建的MediaPlayer对象与调用reset()后的对象有微妙的区别,调用路上英文所述中的方法在Idle状态之后


    对于这两种情况来说都是一个编程错误,在创建MediaPlayer对象后调用如上英文所述的任何一个方法都不会调


    用OnErrorListener.onError()回调,而且状态也不会改变,但是在reset()后调用如上英文所述的任何一个方法


    将调用OnErrorListener.onError()回调并进入错误状态


    It is also recommended that once a MediaPlayer object is no longer being used, call release() immediately so

     that resources used by the internal player engine associated with the MediaPlayer object can be released

     immediately. Resource may include singleton resources such as hardware acceleration components and

     failure to call release() may cause subsequent instances of MediaPlayer objects to fallback to software

     implementations or fail altogether. Once the MediaPlayer object is in the End state, it can no longer be used

     and there is no way to bring it back to any other state.


    (建议一旦MediaPlayer对象不再使用就要调用release()释放资源,一旦MediaPlayer 对象调用release()处于


    End状态后将不能回到前面任何一个状态)


    Furthermore, the MediaPlayer objects created using new is in the Idle state, while those created with one of the

     overloaded convenient create methods are NOT in the Idle state. In fact, the objects are in the Prepared state

     if the creation using create method is successful


    (使用new创建的MediaPlayer对象处于Idle状态,那些使用create静态便利方法创建的MediaPlayer对象不是处


    于Idle状态而是进入了Prepared状态


    In general, some playback control operation may fail due to various reasons, such as unsupported audio/video 

    format, poorly interleaved audio/video, resolution too high, streaming timeout, and the like. Thus, error reporting and

     recovery is an important concern under these circumstances. Sometimes, due to programming errors, invoking a

     playback control operation in an invalid state may also occur. Under all these error conditions, the internal player

     engine invokes a user supplied OnErrorListener.onError() method if an OnErrorListener has been registered

     beforehand via setOnErrorListener(android.media.MediaPlayer.OnErrorListener).


    (播放控制将会失败由于各种原因,如:不支持的格式,分辨率太高,流超时等等,因此错误报告和恢复将是重要的


    在这些情况下,这些所有原因将会调用用户已经注册的回调函数OnErrorListener.onError() 


    It is important to note that once an error occurs, the MediaPlayer object enters the Error state (except as noted

     above), even if an error listener has not been registered by the application.


    (一旦错误发生,MediaPlayer对象将进入Error状态,不管有没有注册错误监听


    In order to reuse a MediaPlayer object that is in the Error state and recover from the error, reset() can be called

     to restore the object to its Idle state.


    (为了重用MediaPlayer对象,调用reset()方法将从错误状态恢复到Idle状


    It is good programming practice to have your application register a OnErrorListener to look out for error

     notifications from the internal player engine.


    (注册错误监听是好的编程习惯为了看出错误)


    IllegalStateException is thrown to prevent programming errors such as calling prepare(), prepareAsync(), or

     one of the overloaded setDataSource methods in an invalid state.


    IllegalStateException错误将被抛出,在调用prepare(),prepareAsync()或任何一个setDataSource()方法


    在无效的状态


    Calling setDataSource(FileDescriptor), or setDataSource(String), or setDataSource(Context, Uri), or

     setDataSource(FileDescriptor, long, long) transfers a MediaPlayer object in the Idle state to the Initialized state.


    (调用任何一个重载的setDataSource方法将从Idle状态进入初始化状态)


    An IllegalStateException is thrown if setDataSource() is called in any other state.


    (在非Idle状态下调用setDataSource()将抛出IllegalStateEx异常ception


    It is good programming practice to always look out for IllegalArgumentException and IOException that may be

     thrown from the overloaded setDataSource methods.


    (在调用setDataSource后检测是否会抛出IllegalArgumentException和IOException异常是一个好的编程习



    A MediaPlayer object must first enter the Prepared state before playback can be started.


    MediaPlayer对象必须进入Prepared状态下播放才能够被开始


    There are two ways (synchronous vs. asynchronous) that the Prepared state can be reached: either a call to

     prepare() (synchronous) which transfers the object to the Prepared state once the method call returns, or a call

     to prepareAsync() (asynchronous) which first transfers the object to the Preparing state after the call returns

     (which occurs almost right way) while the internal player engine continues working on the rest of preparation

     work until the preparation work completes. When the preparation completes or when prepare() call returns, the

     internal player engine then calls a user supplied callback method, onPrepared() of the OnPreparedListener

     interface, if an OnPreparedListener is registered beforehand via

     setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener).


    (有两种方式进入Prepared状态,第一种是synchronous方式,只要调用prepare()后一旦该方法返回就进入了


    Prepared状态,第二种是asynchronous方式,调用prepareAsync()将进入Preparing状态,当Preparing状态


    完成并返回才进入Prepared状态,如果Preparing状态完成或者调用prepare()并返回之后将调用已经注册了的


    OnPreparedListener的onPrepared()方法,通过setOnPreparedListener方式注册


    It is important to note that the Preparing state is a transient state, and the behavior of calling any method with

     side effect while a MediaPlayer object is in the Preparing state is undefined.


    Preparing是一个短暂的状态并且没有定义的


    An IllegalStateException is thrown if prepare() or prepareAsync() is called in any other state.


    (在非初始化状态下下调用prepare()和prepareAsync()将抛出IllegalStateException异常


    While in the Prepared state, properties such as audio/sound volume, screenOnWhilePlaying, looping can be

     adjusted by invoking the corresponding set methods.


    (当在Prepared状态下调用相应的设置属性方法


    To start the playback, start() must be called. After start() returns successfully, the MediaPlayer object is in the

     Started state. isPlaying() can be called to test whether the MediaPlayer object is in the Started state.


    (为了开始播放必须调用start()方法,调用start()返回成功后进入Started状态, isPlaying()可以用来测试是否在


    Started状态


    While in the Started state, the internal player engine calls a

     user supplied OnBufferingUpdateListener.onBufferingUpdate() callback method if a

     OnBufferingUpdateListener has been registered beforehand via

     setOnBufferingUpdateListener(OnBufferingUpdateListener). This callback allows applications to keep track of

     the buffering status while streaming audio/video.


    (当在Started时,播放引擎调用用户设置的OnBufferingUpdateListener.onBufferingUpdate() 回调,这个回


    调运行程序跟踪音频和视频流的状态)


    Calling start() has not effect on a MediaPlayer object that is already in the Started state.


    (已经在Started状态后在调用 start()方法是没有效果的


    Playback can be paused and stopped, and the current playback position can be adjusted. Playback can be paused

     via pause(). When the call to pause() returns, the MediaPlayer object enters the Paused state. Note that the

     transition from the Started state to the Paused state and vice versa happens asynchronously in the player engine. It

     may take some time before the state is updated in calls to isPlaying(), and it can be a number of seconds in the

     case of streamed content.


    (播放器能被暂停,停止或者调整播放位置,当调用pause()方法返回后进入Paused状态,从Started进入Paused状


    态或从Paused状态进入Started状态时异步的,这将花费一定时间,可用isPlaying()进行判断状态


    Calling start() to resume playback for a paused MediaPlayer object, and the resumed playback position is the

     same as where it was paused. When the call to start() returns, the paused MediaPlayer object goes back to

     the Started state.


    (在Paused状态下调用start()将恢复到原来的暂停时的位置


    Calling pause() has no effect on a MediaPlayer object that is already in the Paused state.


    (已经在Paused状态下调用pause()是没有影响的


    Calling stop() stops playback and causes a MediaPlayer in the Started, Paused, Prepared or PlaybackCompleted

     state to enter the Stopped state.


    (调用stop()方法导致播放器从Started状态,Prepared状态,Paused状态或PlaybackCompleted状态进入               

      Stopped状态


    Once in the Stopped state, playback cannot be started until prepare() or prepareAsync() are called to set the

     MediaPlayer object to the Prepared state again.


    (一旦进入了Stopped状态,播放器不能只有调用prepare()或prepareAsync()设置后才能再次进入Prepared状

     


    Calling stop() has no effect on a MediaPlayer object that is already in the Stopped state.


    (已经处于Stopped的MediaPlayer再次调用stop()没有影响的


    The playback position can be adjusted with a call to seekTo(int).


    (能够通过seekTo(int)方法调整播放器的位置


    Although the asynchronuous seekTo(int) call returns right way, the actual seek operation may take a while to

     finish, especially for audio/video being streamed. When the actual seek operation completes, the internal

     player engine calls a user supplied OnSeekComplete.onSeekComplete() if an OnSeekCompleteListener has

     been registered beforehand via setOnSeekCompleteListener(OnSeekCompleteListener).


    seekTo(int)调用会花费一定的时间完成尤其在 audio/video流的情况下,当seek方法嗲用完成会回调由用户


    通过setOnSeekCompleteListener(OnSeekCompleteListener)注册的OnSeekComplete.onSeekComplete()


    方法监听方法


    Please note that seekTo(int) can also be called in the other states, such as Prepared, Paused and

     PlaybackCompleted state.


    (注意,seekTo(int)也能被调用在Prepared状态,Prepared状态或者PlaybackCompleted状态


    Furthermore, the actual current playback position can be retrieved with a call to getCurrentPosition(), which is

     helpful for applications such as a Music player that need to keep track of the playback progress.


    (此外,播放器的确切位置通过调用getCurrentPosition()方法来检索,能够帮助进度条跟踪播放器的进度


    When the playback reaches the end of stream, the playback completes.


    (当播放器到达了流的末尾,播放完成)


    If the looping mode was being set to truewith setLooping(boolean), the MediaPlayer object shall remain in the

     Started state.


    (通过调用setLooping(boolean)设置循环模式,MediaPlayer对象会停留在Started状态


    If the looping mode was set to false , the player engine calls a user supplied callback method,

     OnCompletion.onCompletion(), if a OnCompletionListener is registered beforehand via

     setOnCompletionListener(OnCompletionListener). The invoke of the callback signals that the object is now in

     the PlaybackCompleted state.


    (当looping模式设置为false,播放引擎在播放完成的时候回调用户通过


    setOnCompletionListener(OnCompletionListener)注册的OnCompletion.onCompletion()方法


    While in the PlaybackCompleted state, calling start() can restart the playback from the beginning of the

     audio/video source.


    (在PlaybackCompleted状态时调用start()能重新启动播放器到Started状态,并位于audio/video source的开


    始位置



    详情参见:http://developer.android.com/reference/android/media/MediaPlayer.html


    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,469
精华内容 2,987
热门标签
关键字:

androidmediaplayer