Enviar int s entre Java y C
Tengo un código Java de procesamiento de imagen en Android que actúa sobre dos matrices grandes de int. La mayoría de las veces, Java es lo suficientemente rápido, pero necesito usar C a través de JNI y el NDK para acelerar algunas operaciones.
La única manera que sé que puedo pasar los datos de los arrays de int a C es utilizar ByteBuffer.allocateDirect para crear un nuevo búfer, copiar los datos a eso y luego hacer que el código C actúe sobre el búfer.
- Android-ndk Adición de bibliotecas estáticas al android.mk
- Embalaje RAW AAC en el contenedor m4a?
- Pasar un objeto Java a C ++ a través de JNI y luego volver a Java, a través de void *
- Android ioctl: permisos y uso de root
- No se invoca el método Java cuando se llama desde pthread nativo
Sin embargo, no puedo ver ninguna manera que pueda manipular los datos en este búfer en Java como si el búfer fuera un int [] o un byte []. Por ejemplo, una llamada a ByteBuffer.array () fallará en el búfer recién creado. ¿Hay alguna forma de hacer que esto funcione?
Tengo memoria limitada y quiero reducir cuántos arrays / buffers necesito. Por ejemplo, sería bueno que pudiera usar IntBuffer.wrap (new int […]) para crear el búfer y luego manipular la matriz respaldando el búfer directamente en Java pero no puedo hacer esto porque lo único que parece Trabajo aquí para JNI es ByteBuffer.allocateDirect.
¿Hay alguna otra forma de enviar datos entre C y Java? ¿Puedo de alguna manera asignar memoria en el lado C y tener Java enviar datos directamente a allí?
Edit: Una referencia que compara el uso del búfer con int [] usa:
int size = 1000; IntBuffer allocateDirect = java.nio.ByteBuffer.allocateDirect(4 * size).asIntBuffer(); for (int i = 0; i < 100; ++i) { for (int x = 0; x < size; ++x) { int v = allocateDirect.get(x); allocateDirect.put(x, v + 1); } } int[] intArray = new int[size]; for (int i = 0; i < 100; ++i) { for (int x = 0; x < size; ++x) { int v = intArray[x]; intArray[x] = v + 1; } }
En un teléfono Droid, la versión del búfer lleva ~ 10 segundos para finalizar y la versión del arreglo toma ~ 0.01 segundos.
- OpenCV en Android - Encabezados; No hay tal directorio de archivos
- Es una pérdida de una sola vez de referencia a la memoria nativa asignada por una aplicación Android un gran negocio?
- Error android cargando dinámicamente libc ++.
- Cómo incluir bibliotecas compartidas precompiladas en apk con eclipse
- Cómo vincular cualquier biblioteca en la aplicación ndk
- ¿Cómo realizar llamadas JNI desde un servicio incluso si la aplicación está cerrada?
- C ++ ifstream.getline () significativamente más lento que BufferedReader.readLine () de Java?
- Ndk-stack no funciona
Desde http://java.sun.com/docs/books/jni/html/objtypes.html , utilice JNI's Get/Release<TYPE>ArrayElements(...)
En este ejemplo, pasaré una matriz (por razones de argumento, es int array = new int[10]
y luego llenarlo con 0-9
JNIEXPORT jint JNICALL Java_IntArray_doStuffArray(JNIEnv *env, jobject obj, jintArray arr) { // initializations, declarations, etc jint *c_array; jint i = 0; // get a pointer to the array c_array = (*env)->GetIntArrayElements(env, arr, NULL); // do some exception checking if (c_array == NULL) { return -1; /* exception occurred */ } // do stuff to the array for (i=0; i<10; i++) { c_array[i] = i; } // release the memory so java can have it again (*env)->ReleaseIntArrayElements(env, arr, c_array, 0); // return something, or not.. it's up to you return 0; }
Estudio de la sección 3.3, y específicamente 3.3.2 – esto le permitirá obtener un puntero a la matriz en la memoria de java, modificarlo y liberarlo, en efecto que le permite modificar la matriz en código nativo.
Acabo de usarlo en mi propio proyecto (con arreglos cortos) y funciona muy bien 🙂
Si está utilizando buffers asignados directamente, puede acceder a la matriz de respaldo directamente desde C, utilizando la función GetDirectBufferAddress
. Esto evita la posibilidad de copiar regiones del área.
Usted puede operar en la dirección devuelta directamente como lo haría con una matriz C normal, y modificará directamente el búfer de Java asignado directamente.
A continuación, como estados ephemient, puede utilizar ByteBuffer.asIntBuffer () y la familia para acceder al búfer de una manera que emula los arreglos de las diversas primitivas Java.
http://download.oracle.com/javase/1.4.2/docs/guide/jni/jni-14.html
Puede utilizar la devolución de llamada para enviar los datos desde la capa nativa a Java.
En capa Java: en mi clase nativa tengo los siguientes métodos:
//Native method public native String getStrData(int size); //Callback method public void addData(char[] native_data, int size) { ... }
En capa nativa: en mi implementación nativa:
JNIEXPORT jstring JNICALL Java_com_pkg_NativeClass_getStrData (JNIEnv *env, jobject obj, jint size) { ... jclass native_class; /* Callback: native class */ jmethodID native_method_id; /* Callback: native method id */ jcharArray row; /* Callback: native data */ ... /* Start Callback: Native to Java */ native_class = (*env)->GetObjectClass(env, obj); native_method_id = (*env)->GetMethodID(env, native_class, "addData", "([CI)V"); if (native_method_id == 0) { return (jstring)ERR_NATIVE_METHODID; } row = (jcharArray)(*env)->NewCharArray(env, size); /* jc has the data to be sent to Java */ (*env)->SetCharArrayRegion(env, (jcharArray)row, (jsize)0, size, (jchar *)jc); (*env)->CallVoidMethod(env, obj, native_method_id, row, size); /* End Callback */ ... }