C# 将字节数组引用从android java返回到csharp unity
字节[]字节=调用(“getBytes”);其中getBytes函数返回一个字节[] 调用上述函数以获取csharp中的图像rgb数据。返回的字节[]被深度复制到字节数组中 由于返回字节数组很大,深度复制会增加更多时间 如何使csharp中的字节数组只包含java字节[]的引用C# 将字节数组引用从android java返回到csharp unity,c#,android,unity3d,C#,Android,Unity3d,字节[]字节=调用(“getBytes”);其中getBytes函数返回一个字节[] 调用上述函数以获取csharp中的图像rgb数据。返回的字节[]被深度复制到字节数组中 由于返回字节数组很大,深度复制会增加更多时间 如何使csharp中的字节数组只包含java字节[]的引用 public class TestUtil : MonoBehaviour { public static string TAG = "--------TestUtil------------> ";
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);
}
}
}
公共类TestUtil:MonoBehavior
{
公共静态字符串标记=“-----------TestUtil----------------->”;
私有静态AndroidJavaObject插件类;
公共静态列表rgbList=新列表();
void Start()
{
Log(标记+“启动已调用”);
//mainDataArray=新字节[1280*720*4];
Log(标记+“创建java对象”);
初始化图层();
}
public void initializePlayer()
{
//StreamHandler是Javaclass。这里我创建一个对象StreamHandler
pluginClass=newandroidjavaobject(“com.test.android.decoder.StreamHandler”);
//使用此代码获取上下文
AndroidJavaClass unityPlayer=新的AndroidJavaClass(“com.unity3d.player.unityPlayer”);
AndroidJavaObject activity=unityPlayer.GetStatic(“currentActivity”);
//设置上下文StreamHandler对象
pluginClass.Call(“setActivity”,activity);
//设置接口对象,java类将在其中调用相应的函数
调用(“setOnDecodeListener”,新的AndroidPluginCallback());
//初始化播放器
pluginClass.Call(“init”,ipAddress,port,outWidth,outHeight);
Log(标记+“初始化完成”);
}
公共应用程序(字符串sid)
{
Application.Quit();
}
私有void更新()
{
if(Input.GetKey(KeyCode.Escape)){
Log(标记+“转义”);
应用程序(sId);
}
}
整数计数;
私有更新()
{
如果(0!=rgbList.Count){
//在这里,我将rgb纹理更新为Quad Game Object
}
}
类AndroidPluginCallback:AndroidJavaProxy
{
public AndroidPluginCallback():base(“com.test.android.OnDecodeListener”){}
公共无效成功(字节[]视频路径)
{
}
public void onFrameAvailable()
{
//当java代码成功生成RGBA数据时调用
long startTime=DateTimeOffset.Now.tounixtimemilures();
//需要调用“getBytes()”来获取RGBA帧。
//注意:通常,如果您从另一个java类调用相同的函数,它会对byte[]对象进行浅拷贝
//但在这种情况下,它正在进行深度复制,或者我不确定发生了什么。
byte[]rawBytes=pluginClass.Call(“getBytes”);//帧的宽度和高度为1088x1088
rgbList.Add(rawBytes);
long diff=DateTimeOffset.Now.tounixtimemilures()-startTime;
Debug.Log(标记+)输入到onFrameAvailable回调中。复制到rawbytes所需的时间:“+diff);//diff平均为14毫秒。不确定原因。
}
公共无效失败(字符串错误消息)
{
Log(标记+”输入回调onError:“+errorMessage”);
}
}
}
AndroidJavaObject
使用JNI(Java本机接口)将数据封送至Java land,或从Java land封送数据。根据Java在内存中存储数组的方式,JNI可能需要进行深度复制以形成C#能够理解的数组,例如JVM最初是否将数组存储在非连续块中
这是:
JNI在Java代码和本机代码之间提供了一个干净的接口。为了保持这种分离,数组作为不透明句柄传递,本机代码必须回调JVM,以便使用set和get调用操纵数组元素Java规范将这些调用是否提供对数组的直接访问或返回数组的副本留给JVM实现。例如,当JVM以不连续存储阵列的方式优化了阵列时,可能会返回副本。
因此,这些调用可能会导致复制被操纵的元素。例如,如果在包含1000个元素的数组上调用GetLongArrayElements(),则可能会导致至少8000个字节的分配和复制(1000个元素*每长8个字节)。然后使用ReleaseLongArrayElements()更新数组的内容时,可能需要另一个8000字节的副本来更新数组。即使使用较新的GetPrimitiveArrayCritical(),该规范仍然允许JVM复制完整阵列
因此,基本上,尽量避免跨JNI编组数组(例如使用
AndroidJavaObject
),因为JNI是否进行深度复制并不取决于C。AndroidJavaObject
使用JNI(Java本机接口)根据Java在内存中存储数组的方式,JNI可能需要进行深度复制以形成C#能够理解的数组,例如JVM最初是否将数组存储在非连续块中
这是:
JNI在Java代码和本机代码之间提供了一个干净的接口。为了保持这种分离,数组作为不透明句柄传递,本机代码必须回调JVM,以便使用set和get调用操纵数组元素。Java规范将这些调用是否提供直接访问留给JVM实现返回数组或数组的副本。例如,当JVM以不连续存储数组的方式优化了数组时,可能会返回一个副本。
因此,这些调用可能会导致复制被操纵的元素