繁体   English   中英

将无符号char *从C ++作为字节[]传递给Java的最有效方法

[英]Most efficient way to pass unsigned char* from C++ to java as byte[]

我有一个本机功能,签名就像-

void onRecvData(const unsigned char* pData, int length)

我需要将此pData从C ++传递到Java方法public void OnrecvData(byte[] data)而无需复制数据。 目前,我正在通过分配jByteBuffer并使用SetByteArrayRegion做到这SetByteArrayRegion 但是我认为这种方法无法避免复制。 我正在寻找一种类似GetDirectBufferAddress ,并将指针传递给起始地址和长度以避免复制。

提前致谢!

编辑1

我不会在Java层中修改数据。 只读访问将可以。

编辑2

您可以dequeueInputBuffer(),将该缓冲区传递到本机代码中,并memcpy()数据。 我99%肯定MediaCodec缓冲区是直接的ByteBuffer,因此您可以使用JNI函数获取地址和长度。 如何调用dequeueInputBuffer()由您决定。 您必须使用MediaCodec返回的缓冲区,因此不可避免地需要一个副本,但至少它是编码数据。 (出于多种原因,对于输出端,您希望使用Surface。)

我当前的代码是这样的-

    // ..................
    // ..................
    int inIndex = mMediaCodec.dequeueInputBuffer(mTimeoutUs);
    if (inIndex >= 0) {
        ByteBuffer buffer;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            buffer = mMediaCodec.getInputBuffers()[inIndex];
            buffer.clear();
        } else {
            buffer = mMediaCodec.getInputBuffer(inIndex);
        }
        if (buffer != null) {
            buffer.put(encodedData, 0, encodedDataLength);
            long presentationTimeUs = System.nanoTime() / 1000l;
            mMediaCodec.queueInputBuffer(inIndex, 0, encodedDataLength, presentationTimeUs, 0);
        }
    }

这里的encodedDatabyte[] ,它是使用一次内存分配并每次执行SetByteArrayRegion从本机层SetByteArrayRegion unsigned char*接收的。 因此,我需要像我建议的memcpy方法那样在当前的实现中使用一个副本。 这两种方法都需要一个副本,但是我当前的实现是否比您建议的效率低(发送dequeueInputBuffer地址参考和memcpy )? put ING byte[]ByteBuffer我在Java中没有层?

编辑3

好吧, ByteBuffer.put(byte[], offset, offsetLength)就像将整个byte[]数组像memcpy一样复制到ByteBuffer 因此它也是Java层中的另一个副本。 我现在要实现你的想法。 谢谢 :)

这个问题比看起来要复杂得多。

使数据在Java语言代码中可见的最快方法是预分配“直接” ByteBuffer,然后在其中接收数据。 可以直接从本机或托管代码访问数据。 但是,“可访问”只是意味着Java语言代码可以实现它,而不是它可以快速获取单个字节。

如果从JNI(使用NewDirectByteBuffer )分配直接ByteBuffer,则可以NewDirectByteBuffer传递任意缓冲区,但这意味着没有byte[]支持存储。 如果您使用ByteBuffer#allocateDirect()从托管代码中分配它,则最新版本的Android将为您提供直接缓冲区,该缓冲区位于托管堆中,这意味着也可以通过array()对其进行访问。 这样,用Java编写的代码就可以像访问任何其他byte[]一样访问它,而不必每次访问都调用一个方法。

如果您的数据到达了您无法控制的缓冲区(例如,视频解码器输出),那么您就别无选择。 您要么将数据复制到托管byte[] ,要么在Java端支付每字节的开销。 (理论上,JIT可以识别您在做什么并对其进行优化,但是我不知道这是否正在完成。)

尽量避免分配缓冲区。 预分配和池化可以帮助您提高性能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM