程序问答   发布时间:2022-06-02  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了通过 SWIG 在 Java 中访问 uint8_t 向量大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决通过 SWIG 在 Java 中访问 uint8_t 向量?

开发过程中遇到通过 SWIG 在 Java 中访问 uint8_t 向量的问题如何解决?下面主要结合日常开发的经验,给出你关于通过 SWIG 在 Java 中访问 uint8_t 向量的解决方法建议,希望对你解决通过 SWIG 在 Java 中访问 uint8_t 向量有所启发或帮助;

我正在使用 SWIG 开发 Java C++ 桥;我的c++方法如下:

std::vector<uint8_t> ArduGrabClass::grab() {
    IMAGE_FORMAT fmt = { IMAGE_ENCoding_I420,100 };
    BUFFER *buffer = arducam_capture(camera_instance,&fmt,352000);
    return vector<uint8_t>(buffer->data,buffer->data + buffer->length);
}

即删减,真正的方法持有c++类中的缓冲区对象,以便java端可以释放它。但是,我需要在 Java 端访问这些数据,最好在 ByteBuffer 中,否则在数组中。但是我不知道该怎么做; JNI 方法 NewDirectByteBufer 似乎很合适,但 SWIG 正在处理所有 JNI 内容,所以我不知道如何告诉 SWIG 使用 NewDirectByteBufer 方法。

解决方法

编写一个 typemap 来调用 NewDirectByteBuffer完全可行的,但正如所写的那样,这绝对不是包装代码的正确方法。所写的问题有两个方面:

  1. 您已经按值返回了一个向量,但这意味着一旦超出范围,它的内存就会过期,留下 ByteBuffer 指代不再有效的内存
  2. 如果您确实延长了 vector 的生命周期以避免该问题,那么当 ByteBuffer 被垃圾收集时,目前没有什么可以释放该内存,因此您会泄漏内存
  3. arducam_capture 本身的调用需要以某种方式与对 arducam_release_buffer 的调用配对 - 您可以将其添加到 ArduGrabClass::grab() 函数中,但请参见下文
  4. 即使你做了所有这些,你仍然会复制很多数据,这在某种程度上违背了在 Java 中使用 ByteBuffer 的意义。 (向量的构造函数中至少会有一个副本,可能更多取决于您如何解决它。

因此,如果您想使用 std::vector 副本,我建议您只使用现有的 SWIG 支持 std::vector,或者将其复制到某些 JNI 代码中的新数组中。如果您有兴趣,我可以演示如何做到这一点,但目前我专注于如何正确使用 ByteBufferarducam_capture 的问题。

为了有一个返回 ByteBuffer 并在之后被清理的 Java 方法,我们想安排使用一个 Cleaner 来发现 ByteBuffer 超出范围。

如果我们更改包装函数以返回 BUFFER * 而不是 std::vector 中的副本,我们可以在生成的转换内部使用一些 SWIG 支持来调用我们添加的额外函数进入我们为我们调用 NewDirectByteBuffer 的包装器。然后,在该代码中,我们还可以使用 ByteBuffer 注册 Runnable,该 arducam_release_buffer 将为我们调用 %module test %pragma(java) modulecode=%{ // Create a single cleaner thread for all our buffers to register with // note package level access is deliberate static final java.lang.ref.Cleaner cc = java.lang.ref.Cleaner.create(); static { // actually load our shared object! System.loadLibrary("test"); } %} // later on when we implement toBuffer() we need the environment pointer. // This adds it into our method call automatically %typemap(in,numinputs=0) JNIEnv * %{ $1 = jenv; %} // Our native implementation of toBuffer on BUFFER is going to return // a ByteBuffer sTraight up for us,with no need for conversions %typemap(jtypE) jobject toBuffer "java.nio.byteBuffer" %typemap(jstypE) jobject toBuffer "java.nio.byteBuffer" // When we hand the ByteBuffer off to a caller we need to register // something to do the clean up for us. This is where we register it. %typemap(javaout) jobject toBuffer { java.nio.byteBuffer buf = $jnicall; // actually call the native code System.out.println("In toBuffer"); // To prove it worked! // Our cleaner instance lives in the module itself $module.cc.register(buf,new Runnable(){ public void run() { System.out.println("in buffer cleanup java side"); // We add a (privatE) cleanup function we can just call here BUFFER.this.cleanup(); } }); // Now it's registered actually let them have it return buf; } // Every time we return a BUFFER * call toBuffer() on it instead %typemap(javaout) BUFFER * { return new $javaclassname($jnicall,$owner).toBuffer(); } // Since we're going to call toBuffer() the return type is different %typemap(jstypE) BUFFER * "java.nio.byteBuffer" // Hide lots of thing about the BUFFER class outside our package %typemap(javaclassmodifiers) BUFFER "class" %javamethodmodifiers BUFFER::cleanup() "private"; %javamethodmodifiers BUFFER::toBuffer ""; // BEGIN Faked definitions,just for tesTing... %{ typedef struct { void *data; int len; } BUFFER; typedef struct { enum { IMAGE_ENCODING_I420 } a; int n; } IMAGE_FORMAT; BUFFER * arducam_capture(void * instance,IMAGE_FORMAT *fmt,int timeout) { (void)instance; (void)fmt; (void)timeout; BUFFER *buf = malloc(sizeof *buf); *buf = (BUFFER){ .data = malloc(100),.len = 100,}; return buf; } void arducam_release_buffer(BUFFER *instancE) { free(instance->data); free(instancE); } %} // END TESTinG // All the details of BUFFER are not public for Java users %nodefaultctor BUFFER; %nodefaultdtor BUFFER; typedef struct {} BUFFER; // In addition to what's really in the buffer object we want to add another // two methods. %extend BUFFER { // toBuffer() is used by our internals when returning a BUFFER jobject toBuffer(JNIEnv *jenv) const { // Swig provides JCALLx macros for us,but they are not usable inside %extend :( %#ifdef __cplusplus__ return jenv->NewDirectByteBuffer($self->data,$self->len); %#else return (*jenv)->NewDirectByteBuffer(jenv,$self->data,$self->len); %#endif } // Cleanup is used when the buffer is dead void cleanup() { arducam_release_buffer($self); } } %inline %{ // Now,wrap a modified version of your code BUFFER *do_capture() { void *camera_instance = NULL; IMAGE_FORMAT fmt = { IMAGE_ENCODING_I420,100 }; BUFFER *buffer = arducam_capture(camera_instance,&fmt,352000); return buffer; } %}

为我们执行此操作的 SWIG 接口示例是:

public class run {
        public static void main(String[] argv) {
                for (int i = 0; i < 100; ++i) {
                        java.nio.byteBuffer buf = test.do_capture();
                        System.gc();
                }
        }
}

然后尝试一下:

swig3.0 -java -Wall test.i
gcc -Wall -Wextra -o libtest.so -I/usr/lib/jvm/default-java/include/ -I/usr/lib/jvm/default-java/include/linux test_wrap.c -shared 
javac *.java  -Xlint:deprecation 
LD_LIBRARY_PATH=. java run
In toBuffer
in buffer cleanup java side
......

然后我们可以构建和运行:

pri@R_874_11035@

大佬总结

以上是大佬教程为你收集整理的通过 SWIG 在 Java 中访问 uint8_t 向量全部内容,希望文章能够帮你解决通过 SWIG 在 Java 中访问 uint8_t 向量所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。