我正在尝试将输入和输出缓冲区从C ++传递给java类。 出于效率原因,我需要使用ByteBuffer。
两个缓冲区都是在C ++部分中分配的,我需要将它们传递给一个java函数,该函数将使用输入缓冲区进行一些计算,并将结果写入输出缓冲区。
以下是C ++如何显示的简化示例:
// SWIG mapped with %feature("director") JavaDelegate;
class JavaDelegate {
public:
JavaDelegate() {}
virtual ~JavaDelegate() {}
virtual int compute(const uint8_t* input, size_t inSize,
uint8_t* output, size_t maxOutSize,
int someFlag) = 0;
};
// assume inputBuf is filled with valid data
std::vector<uint8_t> inputBuf;
std::vector<uint8_t> outputBuf(10000);
// delegate also points to a valid SWIG mapped class
JavaDelegate* delegate;
void computeOutput() {
int someFlag = 1;
int numValuesComputed = delegate->compute(inputBuf.data(), inputBuf.size(),
outputBuf.data(), outputBuf.size(),
someFlag);
std::cout << "Computed " << numValuesComputed << " value from input.\n";
}
在Java方面,我希望实现这一点(SWIG已生成JavaDelegate
类):
public class Delegate extends JavaDelegate {
public long compute(java.nio.ByteBuffer input,
java.nio.ByteBuffer output,
long someFlag)
{
// read input
// compute something n values from m input values
// write result to output
return numOutputValues;
}
}
问题是,我根本无法弄清楚如何将一个普通的char *包装到ByteBuffer中,特别是结合SWIG为抽象基类打开的导演功能。 我知道如何将ByteBuffer从Java传递给C ++,但我不知道如何反过来。
任何帮助表示赞赏!
答案 0 :(得分:1)
前言:这不是SWIG-ish解决方案,这是通用的,我发现this与您的问题有些相关
首先,据我所知,Java中没有ref
参数,因此除非您准备更改签名并将其作为返回值,否则不能直接从C ++传递它。这可以通过从Java传递typewrapper并在其中包含C ++创建/设置缓冲区来避免,la:
public class BufferWrapper {
private ByteBuffer mBuffer;
public void setBuffer(ByteBuffer buffer) {
mBuffer = buffer;
}
}
将它传递给C ++并让它分配并设置缓冲区到包装器。
NewDirectByteBuffer JNI函数可以完全满足您的需求:
分配并返回指向的直接java.nio.ByteBuffer 从存储器地址开始并扩展的存储器块 容量字节。
调用此函数并返回结果的本机代码 byte-buffer对象到Java级代码应该确保缓冲区 是指可供阅读的有效记忆区域, 如果合适的话,写作。尝试访问无效内存 来自Java代码的位置将返回任意值,没有 可见效果,或导致抛出未指定的异常。
PS我们可以采取其他方式 - ByteBuffer有wrap方法,允许你包装byte[]
的现有缓冲区,但不是char*
,但我们可以将它们结合起来(看看这个answer)。
深入研究Jni方法:
jsize n = sizeof(yourBuf);
jbyteArray arr = (*env)->NewByteArray(env, n);
(*env)->SetByteArrayRegion(env,arr,0,n, (jbyte*)yourBuf);
然而请注意,根据doc,此功能会导致复制,而不仅仅是包装,所以我在这里做的不太有用