基于android8.1代码,只分析打开本地文件的主干流程
先看一大体流程
MediaPlayer.java
public void setDataSource(String path)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
setDataSource(path, null, null);
}
//省略其他中间调用函数...
private void setDataSource(String path, String[] keys, String[] values,
List cookies)
throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
final Uri uri = Uri.parse(path);
final String scheme = uri.getScheme();
if ("file".equals(scheme)) {
path = uri.getPath();
} else if (scheme != null) {
//省略 ...
}
//将文件的路径转化为FileDescriptor
final File file = new File(path);
if (file.exists()) {
FileInputStream is = new FileInputStream(file);
FileDescriptor fd = is.getFD();
setDataSource(fd);
is.close();
} else {
throw new IOException("setDataSource failed.");
}
}
public void setDataSource(FileDescriptor fd)
throws IOException, IllegalArgumentException, IllegalStateException {
// intentionally less than LONG_MAX
setDataSource(fd, 0, 0x7ffffffffffffffL);
}
public void setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException {
_setDataSource(fd, offset, length);
}
private native void _setDataSource(FileDescriptor fd, long offset, long length)
throws IOException, IllegalArgumentException, IllegalStateException;
这不部分代码,主要是在中间将 文件路径String path转化为FileDescriptor fd,最终调用到jni的setDataSource(FileDescriptor fd, long offset, long length)方法
android_meida_MediaPlayer.cpp
static void
android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
{
//获取nativie 层MediaPlayer
sp mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
//将fileDescriptor 转化为native层能识别的文件fd
if (fileDescriptor == NULL) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
ALOGV("setDataSourceFD: fd %d", fd);
//调用native层的的 setDataSource
process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
}
1 获取native MediaPlayer的实例, 实例是在应用调用 new MediaPlayer()流程中创建的,可以参考
MediaPlayer(四)--MediaPlayer()流程
2 将fileDescriptor 转化为native层能识别的文件fd
3 调用native层的的 setDataSource
mediaplayer.cpp
status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
{
ALOGV("setDataSource(%d, %" PRId64 ", %" PRId64 ")", fd, offset, length);
status_t err = UNKNOWN_ERROR;
const sp service(getMediaPlayerService());
if (service != 0) {
sp player(service->create(this, mAudioSessionId));
if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
(NO_ERROR != player->setDataSource(fd, offset, length))) {
player.clear();
}
err = attachNewPlayer(player);
}
return err;
}
1 const sp
2 sp
3 调用MediaPlayerService::Client的setDataSource
4 attachNewPlayer 修改MediaPlayer状态,将player赋值给成员变量mPlayer, 后续MediaPlayer 才能通过该变量去访问MeidiaPlayerService
关于这部分可参考MediaPlayer(三)--C++ binder框架
MediaPlayerService
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
struct stat sb;
int ret = fstat(fd, &sb);
if (ret != 0) {
ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
return UNKNOWN_ERROR;
}
ALOGV("st_dev = %llu", static_cast(sb.st_dev));
ALOGV("st_mode = %u", sb.st_mode);
ALOGV("st_uid = %lu", static_cast(sb.st_uid));
ALOGV("st_gid = %lu", static_cast(sb.st_gid));
ALOGV("st_size = %llu", static_cast(sb.st_size));
if (offset >= sb.st_size) {
ALOGE("offset error");
return UNKNOWN_ERROR;
}
if (offset + length > sb.st_size) {
length = sb.st_size - offset;
ALOGV("calculated length = %lld", (long long)length);
}
player_type playerType = MediaPlayerFactory::getPlayerType(this,
fd,
offset,
length);
sp p = setDataSource_pre(playerType);
if (p == NULL) {
return NO_INIT;
}
// now set data source
return mStatus = setDataSource_post(p, p->setDataSource(fd, offset, length));
}
sp MediaPlayerService::Client::setDataSource_pre(
player_type playerType)
{
ALOGV("player type = %d", playerType);
// create the right type of player
sp p = createPlayer(playerType);
if (p == NULL) {
return p;
}
//省略...
return p;
}
status_t MediaPlayerService::Client::setDataSource_post(
const sp& p,
status_t status)
{
ALOGV(" setDataSource");
if (status != OK) {
ALOGE(" error: %d", status);
return status;
}
// Set the re-transmission endpoint if one was chosen.
if (mRetransmitEndpointValid) {
status = p->setRetransmitEndpoint(&mRetransmitEndpoint);
if (status != NO_ERROR) {
ALOGE("setRetransmitEndpoint error: %d", status);
}
}
if (status == OK) {
Mutex::Autolock lock(mLock);
mPlayer = p;
}
return status;
}
MediaPlayerService 中主要做了
1 通过MediaPlayerFactory 创建了NuPlayer
2 调用了NuPlayer的setDataSource
总结
setDataSource的主要流程,主要是创建了NuPlayer,并调用NuPlayer的setDataSource.
根据MediaPlayer的状态图,在应用调用setDataSource完,MediaPlayer的状态变为initialize。这部分是在mediaplayer.cpp 等到底层的setDataSource调用返回后,在方法attachNewPlayer中修改的
status_t MediaPlayer::attachNewPlayer(const sp& player)
{
status_t err = UNKNOWN_ERROR;
sp p;
{ // scope for the lock
Mutex::Autolock _l(mLock);
if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
(mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
ALOGE("attachNewPlayer called in state %d", mCurrentState);
return INVALID_OPERATION;
}
clear_l();
p = mPlayer;
mPlayer = player;
if (player != 0) {
//将MediaPlayer的状态修改为MEDIA_PLAYER_INITIALIZED
mCurrentState = MEDIA_PLAYER_INITIALIZED;
player->getDefaultBufferingSettings(&mCurrentBufferingSettings);
err = NO_ERROR;
} else {
mCurrentBufferingSettings = BufferingSettings();
ALOGE("Unable to create media player");
}
}
if (p != 0) {
p->disconnect();
}
return err;
}
NuPlayer的流程就先不分析了,可以后面做一个专题