概述
android中的多媒体播放结构是:client-server模式
client端对应的类是:MediaPlayer -- framework/base/media/java/android/media/MediaPlayer.java
server端对应的类是:MediaPlayer->MediaPlayerService->Stagefrigthplayer->AwesomePlayer
其中mediaplayerservice是service,MediaPlayer通过binder机制与其交互。
这里Java层的MediaPlayer类与Cpp层的MediaPlayer代码交互不介绍了,自己不了解,只介绍下层的过程。
注:对于mediaplayer类的方法介绍,可参考译文
本篇主要介绍一个典型的播放调用过程
下面是一个典型的播放序列:
- MediaPlayer player=new MediaPlayer()
- player->setDataSource(url,header);
- player->prepare();
- player->start();
- ...
MediaPlayer player=new MediaPlayer() player->setDataSource(url,header); player->prepare(); player->start(); ...
1、构造函数下面就介绍具体的调用流程,起点为MediaPlayer.cpp
代码如下
- MediaPlayer::MediaPlayer()
- {
- ALOGV("constructor");
- mListener = NULL;
- mCookie = NULL;
- mStreamType = AUDIO_STREAM_MUSIC;
- mCurrentPosition = -1;
- mSeekPosition = -1;
- mCurrentState = MEDIA_PLAYER_IDLE;
- mPrepareSync =false;
- mPrepareStatus = NO_ERROR;
- mLoop =false;
- mLeftVolume = mRightVolume =1.0;
- mVideoWidth = mVideoHeight =0;
- mLockThreadId =0;
- mAudioSessionId = AudioSystem::newAudioSessionId();
- AudioSystem::acquireAudioSessionId(mAudioSessionId);
- mSendLevel =0;
- mRetransmitEndpointValid =false;
- }
MediaPlayer::MediaPlayer() { ALOGV("constructor"); mListener = NULL; mCookie = NULL; mStreamType = AUDIO_STREAM_MUSIC; mCurrentPosition = -1; mSeekPosition = -1; mCurrentState = MEDIA_PLAYER_IDLE; mPrepareSync =false; mPrepareStatus = NO_ERROR; mLoop =false; mLeftVolume = mRightVolume =1.0; mVideoWidth = mVideoHeight =0; mLockThreadId =0; mAudioSessionId = AudioSystem::newAudioSessionId(); AudioSystem::acquireAudioSessionId(mAudioSessionId); mSendLevel =0; mRetransmitEndpointValid =false; }
主要是基本的初始化,比较简单。
2、setDataSource
入口代码如下
- status_t MediaPlayer::setDataSource(
- constchar *url, const KeyedVector<String8, String8> *headers)
- {
- ALOGV("setDataSource(%s)", url);
- status_t err = BAD_VALUE;
- if(url != NULL) {
- constsp<IMediaPlayerService>& service(getMediaPlayerService());
- if(service != 0) {
- sp<IMediaPlayer> player(service->create(getpid(),this, mAudioSessionId));
- if((NO_ERROR != doSetRetransmitEndpoint(player)) ||
- (NO_ERROR != player->setDataSource(url, headers))) {
- player.clear();
- }
- err = attachNewPlayer(player);
- }
- }
- returnerr;
- }
-
status_t MediaPlayer::setDataSource(
-
constchar *url, const KeyedVector
<String8, String8> *headers)
-
{
-
ALOGV("setDataSource(%s)", url);
-
status_t err = BAD_VALUE;
-
if(url != NULL) {
-
constsp
<IMediaPlayerService>& service(getMediaPlayerService());
-
if(service != 0) {
-
sp
<IMediaPlayer> player(service->create(getpid(),this, mAudioSessionId));
-
if((NO_ERROR != doSetRetransmitEndpoint(player)) ||
-
(NO_ERROR != player->setDataSource(url, headers))) {
-
player.clear();
-
}
-
err = attachNewPlayer(player);
-
}
-
}
-
returnerr;
-
}
先看下 service->create(getpid(), this, mAudioSessionId)操作,代码在mediaplayerservice.cpp中 setDataSource的操作就转成通过与mediaplayerservice的交互来完成了
- sp<IMediaPlayer> MediaPlayerService::create(pid_t pid,const sp<IMediaPlayerClient>& client,
- intaudioSessionId)
- {
- int32_t connId = android_atomic_inc(&mNextConnId);
- 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);
- }
- returnc;
- }
-
sp
<IMediaPlayer> MediaPlayerService::create(pid_t pid,const sp
<IMediaPlayerClient>& client,
-
intaudioSessionId)
-
{
-
int32_t connId = android_atomic_inc(&mNextConnId);
-
-
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);
-
}
-
returnc;
-
}
而且,Client类的继承关系为:Client->BnMediaPlayer->IMediaPlayer分析上面代码,可以看出create方法,是构造了一个Client对象,并且将此client对象添加到mediapalyerservice类的全局列表中:mClient
因此在setDataSource中的
1
|
sp<IMediaPlayer> player(service->create(getpid(),
this
, mAudioSessionId));
|
语句相当于
1
|
sp<IMediaPlayer> player(
new
Client(**));
|
即player最终是用Client对象来初始化,可以直接认为player==client
[说明]c++功力较差,此处可能不严谨
紧接着执行player->setDataSource(url, headers),即Clients::setDataSource
- status_t MediaPlayerService::Client::setDataSource(intfd, int64_t offset, int64_t length)
- {
- ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
- struct stat sb;
- intret = fstat(fd, &sb);
- if(ret != 0) {
- ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
- returnUNKNOWN_ERROR;
- }
- ALOGV("st_dev = %llu", sb.st_dev);
- ALOGV("st_mode = %u", sb.st_mode);
- ALOGV("st_uid = %lu", sb.st_uid);
- ALOGV("st_gid = %lu", sb.st_gid);
- ALOGV("st_size = %llu", sb.st_size);
- if(offset >= sb.st_size) {
- ALOGE("offset error");
- ::close(fd);
- returnUNKNOWN_ERROR;
- }
- if(offset + length > sb.st_size) {
- length = sb.st_size - offset;
- ALOGV("calculated length = %lld", length);
- }
- player_type playerType = MediaPlayerFactory::getPlayerType(this,
- fd,
- offset,
- length);
- sp<MediaPlayerBase> p = setDataSource_pre(playerType);
- if(p == NULL) {
- returnNO_INIT;
- }
- // now set data source
- setDataSource_post(p, p->setDataSource(fd, offset, length));
- returnmStatus;
- }
-
status_t MediaPlayerService::Client::setDataSource(intfd, int64_t offset, int64_t length)
-
{
-
ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
-
struct stat sb;
-
intret = fstat(fd, &sb);
-
if(ret != 0) {
-
ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
-
returnUNKNOWN_ERROR;
-
}
-
-
ALOGV("st_dev = %llu", sb.st_dev);
-
ALOGV("st_mode = %u", sb.st_mode);
-
ALOGV("st_uid = %lu", sb.st_uid);
-
ALOGV("st_gid = %lu", sb.st_gid);
-
ALOGV("st_size = %llu", sb.st_size);
-
-
if(offset >= sb.st_size) {
-
ALOGE("offset error");
-
::close(fd);
-
returnUNKNOWN_ERROR;
-
}
-
if(offset + length > sb.st_size) {
-
length = sb.st_size - offset;
-
ALOGV("calculated length = %lld", length);
-
}
-
-
player_type playerType = MediaPlayerFactory::getPlayerType(this,
-
fd,
-
offset,
-
length);
-
sp
<MediaPlayerBase> p = setDataSource_pre(playerType);
-
if(p == NULL) {
-
returnNO_INIT;
-
}
-
-
// now set data source
-
setDataSource_post(p, p->setDataSource(fd, offset, length));
-
returnmStatus;
-
}
2.1 getPlayerType代码比较清晰,首选是选择播放器类型,之后调用setDataSource_pre以及setDataSource_post下面分别来看。
- #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) { \
- bestScore = getDefaultPlayerType(); \
- } \
- \
- returnret;
- player_type MediaPlayerFactory::getPlayerType(constsp<IMediaPlayer>& client,
- intfd,
- int64_t offset,
- int64_t length) {
- GET_PLAYER_TYPE_IMPL(client, fd, offset, length);
- }
-
#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) { \
-
bestScore = getDefaultPlayerType(); \
-
} \
-
\
-
returnret;
-
-
player_type MediaPlayerFactory::getPlayerType(constsp
<IMediaPlayer>& client,
-
intfd,
-
int64_t offset,
-
int64_t length) {
-
GET_PLAYER_TYPE_IMPL(client, fd, offset, length);
-
}
这里如果所有播放器都不合适,则选择默认播放器这里流程是,从播放器仓库中选取最佳播放器,通过scoreFactory来确定
- player_type MediaPlayerFactory::getDefaultPlayerType() {
- char value[PROPERTY_VALUE_MAX];
- if(property_get("media.stagefright.use-nuplayer", value, NULL)
- && (!strcmp("1", value) || !strcasecmp("true", value))) {
- returnNU_PLAYER;
- }
- returnSTAGEFRIGHT_PLAYER;
- }
player_type MediaPlayerFactory::getDefaultPlayerType() { char value[PROPERTY_VALUE_MAX]; if(property_get("media.stagefright.use-nuplayer", value, NULL) && (!strcmp("1", value) || !strcasecmp("true", value))) { returnNU_PLAYER; } returnSTAGEFRIGHT_PLAYER; }
这里有几种类型的播放器,会在mediaplayerservice服务类 的构造函数中来注册,代码如下代码中可以看出,一般情况下,STAGEFRIGHT_PLAYER为默认播放器
- MediaPlayerService::MediaPlayerService()
- {
- ***
- MediaPlayerFactory::registerBuiltinFactories();
- }
MediaPlayerService::MediaPlayerService() { *** MediaPlayerFactory::registerBuiltinFactories(); }
- void MediaPlayerFactory::registerBuiltinFactories() {
- Mutex::Autolock lock_(&sLock);
- if(sInitComplete)
- return;
- registerFactory_l(newStagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
- registerFactory_l(newNuPlayerFactory(), NU_PLAYER);
- registerFactory_l(newSonivoxPlayerFactory(), SONIVOX_PLAYER);
- registerFactory_l(newTestPlayerFactory(), TEST_PLAYER);
- sInitComplete =true;
- }
void MediaPlayerFactory::registerBuiltinFactories() { Mutex::Autolock lock_(&sLock); if(sInitComplete) return; registerFactory_l(newStagefrightPlayerFactory(), STAGEFRIGHT_PLAYER); registerFactory_l(newNuPlayerFactory(), NU_PLAYER); registerFactory_l(newSonivoxPlayerFactory(), SONIVOX_PLAYER); registerFactory_l(newTestPlayerFactory(), TEST_PLAYER); sInitComplete =true; }
从registerBuiltinFactories的实现可以看出共注册了四个播放器类型。后面会介绍几个播放器的用途等
下面挑选STAGEFRIGHT_PLAYER类型作为例子看下
- class StagefrightPlayerFactory :
- publicMediaPlayerFactory::IFactory {
- public:
- virtual float scoreFactory(constsp<IMediaPlayer>& client,
- intfd,
- int64_t offset,
- int64_t length,
- float curScore) {
- char buf[20];
- lseek(fd, offset, SEEK_SET);
- read(fd, buf, sizeof(buf));
- lseek(fd, offset, SEEK_SET);
- long ident = *((long*)buf);
- // Ogg vorbis?
- if(ident == 0x5367674f)// 'OggS'
- return1.0;
- return0.0;
- }
- virtual sp<MediaPlayerBase> createPlayer() {
- ALOGV(" create StagefrightPlayer");
- returnnew StagefrightPlayer();
- }
- };
-
class StagefrightPlayerFactory :
-
publicMediaPlayerFactory::IFactory {
-
public:
-
virtual float scoreFactory(constsp
<IMediaPlayer>& client,
-
intfd,
-
int64_t offset,
-
int64_t length,
-
float curScore) {
-
char buf[20];
-
lseek(fd, offset, SEEK_SET);
-
read(fd, buf, sizeof(buf));
-
lseek(fd, offset, SEEK_SET);
-
-
long ident = *((long*)buf);
-
-
// Ogg vorbis?
-
if(ident == 0x5367674f)// 'OggS'
-
return1.0;
-
-
return0.0;
-
}
-
-
virtual sp
<MediaPlayerBase> createPlayer() {
-
ALOGV(" create StagefrightPlayer");
-
returnnew StagefrightPlayer();
-
}
-
};
比较简单,就是一些判断条件,这里还提供了createPlayer,返回实际的播放器对象,后面用的着。
2.2 setDataSource_pre
具体代码如下
- sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
- player_type playerType)
- {
- ALOGV("player type = %d", playerType);
- // create the right type of player
- sp<MediaPlayerBase> p = createPlayer(playerType);
- if(p == NULL) {
- returnp;
- }
- if(!p->hardwareOutput()) {
- mAudioOutput =new AudioOutput(mAudioSessionId);
- static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
- }
- returnp;
- }
-
sp
<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
-
player_type playerType)
-
{
-
ALOGV("player type = %d", playerType);
-
-
// create the right type of player
-
sp
<MediaPlayerBase> p = createPlayer(playerType);
-
if(p == NULL) {
-
returnp;
-
}
-
-
if(!p->hardwareOutput()) {
-
mAudioOutput =new AudioOutput(mAudioSessionId);
-
static_cast
<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
-
}
-
-
returnp;
-
}
- 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);
- }
- returnp;
- }
-
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);
-
}
-
-
returnp;
-
}
主要是创建播放器
上面看具体StagefrightPlayerFactory 实现的时候,代码中实现了createPlayer,此处就是调用的此方法
因此等价于return (new StagefrightPlayer()) ;
2.3 setDataSource_post
上面的代码的主要目的是找到对应的播放器,下面主要是执行具体的setdatasource操作
这里需要注意的是 实际的工作是在调用的时候完成的
1
|
setDataSource_post(p, p->setDataSource(fd, offset, length));
|
调用的时候,执行了实际播放器的setDataSource方法,而实际的setDataSource_post 仅仅是将播放器保存在本地成员mPlayer中,代码如下
- void MediaPlayerService::Client::setDataSource_post(
- constsp<MediaPlayerBase>& p,
- status_t status)
- {
- ALOGV(" setDataSource");
- mStatus = status;
- if(mStatus != OK) {
- ALOGE(" error: %d", mStatus);
- return;
- }
- // Set the re-transmission endpoint if one was chosen.
- if(mRetransmitEndpointValid) {
- mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
- if(mStatus != NO_ERROR) {
- ALOGE("setRetransmitEndpoint error: %d", mStatus);
- }
- }
- if(mStatus == OK) {
- mPlayer = p;
- }
- }
-
void MediaPlayerService::Client::setDataSource_post(
-
constsp
<MediaPlayerBase>& p,
-
status_t status)
-
{
-
ALOGV(" setDataSource");
-
mStatus = status;
-
if(mStatus != OK) {
-
ALOGE(" error: %d", mStatus);
-
return;
-
}
-
-
// Set the re-transmission endpoint if one was chosen.
-
if(mRetransmitEndpointValid) {
-
mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
-
if(mStatus != NO_ERROR) {
-
ALOGE("setRetransmitEndpoint error: %d", mStatus);
-
}
-
}
-
-
if(mStatus == OK) {
-
mPlayer = p;
-
}
-
}
下面就进入实际播放器stagefritplayer中看具体实现了(此处以stagefrightplayer为例)
通过上面的介绍,熟悉了如何从MediaPlayer(Java类)一步一步调用到实际工作的类StageFrigtPlayer
这里只是以setDataSource为例,其他方法如prepare等类似。
下面这张图表示了调用流程
总结下几种播放器的区别
StagefrightPlayer: 默认播放器,本地文件基本都使用其播放
NuPlayerDriver:主要用于播放网络视频,http https rtsp等
SonivoxPlayer:用于播放midi等类型的音乐
下一篇着重分析stagefrigtplayer的主要结构