概述

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类的方法介绍,可参考译文

本篇主要介绍一个典型的播放调用过程

下面是一个典型的播放序列:

[html] view plain copy print ?
  1. MediaPlayer player=new MediaPlayer()
  2. player->setDataSource(url,header);
  3. player->prepare();
  4. player->start();
  5. ...

1、构造函数下面就介绍具体的调用流程,起点为MediaPlayer.cpp

代码如下

[html] view plain copy print ?
  1. MediaPlayer::MediaPlayer()
  2. {
  3. ALOGV("constructor");
  4. mListener = NULL;
  5. mCookie = NULL;
  6. mStreamType = AUDIO_STREAM_MUSIC;
  7. mCurrentPosition = -1;
  8. mSeekPosition = -1;
  9. mCurrentState = MEDIA_PLAYER_IDLE;
  10. mPrepareSync =false;
  11. mPrepareStatus = NO_ERROR;
  12. mLoop =false;
  13. mLeftVolume = mRightVolume =1.0;
  14. mVideoWidth = mVideoHeight =0;
  15. mLockThreadId =0;
  16. mAudioSessionId = AudioSystem::newAudioSessionId();
  17. AudioSystem::acquireAudioSessionId(mAudioSessionId);
  18. mSendLevel =0;
  19. mRetransmitEndpointValid =false;
  20. }


主要是基本的初始化,比较简单。

2、setDataSource

入口代码如下

[html] view plain copy print ?
  1. status_t MediaPlayer::setDataSource(
  2. constchar *url, const KeyedVector<String8, String8> *headers)
  3. {
  4. ALOGV("setDataSource(%s)", url);
  5. status_t err = BAD_VALUE;
  6. if(url != NULL) {
  7. constsp<IMediaPlayerService>& service(getMediaPlayerService());
  8. if(service != 0) {
  9. sp<IMediaPlayer> player(service->create(getpid(),this, mAudioSessionId));
  10. if((NO_ERROR != doSetRetransmitEndpoint(player)) ||
  11. (NO_ERROR != player->setDataSource(url, headers))) {
  12. player.clear();
  13. }
  14. err = attachNewPlayer(player);
  15. }
  16. }
  17. returnerr;
  18. }


先看下 service->create(getpid(), this, mAudioSessionId)操作,代码在mediaplayerservice.cpp中 setDataSource的操作就转成通过与mediaplayerservice的交互来完成了

[html] view plain copy print ?
  1. sp<IMediaPlayer> MediaPlayerService::create(pid_t pid,const sp<IMediaPlayerClient>& client,
  2. intaudioSessionId)
  3. {
  4. int32_t connId = android_atomic_inc(&mNextConnId);
  5. sp<Client> c =new Client(
  6. this, pid, connId, client, audioSessionId,
  7. IPCThreadState::self()->getCallingUid());
  8. ALOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid,
  9. IPCThreadState::self()->getCallingUid());
  10. wp<Client> w = c;
  11. {
  12. Mutex::Autolock lock(mLock);
  13. mClients.add(w);
  14. }
  15. returnc;
  16. }


而且,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

[html] view plain copy print ?
  1. status_t MediaPlayerService::Client::setDataSource(intfd, int64_t offset, int64_t length)
  2. {
  3. ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
  4. struct stat sb;
  5. intret = fstat(fd, &sb);
  6. if(ret != 0) {
  7. ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
  8. returnUNKNOWN_ERROR;
  9. }
  10. ALOGV("st_dev = %llu", sb.st_dev);
  11. ALOGV("st_mode = %u", sb.st_mode);
  12. ALOGV("st_uid = %lu", sb.st_uid);
  13. ALOGV("st_gid = %lu", sb.st_gid);
  14. ALOGV("st_size = %llu", sb.st_size);
  15. if(offset >= sb.st_size) {
  16. ALOGE("offset error");
  17. ::close(fd);
  18. returnUNKNOWN_ERROR;
  19. }
  20. if(offset + length > sb.st_size) {
  21. length = sb.st_size - offset;
  22. ALOGV("calculated length = %lld", length);
  23. }
  24. player_type playerType = MediaPlayerFactory::getPlayerType(this,
  25. fd,
  26. offset,
  27. length);
  28. sp<MediaPlayerBase> p = setDataSource_pre(playerType);
  29. if(p == NULL) {
  30. returnNO_INIT;
  31. }
  32. // now set data source
  33. setDataSource_post(p, p->setDataSource(fd, offset, length));
  34. returnmStatus;
  35. }


2.1 getPlayerType代码比较清晰,首选是选择播放器类型,之后调用setDataSource_pre以及setDataSource_post下面分别来看。

[html] view plain copy print ?
  1. #define GET_PLAYER_TYPE_IMPL(a...) \
  2. Mutex::Autolock lock_(&sLock); \
  3. \
  4. player_type ret = STAGEFRIGHT_PLAYER; \
  5. float bestScore =0.0; \
  6. \
  7. for(size_t i = 0; i < sFactoryMap.size(); ++i) { \
  8. \
  9. IFactory* v = sFactoryMap.valueAt(i); \
  10. float thisScore; \
  11. CHECK(v != NULL); \
  12. thisScore = v->scoreFactory(a, bestScore); \
  13. if(thisScore > bestScore) { \
  14. ret = sFactoryMap.keyAt(i); \
  15. bestScore = thisScore; \
  16. } \
  17. } \
  18. \
  19. if(0.0 == bestScore) { \
  20. bestScore = getDefaultPlayerType(); \
  21. } \
  22. \
  23. returnret;
  24. player_type MediaPlayerFactory::getPlayerType(constsp<IMediaPlayer>& client,
  25. intfd,
  26. int64_t offset,
  27. int64_t length) {
  28. GET_PLAYER_TYPE_IMPL(client, fd, offset, length);
  29. }


这里如果所有播放器都不合适,则选择默认播放器这里流程是,从播放器仓库中选取最佳播放器,通过scoreFactory来确定

[html] view plain copy print ?
  1. player_type MediaPlayerFactory::getDefaultPlayerType() {
  2. char value[PROPERTY_VALUE_MAX];
  3. if(property_get("media.stagefright.use-nuplayer", value, NULL)
  4. && (!strcmp("1", value) || !strcasecmp("true", value))) {
  5. returnNU_PLAYER;
  6. }
  7. returnSTAGEFRIGHT_PLAYER;
  8. }


这里有几种类型的播放器,会在mediaplayerservice服务类 的构造函数中来注册,代码如下代码中可以看出,一般情况下,STAGEFRIGHT_PLAYER为默认播放器

[html] view plain copy print ?
  1. MediaPlayerService::MediaPlayerService()
  2. {
  3. ***
  4. MediaPlayerFactory::registerBuiltinFactories();
  5. }
[html] view plain copy print ?
  1. void MediaPlayerFactory::registerBuiltinFactories() {
  2. Mutex::Autolock lock_(&sLock);
  3. if(sInitComplete)
  4. return;
  5. registerFactory_l(newStagefrightPlayerFactory(), STAGEFRIGHT_PLAYER);
  6. registerFactory_l(newNuPlayerFactory(), NU_PLAYER);
  7. registerFactory_l(newSonivoxPlayerFactory(), SONIVOX_PLAYER);
  8. registerFactory_l(newTestPlayerFactory(), TEST_PLAYER);
  9. sInitComplete =true;
  10. }

从registerBuiltinFactories的实现可以看出共注册了四个播放器类型。后面会介绍几个播放器的用途等


下面挑选STAGEFRIGHT_PLAYER类型作为例子看下


[html] view plain copy print ?
  1. class StagefrightPlayerFactory :
  2. publicMediaPlayerFactory::IFactory {
  3. public:
  4. virtual float scoreFactory(constsp<IMediaPlayer>& client,
  5. intfd,
  6. int64_t offset,
  7. int64_t length,
  8. float curScore) {
  9. char buf[20];
  10. lseek(fd, offset, SEEK_SET);
  11. read(fd, buf, sizeof(buf));
  12. lseek(fd, offset, SEEK_SET);
  13. long ident = *((long*)buf);
  14. // Ogg vorbis?
  15. if(ident == 0x5367674f)// 'OggS'
  16. return1.0;
  17. return0.0;
  18. }
  19. virtual sp<MediaPlayerBase> createPlayer() {
  20. ALOGV(" create StagefrightPlayer");
  21. returnnew StagefrightPlayer();
  22. }
  23. };


比较简单,就是一些判断条件,这里还提供了createPlayer,返回实际的播放器对象,后面用的着。

2.2 setDataSource_pre

具体代码如下

[html] view plain copy print ?
  1. sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
  2. player_type playerType)
  3. {
  4. ALOGV("player type = %d", playerType);
  5. // create the right type of player
  6. sp<MediaPlayerBase> p = createPlayer(playerType);
  7. if(p == NULL) {
  8. returnp;
  9. }
  10. if(!p->hardwareOutput()) {
  11. mAudioOutput =new AudioOutput(mAudioSessionId);
  12. static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
  13. }
  14. returnp;
  15. }
[html] view plain copy print ?
  1. sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType)
  2. {
  3. // determine if we have the right player type
  4. sp<MediaPlayerBase> p = mPlayer;
  5. if((p != NULL) && (p->playerType() != playerType)) {
  6. ALOGV("delete player");
  7. p.clear();
  8. }
  9. if(p == NULL) {
  10. p = MediaPlayerFactory::createPlayer(playerType,this, notify);
  11. }
  12. if(p != NULL) {
  13. p->setUID(mUID);
  14. }
  15. returnp;
  16. }


主要是创建播放器

上面看具体StagefrightPlayerFactory 实现的时候,代码中实现了createPlayer,此处就是调用的此方法

因此等价于return (new StagefrightPlayer()) ;

2.3 setDataSource_post

上面的代码的主要目的是找到对应的播放器,下面主要是执行具体的setdatasource操作

这里需要注意的是 实际的工作是在调用的时候完成的

1 setDataSource_post(p, p->setDataSource(fd, offset, length));

调用的时候,执行了实际播放器的setDataSource方法,而实际的setDataSource_post 仅仅是将播放器保存在本地成员mPlayer中,代码如下

[html] view plain copy print ?
  1. void MediaPlayerService::Client::setDataSource_post(
  2. constsp<MediaPlayerBase>& p,
  3. status_t status)
  4. {
  5. ALOGV(" setDataSource");
  6. mStatus = status;
  7. if(mStatus != OK) {
  8. ALOGE(" error: %d", mStatus);
  9. return;
  10. }
  11. // Set the re-transmission endpoint if one was chosen.
  12. if(mRetransmitEndpointValid) {
  13. mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
  14. if(mStatus != NO_ERROR) {
  15. ALOGE("setRetransmitEndpoint error: %d", mStatus);
  16. }
  17. }
  18. if(mStatus == OK) {
  19. mPlayer = p;
  20. }
  21. }


下面就进入实际播放器stagefritplayer中看具体实现了(此处以stagefrightplayer为例)

通过上面的介绍,熟悉了如何从MediaPlayer(Java类)一步一步调用到实际工作的类StageFrigtPlayer

这里只是以setDataSource为例,其他方法如prepare等类似。

下面这张图表示了调用流程

总结下几种播放器的区别

StagefrightPlayer: 默认播放器,本地文件基本都使用其播放

NuPlayerDriver:主要用于播放网络视频,http https rtsp等

SonivoxPlayer:用于播放midi等类型的音乐

下一篇着重分析stagefrigtplayer的主要结构

更多相关文章

  1. ubuntu10.10下的android源码下载及编译
  2. Android截取字符串
  3. Android(安卓)开发笔记1 (MTK)
  4. Android(安卓)AOSP 环境下实现C++直接调用libmedia.so接口播放视
  5. Android(安卓)解决方法数 65536 (65k) 限制
  6. Android中WebView详解
  7. Android(安卓)跨应用调用Activity及Service
  8. js代码
  9. Android(安卓)高效的SQLite型数据库greenDAO使用

随机推荐

  1. Android开发者指南(9) ―― ProGuard
  2. 解决谷歌Android SDK下载慢的问题
  3. android选择图片或拍照图片上传到服务器(
  4. android 模拟器使用
  5. Android状态栏透明(沉浸式效果)
  6. Android的数据存储(二)——SQLite数据库
  7. 【android】平滑Activity过渡动画效果,类
  8. Android(安卓)实现一个Service应用
  9. android添加开机音乐
  10. [转]为Android加入busybox工具