敞开成长之旅!这是我参加「日新计划 12 月更文应战」的第33天,点击检查活动概况

一、Media FrameWork布景

Media Framework (媒体函数库):此函数库让Android 能够播映与录制许多常见的音频与视频文件,支持的文件类型包含MPEG4、H.264、MP3、AAC、AMR、JPG 与PNG 等。 Surface Manager (外观办理函数库):办理图形界面的操作与2D、3D 图层的显示。

二、Media Framework“路线图”

咱们能够看到用赤色框框圈起来的当地。一个是app使用Gallery(也可认为第三方player);别的一个是Media Framework。对,没错,讲了这么多,咱们的主角“Media Framework”登场了。让咱们来看看它的庐山真面目, 如图所示:

Android音视频开发——Media FrameWork框架与源码解析
接下来,给咱们简单介绍下它。看的顺序是→ ↓ ← ↓ →(肿么都觉得是在打表情符号:-D)

2.1 代理端

这一端做的事情仅仅将下面杂乱的逻辑进行封装(java),然后透过jni调用底下的native层方法来完结详细功用。而且,这些个详细的功用是在服务端完结的,他们分属不同的进程,经过Binder来通讯,终究经过调用服务端的方法完结详细的逻辑处理。(有童鞋问:Binder是个什么东东呢? 小弟有时间会解说的,现在就了解它是一个进程间通讯的一种方式就好,求甚解的朋友们能够百度下_)

2.2 服务端

这边的主要任务便是在MediaPlayerFactory中,创建出NuplayerDriver(这个不是底层驱动啦,咱们了解为一个笼统出来的NuPlayer的基类就好啦)。 然后Nuplayer中,咱们能够看到有三大模块。

2.2.1 Source

这儿是为咱们的播映器供给数据源的(解协议,解封装在这儿)。

2.2.2 Decoder

这儿是解码数据的当地(解码在这儿)

2.2.3 Renderer

这儿是用来做Display的,里边触及到A/V同步的问题。

2.2.4 Foundation

这个部分是根底类。在后面的剖析傍边,咱们会知道在NuPlayer中会发动相当多的线程,这些线程如何异步/同步的通讯,需要依托AMessage/ALooper/AHandler来支持

之后, 经过接口类IOMX来经过Binder进程间通讯,长途调用详细的decoder来完结解码。

2.3 OMX端

这一端就比较接近底层了,里边会有各式各样的插件注册其间。它还链接这Codec Driver,这儿面便是放的各种详细的解码器啦。

2.4 Kernel端

终究, OMX的详细解码器在发动Kernel层的A/V Codec Driver完结解码操作。

三、media播映的流程

在framework中触及media播映的流程头文件如下:IMediaPlayer.h mediaplayer.h IMediaPlayerClient.h

其间IMediaPlayer.h 界说了binder通讯相关的接口。 界说了:

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

IMediaPlayer.cpp 是binder通讯接口的完结。

class BpMediaPlayer: public BpInterface; status_t BnMediaPlayer::onTransact();

mediaplayer.h 是界说binder通讯的客户端。在mediaplayer.cpp中如下代码获取BpMediaPlayer:

status_t MediaPlayer::setDataSource(
     const char *url, const KeyedVector *headers)
{
   LOGV("setDataSource(%s)", url);
   status_t err = BAD_VALUE;
   if (url != NULL) {
     const sp& service(getMediaPlayerService());
     if (service != 0) {
       sp player(
           service->create(getpid(), this, url, headers));
       err = setDataSource(player);
     }
   }
   return err;
}
​

服务端在MediaPlayerService中。在MediaPlayerService.h中如下界说:

class Client : public BnMediaPlayer 在MediaPlayerService.cpp中,create函数创建了BnMediaPlayer:

sp MediaPlayerService::create(
​
     pid_t pid, const sp& client, const char* url,
     const KeyedVector *headers)
{
   int32_t connId = android_atomic_inc(&mNextConnId);
   sp c = new Client(this, pid, connId, client);
   LOGV("Create new client(%d) from pid %d, url=%s, connId=%d", connId, pid, url, connId);
   if (NO_ERROR != c->setDataSource(url, headers))
   {
     c.clear();
     return c;
   }
   wp w = c;
   Mutex::Autolock lock(mLock);
   mClients.add(w);
   return c;
}

再来看一下MediaPlayer这个类的界说:

class MediaPlayer : public BnMediaPlayerClient, public virtual IMediaDeathNotifier{} 很古怪:在binder通讯的客户端又有了一个binder通讯的服务端: BnMediaPlayerClient 在IMediaPlayerClient.h 中这个binder通讯只有一个接口:

class IMediaPlayerClient: public IInterface
{
public:
   DECLARE_META_INTERFACE(MediaPlayerClient);
​
   virtual void notify(int msg, int ext1, int ext2) = 0;
};

这个binder通讯服务为谁供给呢?在回来看一下MediaPlayerServer中的create函数:

sp MediaPlayerService::create( pid_t pid, const sp& client, const char* url, const KeyedVector *headers)

客户端就在这儿。这个binder通讯的实质是一个音讯回调函数。framework的media框架式一个双向binder通讯框架。

以seek接口为例剖析一下:

在mediaplayer.cpp 中调用seek 接口:

MediaPlayer (seek)->IMediaPlayer.cpp(bpMediaPlayer.cpp )->IMediaPlayer.cpp(bnMediaPlayer.cpp ) 在这儿其实已经达到了MediaPlayerServer中的client类。当底层的media 完结seek 以后会抛出来一音讯,这个音讯经过 const sp& client 通知给MediaPlayer。

在media相关的头文件中还有一个MediaPlayerInterface.h 。这个头文件界说了底层播映器的接口。

四、Media FrameWork源码剖析

首先,针对android.media.MediaPlayer进行剖析。

里边有许多native代码,咱们找到native_setup这个jni调用,就能够找到整个框架的进口。

咱们检查

android_media_MediaPlayer_native_setup@framworks/base/media/jni/android_media_MediaPlayer.cpp

`static` `void` `android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)``{``  ``LOGV(``"native_setup"``);``  ``sp mp = ``new` `MediaPlayer();``  ``if` `(mp == NULL) {``   ``jniThrowException(env, ``"java/lang/RuntimeException"``, ``"Out of memory"``);``   ``return``;``  ``}` `  ``// create new listener and give it to MediaPlayer``  ``sp 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在这儿实例化了一个变量mp:MediaPlayer。

而且为其设置了一个listener:JNIMediaPlayerListener

在后面咱们会看到对mp的调用,现在让咱们先看看MediaPlayer是什么东东。

MediaPlayer@framworks/base/include/media/mediaplayer.h MediaPlayer@framworks/base/media/libmedia/mediaplayer.cpp

在这儿咱们终于找到了MediaPlayer:BnMediaPlayerClient:IMediaPlayerClient

本来他也是对Bind Native的一个封装,而他本身供给了许多方法用于访问,包含start等。下面是start的cpp代码:

status_t MediaPlayer::start()
{
   LOGV("start");
   Mutex::Autolock _l(mLock);
   if (mCurrentState & MEDIA_PLAYER_STARTED)
     return NO_ERROR;
   if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED |
           MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) {
     mPlayer->setLooping(mLoop);
     mPlayer->setVolume(mLeftVolume, mRightVolume);
     mCurrentState = MEDIA_PLAYER_STARTED;
     status_t ret = mPlayer->start();
     if (ret != NO_ERROR) {
       mCurrentState = MEDIA_PLAYER_STATE_ERROR;
     } else {
       if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) {
         LOGV("playback completed immediately following start()");
       }
     }
     return ret;
   }
   LOGE("start called in state %d", mCurrentState);
   return INVALID_OPERATION;
}

本来这儿又调用了mPlayer:sp

从这儿咱们发现终究的服务,仍是由IMediaPlayer这个东西供给的,而IMediaPlayer@framworks/base/include/media/IMediaPlayer.h

实际上是如下界说的一个类,它继承了IInterface@framworks/base/include/binder/IInterface.h这个类(留意虽然姓名是Interface,可是它确实是个类!:-))

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

为了弄清楚,在什么当地产生的mPlayer,我转而剖析MediaPlayerService@framworks/base/media/libmediaplayerservice/MediaPlayerService.h

其间有如下代码

virtual sp<IMediaRecorder>  createMediaRecorder(pid_t pid);
void   removeMediaRecorderClient(wp<MediaRecorderClient> client);
virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid);
// House keeping for media player clients
virtual sp<IMediaPlayer>   create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url);
virtual sp<IMediaPlayer>   create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length);

本来在这个当地会创建你sp目标。