【发布时间】:2015-10-23 02:59:51
【问题描述】:
我有一个原生函数,签名就像 -
void onRecvData(const unsigned char* pData, int length)
我需要将这个 pData 从 C++ 传递到 Java 方法 public void OnrecvData(byte[] data) 而不复制数据。目前我通过分配jByteBuffer 和使用SetByteArrayRegion 来做到这一点。但我认为这种方法并不能避免复制。我正在寻找与 GetDirectBufferAddress 类似的方法,并将指针传递给起始地址和长度以避免复制。
提前致谢!
编辑 1
我不会修改 Java 层的数据。只读访问就可以了。
编辑 2
您可以 dequeueInputBuffer(),将该缓冲区传递给本机代码,然后 memcpy() 数据。我 99% 确定 MediaCodec 缓冲区是直接的 ByteBuffers,因此您可以使用 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);
}
}
这里的encodedData 是byte[],它是从本地层从unsigned char* 接收的,使用一次内存分配并每次都执行SetByteArrayRegion。因此,我在当前的实现中需要一份副本,例如您建议的memcpy。这两种方法都需要一份副本,但我目前的实现是否比您建议的效率低(发送dequeueInputBuffer 地址参考和memcpy)?就像 puting byte[] 到 ByteBuffer 我在 Java 层做的?
编辑 3
好吧,ByteBuffer.put(byte[], offset, offsetLength) 似乎将整个 byte[] 数组复制到 ByteBuffer 中,例如 memcpy。所以它也是Java层的另一个副本。我现在要实施你的想法。谢谢:)
【问题讨论】:
-
虽然您标记了 JNI,但最好指定您使用的是 JNI 以避免在此处混淆。
标签: java android c++ android-ndk java-native-interface