c# - 从android java返回字节数组引用到csharp unity
问题描述
字节[]字节=调用(“getBytes”);其中 getBytes 函数返回一个字节 []。
调用上述函数以在 csharp 中获取图像 rgb 数据。返回的 byte[] 被深度复制到 bytes 数组中。
由于返回字节数组很大,因此深度复制会增加更多时间。
如何在 csharp 中制作字节数组以仅保存 java byte [] 的引用?
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 以不连续存储数组的方式优化数组时,它可能会返回一个副本。
那么,这些调用可能会导致复制被操作的元素。例如,如果您对具有 1,000 个元素的数组调用 GetLongArrayElements(),您可能会导致分配和复制至少 8,000 个字节(1,000 个元素 * 每个 long 8 个字节)。然后,当您使用 ReleaseLongArrayElements() 更新数组的内容时,可能需要另一个 8,000 字节的副本来更新数组。即使您使用较新的 GetPrimitiveArrayCritical(),规范仍然允许 JVM 制作完整数组的副本。
因此,基本上,尽量避免跨 JNI 编组数组(例如尽可能AndroidJavaObject
多地编组,因为 JNI 是否进行深拷贝并不取决于 C#。
推荐阅读
- mysql - 将 lstart 转换为 mysql 时间戳
- python - f-string 导致 CDSW/linux 上的换行错误
- windows - 在命令行输出中搜索关键字并显示上一行的批处理文件(x5)
- reactjs - 删除 localhost 名称以部署 Next.js 时出现问题
- shadow-dom - 有没有办法使用组合来改变带有阴影 dom 的 web 组件的 CSS?
- php - 从没有 FFMPEG 的 MP4 中提取帧
- php - 如何使用 PHP 将不同数组中的数组值合并到一个数组中?
- mediawiki - MediaWiki 配置 TemplateStyles 以包含 Module:Message box/ambox.css
- python - 使用 statsmodels 在多元线性回归中添加常数
- php - orderby 'meta_value_num' 打破了我的 WP_Query