Android多媒体开发(二)----MediaPlayer的C/S架构以及C++层调用步骤

       上一节主要分析了MediaPlayer从java层到jni层做的一些工作,并且setDataSource和后续流程还没有往下分析。这一节先介绍MediaPlayer的C/S架构,然后顺着架构往下深究,我们的思路会更清晰。

MediaPlayer的C/S架构

       整个MediaPlayer在运行的时候,可以分成Client和Server两个部分,它们分别在两个进程中运行,它们之间使用Binder机制实现IPC通信。架构图如下,我的viso用的不太好,但是还是能看清。

架构图

       1)如果从功能从上往下看,最上层是java层MediaPlayer的API,然后是jni层到C++层之间的IPC通信,最下边就是player的具体实现了(如StageFrightPlayer、MstarPlayer)。
       2)C++层是比较重要的环节,这一块也是C/S架构的核心。主要围绕C++层MediaPlayer通过BpMediaPlayerService这个本地proxy对象,经过IPC与远程服务MediaPlayerService(BnMediaPlayerService)通信,完成C/S架构。(其实Android有很多模块设计都是C/S架构,都是通过BpXXX这个代理皮包和拥有干货的BnXXX通信。这里的p指的是proxy,n就是native)
       3)当Server端收到Client端的请求,MediaPlayerService会为每一个Client进程创建一个会话,这里就是new一个MediaPlayerService:Client对象和其交互。然后这个对象再根据Client端请求的资源类型去判断创建什么类型的Player,就是最下边那些。(其实这些Player有些是芯片商自己做的,每家做的都不一样)

C++层MediaPlayer实现

       上一节我们只是分析了从java层到jni层的一些步骤,应该算是准备工作,正好我们入门。这次我们从jni层入手,应该位于架构图中客户端进程部分,C++层MediaPlayer往上,jni层往下的部分。继续往下,还得从setDataSource入手。

setDataSource C++实现

       通过JNI方式调用到framework层 android_media_MediaPlayer.cpp(\frameworks\base\media\jni\android_media_MediaPlayer.cpp),继而调用mediaplayer.cpp(frameworks\av\media\libmedia\MediaPlayer.cpp)。我们找到setDataSource方法,上次我们分析的而是获取文件描述符的重载方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
status_t err = UNKNOWN_ERROR;
//获取BpMediaPlayerService这个代理MediaPlayerService的proxy对象
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
//从service manager中获得MediaPlayerService 服务,然后通过服务来创建player,这个player就是架构图最下层那些拥有真正干活本领的player
sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
//会走到这里,调用那些能够干活的player的setDataSource方法
(NO_ERROR != player->setDataSource(fd, offset, length))) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}

       在整个应用程序的进程中,Mediaplayer.cpp 中 setDataSource会从service manager中获得MediaPlayerService 服务,然后通过服务来创建player,这个player就是播放器的真实实例。

       分工步骤如下:

通过Binder获取远程服务

       通过 getMediaPlayerService 得到的service其实是 BpMediaPlayerService,这是和MediaPlayerService进程中的BnMediaPlayerService 相对应负责binder通讯。BpMediaPlayerService中的create其实通过binder机制将CREATE消息发送出去。位于framework/av/media/libmedia/IMediaPlayerService.cpp:

1
2
3
4
5
6
7
8
9
10
11
virtual sp<IMediaPlayer> create(
const sp<IMediaPlayerClient>& client, int audioSessionId) {
//发送数据data,相应数据reply
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeStrongBinder(client->asBinder());
data.writeInt32(audioSessionId);
//通过binder将CTEATE消息发送出去
remote()->transact(CREATE, data, &reply);
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
}

       在对面的BnMediaPlayerService中,通过onTransact()接受这些消息。并把结果返回。同样位于framework/av/media/libmedia/IMediaPlayerService.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
status_t BnMediaPlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch (code) {
case CREATE: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
sp<IMediaPlayerClient> client =
interface_cast<IMediaPlayerClient>(data.readStrongBinder());
int audioSessionId = data.readInt32();
//BnMediaPlayerService的子类是MediaPlayerService,因此会调用MediaPlayerService的create方法
sp<IMediaPlayer> player = create(client, audioSessionId);
//将create创建的player回执给客户端
reply->writeStrongBinder(player->asBinder());
return NO_ERROR;
} break;
case DECODE_URL:
......
}
}

服务端创建会话

       当发现是CREATE才真正调用了MediaPlayerService 中的create函数,位于framework/av/media/libmediaplayerservice/MediaPlayerService.cpp中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sp<IMediaPlayer> MediaPlayerService::create(const sp<IMediaPlayerClient>& client,
int audioSessionId)
{
pid_t pid = IPCThreadState::self()->getCallingPid();
int32_t connId = android_atomic_inc(&mNextConnId);
//在create函数中其实是创建了一个MediaPlayerService::Client的实例,也就是
//说MediaPlayerService会为每个client应用进程创建一个相应的MediaPlayerService::Client的实例,来提供服务
sp<Client> c = new Client(
this, pid, connId, client, audioSessionId,
IPCThreadState::self()->getCallingUid());

ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
IPCThreadState::self()->getCallingUid());

wp<Client> w = c;
{
Mutex::Autolock lock(mLock);
mClients.add(w);
}
return c;

       在create函数中其实是创建了一个MediaPlayerService::Client的实例,也就是 说MediaPlayerService会为每个client应用进程创建一个相应的MediaPlayerService::Client的实例,来提供服务。
       这样Mediaplayer.cpp就得到了一个player的实例,对他来说这个实例和本地的其他类的实例没什么用法上的区别,殊不知其实这个实例是运行在另外一个进程中。实现这种假象的就是binder机制。
       如果对Binder机制不是很了解,可以看看这篇文章

回执后setDataSource流程

       获得这个实例后继续player->setDataSource().在MediaPlayerService的进程中他的实际函数中,才会真正的创建框架图最下面那些具有干活能力的播放器具体实例。
       我们继续查看MediaPlayerService::Client::setDataSource方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
......
//获取播放器类型
player_type playerType = MediaPlayerFactory::getPlayerType(this,
fd,
offset,
length);
//这里会根据上面选择的播放器类型去创建相应的播放器
sp<MediaPlayerBase> p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
}

// now set data source
//最后在这里在将数据源设置给播放器
setDataSource_post(p, p->setDataSource(fd, offset, length));
return mStatus;

       这也也要分步骤执行,我们一步一步去看,然后才能弄清楚每一步的职责。
       1)先是获取播放器的类型,我们进入MediaPlayerFactory类看看getPlayerType方法,位于framework/av/media/libmediaplayerservice/MediaPlayerFactory.cpp中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
player_type MediaPlayerFactory::getPlayerType(const sp<IMediaPlayer>& client,
int fd,
int64_t offset,
int64_t length) {
//这是一个宏,我们看看它的宏定义
GET_PLAYER_TYPE_IMPL(client, fd, offset, length);
}
//注册不同播放器的map
MediaPlayerFactory::tFactoryMap MediaPlayerFactory::sFactoryMap;

//这就是它的宏定义
#define GET_PLAYER_TYPE_IMPL(a...) \
Mutex::Autolock lock_(&sLock); \
\
player_type ret = STAGEFRIGHT_PLAYER; \
float bestScore = 0.0; \
\
for (size_t i = 0; i < sFactoryMap.size(); ++i) { \
\
IFactory* v = sFactoryMap.valueAt(i); \
float thisScore; \
CHECK(v != NULL); \
thisScore = v->scoreFactory(a, bestScore); \
if (thisScore > bestScore) { \
ret = sFactoryMap.keyAt(i); \
bestScore = thisScore; \
} \
} \
\
if (0.0 == bestScore) { \
ret = getDefaultPlayerType(); \
} \
\
return ret;

       这里定义一个宏来选择播放器类型。里面的for循环也很简单,就是查询注册进来的播放器map中的score得分,谁的得分最高,就返回这个播放器。
       这里默认返回的是StageFright,舞台恐惧者,Google总喜欢用一些稀奇古怪的名字命名它的模块组件。

       我看可以查看MediaPlayerFactory.cpp这个文件,这个文件里面有许多种类型的播放器工厂,可以创建出不同的播放器,如StagefrightPlayer、NuPlayerDriver、MidiFile等等。如果厂商要定制自己的播放器,就可以在这里做文章。比如Mstar或者海思自己的播放器,MstarPlayer、HisiPlayer。创建自己的工厂类,实现createPlayer方法,然后修改scoreFactory返回得分值为一个较大的数值,再注册进sFactoryMap变量。或者直接修改GET_PLAYER_TYPE_IMPL宏和getDefaultPlayerType方法的规则。

       这里我们就选取默认值STAGEFRIGHT_PLAYER,位于framework/av/media/libmediaplayerservice/MediaPlayerFactory.h:

1
2
3
4
5
6
7
8
9
10
enum player_type {
PV_PLAYER = 1,
SONIVOX_PLAYER = 2,
STAGEFRIGHT_PLAYER = 3,//这个是默认值
NU_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,
};

       2)根据上述选取的STAGEFRIGHT_PLAYER 创建播放器。回到上面继续查看setDataSource_pre方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
player_type playerType)
{
ALOGV("player type = %d", playerType);

// create the right type of player
//调用createPlayer方法,这一步继续跟进
sp<MediaPlayerBase> p = createPlayer(playerType);
if (p == NULL) {
return p;
}
//设置音频输出
if (!p->hardwareOutput()) {
mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
mPid, mAudioAttributes);
static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
}

return p;
}

sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
{
// determine if we have the right player type
//确定正确的播放器类型,如果不对,则删除旧的
sp<MediaPlayerBase> p = mPlayer;
if ((p != NULL) && (p->playerType() != playerType)) {
ALOGV("delete player");
p.clear();
}
if (p == NULL) {
//根据工厂类创建播放器实例
p = MediaPlayerFactory::createPlayer(playerType, this, notify);
}

if (p != NULL) {
p->setUID(mUID);
}

return p;
}

       最后会调用MediaPlayerFactory::createPlayer静态方法,我们进去看看怎么实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
sp<MediaPlayerBase> MediaPlayerFactory::createPlayer(
player_type playerType,
void* cookie,
notify_callback_f notifyFunc) {
sp<MediaPlayerBase> p;
IFactory* factory;
status_t init_result;
Mutex::Autolock lock_(&sLock);
//查询检测
if (sFactoryMap.indexOfKey(playerType) < 0) {
ALOGE("Failed to create player object of type %d, no registered"
" factory", playerType);
return p;
}
//找出播放器工厂类
factory = sFactoryMap.valueFor(playerType);
CHECK(NULL != factory);
//这句才是创建播放器
p = factory->createPlayer();

if (p == NULL) {
ALOGE("Failed to create player object of type %d, create failed",
playerType);
return p;
}
//通知回调
init_result = p->initCheck();
if (init_result == NO_ERROR) {
p->setNotifyCallback(cookie, notifyFunc);
} else {
ALOGE("Failed to create player object of type %d, initCheck failed"
" (res = %d)", playerType, init_result);
p.clear();
}

return p;

       因为我们的播放器类型为STAGEFRIGHT_PLAYER ,所以对应的工厂类为StagefrightPlayerFactory,继续进入MediaPlayerFactory.cpp中查看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class StagefrightPlayerFactory :
public MediaPlayerFactory::IFactory {
public:
virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/,
int fd,
int64_t offset,
int64_t /*length*/,
float /*curScore*/)
{

if (getDefaultPlayerType()
== STAGEFRIGHT_PLAYER) {
char buf[20];
lseek(fd, offset, SEEK_SET);
read(fd, buf, sizeof(buf));
lseek(fd, offset, SEEK_SET);

uint32_t ident = *((uint32_t*)buf);

// Ogg vorbis?
if (ident == 0x5367674f) // 'OggS'
return 1.0;
}

return 0.0;
}

virtual sp<MediaPlayerBase> createPlayer() {
ALOGV(" create StagefrightPlayer");
return new StagefrightPlayer();
}
};

       这里他就创建了StagefrightPlayer这个播放器对象了。在这里已经看不到openCore的影子了,android高版本已经舍弃了openCore了。

       3)最后一部就是用上面创建的StagefrightPlayer对象设置数据源了。这一步下一节讲Stagefright框架时会讲的。

StageFright 与openCore

       Android froyo版本多媒体引擎做了变动,新添加了stagefright框架,并且默认情况android选择stagefright,并没有完全抛弃opencore,主要是做了一个OMX层,仅仅是对 opencore的omx-component部分做了引用。stagefright是在MediaPlayerService这一层加入的,和opencore是并列的。Stagefright在 Android中是以shared library的形式存在(libstagefright.so),其中的module – AwesomePlayer可用来播放video/audio。 AwesomePlayer提供许多API,可以让上层的应用程序(Java/JNI)来调用。

小结

       以上就是本节分析的内容,承接上一节jni层setDataSource,一直到本届C++层setDataSource。步骤如下:

  • jni层调用C++层MediaPlayer的setDataSource;
  • 通过IPC获取MediaPlayerService服务,为客户端进程分配一个回话;
  • 服务端setDataSource过程中创建指定类型的播放器;
  • 播放器设置setDataSource。

       本届内容就这么多,依然止于setDataSource,不过是StageFright的setDataSource,我们在这里做个标记。
       下一节我们将详细分析StageFright框架。
妹子

坚持技术分享,您的支持将鼓励我继续创作!