一:上层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里了