使用现有私有函数将相机图像从 Java 传递到本机库
Pass camera image from Java to native library using existing private function
我正在 Java 中为 Unity 构建一个插件。我在 Java 中自己设置了设备摄像头,效果很好。然而,事实证明,将相机预览数据传递给 Unity 很困难。
我已经使用 ARToolkit 库测试了所有工作,它具有将相机预览数据传递给 Unity 的功能。
但是 Unity 本身也有这样的功能,Android 中也有相机支持,我宁愿使用它。这个函数叫做
private final native void nativeVideoFrameCallback(int var1, byte[] var2, int var3, int var4);
在UnityPlayer中class,在classes.jar中。
您可以从这里下载 classes.jar 进行检查:https://github.com/PlayFab/Unity3d_Login_Example_Project/blob/master/Assets/Facebook/Editor/android/android-libs/unity-classes.jar(按 'Raw' 按钮)。
如您所见,它已设置为私有,因此我无法调用它。
UnityPlayer 的原始使用
nativeVideoFrameCallback 最初由 Unity 在以下位置调用:
public void onCameraFrame(final com.unity3d.player.a var1, final byte[] var2) {
final int var3 = var1.a();
final Size var4 = var1.b();
this.a(new UnityPlayer.c((byte)0) {
public final void a() {
UnityPlayer.this.nativeVideoFrameCallback(var3, var2, var4.width, var4.height);
var1.a(var2);
}
});
}
是public,但要求一个非public变量"com.unity3d.player.a var1",我无法实例化。
可能的解决方案
我的解决方案是为 nativeVideoFrameCallback 创建一个新的本机函数 link,但它会导致 FatalException。当我不调用我自己的 nativeVideoFrameCallback link 时,我没有得到这个异常,所以 Unity 确实成功了。
UnsatisfiedLinkError: No Implementation found for ...package...UnityPlayer.nativeVideoFrameCallback)int, yte[], int, int).
我的UnityPlayer class:
public class UnityPlayer extends com.unity3d.player.UnityPlayer {
private final ConcurrentLinkedQueue<Runnable> jobs = new ConcurrentLinkedQueue<Runnable>();
public UnityPlayer(ContextWrapper contextWrapper) {
super(contextWrapper);
}
public void addJob(final Camera camera, final int cam, final byte[] data, final int width, final int height) {
jobs.add(new Runnable() {
@Override
public void run() {
nativeVideoFrameCallback(cam, data, width, height);
camera.addCallbackBuffer(data);
}
});
}
private final native void nativeVideoFrameCallback(int var1, byte[] var2, int var3, int var4);
static {
try {
System.loadLibrary("main"); // Is this still required? I would think not, as Unity already loads it
} catch (UnsatisfiedLinkError var1) {
Log.d(Constants.TAG, "Unable to find " + "main");
} catch (Exception var2) {
Log.d(Constants.TAG, "Unknown error " + var2);
}
}
@Override
protected void executeGLThreadJobs() {
super.executeGLThreadJobs();
Runnable job = jobs.poll();
if (job != null) {
job.run();
}
}
}
这需要 UnityNativeActivity 的副本和上面的 UnityPlayer 实例化而不是 com.unity3d.player.UnityPlayer.
我使用反射让它工作。使用反射不是最优的,所以如果有人知道没有反射的解决方案,我会接受它作为答案。
对于希望使用 Unity 在 Android 上管理自己的摄像机的任何其他人:
public class UnityPlayer extends com.unity3d.player.UnityPlayer {
private final ConcurrentLinkedQueue<Runnable> jobs = new ConcurrentLinkedQueue<Runnable>();
public UnityPlayer(ContextWrapper contextWrapper) {
super(contextWrapper);
}
public void addJob(final Camera camera, final int cam, final byte[] data, final int width, final int height) { // execute on opengl thread using jobs
jobs.add(new Runnable() {
@Override
public void run() {
videoFrameCallback(cam, data, width, height);
camera.addCallbackBuffer(data);
}
});
}
@Override
protected int[] initCamera(int var1, int var2, int var3, int var4) {
return new int[]{640, 480}; // return width and height of camera
}
// private final native void nativeVideoFrameCallback(int var1, byte[] var2, int var3, int var4); ==> camera id (0 back, 1 front), imagedata, width, height
private void videoFrameCallback(int var1, byte[] var2, int var3, int var4) {
try {
Method m = com.unity3d.player.UnityPlayer.class.getDeclaredMethod("nativeVideoFrameCallback", Integer.TYPE, byte[].class, Integer.TYPE, Integer.TYPE);
m.setAccessible(true);
m.invoke(this, var1, var2, var3, var4);
} catch (Exception e) {
Log.d(Constants.TAG, e.toString());
}
}
@Override
protected void executeGLThreadJobs() {
super.executeGLThreadJobs();
Runnable job = jobs.poll();
if (job != null) {
job.run();
}
}
}
我正在 Java 中为 Unity 构建一个插件。我在 Java 中自己设置了设备摄像头,效果很好。然而,事实证明,将相机预览数据传递给 Unity 很困难。
我已经使用 ARToolkit 库测试了所有工作,它具有将相机预览数据传递给 Unity 的功能。
但是 Unity 本身也有这样的功能,Android 中也有相机支持,我宁愿使用它。这个函数叫做
private final native void nativeVideoFrameCallback(int var1, byte[] var2, int var3, int var4);
在UnityPlayer中class,在classes.jar中。
您可以从这里下载 classes.jar 进行检查:https://github.com/PlayFab/Unity3d_Login_Example_Project/blob/master/Assets/Facebook/Editor/android/android-libs/unity-classes.jar(按 'Raw' 按钮)。
如您所见,它已设置为私有,因此我无法调用它。
UnityPlayer 的原始使用
nativeVideoFrameCallback 最初由 Unity 在以下位置调用:
public void onCameraFrame(final com.unity3d.player.a var1, final byte[] var2) {
final int var3 = var1.a();
final Size var4 = var1.b();
this.a(new UnityPlayer.c((byte)0) {
public final void a() {
UnityPlayer.this.nativeVideoFrameCallback(var3, var2, var4.width, var4.height);
var1.a(var2);
}
});
}
是public,但要求一个非public变量"com.unity3d.player.a var1",我无法实例化。
可能的解决方案
我的解决方案是为 nativeVideoFrameCallback 创建一个新的本机函数 link,但它会导致 FatalException。当我不调用我自己的 nativeVideoFrameCallback link 时,我没有得到这个异常,所以 Unity 确实成功了。
UnsatisfiedLinkError: No Implementation found for ...package...UnityPlayer.nativeVideoFrameCallback)int, yte[], int, int).
我的UnityPlayer class:
public class UnityPlayer extends com.unity3d.player.UnityPlayer {
private final ConcurrentLinkedQueue<Runnable> jobs = new ConcurrentLinkedQueue<Runnable>();
public UnityPlayer(ContextWrapper contextWrapper) {
super(contextWrapper);
}
public void addJob(final Camera camera, final int cam, final byte[] data, final int width, final int height) {
jobs.add(new Runnable() {
@Override
public void run() {
nativeVideoFrameCallback(cam, data, width, height);
camera.addCallbackBuffer(data);
}
});
}
private final native void nativeVideoFrameCallback(int var1, byte[] var2, int var3, int var4);
static {
try {
System.loadLibrary("main"); // Is this still required? I would think not, as Unity already loads it
} catch (UnsatisfiedLinkError var1) {
Log.d(Constants.TAG, "Unable to find " + "main");
} catch (Exception var2) {
Log.d(Constants.TAG, "Unknown error " + var2);
}
}
@Override
protected void executeGLThreadJobs() {
super.executeGLThreadJobs();
Runnable job = jobs.poll();
if (job != null) {
job.run();
}
}
}
这需要 UnityNativeActivity 的副本和上面的 UnityPlayer 实例化而不是 com.unity3d.player.UnityPlayer.
我使用反射让它工作。使用反射不是最优的,所以如果有人知道没有反射的解决方案,我会接受它作为答案。
对于希望使用 Unity 在 Android 上管理自己的摄像机的任何其他人:
public class UnityPlayer extends com.unity3d.player.UnityPlayer {
private final ConcurrentLinkedQueue<Runnable> jobs = new ConcurrentLinkedQueue<Runnable>();
public UnityPlayer(ContextWrapper contextWrapper) {
super(contextWrapper);
}
public void addJob(final Camera camera, final int cam, final byte[] data, final int width, final int height) { // execute on opengl thread using jobs
jobs.add(new Runnable() {
@Override
public void run() {
videoFrameCallback(cam, data, width, height);
camera.addCallbackBuffer(data);
}
});
}
@Override
protected int[] initCamera(int var1, int var2, int var3, int var4) {
return new int[]{640, 480}; // return width and height of camera
}
// private final native void nativeVideoFrameCallback(int var1, byte[] var2, int var3, int var4); ==> camera id (0 back, 1 front), imagedata, width, height
private void videoFrameCallback(int var1, byte[] var2, int var3, int var4) {
try {
Method m = com.unity3d.player.UnityPlayer.class.getDeclaredMethod("nativeVideoFrameCallback", Integer.TYPE, byte[].class, Integer.TYPE, Integer.TYPE);
m.setAccessible(true);
m.invoke(this, var1, var2, var3, var4);
} catch (Exception e) {
Log.d(Constants.TAG, e.toString());
}
}
@Override
protected void executeGLThreadJobs() {
super.executeGLThreadJobs();
Runnable job = jobs.poll();
if (job != null) {
job.run();
}
}
}