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#