Android多媒体播放器源码解析(stagefright框架)

来源:互联网 发布:金蝶软件数据导出 编辑:程序博客网 时间:2024/05/01 09:46

一、android多媒体播放的调用步骤:

a)android中定义一个MediaPlayer类

b)在MediaPlayer中使用JNI技术调用的是android_media_MediaPlayer.cpp(media\jni,在这个类中对标准的JNI函数名称进行的转换)

c)以下涉及的都是C++,android_media_MediaPlayer中调用的是mediaplayer.cpp(media\libmedia,涉及的库libmedia.so)中的函数

d)然后调用MediaPlayerService.cpp(media\libmediaplayerservice)中的函数

e)之后开始选择是使用OpenCore还是Stagefright(2.3中使用的是Stagefright),因此接下来调用的是StagefrightPlayer.cpp(media\libmediaplayerservice)中的相关函数

f)接下去就到了最关键的一个类AwesomePlayer.cpp(media\libstagefright),在这个类里面我们要对read进的buffer进行一些相应的处理,然后再render渲染到surface(这边涉及的库可能是libStagefright.so)

二、以setDataSource()来分析android多媒体播放过程:

a)MediaPlayer类有setDataSource方法,查看源码,它最后调用的是一个native函数(JNI标准),publicnativevoidsetDataSource(Stringpath),这个函数在android_media_MediaPlayer.cpp中实现

b)android_media_MediaPlayer.cpp中

android_media_MediaPlayer_setDataSourceAndHeaders(

JNIEnv*env,jobjectthiz,jstringpath,jobjectheaders)

sp<MediaPlayer>mp=getMediaPlayer(env,thiz);

。。。

status_topStatus=mp->setDataSource(String8(pathStr),headers?&headersVector:NULL);

。。。

其中mp是一个MediaPlayer的实例对象,pathStr是视频路径,之后会进入到 mediaplayer.cpp中的 setDataSource()函数

c)Mediaplayer.cpp中

status_tMediaPlayer::setDataSource(

constchar*url,constKeyedVector<String8,String8>*headers)

{

LOGV("setDataSource(%s)",url);

status_terr=BAD_VALUE;

if(url!=NULL){

constsp<IMediaPlayerService>&service(getMediaPlayerService());

if(service!=0){

sp<IMediaPlayer>player(

service->create(getpid(),this,url,headers,mAudioSessionId));

err=setDataSource(player);

}

}

returnerr;

}

这里会调用service的create()函数

d)在MediaPlayerService.cpp中

sp<IMediaPlayer>MediaPlayerService::create(

pid_tpid,constsp<IMediaPlayerClient>&client,constchar*url,

constKeyedVector<String8,String8>*headers,intaudioSessionId)

{

int32_tconnId=android_atomic_inc(&mNextConnId);

sp<Client>c=newClient(this,pid,connId,client,audioSessionId);

LOGV("Createnewclient(%d)frompid%d,url=%s,connId=%d,audioSessionId=%d",

connId,pid,url,connId,audioSessionId);

if(NO_ERROR!=c->setDataSource(url,headers))

{

c.clear();

returnc;

}

wp<Client>w=c;

Mutex::Autolocklock(mLock);

mClients.add(w);

returnc;

}

其中调用了Client类的setDataSource()函数,这个Client比较难找,其实它 是在MediaPlayerService.h中定义的,在java中叫内部类,C++中忘了,查看 Client类中的setDataSource()函数的代码

status_tMediaPlayerService::Client::setDataSource(

constchar*url,constKeyedVector<String8,String8>*headers)

{

LOGV("setDataSource(%s)",url);

if(url==NULL)

returnUNKNOWN_ERROR;

if(strncmp(url,"content://",10)==0){

//getafiledescriptorforthecontentUriand

//passittothesetDataSource(fd)method

String16url16(url);

intfd=android::openContentProviderFile(url16);

if(fd<0)

{

LOGE("Couldn'topenfdfor%s",url);

returnUNKNOWN_ERROR;

}

setDataSource(fd,0,0x7fffffffffLL);//thissetsmStatus

close(fd);

returnmStatus;

}else{

player_typeplayerType=getPlayerType(url);

LOGV("playertype=%d",playerType);

//createtherighttypeofplayer

sp<MediaPlayerBase>p=createPlayer(playerType);

if(p==NULL)returnNO_INIT;

if(!p->hardwareOutput()){

mAudioOutput=newAudioOutput(mAudioSessionId);

static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);

}

//nowsetdatasource

LOGV("setDataSource");

mStatus=p->setDataSource(url,headers);

if(mStatus==NO_ERROR){

mPlayer=p;

}else{

LOGE("error:%d",mStatus);

}

returnmStatus;

}

}

其中定义了一个MediaPlayerBase类的实例对象p,并且接下去调用了p的 setDataSource()函数,我们先看看createPlayer()这个函数的源码

staticsp<MediaPlayerBase>createPlayer(player_typeplayerType,void*cookie,

notify_callback_fnotifyFunc)

{

sp<MediaPlayerBase>p;

switch(playerType){

#ifndefNO_OPENCORE

casePV_PLAYER:

LOGV("createPVPlayer");

p=newPVPlayer();

break;

#endif

caseSONIVOX_PLAYER:

LOGV("createMidiFile");

p=newMidiFile();

break;

caseSTAGEFRIGHT_PLAYER:

LOGV("createStagefrightPlayer");

p=newStagefrightPlayer;

break;

caseTEST_PLAYER:

LOGV("CreateTestPlayerstub");

p=newTestPlayerStub();

break;

}

if(p!=NULL){

if(p->initCheck()==NO_ERROR){

p->setNotifyCallback(cookie,notifyFunc);

}else{

p.clear();

}

}

if(p==NULL){

LOGE("Failedtocreateplayerobject");

}

returnp;

}

值得注意的是红色部分,这边就到了StagefrightPlayer.cpp,上面说到定义了一 个MediaPlayerBase类的实例对象p,并且接下去调用了p的 setDataSource() 函数,那么我们就理所当然地去找MediaPlayerBase类了,但是找了很久没找到, 现在知道了,上面红色部分将new出来的StagefrightPlayer对象赋给了P,那么 P调 用的setDataSource()事实上是StagefrightPlayer这个类中的 setDataSource()这个函数

e)在StagefrightPlayer.cpp中

status_tStagefrightPlayer::setDataSource(

constchar*url,constKeyedVector<String8,String8>*headers){

LOGI("setDataSource('%s')",url);

returnmPlayer->setDataSource(url,headers);

}

其中,直接调用mPlayer->setDataSource(url,headers),那么这个mPlayer是什么 呢?在上一个步骤中的newStagefrightPlayer中其实已经赋值了,源码如下

StagefrightPlayer::StagefrightPlayer()

:mPlayer(newAwesomePlayer){

LOGV("StagefrightPlayer");

mPlayer->setListener(this);

}

从红色部分可以看出mPlayer是一个AwesomePlayer类的实例对象,那么这个 setDataSource()函数自然就到这个类中去找了

f)在AwesomePlayer.cpp中

voidAwesomePlayer::onVideoEvent(){

。。。。。。

for(;;){

。。。。。。

status_terr=mVideoSource->read(&mVideoBuffer,&options);

options.clearSeekTo();

。。。。。。

。。。。。。

if(mVideoRenderer!=NULL){

mVideoRenderer->render(mVideoBuffer);

}

。。。。。。

}

第一行红色字表示将帧数据读入mVideoBuffer,第二行红色字体是将这些帧数据渲染到画布中。我们需要修改的就是这个部分,不往下分析了。

三、以start()来分析android多媒体播放过程

a)首先查看MediaPlayer.java这个类的源码

publicvoidstart()throwsIllegalStateException{

stayAwake(true);

_start();

}

之后调用的是_start()这个native函数(JNI标准),即privatenativevoid_start()throwsIllegalStateException这个函数在android_media_MediaPlayer.cpp中实现

b)在Android_media_MediaPlayer.cpp中

staticvoid

android_media_MediaPlayer_start(JNIEnv*env,jobjectthiz)

{

LOGV("start");

sp<MediaPlayer>mp=getMediaPlayer(env,thiz);

if(mp==NULL){

jniThrowException(env,"java/lang/IllegalStateException",NULL);

return;

}

process_media_player_call(env,thiz,mp->start(),NULL,NULL);

}

我们看红色部分的代码,最终调用的是mp->start(),这个mp其实是MediaPlayer的一个对象,那么我们就去MediaPlayer.cpp中查看源码

c)在MediaPlayer.cpp中

status_tMediaPlayer::start()

{

。。。。。。

mCurrentState=MEDIA_PLAYER_STARTED;

status_tret=mPlayer->start();

if(ret!=NO_ERROR){

mCurrentState=MEDIA_PLAYER_STATE_ERROR;

}else{

。。。。。。

}
这时候调用了mPlayer的start()这个函数,查看MediaPlayer.h中,可以发现sp<IMediaPlayer>mPlayer,那么再去IMediaPlayer.cpp中去看看

d)在IMediaPlayer.cpp中

status_tstart()

{

Parceldata,reply;

data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());

remote()->transact(START,data,&reply);

returnreply.readInt32();

}


0 0
原创粉丝点击