Skip to content Skip to sidebar Skip to footer

Android Using Jni Without Static Variables

I created my own version of Android's MediaMetadataRetriever using the source code for MediaMetadataRetriever.java as the basis. My version uses FFmpeg to retrieve the metadata. Th

Solution 1:

Restructuring the code would be very straight forward. Instead of using pFormatCtx you simply extend the interfaces of the JNI calls so you can pass around the pointer you stored in pFormatCtx before. Now the big guestion is how to pass around the pointers while java doesn't know such a datatype? The most straight forward soulution would be to use ints (for 32 bit systems) or longs (for 64 bit systems) to passing pointers to and from the Java environment. Unfortunately you could get you a bit in hot water as soon as you switch between 64 and 32 bit versions of your library.

While I was trying to solve this problem some months ago I stumbled over an article of Clebert Suconic. He pointed out a very elegant way for passing pointers safely through JNI without "hacking" around with typecasting. Instead he proposes to use java.nio.ByteBuffer.

The concept put in a nutshell is: He suggest to create a new ByteBuffer object of length zero: env->NewDirectByteBuffer(myPointer, 0); and pass the resulting jobject through the JNI back and forth.

The call env->NewDirectByteBuffer(myPointer, 0); creates a imutable byte buffer object pointing to the location you wanted to pass around. The fact that the buffer is imutable is perfect as you don't want to modify the memory location, you only want to store the location itself. What you get is an object encapsulating your pointer and you can leave the pointer size issues to the JVM.

Edit: Just for completeness: The pointer can later be retrieved calling env->GetDirectBufferAddress(myPointer);.

Solution 2:

Add a long field (or int if you know you'll only ever be on a 32-bit system) to store the native pointer, and to dispose of it in your object's finalizer when the object is GC'd. From JNI, you can then save to that field the pointer obtained when you "open" your resource.

From the JNI manual:

Procedure for Accessing a Java Field

To get and set Java fields from a native method, you must do the following:

Obtain the identifier for that field from its class, name, and type signature. For example, in FieldAccess.c, we have:

fid = (*env)->GetStaticFieldID(env, cls, "si", "I");

and:

fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;");

Use one of several JNI functions to either get or set the field specified by the field identifier. Pass the class to the appropriate static field access functions. Pass the object to the appropriate instance field access functions. For example, in FieldAccess.c, we have:

si = (*env)->GetStaticIntField(env, cls, fid);

and:

jstr = (*env)->GetObjectField(env, obj, fid);

Similar to calling a Java method, we factor out the cost of field lookup using a two-step process. The field ID uniquely identifies a field in a given class. Similar to method IDs, a field ID remains valid until the class from which it is derived is unloaded. Field Signatures

Field signatures are specified following the same encoding scheme as method signatures. The general form of a field signature is:

"field type"

The field signature is the encoded symbol for the type of the field, enclosed in double quotes (""). The field symbols are the same as the argument symbols in the method signature. That is, you represent an integer field with "I", a float field with "F", a double field with "D", a boolean field with "Z", and so on.

The signature for a Java object, such as a String, begins with the letter L, followed by the fully-qualified class for the object, and terminated by a semicolon (;). Thus, you form the field signature for a String variable (c.s in FieldAccess.java) as follows:

"Ljava/lang/String;"

Arrays are indicated by a leading square bracket ([) followed by the type of the array. For example, you designate an integer array as follows:

"[I"

Refer to the table in previous section which summarizes the encoding for the Java type signatures and their matching Java types.

You can use javap with option "-s" to generate the field signatures from class files. For example, run:

> javap -s -p FieldAccess

This gives you output containing:

... 
static si I 
s Ljava/lang/String; 
...

Post a Comment for "Android Using Jni Without Static Variables"