一、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();
}