http://hi.baidu.com/dean_wang/blog/item/c45aec3a96b30ed5d4622515.html
剖析android的MediaPlay.java的JNI实现;【封装太深】
MediaPlay.java在源码frameworks\base\media\java\android\media文件夹位置;
所有的JNI接口实现在frameworks\base\media\jni下android_media_MediaPlayer.cpp文件;
从初始化开始;
MediaPlay.java:
static {
System.loadLibrary("media_jni");
native_init();
}
调用了native_init;映射到android_media_MediaPlayer.cpp的android_media_MediaPlayer_native_init函数,主要进行该cpp内struct 变量field的初始化;
MediaPlayer.java的构造函数调用native_setup函数映射到android_media_MediaPlayer_native_setup函数,主要操作是:
sp
setMediaPlayer(env, thiz, mp);
构造了一个MediaPlayer类并将指针赋值给上层MediaPlayer.java的mNativeContext变量;
JNI层 的MediaPlayer是一个C++类,头文件在frameworks\base\include\media\mediaplayer.h,实现在frameworks\base\media\libmedia\mediaplayer.cpp;
来看mediaplayer.h函数的setDataSource实现;两个不同参数的setDataSource函数都调用了
const sp
sp
setDataSource(player);
上述代码有两步:1、getMediaPlayerService,并调用service->create;2、调用另一个内部的函数setDataSource(player);
第二步做的主要事情就是将第一步创建出来的player设置为mPlayer;
分析第一步:
getMediaPlayerService()函数是底层MediaPlayer的父类IMediaDeathNotifier的一个成员函数:
IMediaDeathNotifier::getMediaPlayerService()
{
LOGV("getMediaPlayerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService.get() == 0) {
sp
sp
do {
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
LOGW("Media player service not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast
}
LOGE_IF(sMediaPlayerService == 0, "no media player service!?");
return sMediaPlayerService;
}
defaultServiceManager函数是frameworks/base/libs/utils/IServiceManager.cpp下实现,头文件是frameworks\base\include\binder\IServiceManager.h;
基本上到这一步就是系统服务管理的东西了。打止。
回到MediaService;查看frameworks\base\media\libmediaplayerservice\MediaPlayerService.h和MediaPlayerService.cpp文件;找create函数;
sp
int fd, int64_t offset, int64_t length)
{
int32_t connId = android_atomic_inc(&mNextConnId);
sp
LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld",
connId, pid, fd, offset, length);
if (NO_ERROR != c->setDataSource(fd, offset, length)) {
c.clear();
} else {
wp
Mutex::Autolock lock(mLock);
mClients.add(w);
}
::close(fd);
return c;
}
另外一个函数大致流程也一样,只不过接收参数是URL;都是先创建一个Client然后调用Client的setDataSource方法;
Client是MediaPlayerService的一个内部类;在MediaPlayerService.cpp文件内找到Client里面的setDataSource方法实现:
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
struct stat sb;
int ret = fstat(fd, &sb);
if (ret != 0) {
LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
return UNKNOWN_ERROR;
}
LOGV("st_dev = %llu", sb.st_dev);
LOGV("st_mode = %u", sb.st_mode);
LOGV("st_uid = %lu", sb.st_uid);
LOGV("st_gid = %lu", sb.st_gid);
LOGV("st_size = %llu", sb.st_size);
if (offset >= sb.st_size) {
LOGE("offset error");
::close(fd);
return UNKNOWN_ERROR;
}
if (offset + length > sb.st_size) {
length = sb.st_size - offset;
LOGV("calculated length = %lld", length);
}
player_type playerType = getPlayerType(fd, offset, length);
LOGV("player type = %d", playerType);
// create the right type of player
sp
if (p == NULL) return NO_INIT;
if (!p->hardwareOutput()) {
mAudioOutput = new AudioOutput();
static_cast
}
// now set data source
mStatus = p->setDataSource(fd, offset, length);
if (mStatus == NO_ERROR) mPlayer = p;
return mStatus;
}
Client做的主要事情:
1、调用getPlayerType
2、调用createPlayer创建一个MediaPlayerBase并调用其setDataSource方法