【stagefrightplayer】1 调用过程

概述

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();
...

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;
}


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

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;
}


先看下 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;
}


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


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);
}


这里如果所有播放器都不合适,则选择默认播放器这里流程是,从播放器仓库中选取最佳播放器,通过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;
}


这里有几种类型的播放器,会在mediaplayerservice服务类 的构造函数中来注册,代码如下代码中可以看出,一般情况下,STAGEFRIGHT_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;
    }
}


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

 

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

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

 

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

 

 

总结下几种播放器的区别

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

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

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

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


文章系原创,转载请注明出处!

你可能感兴趣的:(【stagefrightplayer】1 调用过程)