一:上层mediaPlayer 是如何调到Stagefright的
[java]
mediaPlayer=new MediaPlayer();
mediaPlayer.setDataSource(path);
mediaPlayer.setDisplay(surfaceView.getHolder());
mediaPlayer.prepare();
mediaPlayer.start();
不用考虑文件来源、协议、文件容器格式、文件音视频格式等等有关技术,只需遵循SDK接口规范简单几步就能把视频播出来。这也是android这个软件栈所要达到的目的。但是真正的播放器功能实现是在frameworks层,主要是Stagefright。
在我们研究Stagefright之前,有个问题需要解决:上层mediaPlayer 是如何调到Stagefright的?
先来张android的架构图,android的分层结构还是很清晰的。但是上层的java程序是不是顺序的一层一层调到media framework的呢?,如果按照传统的这种思想看代码的话你的脑袋都会看大。所以这里要先稍稍解释一下android的灵魂 binder。binder是android 系统下的一种IPC机制。是进程间交互的一种方式。在开发android应用时,脑袋一定要一直保持C/S结构的思想。android应用的开发说白了就是通过android提供的一系列的服务来完成自己的目的。apk是一个独立的进程,android的系统服务也是很多个独立的进程。binder的功能就是把client 和 service 连接起来。
来张简图
在你我开发应用之前,android已经为我们提供了很多种service服务。包括mediaplayerser 这种视频播放的服务,所以我们开发应用就会很简单,只需申请这些服务就行。如果把这些服务看成是姑娘们,当然需要一个嬷嬷来管理这些姑娘,因为在你没给钱之前嬷嬷不会让你和姑娘见面,为你服务。这个嬷嬷就是Service Manager,Service Manager这个嬷嬷手中有个姑娘的表,新来的姑娘都会先来这里登记一下姓名和住址信息。这个时候你(client)来了,你需要一个擅长播放的姑娘(service)为你服务。你需要先联系嬷嬷,嬷嬷会根据你的需求查表来找到这个播放的姑娘,接下来这个姑娘就为你服务了。binder 机制支持了嬷嬷和姑娘之间的交互通讯工作。可见binder是一个非常基础的组件。
http://www.2cto.com/kf/201209/158014.html
二:下层mediaPlayer 是怎么调到Stagefright的
基于android 4.1.1 源码
【1】mediaserver 启动后会把media相关一些服务添加到servicemanager中,其中就有mediaPlayerService.这样应用启动前,系统就有了mediaPlayerService这个服务程序。
void MediaPlayerService::instantiate() { defaultServiceManager()->addService( String16("media.player"), new MediaPlayerService()); }
【2】应用层 mediaPlayer调用SDK中 MediaPlayer.java(frameworks\base\media\java\android\media\
下面是MediaPlayer的构造函数: * Default constructor. Consider using one of the create() methods for * synchronously instantiating a MediaPlayer from a Uri or resource. * <p>When done with the MediaPlayer, you should call {@link #release()}, * to free the resources. If not released, too many MediaPlayer instances may * result in an exception.</p> */ 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); mOutOfBandSubtitleTracks = new Vector<SubtitleTrack>(); mOpenSubtitleSources = new Vector<InputStream>(); mInbandSubtitleTracks = new SubtitleTrack[0]; /* 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)); }
通过JNI方式调用到framework层 android_media_MediaPlayer.cpp(\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); }
因为文件开头#include <media/mediaplayer.h>,而MediaPlayer.java在package android.media中;
所以new MediaPlayer()创建的对象是调用mediaplayer.h中的构造函数创建的。
继而调用mediaplayer.cpp(frameworks\av\media\libmedia\mediaplayer.cpp)
status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source) { ALOGV("setDataSource"); status_t err = UNKNOWN_ERROR; #if MEDIAPLAYER_REUSE if (mPlayer == NULL) { const sp<IMediaPlayerService>&service(getMediaPlayerService())//getMediaPlayerService()的作用:establish binder interface to MediaPlayerService
//service是一个指向对象的指针,对象类型是IMediaPlayerService
// const sp<IMediaPlayerService>& service(getMediaPlayerService())等价于:
<span style="font-family: Arial, Helvetica, sans-serif;">// const sp<IMediaPlayerService> temp=getMediaPlayerService();</span>
<span style="font-family: Arial, Helvetica, sans-serif;">// const sp<IMediaPlayerService>& service=temp;</span>
if (service != 0) { sp<IMediaPlayer> player(service->create(this, mAudioSessionId));<span style="font-family: Arial, Helvetica, sans-serif;">//player是一个指向对象的指针,对象类型是IMediaPlaye</span>
if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(source))) { player.clear(); } err =attachNewPlayer(player); } } else { ALOGV("Use the old MediaPlayer"); clear_l(); mCurrentState = MEDIA_PLAYER_INITIALIZED; err = NO_ERROR; if ((NO_ERROR != doSetRetransmitEndpoint(mPlayer)) || (NO_ERROR != mPlayer->setDataSource(source))) { err = UNKNOWN_ERROR; ALOGE("setDataSource error"); } } #else // #if MEDIAPLAYER_REUSE const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != 0) { sp<IMediaPlayer> player(service->create(this, mAudioSessionId)); if ((NO_ERROR != doSetRetransmitEndpoint(player)) || (NO_ERROR != player->setDataSource(source))) { player.clear(); } err = attachNewPlayer(player); } #endif // #if MEDIAPLAYER_REUSE return err; }【4】通过 getMediaPlayerService 得到的service其实是 BpMediaPlayerService,这是和 mediaPlayerService 进程中的BnMediaPlayerService 相对应负责binder通讯。BpMediaPlayerService中的create其实通过binder机制将CREATE消息发送出去。
<pre name="code" class="cpp"> virtual sp<IMediaPlayer> create( const sp<IMediaPlayerClient>& client, int audioSessionId) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); data.writeStrongBinder(client->asBinder()); data.writeInt32(audioSessionId); remote()->transact(CREATE, data, &reply); return interface_cast<IMediaPlayer>(reply.readStrongBinder()); }
</pre><span style="color:rgb(51,51,51); font-family:Tahoma; font-size:14px; line-height:24px"></span><div style="text-align:left">当发现是CREATE才真正调用了MediaPlayerService 中的create函数。在create函数中其实是创建了一个MediaPlayerService::Client的实例,也就是 说<span style="text-indent:2em; font-family:Arial; line-height:26px; margin:0px; padding:0px; list-style:none outside none; word-break:normal; word-wrap:break-word">MediaPlayerService会为每个client应用进程创建一个相应的MediaPlayerService::Client的实例,来提供服务。</span></div><p style="color:rgb(51,51,51); font-family:Tahoma; font-size:14px; line-height:24px; margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px"></p><p style="color:rgb(51,51,51); font-family:Tahoma; font-size:14px; line-height:24px; margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px"><span style="margin:0px; padding:0px; list-style:none outside none; word-break:normal; word-wrap:break-word; font-family:Arial; line-height:26px"></span></p><pre name="code" class="cpp" style="color: rgb(51, 51, 51); font-family: Tahoma; font-size: 14px; line-height: 24px; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
在上面中已经看不到opencore的影子了,creatPlayer 中会根据类型来创建播放器的实例。Stagefright的实例就是在这里创建的。
下一步我们能真正进入到Stagefright里了