IJKPlayer阅读笔记(二)setDataSource

1,555 阅读2分钟

入口方法

ijkMediaPlayer.setDataSource(path);

分析

Java

@Override
public void setDataSource(String path)throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
    mDataSource = path;
     _setDataSource(path, null, null);
}

又是一个native方法,只传递了资源路径,剩下的参数都是null

Native

查询jni映射,得知对应的方法为IjkMediaPlayer_setDataSourceCallback

  • IjkMediaPlayer_setDataSourceCallback
    该文件在ijkmedia/ijkplayer/android/ijkplayer_jni.c
static void
IjkMediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject callback) {
    char uri[128];
    int64_t nativeMediaDataSource = 0;
    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);
    nativeMediaDataSource = jni_set_media_data_source(env, thiz, callback);
    snprintf(uri, sizeof(uri), "ijkmediadatasource:%"
    PRId64, nativeMediaDataSource);
    retval = ijkmp_set_data_source(mp, uri);
}

去除掉无用的代码后,首先会调用jni_get_media_player

  • jni_get_media_player
    该方法在同一文件下
    static IjkMediaPlayer *jni_get_media_player(JNIEnv *env, jobject thiz) {
        IjkMediaPlayer *mp = (IjkMediaPlayer *) (intptr_t) J4AC_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll(env, thiz);
        if (mp) {
            ijkmp_inc_ref(mp);
        }
        return mp;
    }
    

J4AC_IjkMediaPlayer__mNativeMediaPlayer__get__catchAll这个方法用来获取java层的ijkplayer的,ijkmp_inc_ref则是将引用计数+1的。也就是说这个方法用于获取java层的ijkplayer
接下来会去调用jni_set_media_data_source方法,该方法也在ijkplayer_jni中。

  • jni_set_media_data_source
    static int64_t jni_set_media_data_source(JNIEnv *env, jobject thiz, jobject media_data_source) {
        int64_t nativeMediaDataSource = 0;
    
        jobject old = (jobject)(intptr_t)J4AC_IjkMediaPlayer__mNativeMediaDataSource__get__catchAll(env, thiz);
        if (old) {
            J4AC_IMediaDataSource__close__catchAll(env, old);
            J4A_DeleteGlobalRef__p(env, &old);
            J4AC_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll(env, thiz, 0);
        }
    
        if (media_data_source) {
            jobject global_media_data_source = (*env)->NewGlobalRef(env, media_data_source);
            
            nativeMediaDataSource = (int64_t)(intptr_t)global_media_data_source;
            J4AC_IjkMediaPlayer__mNativeMediaDataSource__set__catchAll(env, thiz,(jlong) nativeMediaDataSource);
        }
    }
    

先获取到旧的dataSource(java层的IjkMediaPlayer.mNativeMediaDataSource),然后进行清空操作,然后设置新得dataSource
接下来就是ijkmp_set_data_source方法了。

  • ijkmp_set_data_source
    该方法定义在ijkplayer.c中。
int ijkmp_set_data_source(IjkMediaPlayer *mp,const char *url) {
    int retval = ijkmp_set_data_source_l(mp, url);
    return retval;
}

这里调用了ijkmp_set_data_source_l这个方法

  • ijkmp_set_data_source_l
    该方法定义在ijkplayer.c中。
static int ijkmp_set_data_source(IjkMediaPlayer *mp, const char *url) {
    //没搞懂这段代码,看起来应该是检查状态的
    // MPST_RET_IF_EQ(mp->mp_stateMP_STATE_IDLE);
    MPST_RET_IF_EQ(mp->mp_stateMP_STATE_INITIALIZED);
    MPST_RET_IF_EQ(mp->mp_stateMP_STATE_ASYNC_PREPARING);
    MPST_RET_IF_EQ(mp->mp_stateMP_STATE_PREPARED);
    MPST_RET_IF_EQ(mp->mp_stateMP_STATE_STARTED);
    MPST_RET_IF_EQ(mp->mp_stateMP_STATE_PAUSED);
    MPST_RET_IF_EQ(mp->mp_stateMP_STATE_COMPLETED);
    MPST_RET_IF_EQ(mp->mp_stateMP_STATE_STOPPED);
    MPST_RET_IF_EQ(mp->mp_stateMP_STATE_ERROR);
    MPST_RET_IF_EQ(mp->mp_state, MP_STATE_END)
    freep((void **) &mp->data_source);
    mp->data_source = strdup(url);
    ijkmp_change_state_l(mpMP_STATE_INITIALIZED);
    return 0;
}

那些调用宏定义的代码没搞清楚是什么含义,猜测是用来检测状态的,freep看起来是释放指针的。接下来将mpdata_source的指针指向到url,接下来调用ijkmp_change_state_l

  • ijkmp_change_state_l
    该方法定义在ijkplayer.c
void ijkmp_change_state_l(IjkMediaPlay*mp, int new_state) {
    mp->mp_state = new_state;
    ffp_notify_msg1(mp->ffplayeFFP_MSG_PLAYBACK_STATE_CHANGED);
}

传递进来的stateMP_STATE_INITIALIZED,意义为初始化状态。接着调用ffp_notify_msg1

  • ffp_notify_msg1
    该函数定义在ijkmedia/ijkplayer/ff_ffplay_def.h
inline static void ffp_notify_(FFPlayer *ffp, int what{
    msg_queue_put_simplffp->msg_queue, what, 0, 0);
}

该方法为一个内联方法,msg_queue_put_simple3作用是把what(FFP_MSG_PLAYBACK_STATE_CHANGED)放入到ffp->msg_queue队列中 这里我们回到IjkMediaPlayer_setDataSourceCallback方法中,发现IjkMediaPlayer_setDataSourceCallback已全部执行完毕

总结

ijkmediaplayersetDataSource相比较初始化流程较短,主要执行了重设javamNativeMediaDataSource,然后将url赋予给nativemp中的data_source,然后调整mp的状态为MP_STATE_INITIALIZED,最后通过ffplayermsg_queueFFP_MSG_PLAYBACK_STATE_CHANGED状态传递出去

结构

--->ijkmedia/ijkplayer/android/ijkplayer_jni.c/IjkMediaPlayer_setDataSourceCallback
------->ijkmedia/ijkplayer/android/ijkplayer_jni.c/jni_get_media_player
------->ijkmedia/ijkplayer/android/ijkplayer_jni.c/jni_set_media_data_source
----------->ijkmedia/ijkplayer/ijkplayer.c/ijkmp_set_data_source
--------------->ijkmedia/ijkplayer/ijkplayer.c/ijkmp_set_data_source_l
------------------->ijkmedia/ijkplayer/ijkplayer.c/ijkmp_change_state_l
----------------------->ijkmedia/ijkplayer/ijkplayer.c/ffp_notify_msg1
--------------------------->ijkmedia/ijkplayer/ff_ffplay_def.h