2012-03-01 14 views
11

Mi objetivo es pasar una matriz de bytes de longitud variable desde el código nativo al lado Java. El método de instancia de la clase Java toma bytearray como su argumento:Pasando matriz de bytes desde el código nativo al lado Java

private void writeBuffer(final byte[] buffer) 
{ 
} 

soy capaz de encontrar un método de identificación en el código nativo:

jclass cls = (*env)->FindClass(env,"class_path"); 
jmethodID writeBufferMethodID = (*env)->GetMethodID(env, cls, "writeBuffer", "([B)V"); 

pero todavía no puede encontrar la manera de pasar un byte matriz correctamente He tratado:

jbyteArray retArray = (*env)->NewByteArray(env, data_size); 
void *temp = (*env)->GetPrimitiveArrayCritical(env, (jarray)retArray, 0); 
memcpy(temp, decoded_frame->data[0], data_size); 
(*env)->CallVoidMethod(env, obj, writeBufferMethodID, retArray); 
(*env)->ReleasePrimitiveArrayCritical(env, retArray, temp, 0); 

y también:

retArray = (*env)->NewByteArray(env, data_size); 
(*env)->SetByteArrayRegion(env, retArray, 0, data_size, (jbyte *)decoded_frame->data[0]); 
(*env)->CallVoidMethod(env, obj, writeBufferMethodID, retArray); 

El método Java se llama, pero después de un tiempo la aplicación se bloquea. Además, todos los valores en los buffers de Java que recibo son iguales a cero, por lo que parece que el contenido no se copia en absoluto.

He verificado el contenido de los buffers (decoded_frame-> data [0]) en el lado nativo al escribirlos en el archivo binario y no hay ningún problema, el archivo contiene exactamente lo que esperaba.

Llamo a ese método periódicamente; el tamaño de la matriz puede variar en cada llamada.

¿Cuál es la forma correcta y más efectiva? La asignación de una nueva matriz durante cada llamada es obviamente una idea tonta, pero no sé cómo evitarla si el tamaño de la matriz varía.

EDIT:

he vuelto a escribir mi código de esta manera y parece estar bien ahora.

llamada en un bucle while:

... hacer algo de decodificación ...

if(!retArray) 
retArray = (*env)->NewByteArray(env, data_size); 

if((*env)->GetArrayLength(env, retArray) != data_size) 
{ 
(*env)->DeleteLocalRef(env, retArray); 
retArray = (*env)->NewByteArray(env, data_size); 
} 

void *temp = (*env)->GetPrimitiveArrayCritical(env, (jarray)retArray, 0); 
memcpy(temp, decoded_frame->data[0], data_size); 
(*env)->CallVoidMethod(env, obj, writeBufferMethodID, retArray); 
(*env)->ReleasePrimitiveArrayCritical(env, retArray, temp, 0); 

llamada en la salida del bucle:

(*env)->DeleteLocalRef(env, retArray); 

Respuesta

5

Intente llamar ReleasePrimitiveArrayCritical antes de llamar CallVoidMethod.

+0

Lo intenté pero nada cambió. Después de un tiempo, noté el error de JVM: 'No se pudo agregar a la tabla de referencia local JNI (tiene 512 entradas)' que me indicó un problema al eliminar las referencias locales de 'retArray'. He reescrito mi código - vea la parte de edición en la pregunta. Ahora pasa la matriz correctamente, pero ocurre otro problema en el lado de Java, no en el alcance de esta pregunta. – vitakot

+3

Todavía es incorrecto llamar a los métodos jni después de GetPrimitiveArrayCritical y antes de ReleasePrimitveArrayCritical. Lea aquí: http://java.sun.com/docs/books/jni/html/functions.html#64717 (busque GetPrimitiveArrayCritical) –

+0

Sí, tiene razón, ¡gracias! Votó para arriba, pero no puede aceptar la respuesta, ya que no fue una fuente de error, en mi caso. – vitakot

3

El ejemplo siguiente funciona para pasar char [] del código C al byte Java [].

void JNICALL Java_com_example_testapplication_MainActivity_getJNIByteArrayArg(JNIEnv *jenv, jobject jobj) 
{ 
jclass clazz = (*jenv)->FindClass(jenv, "com/example/testapplication/MainActivity"); // class path 
jmethodID mid = (*jenv)->GetMethodID(jenv, clazz, "addData", "([B)V");// function name 

jbyteArray retArray; 
char data[] = {'a','b',3,4,5}; 
int data_size = 5; 
if(!retArray) 
retArray = (*jenv)->NewByteArray(jenv, data_size); 

if((*jenv)->GetArrayLength(jenv, retArray) != data_size) 
{ 
    (*jenv)->DeleteLocalRef(jenv, retArray); 
    retArray = (*jenv)->NewByteArray(jenv, data_size); 
} 

void *temp = (*jenv)->GetPrimitiveArrayCritical(jenv, (jarray)retArray, 0); 
memcpy(temp, data, data_size); 
(*jenv)->ReleasePrimitiveArrayCritical(jenv, retArray, temp, 0); 

(*jenv)->CallVoidMethod(jenv, jobj, mid, retArray); 
} 
public void addData(byte[] data) { 
System.out.println("Buyya: From C: " + new String(data)); 
} 
Cuestiones relacionadas