查看原文
其他

NDK开发之 JNI 静态注册与动态注册

AndroidPub 2023-02-21

The following article is from 字节卷动 Author 字节卷动


一、起因

前段时间学习OpenGL ES相关技术,下载了一个Github项目学习,项目地址在:https://github.com/githubhaohao/NDK_OpenGLES_3_0

项目的关键代码都是C++实现的,所以需要使用JNI技术。

我打开定义native方法的java类,如下所示:全部都是红色警告,



原因是,C++代码层没有对应的遵循特定JNI格式的JNI函数。

其实这个项目没有使用静态注册方法,而是使用了动态注册方法。下面我们分别来讲一下两种方式的区别。

二、静态注册

2.1 实现原理

根据函数名来建立java方法和JNI函数间的一一对应关系。

2.2 实现过程

  1. 编写.java代码;

  2. 编译.java代码,生成.class文件;

  3. 用过javah指令,利用生成的.class文件生成JNI.h文件;

  4. 生成后的JNI头文件中包含了Java函数在JNI层的声明;

可以参考下面几篇博客:

  • 【我的Android进阶之旅】Android Studio中JNI开发如何通过Extranal Tools 快速一键生成.h头文件

(https://blog.csdn.net/ouyang_peng/article/details/8715602)

  • 【我的Android进阶之旅】Android调用JNI出错 java.lang.UnsatisfiedLinkError: No implementation found for的解决方法

(https://blog.csdn.net/ouyang_peng/article/details/52997698)

  • 【我的Android进阶之旅】如果通过NDK编程,使用JNI来调用已经封装完毕的无法修改的so库(第三方)

(https://blog.csdn.net/ouyang_peng/article/details/112382141)

  • 【我的Android进阶之旅】如何通过JNI来封装已有的C源码算法,然后让Java层调用C语言写的算法

(https://blog.csdn.net/ouyang_peng/article/details/109299224)

2.3 弊端

  1. 书写很不方便,因为JNI层函数的名字必须遵循特定的格式,且名字特别长;

  2. 会导致程序员的工作量很大,因为必须为所有声明了native函数的java类编写JNI头文件;

  3. 程序运行效率低,因为初次调用native函数时需要根据根据函数名在JNI层中搜索对应的本地函数,然后建立对应关系,这个过程比较耗时。

关于第1和第2点,随着Android Studio升级,现在可以直接写完java native方法 就可以使用快捷键【Alt  + Enter】就会弹出提示提示【Create JNI function for xxx native method】,如下所示:

1public class MyNativeRender {
2    ...  其他代码
3
4    static {
5        System.loadLibrary("native-render");
6    }
7
8    public native void native_Init();
9
10    public native void native_UnInit();
11
12    ...  其他代码
13}
在这里插入图片描述

比如我们生成一下,自动生成如下代码:

1extern "C"
2JNIEXPORT void JNICALL
3Java_com_byteflow_app_MyNativeRender_native_1Init(JNIEnv *env, jobject thiz) 
{
4    // TODO: implement native_Init()
5}
在这里插入图片描述

再回到java层,就可以看到坐标有个C++的logo,点击即可跳转到对应的cpp代码的jni函数。

在这里插入图片描述

2.4 示例

目前我项目中还是使用的这种静态注册的方法。大家可以在下面的github查看

  • https://github.com/ouyangpeng/OpenGLESDemo


  1. java 层代码

java层代码编写native函数在com/oyp/openglesdemo/render/MyNativeRenderer.kt中,如下所示:

1package com.oyp.openglesdemo.render
2
3import android.app.Activity
4import android.content.res.AssetManager
5import android.opengl.GLSurfaceView
6import javax.microedition.khronos.egl.EGLConfig
7import javax.microedition.khronos.opengles.GL10
8
9class MyNativeRenderer(activity: Activity) : GLSurfaceView.Renderer, RenderAction 
{
10    private var mActivity: Activity = activity
11    var mSampleType = 0
12
13    init {
14        System.loadLibrary("ouyangpeng-opengles-lib")
15    }
16
17    // 通用的
18    private external fun nativeSurfaceCreate(assetManager: AssetManager)
19    private external fun nativeSurfaceChange(width: Int, height: Int)
20    private external fun nativeDrawFrame()
21    private external fun nativeSetRenderType(sampleCategoryType: Int, renderSampleType: Int)
22    private external fun nativeOnDestroy()
23
24    // 特定的方法
25    private external fun nativeSwitchBlendingMode()
26
27    // 特定的方法
28    private external fun nativeSetDelta(x: Float, y: Float)
29    private external fun nativeSetMinFilter(filter: Int)
30    private external fun nativeSetMagFilter(filter: Int)
31
32    private external fun nativeSetImageData(
33        format: Int,
34        width: Int,
35        height: Int,
36        imageData: ByteArray?
37    )
38
39    private external fun nativeSetImageDataWithIndex(
40        index: Int,
41        format: Int,
42        width: Int,
43        height: Int,
44        imageData: ByteArray?
45    )
46
47    private external fun nativeUpdateTransformMatrix(
48        rotateX: Float,
49        rotateY: Float,
50        scaleX: Float,
51        scaleY: Float
52    )
53
54
55    override fun onSurfaceCreated(gl: GL10, config: EGLConfig) 
{
56        val assetManager: AssetManager = mActivity.assets
57        nativeSurfaceCreate(assetManager)
58    }
59
60    override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) 
{
61        nativeSurfaceChange(width, height)
62    }
63
64    override fun onDrawFrame(gl: GL10) {
65        nativeDrawFrame()
66    }
67
68    fun setRenderType(sampleCategoryType: Int, renderSampleType: Int) {
69        if (sampleCategoryType == IMyNativeRendererType.SAMPLE_TYPE) {
70            mSampleType = renderSampleType
71        }
72        nativeSetRenderType(sampleCategoryType, renderSampleType)
73    }
74
75    fun onDestroy() {
76        nativeOnDestroy()
77    }
78
79    override fun switchBlendingMode() {
80        nativeSwitchBlendingMode()
81    }
82
83    override fun setMinFilter(filter: Int) {
84        nativeSetMinFilter(filter)
85    }
86
87    override fun setMagFilter(filter: Int) {
88        nativeSetMagFilter(filter)
89    }
90
91    override fun setDelta(deltaX: Float, deltaY: Float) {
92        nativeSetDelta(deltaX, deltaY)
93    }
94
95    override fun setImageData(
96        format: Int,
97        width: Int,
98        height: Int,
99        imageData: ByteArray
100    ) 
{
101        nativeSetImageData(format, width, height, imageData)
102    }
103
104    override fun setImageDataWithIndex(
105        index: Int,
106        format: Int,
107        width: Int,
108        height: Int,
109        imageData: ByteArray
110    ) 
{
111        nativeSetImageDataWithIndex(index, format, width, height, imageData)
112    }
113
114    override fun updateTransformMatrix(
115        rotateX: Float,
116        rotateY: Float,
117        scaleX: Float,
118        scaleY: Float
119    ) 
{
120        nativeUpdateTransformMatrix(rotateX, rotateY, scaleX, scaleY)
121    }
122}

  1. 对应的JNI方法

对应的JNI方法实现在app/src/main/cpp/jni/JniImpl.cpp文件中,如下所示:

1//
2// Created by OuyangPeng on 2021/11/26.
3//
4#include <jni.h>
5#include <MyGLRenderContext.h>
6#include <EGLRender.h>
7
8extern "C"
9JNIEXPORT void JNICALL
10Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSurfaceCreate(
11        JNIEnv *env, jobject thiz, jobject asset_manager) 
{
12    MyGLRenderContext::GetInstance()->OnSurfaceCreated(env, asset_manager);
13}
14
15extern "C"
16JNIEXPORT void JNICALL
17Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSurfaceChange(
18        JNIEnv *env, jobject thiz, jint width, jint height) 
{
19    MyGLRenderContext::GetInstance()->OnSurfaceChanged(width, height);
20}
21
22extern "C"
23JNIEXPORT void JNICALL
24Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeDrawFrame(JNIEnv *env, jobject thiz) 
{
25    MyGLRenderContext::GetInstance()->OnDrawFrame();
26}
27
28extern "C"
29JNIEXPORT void JNICALL
30Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetRenderType(
31        JNIEnv *env, jobject thiz, jint sampleCategoryType, jint renderSampleType) 
{
32    MyGLRenderContext::GetInstance()->SetRenderType(sampleCategoryType, renderSampleType);
33}
34
35extern "C"
36JNIEXPORT void JNICALL
37Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeOnDestroy(JNIEnv *env, jobject thiz) 
{
38    MyGLRenderContext::DestroyInstance();
39}
40
41extern "C"
42JNIEXPORT void JNICALL
43Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSwitchBlendingMode(JNIEnv *env, jobject thiz) 
{
44    MyGLRenderContext::GetInstance()->SwitchBlendingMode();
45}
46extern "C"
47JNIEXPORT void JNICALL
48Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetDelta(
49        JNIEnv *env, jobject thiz, jfloat x, jfloat y) 
{
50    MyGLRenderContext::GetInstance()->SetDelta(x, y);
51}
52extern "C"
53JNIEXPORT void JNICALL
54Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetMinFilter(
55        JNIEnv *env, jobject thiz, jint filter) 
{
56    MyGLRenderContext::GetInstance()->SetMinFilter(filter);
57}
58extern "C"
59JNIEXPORT void JNICALL
60Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetMagFilter(
61        JNIEnv *env, jobject thiz, jint filter) 
{
62    MyGLRenderContext::GetInstance()->SetMagFilter(filter);
63}
64extern "C"
65JNIEXPORT void JNICALL
66Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetImageData(
67        JNIEnv *env, jobject thiz,
68        jint format, jint width, jint height, jbyteArray imageData) 
{
69
70    int len = env->GetArrayLength(imageData);
71    u_int8_t *buf = new u_int8_t[len];
72    env->GetByteArrayRegion(imageData, 0, len, reinterpret_cast<jbyte *>(buf));
73
74    MyGLRenderContext::GetInstance()->SetImageData(format, width, height, buf);
75    delete[]buf;
76    env->DeleteLocalRef(imageData);
77}
78
79extern "C"
80JNIEXPORT void JNICALL
81Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeSetImageDataWithIndex(
82        JNIEnv *env, jobject thiz,
83        jint index, jint format, jint width, jint height, jbyteArray imageData) 
{
84
85    int len = env->GetArrayLength(imageData);
86    u_int8_t *buf = new u_int8_t[len];
87    env->GetByteArrayRegion(imageData, 0, len, reinterpret_cast<jbyte *>(buf));
88
89    MyGLRenderContext::GetInstance()->SetImageDataWithIndex(index, format, width, height, buf);
90    delete[]buf;
91    env->DeleteLocalRef(imageData);
92}
93
94extern "C"
95JNIEXPORT void JNICALL
96Java_com_oyp_openglesdemo_render_MyNativeRenderer_nativeUpdateTransformMatrix(
97        JNIEnv *env, jobject thiz, jfloat rotateX,jfloat rotateY,jfloat scaleX,jfloat scaleY) 
{
98    MyGLRenderContext::GetInstance()->UpdateTransformMatrix(rotateX, rotateY, scaleX, scaleY);
99}
100
101////////////////////////////////////////////   EGL 渲染相关 ////////////////////////////////////////////////////////////////////
102
103extern "C"
104JNIEXPORT void JNICALL
105Java_com_oyp_openglesdemo_render_egl_NativeEglRender_nativeEglRenderInit(JNIEnv *env, jobject thiz, jobject asset_manager) 
{
106    EGLRender::GetInstance()->Init(env,asset_manager);
107}
108
109extern "C"
110JNIEXPORT void JNICALL
111Java_com_oyp_openglesdemo_render_egl_NativeEglRender_nativeEglRenderSetImageData(
112        JNIEnv *env, jobject thiz, jbyteArray data, jint width, jint height) 
{
113
114    int len = env->GetArrayLength (data);
115    uint8_t* buf = new uint8_t[len];
116    env->GetByteArrayRegion(data, 0, len, reinterpret_cast<jbyte*>(buf));
117
118    EGLRender::GetInstance()->SetImageData(buf, width, height);
119
120    delete[] buf;
121    env->DeleteLocalRef(data);
122}
123extern "C"
124JNIEXPORT void JNICALL
125Java_com_oyp_openglesdemo_render_egl_NativeEglRender_nativeEglRenderSetFragmentShaderType(
126        JNIEnv *env, jobject thiz, jint param_type, jint fShaderType) 
{
127    EGLRender::GetInstance()->SetFragmentShaderType(param_type, fShaderType);
128}
129extern "C"
130JNIEXPORT void JNICALL
131Java_com_oyp_openglesdemo_render_egl_NativeEglRender_nativeEglRenderDraw(JNIEnv *env, jobject thiz) 
{
132    EGLRender::GetInstance()->Draw();
133}
134extern "C"
135JNIEXPORT void JNICALL
136Java_com_oyp_openglesdemo_render_egl_NativeEglRender_nativeEglRenderUnInit(JNIEnv *env, jobject thiz) 
{
137    EGLRender::GetInstance()->UnInit();
138}
139
140////////////////////////////////////////////   EGL 渲染相关 ////////////////////////////////////////////////////////////////////

实际上在Android Studio中,显示的效果还行,如下所示:


三、动态注册

由上面的介绍可以发现,通过Android Studio等IDE的功能越来越完善,关于JNI函数名很长的问题其实并不是瓶颈。

上面有提到一个弊端是程序运行效率低 :因为初次调用native函数时需要根据根据函数名在JNI层中搜索对应的本地函数,然后建立对应关系,这个过程比较耗时。

应用层的Java类别通过VM而调用到native函数。一般是通过VM去寻找*.so里的native函数。
如果需要连续呼叫很多次,每次都需要寻找一遍,会多花许多时间。

此时,C组件开发者可以将本地函数向VM进行注册,以便能加快后续调用native函数的效率。

可以这么想象一下,假设VM内部一个native函数链表,初始时是空的,在未动态注册之前此native函数链表是空的,每次java调用native函数之前会首先在此链表中查找需要查找需要调用的native函数,如果找到就直接使用,如果未找到,得再通过载入的.so文件中的函数列表中去查找,且每次java调用native函数都是进行这样的流程,因此,效率就自然会下降。

为了克服这样现象,我们可以通过在.so文件载入初始化时,即JNI_OnLoad函数中,先行将native函数注册到VMnative函数链表中去,这样一来,后续每次java调用native函数时都会在VM中的native函数链表中找到对应的函数,从而加快速度.

注:在Android 源码开发环境下,大多采用动态注册native方法.

下面我们来介绍一下动态注册的方式。

3.1 实现原理

直接告诉native函数其在JNI中对应函数的指针;

3.2 实现过程

  1. 利用结构体JNINativeMethod保存Java Native函数和JNI函数的对应关系;

  2. 在一个JNINativeMethod数组中保存所有native函数和JNI函数的对应关系;

  3. Java中通过System.loadLibrary加载完JNI动态库之后,调用JNI_OnLoad函数,开始动态注册;

  4. JNI_OnLoad中会调用AndroidRuntime::registerNativeMethods函数进行函数注册;

  5. AndroidRuntime::registerNativeMethods中最终调用jni RegisterNativeMethods完成注册。

3.3 优点

克服了静态注册的弊端。

  1. RegisterNatives方法能帮助你把C/C++中的方法隐射到Java中的native方法,而无需遵循特定的方法命名格式。

  2. 更有效率去找到函数。  

  3. 在执行期间进行抽换。

3.4 示例

我们就以 https://github.com/githubhaohao/NDK_OpenGLES_3_0的代码作为示例:

  • java层代码

代码定义在 app/src/main/java/com/byteflow/app/MyNativeRender.java 文件中

1/**
2 *
3 * Created by 公众号:字节流动 on 2021/3/12.
4 * https://github.com/githubhaohao/NDK_OpenGLES_3_0
5 * 最新文章首发于公众号:字节流动,有疑问或者技术交流可以添加微信 Byte-Flow ,领取视频教程, 拉你进技术交流群
6 *
7 * */

8
9package com.byteflow.app;
10
11public class MyNativeRender {
12    其他代码
13
14
15    static {
16        System.loadLibrary("native-render");
17    }
18
19    public native void native_Init();
20
21    public native void native_UnInit();
22
23    public native void native_SetParamsInt(int paramType, int value0, int value1);
24
25    public native void native_SetParamsFloat(int paramType, float value0, float value1);
26
27    public native void native_UpdateTransformMatrix(float rotateX, float rotateY, float scaleX, float scaleY);
28
29    public native void native_SetImageData(int format, int width, int height, byte[] bytes);
30
31    public native void native_SetImageDataWithIndex(int index, int format, int width, int height, byte[] bytes);
32
33    public native void native_SetAudioData(short[] audioData);
34
35    public native void native_OnSurfaceCreated();
36
37    public native void native_OnSurfaceChanged(int width, int height);
38
39    public native void native_OnDrawFrame();
40}
在这里插入图片描述
  1. Native层代码
    代码定义在 app/src/main/cpp/JniImpl.cpp 文件中

  • 定义JNI NativeMethod的映射关系

g_RenderMethods[]和g_BgRenderMethods[]是2个<名称,函数指针>对照表,在程序执行时,可多次呼叫RegisterNativeMethods()函数来更换本地函数之指针,而达到弹性抽换本地函数之目的。

1static JNINativeMethod g_RenderMethods[] = {
2    {"native_Init",                      "()V",       (void *)(native_Init)},
3    {"native_UnInit",                    "()V",       (void *)(native_UnInit)},
4    {"native_SetImageData",              "(III[B)V",  (void *)(native_SetImageData)},
5    {"native_SetImageDataWithIndex",     "(IIII[B)V", (void *)(native_SetImageDataWithIndex)},
6    {"native_SetParamsInt",              "(III)V",    (void *)(native_SetParamsInt)},
7    {"native_SetParamsFloat",            "(IFF)V",    (void *)(native_SetParamsFloat)},
8    {"native_SetAudioData",              "([S)V",     (void *)(native_SetAudioData)},
9    {"native_UpdateTransformMatrix",     "(FFFF)V",   (void *)(native_UpdateTransformMatrix)},
10    {"native_OnSurfaceCreated",          "()V",       (void *)(native_OnSurfaceCreated)},
11    {"native_OnSurfaceChanged",          "(II)V",     (void *)(native_OnSurfaceChanged)},
12    {"native_OnDrawFrame",               "()V",       (void *)(native_OnDrawFrame)},
13};
14
15static JNINativeMethod g_BgRenderMethods[] = {
16    {"native_EglRenderInit",          "()V",       (void *)(native_EglRenderInit)},
17    {"native_EglRenderSetImageData",  "([BII)V",   (void *)(native_EglRenderSetImageData)},
18    {"native_EglRenderSetIntParams",  "(II)V",     (void *)(native_EglRenderSetIntParams)},
19    {"native_EglRenderDraw",          "()V",       (void *)(native_EglRenderDraw)},
20    {"native_EglRenderUnInit",        "()V",       (void *)(natuve_BgRenderUnInit)},
21};



在这里插入图片描述
  • 定义要关联的对应Java类

1#define NATIVE_RENDER_CLASS_NAME "com/byteflow/app/MyNativeRender"
2#define NATIVE_BG_RENDER_CLASS_NAME "com/byteflow/app/egl/NativeEglRender"
在这里插入图片描述
  • 然后定义RegisterNativeMethods函数和UnregisterNativeMethods函数

1static int RegisterNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int methodNum)
2
{
3    LOGCATE("RegisterNativeMethods");
4    jclass clazz = env->FindClass(className);
5    if (clazz == NULL)
6    {
7        LOGCATE("RegisterNativeMethods fail. clazz == NULL");
8        return JNI_FALSE;
9    }
10    if (env->RegisterNatives(clazz, methods, methodNum) < 0)
11    {
12        LOGCATE("RegisterNativeMethods fail");
13        return JNI_FALSE;
14    }
15    return JNI_TRUE;
16}
17
18static void UnregisterNativeMethods(JNIEnv *env, const char *className)
19
{
20    LOGCATE("UnregisterNativeMethods");
21    jclass clazz = env->FindClass(className);
22    if (clazz == NULL)
23    {
24        LOGCATE("UnregisterNativeMethods fail. clazz == NULL");
25        return;
26    }
27    if (env != NULL)
28    {
29        env->UnregisterNatives(clazz);
30    }
31}
在这里插入图片描述


  • JNI_OnLoad 函数和 JNI_OnUnload函数

JNI组件被成功加载和卸载时,会进行函数回调,
VM执行到System.loadLibrary(xxx)函数时,首先会去执行JNI组件中的JNI_OnLoad()函数,
而当VM释放该组件时会呼叫JNI_OnUnload()函数。

JNI_OnLoad()有两个重要的作用:

  1. 指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),如果要使用新版本的JNI,例如JNI 1.6版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_6(该常量定义在jni.h中) 来告知VM

  2. 初始化设定,当VM执行到System.loadLibrary()函数时,会立即先呼叫JNI_OnLoad()方法,因此在该方法中进行各种资源的初始化操作最为恰当。

JNI_OnUnload()的作用与JNI_OnLoad()对应,当VM释放JNI组件时会呼叫它,因此在该方法中进行善后清理,资源释放的动作最为合适。

1extern "C" jint JNI_OnLoad(JavaVM *jvm, void *p)
2
{
3    LOGCATE("===== JNI_OnLoad =====");
4    jint jniRet = JNI_ERR;
5    JNIEnv *env = NULL;
6    if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK)
7    {
8        return jniRet;
9    }
10
11    jint regRet = RegisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME, g_RenderMethods,
12                                        sizeof(g_RenderMethods) /
13                                        sizeof(g_RenderMethods[0]));
14    if (regRet != JNI_TRUE)
15    {
16        return JNI_ERR;
17    }
18
19    regRet = RegisterNativeMethods(env, NATIVE_BG_RENDER_CLASS_NAME, g_BgRenderMethods,
20                                        sizeof(g_BgRenderMethods) /
21                                        sizeof(g_BgRenderMethods[0]));
22    if (regRet != JNI_TRUE)
23    {
24        return JNI_ERR;
25    }
26
27    return JNI_VERSION_1_6;
28}
29
30extern "C" void JNI_OnUnload(JavaVM *jvm, void *p)
31
{
32    JNIEnv *env = NULL;
33    if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK)
34    {
35        return;
36    }
37
38    UnregisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME);
39
40    UnregisterNativeMethods(env, NATIVE_BG_RENDER_CLASS_NAME);
41}


  • 完整代码
    完整代码如下所示:


1//
2// Created by ByteFlow on 2019/7/9.
3//
4#include "util/LogUtil.h"
5#include <MyGLRenderContext.h>
6#include <EGLRender.h>
7#include "jni.h"
8
9#define NATIVE_RENDER_CLASS_NAME "com/byteflow/app/MyNativeRender"
10#define NATIVE_BG_RENDER_CLASS_NAME "com/byteflow/app/egl/NativeEglRender"
11
12#ifdef __cplusplus
13extern "C" {
14#endif
15/*
16 * Class:     com_byteflow_app_MyNativeRender
17 * Method:    native_Init
18 * Signature: ()V
19 */

20JNIEXPORT void JNICALL native_Init(JNIEnv *env, jobject instance)
21
{
22    MyGLRenderContext::GetInstance();
23
24}
25
26/*
27 * Class:     com_byteflow_app_MyNativeRender
28 * Method:    native_UnInit
29 * Signature: ()V
30 */

31JNIEXPORT void JNICALL native_UnInit(JNIEnv *env, jobject instance)
32
{
33    MyGLRenderContext::DestroyInstance();
34}
35
36/*
37 * Class:     com_byteflow_app_MyNativeRender
38 * Method:    native_SetImageData
39 * Signature: (III[B)V
40 */

41JNIEXPORT void JNICALL native_SetImageData
42(JNIEnv *env, jobject instance, jint format, jint width, jint height, jbyteArray imageData)
43
{
44    int len = env->GetArrayLength (imageData);
45    uint8_t* buf = new uint8_t[len];
46    env->GetByteArrayRegion(imageData, 0, len, reinterpret_cast<jbyte*>(buf));
47    MyGLRenderContext::GetInstance()->SetImageData(format, width, height, buf);
48    delete[] buf;
49    env->DeleteLocalRef(imageData);
50}
51
52/*
53 * Class:     com_byteflow_app_MyNativeRender
54 * Method:    native_SetImageDataWithIndex
55 * Signature: (IIII[B)V
56 */

57JNIEXPORT void JNICALL native_SetImageDataWithIndex
58        (JNIEnv *env, jobject instance, jint index, jint format, jint width, jint height, jbyteArray imageData)
59
{
60    int len = env->GetArrayLength (imageData);
61    uint8_t* buf = new uint8_t[len];
62    env->GetByteArrayRegion(imageData, 0, len, reinterpret_cast<jbyte*>(buf));
63    MyGLRenderContext::GetInstance()->SetImageDataWithIndex(index, format, width, height, buf);
64    delete[] buf;
65    env->DeleteLocalRef(imageData);
66}
67
68/*
69 * Class:     com_byteflow_app_MyNativeRender
70 * Method:    native_SetParamsInt
71 * Signature: (III)V
72 */

73JNIEXPORT void JNICALL native_SetParamsInt
74        (JNIEnv *env, jobject instance, jint paramType, jint value0, jint value1)
75
{
76    MyGLRenderContext::GetInstance()->SetParamsInt(paramType, value0, value1);
77}
78
79/*
80 * Class:     com_byteflow_app_MyNativeRender
81 * Method:    native_SetParamsFloat
82 * Signature: (IFF)V
83 */

84JNIEXPORT void JNICALL native_SetParamsFloat
85        (JNIEnv *env, jobject instance, jint paramType, jfloat value0, jfloat value1)
86
{
87    MyGLRenderContext::GetInstance()->SetParamsFloat(paramType, value0, value1);
88}
89
90
91/*
92 * Class:     com_byteflow_app_MyNativeRender
93 * Method:    native_SetAudioData
94 * Signature: ([B)V
95 */

96JNIEXPORT void JNICALL native_SetAudioData
97        (JNIEnv *env, jobject instance, jshortArray data)
98
{
99    int len = env->GetArrayLength(data);
100    short *pShortBuf = new short[len];
101    env->GetShortArrayRegion(data, 0, len, reinterpret_cast<jshort*>(pShortBuf));
102    MyGLRenderContext::GetInstance()->SetParamsShortArr(pShortBuf, len);
103    delete[] pShortBuf;
104    env->DeleteLocalRef(data);
105}
106
107/*
108 * Class:     com_byteflow_app_MyNativeRender
109 * Method:    native_UpdateTransformMatrix
110 * Signature: (FFFF)V
111 */

112JNIEXPORT void JNICALL native_UpdateTransformMatrix(JNIEnv *env, jobject instance, jfloat rotateX, jfloat rotateY, jfloat scaleX, jfloat scaleY)
113
{
114    MyGLRenderContext::GetInstance()->UpdateTransformMatrix(rotateX, rotateY, scaleX, scaleY);
115}
116
117/*
118 * Class:     com_byteflow_app_MyNativeRender
119 * Method:    native_OnSurfaceCreated
120 * Signature: ()V
121 */

122JNIEXPORT void JNICALL native_OnSurfaceCreated(JNIEnv *env, jobject instance)
123
{
124    MyGLRenderContext::GetInstance()->OnSurfaceCreated();
125}
126
127/*
128 * Class:     com_byteflow_app_MyNativeRender
129 * Method:    native_OnSurfaceChanged
130 * Signature: (II)V
131 */

132JNIEXPORT void JNICALL native_OnSurfaceChanged
133(JNIEnv *env, jobject instance, jint width, jint height)
134
{
135    MyGLRenderContext::GetInstance()->OnSurfaceChanged(width, height);
136
137}
138
139/*
140 * Class:     com_byteflow_app_MyNativeRender
141 * Method:    native_OnDrawFrame
142 * Signature: ()V
143 */

144JNIEXPORT void JNICALL native_OnDrawFrame(JNIEnv *env, jobject instance)
145
{
146    MyGLRenderContext::GetInstance()->OnDrawFrame();
147
148}
149
150
151/*
152 * Class:     com_byteflow_app_egl_NativeBgRender
153 * Method:    native_EglRenderInit
154 * Signature: ()V
155 */

156JNIEXPORT void JNICALL native_EglRenderInit(JNIEnv *env, jobject instance)
157
{
158    EGLRender::GetInstance()->Init();
159
160}
161
162/*
163 * Class:     com_byteflow_app_egl_NativeBgRender
164 * Method:    native_EglRenderSetImageData
165 * Signature: ([BII)V
166 */

167JNIEXPORT void JNICALL native_EglRenderSetImageData(JNIEnv *env, jobject instance, jbyteArray data, jint width, jint height)
168
{
169    int len = env->GetArrayLength (data);
170    uint8_t* buf = new uint8_t[len];
171    env->GetByteArrayRegion(data, 0, len, reinterpret_cast<jbyte*>(buf));
172    EGLRender::GetInstance()->SetImageData(buf, width, height);
173    delete[] buf;
174    env->DeleteLocalRef(data);
175
176
177}
178
179/*
180 * Class:     com_byteflow_app_egl_NativeBgRender
181 * Method:    native_EglRenderSetIntParams
182 * Signature: (II)V
183 */

184JNIEXPORT void JNICALL native_EglRenderSetIntParams(JNIEnv *env, jobject instance, jint type, jint param)
185
{
186    EGLRender::GetInstance()->SetIntParams(type, param);
187
188}
189
190/*
191 * Class:     com_byteflow_app_egl_NativeBgRender
192 * Method:    native_EglRenderDraw
193 * Signature: ()V
194 */

195JNIEXPORT void JNICALL native_EglRenderDraw(JNIEnv *env, jobject instance)
196
{
197    EGLRender::GetInstance()->Draw();
198}
199
200/*
201 * Class:     com_byteflow_app_egl_NativeBgRender
202 * Method:    natuve_BgRenderUnInit
203 * Signature: ()V
204 */

205JNIEXPORT void JNICALL natuve_BgRenderUnInit(JNIEnv *env, jobject instance)
206
{
207    EGLRender::GetInstance()->UnInit();
208}
209
210#ifdef __cplusplus
211}
212#endif
213
214static JNINativeMethod g_RenderMethods[] = {
215        {"native_Init",                      "()V",       (void *)(native_Init)},
216        {"native_UnInit",                    "()V",       (void *)(native_UnInit)},
217        {"native_SetImageData",              "(III[B)V",  (void *)(native_SetImageData)},
218        {"native_SetImageDataWithIndex",     "(IIII[B)V", (void *)(native_SetImageDataWithIndex)},
219        {"native_SetParamsInt",              "(III)V",    (void *)(native_SetParamsInt)},
220        {"native_SetParamsFloat",            "(IFF)V",    (void *)(native_SetParamsFloat)},
221        {"native_SetAudioData",              "([S)V",     (void *)(native_SetAudioData)},
222        {"native_UpdateTransformMatrix",     "(FFFF)V",   (void *)(native_UpdateTransformMatrix)},
223        {"native_OnSurfaceCreated",          "()V",       (void *)(native_OnSurfaceCreated)},
224        {"native_OnSurfaceChanged",          "(II)V",     (void *)(native_OnSurfaceChanged)},
225        {"native_OnDrawFrame",               "()V",       (void *)(native_OnDrawFrame)},
226};
227
228static JNINativeMethod g_BgRenderMethods[] = {
229        {"native_EglRenderInit",          "()V",       (void *)(native_EglRenderInit)},
230        {"native_EglRenderSetImageData",  "([BII)V",   (void *)(native_EglRenderSetImageData)},
231        {"native_EglRenderSetIntParams",  "(II)V",     (void *)(native_EglRenderSetIntParams)},
232        {"native_EglRenderDraw",          "()V",       (void *)(native_EglRenderDraw)},
233        {"native_EglRenderUnInit",        "()V",       (void *)(natuve_BgRenderUnInit)},
234};
235
236static int RegisterNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int methodNum)
237
{
238    LOGCATE("RegisterNativeMethods");
239    jclass clazz = env->FindClass(className);
240    if (clazz == NULL)
241    {
242        LOGCATE("RegisterNativeMethods fail. clazz == NULL");
243        return JNI_FALSE;
244    }
245    if (env->RegisterNatives(clazz, methods, methodNum) < 0)
246    {
247        LOGCATE("RegisterNativeMethods fail");
248        return JNI_FALSE;
249    }
250    return JNI_TRUE;
251}
252
253static void UnregisterNativeMethods(JNIEnv *env, const char *className)
254
{
255    LOGCATE("UnregisterNativeMethods");
256    jclass clazz = env->FindClass(className);
257    if (clazz == NULL)
258    {
259        LOGCATE("UnregisterNativeMethods fail. clazz == NULL");
260        return;
261    }
262    if (env != NULL)
263    {
264        env->UnregisterNatives(clazz);
265    }
266}
267
268// call this func when loading lib
269extern "C" jint JNI_OnLoad(JavaVM *jvm, void *p)
270
{
271    LOGCATE("===== JNI_OnLoad =====");
272    jint jniRet = JNI_ERR;
273    JNIEnv *env = NULL;
274    if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK)
275    {
276        return jniRet;
277    }
278
279    jint regRet = RegisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME, g_RenderMethods,
280                                        sizeof(g_RenderMethods) /
281                                        sizeof(g_RenderMethods[0]));
282    if (regRet != JNI_TRUE)
283    {
284        return JNI_ERR;
285    }
286
287    regRet = RegisterNativeMethods(env, NATIVE_BG_RENDER_CLASS_NAME, g_BgRenderMethods,
288                                        sizeof(g_BgRenderMethods) /
289                                        sizeof(g_BgRenderMethods[0]));
290    if (regRet != JNI_TRUE)
291    {
292        return JNI_ERR;
293    }
294
295    return JNI_VERSION_1_6;
296}
297
298extern "C" void JNI_OnUnload(JavaVM *jvm, void *p)
299
{
300    JNIEnv *env = NULL;
301    if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK)
302    {
303        return;
304    }
305
306    UnregisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME);
307
308    UnregisterNativeMethods(env, NATIVE_BG_RENDER_CLASS_NAME);
309}



-- END --

推荐阅读

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存