MeidaPlayer(五)--setDataSource(String path)流程

基于android8.1代码,只分析打开本地文件的主干流程

先看一大体流程


MeidaPlayer(五)--setDataSource(String path)流程_第1张图片
SetDataSource.png

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 service(getMediaPlayerService()); 这一步其实是获取了BpMediaPlayerService
2 sp player(service->create(this, mAudioSessionId)); 这一步是通过BpMediaPlayerService 的create方法返回了BpMediaPlayer
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的流程就先不分析了,可以后面做一个专题

你可能感兴趣的:(MeidaPlayer(五)--setDataSource(String path)流程)