博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【stagefrightplayer】1 调用过程
阅读量:2456 次
发布时间:2019-05-11

本文共 15435 字,大约阅读时间需要 51 分钟。

概述


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]
  1. MediaPlayer player=new MediaPlayer()
  2. player->setDataSource(url,header);
  3. player->prepare();
  4. player->start();
  5. ...
MediaPlayer player=new MediaPlayer()player->setDataSource(url,header);player->prepare();player->start();...
1、构造函数下面就介绍具体的调用流程,起点为MediaPlayer.cpp


代码如下

[html]
  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. }
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


入口代码如下

[html]
  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. }
status_t MediaPlayer::setDataSource(        constchar *url, const KeyedVector
*headers){ ALOGV("setDataSource(%s)", url); status_t err = BAD_VALUE; if(url != NULL) { constsp
& service(getMediaPlayerService()); if(service != 0) { sp
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的交互来完成了

[html]
  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. }
sp
MediaPlayerService::create(pid_t pid,const sp
& client, intaudioSessionId){ int32_t connId = android_atomic_inc(&mNextConnId); sp
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
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

[html]
  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. }
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
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下面分别来看。

[html]
  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. }
#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
& client, intfd, int64_t offset, int64_t length) { GET_PLAYER_TYPE_IMPL(client, fd, offset, length);}
这里如果所有播放器都不合适,则选择默认播放器这里流程是,从播放器仓库中选取最佳播放器,通过scoreFactory来确定

[html]
  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. }
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为默认播放器

[html]
  1. MediaPlayerService::MediaPlayerService()
  2. {
  3. ***
  4. MediaPlayerFactory::registerBuiltinFactories();
  5. }
MediaPlayerService::MediaPlayerService(){    ***    MediaPlayerFactory::registerBuiltinFactories();}
[html]
  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. }
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类型作为例子看下

[html]
  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. };
class StagefrightPlayerFactory :    publicMediaPlayerFactory::IFactory {  public:    virtual float scoreFactory(constsp
& 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
createPlayer() { ALOGV(" create StagefrightPlayer"); returnnew StagefrightPlayer(); }};

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

2.2 setDataSource_pre

具体代码如下

[html]
  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. }
sp
MediaPlayerService::Client::setDataSource_pre( player_type playerType){ ALOGV("player type = %d", playerType); // create the right type of player sp
p = createPlayer(playerType); if(p == NULL) { returnp; } if(!p->hardwareOutput()) { mAudioOutput =new AudioOutput(mAudioSessionId); static_cast
(p.get())->setAudioSink(mAudioOutput); } returnp;}
[html]
  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. }
sp
MediaPlayerService::Client::createPlayer(player_type playerType){ // determine if we have the right player type sp
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中,代码如下

[html]
  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. }
void MediaPlayerService::Client::setDataSource_post(        constsp
& 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的主要结构

你可能感兴趣的文章
java bitset_Java BitSet size()方法与示例
查看>>
java reader_Java Reader skip()方法与示例
查看>>
java treemap_Java TreeMap get()方法与示例
查看>>
python 示例_带有示例的Python File tell()方法
查看>>
C ++中带有示例的nanl()函数
查看>>
CSS中的对象适合属性
查看>>
scala 数字阶乘_Scala程序查找数字的阶乘
查看>>
数据挖掘 数据增强_增强数据结构
查看>>
Java Dictionary put()方法与示例
查看>>
strictmath_Java StrictMath pow()方法与示例
查看>>
java treemap_Java TreeMap values()方法与示例
查看>>
avr446是什么_什么是AVR(高级虚拟Risc)?
查看>>
贪婪算法 python_在Python中使用贪婪算法进行优化
查看>>
scala不可变和可变_在Scala中将不可变地图转换为可变地图
查看>>
pcy 算法_大数据分析中的PCY算法
查看>>
stl vector 函数_vector :: begin()函数以及C ++ STL中的示例
查看>>
Java BigInteger类| max()方法与示例
查看>>
Java BigInteger类| gcd()方法与示例
查看>>
Java类class isEnum()方法及示例
查看>>
Java PriorityQueue peek()方法与示例
查看>>