I’m currently retrieving image data from an iSight camera and I’d like to hand it over to Java for processing. I originally tried to put the data in a jbyteArray and return the jbyteArray. This works once per process. Calling the native function a second time will result in an invalid memory access.
Since I’m working with objective-c and Cocoa, I must use the JNF_COCOA_ENTER(…) and JNF_COCOA_EXIT(…) functions. Sadly, if I can’t return the jbyteArray because doing so would result in JNF_COCOA_EXIT(…) not getting called. It was suggested to use a direct ByteBuffer to pass the data from JNI land to java land. Unfortunately, all the resources and references I’ve been using don’t outline this straightforwardly enough for my brain to comprehend. I deeply apologize if this is a “duh” moment or has already been asked (I’ve searched with no luck), but…
1) What is the most efficient way to bring this image data to Java?
2) How should I use the ByteBuffer class to accomplish this? (if relevant)
Thanks!
Code might be helpful here. It’s not as difficult as you might imagine once you get an idea of what those macros do, and how to separate the java and cocoa concerns from each other.
What you need to remember is that JNF_COCOA_ENTER and JNF_COCOA_EXIT do two main things for you:
They establish a local scope (so variables defined inside are not available outside – this is to help you not do “dumb” things with variables you shouldn’t be touching) and also to set up an auto-release pool, so cocoa objects which are “autoreleased” inside that scope will be gone when the scope disappears. (this is part of why the local scope is useful/helpful) They’ll also do some exception parsing so that you can catch Cocoa exceptions in Java.
That said, the following code IS LEGAL, you just need to be quite careful about managing memory access and ownership of data. Avoid mixing Java ownership and Objective-C ownership if possible, or else have your object manage the ownership, and clean up when the java object is GCed.
Using Java Objects from C is complex, but not unworkable. Still, the number of method calls is non-trivial, and the jump back and fourth is time consuming, so if you’ll be calling this method often, or it’s time critical, stick with the basic types as much as possible.
If you need to push data from Cocoa to Java from a delegate, things are a little bit more complicated, but not unworkable. Here’s a segment from a project I manage called QTCubed, which does exactly that. didOutputVideoFrame is the delegate method, and this object MUST be initialized with the target Java Object Reference, and Java Environment from a JNI called method. Once initialized, it’s then set as a delegate object, and receives updates from the camera.
Here’s the method signature on the java side for the java object reference that is passed in:
Once you have a running application, USE INSTRUMENTS TO MAKE SURE YOU’RE DISPOSING OF REFERENCES PROPERLY!