【问题标题】:returning byte array reference from android java to csharp unity从android java返回字节数组引用到csharp unity
【发布时间】:2019-07-18 18:20:37
【问题描述】:

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

调用上述函数以获取 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);
        }

    }
}

【问题讨论】:

  • 我们需要更多地了解Call("getBytes") 的确切作用。请发布足够的代码来重现您的问题陈述。
  • 我已将图像数据转换为 rgba 格式,保存在 byte[] 中。我正在统一调用 getBytes() 函数。 public void getByted(){ return rgbBug;}
  • 如果你正在做return rgbBug,那是按值返回引用,所以它不应该是深拷贝......
  • 我仔细检查过,unity 正在做深拷贝。我想避免这种情况
  • 这里没有足够的信息来复制您的问题。请添加更多信息,以便我们通过在问题中添加 minimal reproducible example 来重现问题陈述。

标签: c# android unity3d


【解决方案1】:

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

这里是IBM's description

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#。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-27
    • 1970-01-01
    • 2012-06-19
    • 1970-01-01
    • 1970-01-01
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多