前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MediaPlayer(七)--prepareAsync

MediaPlayer(七)--prepareAsync

作者头像
小蚂蚁与大象
发布2020-04-21 11:40:08
1.2K0
发布2020-04-21 11:40:08
举报

frameworks/base/media/java/android/media/MediaPlayer.java

    /**
     * Prepares the player for playback, asynchronously.
     *
     * After setting the datasource and the display surface, you need to either
     * call prepare() or prepareAsync(). For streams, you should call prepareAsync(),
     * which returns immediately, rather than blocking until enough data has been
     * buffered.
     *
     * @throws IllegalStateException if it is called in an invalid state
     */
    public native void prepareAsync() throws IllegalStateException;

MediaPlayer.java 没有任何流程,直接调用了jni。从注释可以了解到,设置完datasource和 display surface就需要调用prepare或prepareAsync。prepare是阻塞的接口,prepareAsync是异步的接口。

/home/llm/project/rk/8.1/frameworks/base/media/jni/android_media_MediaPlayer.cpp

static void
android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
{
    sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
    if (mp == NULL ) {
        jniThrowException(env, "java/lang/IllegalStateException", NULL);
        return;
    }

    // Handle the case where the display surface was set before the mp was
    // initialized. We try again to make it stick.
    sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
    mp->setVideoSurfaceTexture(st);

    process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
}

首先重新设置了display surface,从注释看setDisplay接口可以在setDataSource之前被调用。接着调用到mediaplayer.cpp的接口

status_t MediaPlayer::prepareAsync()
{
    ALOGV("prepareAsync");
    Mutex::Autolock _l(mLock);
    return prepareAsync_l();
}

// must call with lock held
status_t MediaPlayer::prepareAsync_l()
{
    if ( (mPlayer != 0) && ( mCurrentState & (MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) {
        if (mAudioAttributesParcel != NULL) {
            mPlayer->setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, *mAudioAttributesParcel);
        } else {
            mPlayer->setAudioStreamType(mStreamType);
        }
        mCurrentState = MEDIA_PLAYER_PREPARING;
        return mPlayer->prepareAsync();
    }
    ALOGE("prepareAsync called in state %d, mPlayer(%p)", mCurrentState, mPlayer.get());
    return INVALID_OPERATION;
}

首先是对audio的设置,这部分笔者也没研究。 其次是将播放器的状态置为MEDIA_PLAYER_PREPARING 最后调用服务端的prepareAsync

frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

status_t MediaPlayerService::Client::prepareAsync()
{
    ALOGV("[%d] prepareAsync", mConnId);
    mMaybeVideoAlive = (mConnectedWindow.get() != NULL);
    sp<MediaPlayerBase> p = getPlayer();
    if (p == 0) return UNKNOWN_ERROR;
    status_t ret = p->prepareAsync();
#if CALLBACK_ANTAGONIZER
    ALOGD("start Antagonizer");
    if (ret == NO_ERROR) mAntagonizer->start();
#endif
    return ret;
}prepare

留下两个知识盲点:mConnectedWindow,CALLBACK_ANTAGONIZER 主要是直接调用到NuPlayer的prepareAsync.NuPlayer处理完后会通过notify回调函数通知java层,流程大概如下 NuPlayer -->MediaPlayerService::Client::notify--> MediaPlayer::notify--> JNIMediaPlayerListener::notify -->postEventFromNative(java)

根据MediaPlayer的状态图,MeidiaPlayer在执行往prepareAsync后会将状态置为prepared,这个操作是在MediaPlayer::notify处理的

void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
    case MEDIA_PREPARED:
        ALOGV("MediaPlayer::notify() prepared");
        mCurrentState = MEDIA_PLAYER_PREPARED;
        if (mPrepareSync) {
            ALOGV("signal application thread");
            mPrepareSync = false;
            mPrepareStatus = NO_ERROR;
            mSignal.signal();
        }
        break;

}

mSignal.signal();是一种信号量的通讯方式,其他调用了mSignal.wait的地方会阻塞等待,当收到signal的信号后就可以继续往下执行。我们知道MediaPlayer prepare方法是阻塞的,实际上prepare就是调用mSignal.wait进行等待,其他地方跟prepareAsync的流程是差不多的

status_t MediaPlayer::prepare()
{
    ALOGV("prepare");
    Mutex::Autolock _l(mLock);
    mLockThreadId = getThreadId();
    if (mPrepareSync) {
        mLockThreadId = 0;
        return -EALREADY;
    }
    mPrepareSync = true;
    status_t ret = prepareAsync_l();
    if (ret != NO_ERROR) {
        mLockThreadId = 0;
        return ret;
    }

    if (mPrepareSync) {
        mSignal.wait(mLock);  // wait for prepare done
        mPrepareSync = false;
    }
    ALOGV("prepare complete - status=%d", mPrepareStatus);
    mLockThreadId = 0;
    return mPrepareStatus;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档