必威体育Betway必威体育官网
当前位置:首页 > IT技术

stagefrightplayer调用过程

时间:2019-10-30 02:42:12来源:IT技术作者:seo实验室小编阅读:63次「手机版」
 

stagefright

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

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

  1. mediaplayer player=new MediaPlayer(); 
  2. player->setdatasource(url,header);

  3. player->prepare(); 

  4. player->start();

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

MediaPlayer::MediaPlayer()  主要是基本的初始化,比较简单。

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(newClient(**));

即player最终是用Client对象来初始化,可以直接认为player==client,创建Player,真正实现是MediaPlayerService创建的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下面分别来看。

这里有几种类型的播放器,会在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的主要结构

文章最后发布于: 2015-07-28 16:09:07

相关阅读

高德地图API的调用

项目中需要调用一下第三方地图的API,因为自己一直用的是高德地图,所以优先采用高德地图。事实证明我也没选错,百度地图的API使用起来

关于CoInitialize和CoUninitialize调用的有关问题

本人封装了一个类,里面需要用到ADO连接数据库,所以需要初始化COM环境以及释放COM环境,我打算在构造函数里面执行CoInitialize,在析构

调用bing上地图

smmUtility::mapIt(LogisticsPostalAddress::findByLocation(logisticsLocation.RecId));

python调用若快打码接口

# encoding=utf8 import requests import time def get_verify_code(im, typeid): verify_code = '****' url = 'http://ap

腾讯回应QQ浏览器调用摄像头:不会采集用户任何隐私

A5创业网(公众号:iadmin5)6月29日报道,日前,有用户称,在vivo NEX手机设备上通过手机QQ浏览器打开某些网页时,手机摄像头会出现&ldquo;自

分享到:

栏目导航

推荐阅读

热门阅读