将字节数组引用从 Android Java 返回给 Csharp Unity



byte[] bytes = Call("getBytes") ; 其中 getBytes 函数返回一个字节 []。

调用上述函数以在 CSHARP 中获取图像 RGB 数据。返回的 byte[] 被深度复制到字节数组中。

由于返回字节数组很大,因此深度复制会增加更多时间。

如何在 CSHARP 中使字节数组仅保存 Java 字节[] 的引用?


public class TestUtil : MonoBehaviour
{
public static string TAG = "--------TestUtil------------> ";
private static AndroidJavaObject pluginClass;    
public static List<byte[]> rgbList = new List<byte[]>();
void Start()
{

Debug.Log(TAG + "start called");
//mainDataArray = new byte[1280*720*4];
Debug.Log(TAG + "creating java object");
initializePlayer();
}
public void initializePlayer()
{
// StreamHandler is the Javaclass. here i am creating a object StreamHandler
pluginClass = new AndroidJavaObject("com.test.android.decoder.StreamHandler");
// using this code to get the context
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
// setting context StreamHandler object
pluginClass.Call("setActivity", activity);
// setting the interface object, where java class will call the respective function
pluginClass.Call("setOnDecodeListener", new AndroidPluginCallback());       
// initializing the player
pluginClass.Call("init", ipAddress, port, outWidth, outHeight);
Debug.Log(TAG + " Initialization done");
}
public void quitApplication(string sid)
{
Application.Quit();
}
private void Update()
{
if (Input.GetKey(KeyCode.Escape)) {
Debug.Log(TAG + "Escape");
quitApplication(sId);
}        
}
int count;
private void LateUpdate()
{

if (0 != rgbList.Count) {
// here i am updating the rgb texture to Quad gameobject
}
}
class AndroidPluginCallback : AndroidJavaProxy
{
public AndroidPluginCallback() : base("com.test.android.OnDecodeListener") { }
public void success(byte[] videoPath)
{            
}
public void onFrameAvailable()
{
// Called when java code successfully generate RGBA data
long startTime = DateTimeOffset.Now.ToUnixTimeMilliseconds();
// Need to call "getBytes()" to get the RGBA frame. 
//Note: generally if you call same function from another java class it do shallow copy to byte[] object 
// but in this case it is doing deep copy or i am not sure whats going on.
byte[] rawBytes = pluginClass.Call<byte[]>("getBytes"); // width and height of frame is 1088x1088
rgbList.Add(rawBytes);
long diff = DateTimeOffset.Now.ToUnixTimeMilliseconds() - startTime;
Debug.Log(TAG + "Entered into onFrameAvailable callback. time taken to copy to rawbytes: " + diff); // diff is 14ms on average. Not sure why.
}
public void fail(string errorMessage)
{
Debug.Log(TAG + "ENTER callback onError: " + errorMessage);
}
}
}

>AndroidJavaObject使用JNI(Java本机接口)将数据封送到Java土地和从Java土地封送数据。根据 Java 在内存中存储数组的方式,JNI 可能需要执行深度复制以形成 C# 可以理解的数组,例如 JVM 最初将数组存储在非连续块中。

以下是 IBM 的描述:

JNI在Java代码和本机代码之间提供了一个干净的接口。为了保持这种分离,数组作为不透明句柄传递,本机代码必须回调到 JVM,以便使用 set 和 get 调用来操作数组元素。Java 规范将 JVM 实现留给 JVM 实现,这些调用是提供对数组的直接访问还是返回数组的副本。例如,当 JVM 以不连续存储阵列的方式优化阵列时,它可能会返回一个副本。

然后,这些调用可能会导致复制正在操作的元素。例如,如果在包含 1,000 个元素的数组上调用 GetLongArrayElements(),则可能会导致分配和复制至少 8,000 个字节(1,000 个元素 * 每个长 8 个字节)。然后使用 ReleaseLongArrayElements() 更新数组的内容时,可能需要另一个 8,000 字节的副本来更新数组。即使您使用较新的 GetPrimitiveArrayCritical(),该规范仍然允许 JVM 制作完整阵列的副本。

因此,基本上,尽量避免跨 JNI 封送数组(例如尽可能使用AndroidJavaObject,因为 JNI 是否制作深层副本并不取决于 C#。

最新更新