理解ijkplayer(二)项目结构分析

1. 整体结构

.
├── android/   #android项目的demo和so库的输出路径
├── config/
├── doc/
├── extra/      #ijkplayer依赖的第三方库的源码,例如ffmpeg
├── ijkmedia/ #ijkplayer源码
├── ijkprof/
├── ios/
├── tools/
├── COPYING.GPLv2
├── COPYING.GPLv3
├── COPYING.LGPLv2.1
├── COPYING.LGPLv2.1.txt -> COPYING.LGPLv2.1
├── COPYING.LGPLv3
├── MODULE_LICENSE_APACHE2
├── NEWS.md
├── NOTICE
├── README.md
├── compile-android-j4a.sh*
├── init-android-exo.sh*
├── init-android-j4a.sh*
├── init-android-libsoxr.sh*
├── init-android-libyuv.sh*
├── init-android-openssl.sh*
├── init-android-prof.sh*
├── init-android-soundtouch.sh*
├── init-android.sh*
├── init-config.sh*
├── init-ios-openssl.sh*
├── init-ios.sh*
└── version.sh*

看源码只需要重点关注/ijkmediaextra/

2. 入口:ijkplayer_jni.c

ijkmedia/ijkplayer/android/ijkplayer_jni.c

这是android的入口文件,用动态加载的方式声明了jni方法:

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved){
  //.
}

g_methods数组中动态注册了jni方法。

static JNINativeMethod g_methods[] = {
    {
        "_setDataSource",
        "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
        (void *) IjkMediaPlayer_setDataSourceAndHeaders
    },
    { "_setDataSourceFd",       "(I)V",     (void *) IjkMediaPlayer_setDataSourceFd },
    { "_setDataSource",         "(Ltv/danmaku/ijk/media/player/misc/IMediaDataSource;)V", (void *)IjkMediaPlayer_setDataSourceCallback },
    { "_setAndroidIOCallback",  "(Ltv/danmaku/ijk/media/player/misc/IAndroidIO;)V", (void *)IjkMediaPlayer_setAndroidIOCallback },

    { "_setVideoSurface",       "(Landroid/view/Surface;)V", (void *) IjkMediaPlayer_setVideoSurface },
    { "_prepareAsync",          "()V",      (void *) IjkMediaPlayer_prepareAsync },
    { "_start",                 "()V",      (void *) IjkMediaPlayer_start },
    { "_stop",                  "()V",      (void *) IjkMediaPlayer_stop },
    { "seekTo",                 "(J)V",     (void *) IjkMediaPlayer_seekTo },
    { "_pause",                 "()V",      (void *) IjkMediaPlayer_pause },
    { "isPlaying",              "()Z",      (void *) IjkMediaPlayer_isPlaying },
    { "getCurrentPosition",     "()J",      (void *) IjkMediaPlayer_getCurrentPosition },
    { "getDuration",            "()J",      (void *) IjkMediaPlayer_getDuration },
    { "_release",               "()V",      (void *) IjkMediaPlayer_release },
    { "_reset",                 "()V",      (void *) IjkMediaPlayer_reset },
    { "setVolume",              "(FF)V",    (void *) IjkMediaPlayer_setVolume },
    { "getAudioSessionId",      "()I",      (void *) IjkMediaPlayer_getAudioSessionId },
    { "native_init",            "()V",      (void *) IjkMediaPlayer_native_init },
    { "native_setup",           "(Ljava/lang/Object;)V", (void *) IjkMediaPlayer_native_setup },
    { "native_finalize",        "()V",      (void *) IjkMediaPlayer_native_finalize },

    { "_setOption",             "(ILjava/lang/String;Ljava/lang/String;)V", (void *) IjkMediaPlayer_setOption },
    { "_setOption",             "(ILjava/lang/String;J)V",                  (void *) IjkMediaPlayer_setOptionLong },

    { "_getColorFormatName",    "(I)Ljava/lang/String;",    (void *) IjkMediaPlayer_getColorFormatName },
    { "_getVideoCodecInfo",     "()Ljava/lang/String;",     (void *) IjkMediaPlayer_getVideoCodecInfo },
    { "_getAudioCodecInfo",     "()Ljava/lang/String;",     (void *) IjkMediaPlayer_getAudioCodecInfo },
    { "_getMediaMeta",          "()Landroid/os/Bundle;",    (void *) IjkMediaPlayer_getMediaMeta },
    { "_setLoopCount",          "(I)V",                     (void *) IjkMediaPlayer_setLoopCount },
    { "_getLoopCount",          "()I",                      (void *) IjkMediaPlayer_getLoopCount },
    { "_getPropertyFloat",      "(IF)F",                    (void *) ijkMediaPlayer_getPropertyFloat },
    { "_setPropertyFloat",      "(IF)V",                    (void *) ijkMediaPlayer_setPropertyFloat },
    { "_getPropertyLong",       "(IJ)J",                    (void *) ijkMediaPlayer_getPropertyLong },
    { "_setPropertyLong",       "(IJ)V",                    (void *) ijkMediaPlayer_setPropertyLong },
    { "_setStreamSelected",     "(IZ)V",                    (void *) ijkMediaPlayer_setStreamSelected },

    { "native_profileBegin",    "(Ljava/lang/String;)V",    (void *) IjkMediaPlayer_native_profileBegin },
    { "native_profileEnd",      "()V",                      (void *) IjkMediaPlayer_native_profileEnd },

    { "native_setLogLevel",     "(I)V",                     (void *) IjkMediaPlayer_native_setLogLevel },
    { "_setFrameAtTime",        "(Ljava/lang/String;JJII)V", (void *) IjkMediaPlayer_setFrameAtTime },
};

我们可以看到规则,每当java层调用jni方法例如:

java调用的jni方法 对应Ijkplayer内部的方法
_setDataSource IjkMediaPlayer_setDataSourceAndHeaders
_start IjkMediaPlayer_start

即Java层调用的XXX方法,对应在ijkplayer的c层是IjkMediaPlayer_XXX

IjkMediaPlayer_XXX方法全部生命在ijkplayer_jni.c文件中,也难怪后者有1200多行了。

3. 中转,调度:ijkplayer.c

ijkmedia/ijkplayer/ijkplayer.c

我们拿一个jni方法来看下:

//ijkplayer_jni.c

static void
IjkMediaPlayer_start(JNIEnv *env, jobject thiz)
{
    MPTRACE("%s\n", __func__);
    //获取IjkMediaPlayer对象(是个结构体,但是就是一个对象)
    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);
    JNI_CHECK_GOTO(mp, env, "java/lang/IllegalStateException", "mpjni: start: null mp", LABEL_RETURN);
        //跳转到了ijkplayer.c的函数了
    ijkmp_start(mp);

LABEL_RETURN:
    ijkmp_dec_ref_p(&mp);
}

Ijkplayer_jin.c的每一个Jni映射方法几乎都是这样,拿到一个IjkMediaPlayer对象,然后跳转到ijkplayer.c中的函数。

注意:Ijkplayer_jin.c是通过

#include "ijkplayer_android.h"

ijkplayer_android.h中,又

#include "../ijkplayer.h"

所以,具备了调用ijkpalyer.h的能力的,而ijkplayer.h的实现是ijkplayer.c因此主要看后者就行了。

而在这一层映射中,函数命名也有对应关系:

ijkplayer_jin.c ijkplayer.h / ijkpalyer.c
IjkMediaPlayer_prepareAsync ijkmp_prepare_async
IjkMediaPlayer_start ijkmp_start

4. 封装:ff_ffplay.c

ijkplayer.c中的代码会调用到ff_ffplay.c中的代码,以及类似的ff_ffxxx.c中的代码:

即以ff开头的文件中的函数:

理解ijkplayer(二)项目结构分析_第1张图片

你可能感兴趣的:(理解ijkplayer(二)项目结构分析)