一、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标准),public native void setDataSource(String path),这个函数在android_media_MediaPlayer.cpp中实现
b) android_media_MediaPlayer.cpp中
android_media_MediaPlayer_setDataSourceAndHeaders(
JNIEnv *env, jobject thiz, jstring path, jobject headers)
{
sp
。。。
status_t opStatus = mp->setDataSource(String8(pathStr), headers ? &headersVector : NULL);
。。。
}
其中mp是一个MediaPlayer的实例对象,pathStr是视频路径,之后会进入到 mediaplayer.cpp中的 setDataSource()函数
c) Mediaplayer.cpp中
status_t MediaPlayer::setDataSource(
const char *url, const KeyedVector
{
LOGV("setDataSource(%s)", url);
status_t err = BAD_VALUE;
if (url != NULL) {
const sp
if (service != 0) {
sp
service->create(getpid(), this, url, headers, mAudioSessionId));
err = setDataSource(player);
}
}
return err;
}
这里会调用service的create()函数
d) 在MediaPlayerService.cpp中
sp
pid_t pid, const sp
const KeyedVector
{
int32_t connId = android_atomic_inc(&mNextConnId);
sp
LOGV("Create new client(%d) from pid %d, url=%s, connId=%d, audioSessionId=%d",
connId, pid, url, connId, audioSessionId);
if (NO_ERROR != c->setDataSource(url, headers))
{
c.clear();
return c;
}
wp
Mutex::Autolock lock(mLock);
mClients.add(w);
return c;
}
其中调用了Client类的setDataSource()函数,这个Client比较难找,其实它 是在MediaPlayerService.h中定义的,在java中叫内部类,C++中忘了,查看 Client类中的setDataSource()函数的代码
status_t MediaPlayerService::Client::setDataSource(
const char *url, const KeyedVector
{
LOGV("setDataSource(%s)", url);
if (url == NULL)
return UNKNOWN_ERROR;
if (strncmp(url, "content://", 10) == 0) {
// get a filedescriptor for the content Uri and
// pass it to the setDataSource(fd) method
String16 url16(url);
int fd = android::openContentProviderFile(url16);
if (fd < 0)
{
LOGE("Couldn't open fd for %s", url);
return UNKNOWN_ERROR;
}
setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus
close(fd);
return mStatus;
} else {
player_type playerType = getPlayerType(url);
LOGV("player type = %d", playerType);
// create the right type of player
sp
if (p == NULL) return NO_INIT;
if (!p->hardwareOutput()) {
mAudioOutput = new AudioOutput(mAudioSessionId);
static_cast
}
// now set data source
LOGV(" setDataSource");
mStatus = p->setDataSource(url, headers);
if (mStatus == NO_ERROR) {
mPlayer = p;
} else {
LOGE(" error: %d", mStatus);
}
return mStatus;
}
}
其中定义了一个MediaPlayerBase类的实例对象p,并且接下去调用了p的 setDataSource()函数,我们先看看createPlayer()这个函数的源码
static sp
notify_callback_f notifyFunc)
{
sp
switch (playerType) {
#ifndef NO_OPENCORE
case PV_PLAYER:
LOGV(" create PVPlayer");
p = new PVPlayer();
break;
#endif
case SONIVOX_PLAYER:
LOGV(" create MidiFile");
p = new MidiFile();
break;
case STAGEFRIGHT_PLAYER:
LOGV(" create StagefrightPlayer");
p = new StagefrightPlayer;
break;
case TEST_PLAYER:
LOGV("Create Test Player stub");
p = new TestPlayerStub();
break;
}
if (p != NULL) {
if (p->initCheck() == NO_ERROR) {
p->setNotifyCallback(cookie, notifyFunc);
} else {
p.clear();
}
}
if (p == NULL) {
LOGE("Failed to create player object");
}
return p;
}
值得注意的是红色部分,这边就到了StagefrightPlayer.cpp,上面说到定义了一 个MediaPlayerBase类的实例对象p,并且接下去调用了p的 setDataSource() 函数,那么我们就理所当然地去找MediaPlayerBase类了,但是找了很久没找到, 现在知道了,上面红色部分将new出来的StagefrightPlayer对象赋给了P,那么 P调 用的setDataSource()事实上是StagefrightPlayer这个类中的 setDataSource()这个函数
e) 在StagefrightPlayer.cpp中
status_t StagefrightPlayer::setDataSource(
const char *url, const KeyedVector
LOGI("setDataSource('%s')", url);
return mPlayer->setDataSource(url, headers);
}
其中,直接调用mPlayer->setDataSource(url, headers),那么这个mPlayer是什么 呢?在上一个步骤中的new StagefrightPlayer中其实已经赋值了,源码如下
StagefrightPlayer::StagefrightPlayer()
: mPlayer(new AwesomePlayer) {
LOGV("StagefrightPlayer");
mPlayer->setListener(this);
}
从红色部分可以看出mPlayer是一个AwesomePlayer类的实例对象,那么这个 setDataSource()函数自然就到这个类中去找了
f) 在AwesomePlayer.cpp中
void AwesomePlayer::onVideoEvent() {
。。。。。。
for (;;) {
。。。。。。
status_t err = mVideoSource->read(&mVideoBuffer, &options);
options.clearSeekTo();
。。。。。。
}
。。。。。。
if (mVideoRenderer != NULL) {
mVideoRenderer->render(mVideoBuffer);
}
。。。。。。
}
第一行红色字表示将帧数据读入mVideoBuffer,第二行红色字体是将这些帧数据渲染到画布中。我们需要修改的就是这个部分,不往下分析了。
三、以start()来分析android多媒体播放过程
a) 首先查看MediaPlayer.java这个类的源码
public void start() throws IllegalStateException {
stayAwake(true);
_start();
}
之后调用的是_start()这个native函数(JNI标准),即private native void _start() throws IllegalStateException这个函数在android_media_MediaPlayer.cpp中实现
b) 在Android_media_MediaPlayer.cpp中
static void
android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{
LOGV("start");
sp
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_t MediaPlayer::start()
{
。。。。。。
mCurrentState = MEDIA_PLAYER_STARTED;
status_t ret = mPlayer->start();
if (ret != NO_ERROR) {
mCurrentState = MEDIA_PLAYER_STATE_ERROR;
} else {
。。。。。。
}
这时候调用了mPlayer的start()这个函数,查看MediaPlayer.h中,可以发现sp
d) 在IMediaPlayer.cpp中
status_t start()
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
remote()->transact(START, data, &reply);
return reply.readInt32();
}