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 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include

#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#示例

/// 
    /// 视频帧数据
    /// 
    /// 
    [DllImport("libnative")]
    public static extern void LibOnCaptureVideoFrame(MediaFrameBack onVidoeFrameData);

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

调用流程:

java -> jni -> C#

你可能感兴趣的:(Unity调用Android JNI示例)