Unity调用Android JNI示例

Android, java to class接口示例

包名和类名可以随意起,unity端只要知道其名称即可,但请不要轻易更改(反射要写死在代码里)

主接口

package com.yicheng.serviceandroid;

public class UnityToAndroid {
  private static final UnityToAndroid ourInstance = new UnityToAndroid();
  public static UnityToAndroid getInstance() {
        return ourInstance;
   }
  private UnityToAndroid() {
  }
  
 
  // java native方法申明
  // 将图像,输入到jni中,传输给c#端.更优质的方式是,直接在jni中调用,省略这一层
  public native void updateFrame(byte[] byteArray, int nWidth, int nHeight, long nFlag, int dataType);

}

Android JNI接口示例

CPP文件

#include <jni.h>
#include <string>
#include <android/log.h>
#include <android/native_window_jni.h>
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <string.h>
#include<stdio.h>
#include<pthread.h>

#define LOGD(...) __android_log_print(ANDROID_LOG_WARN,"yuvLibNative",__VA_ARGS__)

struct VideoFrameData
{
    uint64_t uid;
    bool yuv;
    int width;
    int height;
    int yStride;
    int uvStride;
    int uvWidth;
    int uvHeight;

    char* yBuffer;
    char* uBuffer;
    char* vBuffer;

    int rotation;
};

typedef void (*FrameBack)(VideoFrameData data);


FrameBack frameBack = 0;

JavaVM *local_jvm = NULL;
jobject local_object = NULL;

jmethodID notifyVideo;

// java调用
extern "C"
JNIEXPORT void JNICALL
Java_com_ yicheng_serviceandroid_UnityToAndroid_updateFrame(JNIEnv *env,
        jobject thiz,jbyteArray byteArray, jint nWidth, jint nHeight, jlong nFlag, jint dataType) {
     if (local_jvm == NULL){
        env->GetJavaVM(&local_jvm); //保存到全局变量JVM中
        local_object = env->NewGlobalRef(thiz); /* 创建对象的本地变量 */
     }
    // 视频,nFlag为0的时候代表本地视频,不然为uid
    jbyte *byte = env->GetByteArrayElements(byteArray, 0);
    int len_arr = env->GetArrayLength(byteArray);
    int width = (int)nWidth;
    int height = (int)nHeight;
    if ( frameBack != 0 ){
        VideoFrameData data;
        data.yBuffer = (char *)byte;
        data.uBuffer = (char *)(byte + width * height);
        data.vBuffer = (char *)(byte + width * height + width * height / 4);

        data.rotation = 0;
        data.uid = (uint64_t)nFlag;
        // datatype  其中0代表I420声网返回的数据格式 。 1代表NV21yy返回的数据格式
        if (dataType == 0) {
            data.yuv = true;
        } else {
            data.yuv = false;
        }
        data.width = width;
        data.height = height;
        data.uvWidth = width/2;
        data.uvHeight = height/2;
        data.yStride = width;
        data.uvStride = width/2;
        //LOGD("updateFrameuid: %llu ", data.uid);
        //LOGD("updateFramewidth: %d ", data.width);
        //LOGD("updateFrameheight: %d ", data.height);
        frameBack(data);
    }
    env->ReleaseByteArrayElements(byteArray,byte,0);
}
// C# 调用
extern "C"  {

        void LibOnCaptureVideoFrame(FrameBack cb){
            frameBack = cb;
        }

        void NotifyVideoFrameDraw(long remoteUid, long renderTimeMs){
            JNIEnv *env;
            jclass clz;
            jmethodID mid;
            if(local_jvm->AttachCurrentThread(&env, NULL) != JNI_OK)
            {
                LOGD("%s: AttachCurrentThread() failed", __FUNCTION__);
                return;
            }
            clz = env->GetObjectClass(local_object);
            if(clz == NULL)
            {
                LOGD("FindClass() Error...");
                return;
            }
            mid = env->GetMethodID(clz, "notifyVideoFrameDraw", "(JJ)V");
            if (mid == NULL)
            {
                LOGD("GetMethodID() Error...");
                return;
            }
            env->CallVoidMethod(local_object, mid , remoteUid, renderTimeMs);
        }
}

C#示例

/// <summary>
    /// 视频帧数据
    /// </summary>
    /// <param name="MediaFrameBack"></param>
    [DllImport("libnative")]
    public static extern void LibOnCaptureVideoFrame(MediaFrameBack onVidoeFrameData);

    /// <summary>
    /// 渲染后,调用sdk返回结果
    /// </summary>
    /// <param name="remoteUid"></param>
    /// <param name="renderTimeMs"></param>
    [DllImport("libnative")]
    public static extern void NotifyVideoFrameDraw(long remoteUid, long renderTimeMs);

调用流程:

java -> jni -> C#

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容