Android2.3 MediaPlayer系统祥解系列(概述)

Android 的mediaplayer包含audio及video两部分的播放功能上,单独的音频或视频都是一个系统中的重要组成部分,另外一个就是显示系统部分在,在android系统最核心的就是SurfaceFlinger组件了。而音视频也同时存在核心部分:
AndioFlinger及Stagefright(OpenCore)做具体的视频处理工作。



1、代码位置
   需要从代码阅读了解其设计思想,则必须知道其代码主要目录
JAVA类的路径:frameworks/base/media/java/android/media/MediaPlayer.java
JAVA本地调用部分(JNI):frameworks/base/media/jni/<p align="justify">android_media_MediaPlayer.cpp </p>
这部分内容编译成为目标是libmedia_jni.so。
主要的头文件在以下的目录中:frameworks/base/include/media/
多媒体底层库在以下的目录中:frameworks/base/media/libmedia/ 
这部分的内容被编译成库libmedia.so。
多媒体服务部分:frameworks/base/media/libmediaplayerservice/ 
文件为mediaplayerservice.h和mediaplayerservice.cpp 
这部分内容被编译成库libmediaplayerservice.so。


 2.2系统目录:
基于OpenCore的多媒体播放器部分 external/opencore/ 
这部分内容被编译成库libopencoreplayer.so。从程序规模上来看,libopencoreplayer.so是主要的实现部分,而其他的库基本上都是在其上建立的封装和为建立进程间通讯的机制。


2.3系统目录:
基于Statefright的多媒体播放器部分 frameworks\base\media\libstagefright
这部分内容被编译成库 libstagefright.so。从程序规模上来看,libstagefright.so是主要的实现部分,而其他的库基本上都是在其上建立的封装和为建立进程间通讯的机制。
    
2、整体架构图
   Android2.3 MediaPlayer系统祥解系列(概述)_第1张图片

   在各个库中,libmedia.so位于核心的位置,它对上层的提供的接口主要是MediaPlayer类,类libmedia_jni.so通过调用 
   MediaPlayer类提供对JAVA的接口,并且实现了android.media.MediaPlayer类。 
   libmediaplayerservice.so是Media的服务器,它通过继承libmedia.so的类实现服务器的功能,而 libmedia.so中的另外
   一部分内容则通过进程间通讯和libmediaplayerservice.so进行通讯。 
   libmediaplayerservice.so的真正功能通过调用Stagefright Player来完成
   
3、框架主要头文件
目录:frameworks\base\include\media
IMediaPlayerClient.h 
mediaplayer.h 
IMediaPlayer.h 

IMediaPlayerService.h 

MediaPlayerInterface.h

都为纯虚类接口,这些接口类必须被实现类继承才能够使用

其基本的头文件继承关系:
Android2.3 MediaPlayer系统祥解系列(概述)_第2张图片


下面重点分析一下这几个头文件:
A、IMediaPlayerClient.h 
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);
};


只提供了一个notify函数,用于服务器端回应客户端消息

B、mediaplayer.h
mediaplayer.h是对外的接口类,它最主要是定义了一个MediaPlayer类

class MediaPlayer : public BnMediaPlayerClient,
                    public virtual IMediaDeathNotifier

主要的接口功能如下:
方法:create(Context context, Uri uri) 
解释:静态方法,通过Uri创建一个多媒体播放器。 

方法:create(Context context, int resid) 
解释:静态方法,通过资源ID创建一个多媒体播放器 

方法:create(Context context, Uri uri, SurfaceHolder holder) 
解释:静态方法,通过Uri和指定 SurfaceHolder 【抽象类】 创建一个多媒体播放器 

方法: getCurrentPosition() 
解释:返回 Int, 得到当前播放位置 

方法: getDuration() 
解释:返回 Int,得到文件的时间 

方法:getVideoHeight() 
解释:返回 Int ,得到视频的高度 

方法:getVideoWidth() 
解释:返回 Int,得到视频的宽度 

方法:isLooping() 
解释:返回 boolean ,是否循环播放 

方法:isPlaying() 
解释:返回 boolean,是否正在播放 

方法:pause() 
解释:无返回值 ,暂停 

方法:prepare() 
解释:无返回值,准备同步 

方法:prepareAsync() 
解释:无返回值,准备异步 

方法:release() 
解释:无返回值,释放 MediaPlayer 对象 

方法:reset() 
解释:无返回值,重置 MediaPlayer 对象 

方法:seekTo(int msec) 
解释:无返回值,指定播放的位置(以毫秒为单位的时间) 

方法:setAudioStreamType(int streamtype) 
解释:无返回值,指定流媒体的类型 

方法:setDataSource(String path) 
解释:无返回值,设置多媒体数据来源【根据 路径】 

方法:setDataSource(FileDescriptor fd, long offset, long length) 
解释:无返回值,设置多媒体数据来源【根据 FileDescriptor】 

方法:setDataSource(FileDescriptor fd) 
解释:无返回值,设置多媒体数据来源【根据 FileDescriptor】 

方法:setDataSource(Context context, Uri uri) 
解释:无返回值,设置多媒体数据来源【根据 Uri】 

方法:setDisplay(SurfaceHolder sh) 
解释:无返回值,设置用 SurfaceHolder 来显示多媒体 

方法:setLooping(boolean looping) 
解释:无返回值,设置是否循环播放 

事件:setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener listener) 
解释:监听事件,网络流媒体的缓冲监听 

事件:setOnCompletionListener(MediaPlayer.OnCompletionListener listener) 
解释:监听事件,网络流媒体播放结束监听 

事件:setOnErrorListener(MediaPlayer.OnErrorListener listener) 
解释:监听事件,设置错误信息监听 

事件:setOnVideoSizeChangedListener(MediaPlayer.OnVideoSizeChangedListener listener) 
解释:监听事件,视频尺寸监听 

方法:setScreenOnWhilePlaying(boolean screenOn) 
解释:无返回值,设置是否使用 SurfaceHolder 显示 

方法:setVolume(float leftVolume, float rightVolume) 
解释:无返回值,设置音量 

方法:start() 
解释:无返回值,开始播放 

方法:stop() 
解释:无返回值,停止播放
MediaPlayer类主要实现了一个MediaPlayer的基本操作,例如播放(start)、停止(stop)、暂停(pause)等

C、IMediaPlayer.h 
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        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;
   virtual status_t        suspend() = 0;
   virtual status_t        resume() = 0;
   virtual status_t        setAuxEffectSendLevel(float level) = 0;
   virtual status_t        attachAuxEffect(int effectId) = 0;
   virtual status_t        invoke(const Parcel& request, Parcel *reply) = 0;
   virtual status_t        setMetadataFilter(const Parcel& filter) = 0;
   virtual status_t        getMetadata(bool update_only,
                                       bool apply_filter,
                                       Parcel *metadata) = 0;
};

// ----------------------------------------------------------------------------

class BnMediaPlayer: public BnInterface<IMediaPlayer>
{
public:
   virtual status_t    onTransact( uint32_t code,
                                   const Parcel& data,
                                   Parcel* reply,
                                   uint32_t flags = 0);
};

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

D、IMediaPlayerService.h 
IMediaPlayerService.h用于描述一个MediaPlayer的服务
class IMediaPlayerService: public IInterface
{
public:
   DECLARE_META_INTERFACE(MediaPlayerService);

   virtual sp<IMediaRecorder>  createMediaRecorder(pid_t pid) = 0;
   virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
   virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client,
           const char* url, const KeyedVector<String8, String8> *headers = NULL,
           int audioSessionId = 0) = 0;
   virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client,
           int fd, int64_t offset, int64_t length, int audioSessionId) = 0;
   virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
   virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
   virtual sp<IOMX>            getOMX() = 0;
};

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

E、MediaPlayerInterface.h
实现具体的player播放器头文件


4、说明一下应用中使用
如果我们想播放手机卡里的音乐,或者URL下载流媒体来播放,示意程序如下:
MediaPlayer mp = new MediaPlayer();   
mp.setDataSource(String URL/FILE_PATH); 
mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
mp.setDisplay(SurfaceHolder); //use for displaying the video portion of the media.
mp.prepare(); 
mp.start(); 

 
以上程序主要是通过MediaPlayer.setDataSource() 的方法,将URL或文件路径以字符串的方式传入.使用setDataSource ()方法时,要注意以下三点:
1.构建完成的MediaPlayer 必须实现Null 对像的检查.
2.必须实现接收IllegalArgumentException 与IOException 等异常,在很多情况下,你所用的文件当下并不存在.
3.若使用URL 来播放在线媒体文件,该文件应该要能支持pragressive 下载.   


createPlayer 创建具体的播放器(实现接口MediaPlayerInterface.h)
目前有如下几种类型:
enum player_type {
   PV_PLAYER = 1,
   SONIVOX_PLAYER = 2,
   STAGEFRIGHT_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,
};

switch(playerType){
case PV_PLAYER:
            LOGV(" create PVPlayer");
            p = new PVPlayer();
            break;
        case SONIVOX_PLAYER:
            LOGV(" create MidiFile");
            p = new MidiFile();
            break;
        case STAGEFRIGHT_PLAYER:
            LOGV(" create StagefrightPlayer");
            p = new StagefrightPlayer;
            break;
        case TEST_PLAYER:
            LOGV("Create Test Player stub");
            p = new TestPlayerStub();
            break;
  }

根据layerType的类型建立不同的播放器:对于大多数情况,类型将是PV_PLAYER,这时会调用了new PVPlayer()
建立一个PVPlayer,然后将其指针转换成MediaPlayerBase来使用;对于Mini文件的情况,类型为SONIVOX_PLAYER,
将会建立一个MidiFile;对于其它格式的情况,将会建立一个STAGEFRIGHT_PLAYER。

其中STAGEFRIGHT_PLAYER在frameworks\base\media\libstagefright中实现,代码非常多。后面会详细分析之。

你可能感兴趣的:(Android2.3 MediaPlayer系统祥解系列(概述))