概述
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::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; }
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; }
因此在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; }
#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); }
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::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; }
从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(); } };
比较简单,就是一些判断条件,这里还提供了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::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; } }
通过上面的介绍,熟悉了如何从MediaPlayer(Java类)一步一步调用到实际工作的类StageFrigtPlayer
这里只是以setDataSource为例,其他方法如prepare等类似。
下面这张图表示了调用流程
总结下几种播放器的区别
StagefrightPlayer: 默认播放器,本地文件基本都使用其播放
NuPlayerDriver:主要用于播放网络视频,http https rtsp等
SonivoxPlayer:用于播放midi等类型的音乐
下一篇着重分析stagefrigtplayer的主要结构
文章系原创,转载请注明出处!