passing a bytebuffer to jni...

6,722 views
Skip to first unread message

phil

unread,
Aug 16, 2009, 11:13:13 AM8/16/09
to android-ndk
I am trying to pass a bytebuffer to a jni method, and i can't seem to
get it to work --

Here's my java code --

byte[] buf1Bytes = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
ByteBuffer buf1 = ByteBuffer.wrap( buf1Bytes );
int buf1Len = buf1.capacity();

byte[] buf2Bytes = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
ByteBuffer buf2 = ByteBuffer.wrap( buf1Bytes );
int buf2Len = buf2Buf.capacity();

try {
ProcessBuffers(buf1, 0, buf1Len, buf2, 0, buf2en); // jni
call
} catch (Throwable t) {
System.out.println("t: " + t);
}

StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf2Len; i++) {
sb.append(i + 1 + ": " + buf2.get(i));
sb.append("\n");
}
tv.setText( sb.toString() );

Here's my c code.

jint
Java_com_example_testjni_testJni_ProcessBuffer(JNIEnv* env, jobject
thiz, jobject buf1, jint buf1Off, jint buf1Len, jobject buf2Buf, jint
buf2Off, jint buf2Len)
{
int i;
int n;
jbyte* _buf1;
jbyte* _buf2;

_buf1 = (*env)->GetDirectBufferAddress(env, buf1);
_buf2 = (*env)->GetDirectBufferAddress(env, buf2);
n = buf2Len;

for (i = 0; i < n; i++) {
_buf2[i] = (_buf1[buf1Off + (i % buf1Len)] + 1) % 255;
}

}

The first thing it was doing was just completely dying when it tried
to make the call.

After I put a try/catch around it, I thought I would be able to set a
breakpoint in the catch, but it didn't trigger the breakpoint and it
wound up printing:

1: 0
2: 0
...

any ideas?

tia

Doug Schaefer

unread,
Aug 16, 2009, 12:08:52 PM8/16/09
to andro...@googlegroups.com
I have a feeling the ByteBuffer.wrap call doesn't give you a direct byte buffer. Try using the allocationDirect method instead and put() your byte array into it.

phil

unread,
Aug 16, 2009, 3:23:31 PM8/16/09
to android-ndk
hey wow! that worked, thanks!

On Aug 16, 9:08 am, Doug Schaefer <cdtd...@gmail.com> wrote:
> I have a feeling the ByteBuffer.wrap call doesn't give you a direct byte
> buffer. Try using the allocationDirect method instead and put() your byte
> array into it.
>

phil

unread,
Aug 16, 2009, 3:25:39 PM8/16/09
to android-ndk
one concern I have is that the put(byte[]) winds up being a "copy" -
on a small buffer, it's not that big of a deal, but on a bigger
one......

thoughts?

Doug Schaefer

unread,
Aug 16, 2009, 3:59:09 PM8/16/09
to andro...@googlegroups.com
Don't think it's that big a deal. The direct byte buffer is real memory. put is the only way to get the bytes into there. The java may be slow, but your native code will more than compensate for that. It's definitely the recommended approach to get binary data back and forth over JNI.

phil

unread,
Aug 16, 2009, 4:06:16 PM8/16/09
to android-ndk
I want to use JNI for audio decoding.

So, I'm reading encoded data into a byte[] array in java.

Create a ByteBuffer which creates a copy of the byte[] array, then
calls the JNI function.

The JNI function, decodes the data, and puts the result into a byte
buffer (allocated on the java side).

Then when I get back into the java code, I've got to do another copy
from the the byte buffer into a byte[] array so i can feed it to an
AudioTrack.

Seems a bit inefficient to me (two buffer copies!). There must be a
way to avoid at least one of these "copies"...

-phil

On Aug 16, 12:59 pm, Doug Schaefer <cdtd...@gmail.com> wrote:
> Don't think it's that big a deal. The direct byte buffer is real memory. put
> is the only way to get the bytes into there. The java may be slow, but your
> native code will more than compensate for that. It's definitely the
> recommended approach to get binary data back and forth over JNI.
>

fadden

unread,
Aug 17, 2009, 4:45:47 PM8/17/09
to android-ndk
On Aug 16, 1:06 pm, phil <phil.pellouch...@gmail.com> wrote:
> So, I'm reading encoded data into a byte[] array in java.

Can you read it directly into the ByteBuffer? (e.g.
java.nio.FileChannel)

WoodManEXP

unread,
Sep 2, 2009, 11:00:15 AM9/2/09
to android-ndk
Why create the ByteBuffer? What would happen if you passed the byte[]
array to the JNI function rather than creating and passing the
ByteBuffer? Then later on if you need a ByteBuffer you might wrap it
around the byte[] (No copying or second buffer)/

Maybe?
> > > > > > tia- Hide quoted text -
>
> - Show quoted text -

WoodManEXP

unread,
Sep 2, 2009, 12:47:38 PM9/2/09
to android-ndk
If ya want to wait all day for it to complete, you can. :-)

fadden

unread,
Sep 2, 2009, 3:33:32 PM9/2/09
to android-ndk
On Sep 2, 8:00 am, WoodManEXP <woodman...@gmail.com> wrote:
> Why create the ByteBuffer? What would happen if you passed the byte[]
> array to the JNI function rather than creating and passing the
> ByteBuffer? Then later on if you need a ByteBuffer you might wrap it
> around the byte[] (No copying or second buffer)/

You need to call GetByteArrayElements to get at the contents of the
array. The VM has the option of pinning the original data and
returning a pointer to it, or copying the data into a new buffer and
returning that. So if you want to be guaranteed that no copying is
going on, a direct buffer is a better choice. You do have more
overhead when filling the buffer from the Java-language side, though
in theory the NIO I/O routines should avoid that for large operations.

Andreas Reuterberg

unread,
Sep 2, 2009, 3:54:10 PM9/2/09
to andro...@googlegroups.com
Using a ByteBuffer with allocateDirect you can get direct access to
the bytes in JNI with:

jbyte *bb = (*env)->GetDirectBufferAddress(env, byteBuffer);

Perhaps that's why he wanted to use a ByteBuffer?


I had to settle for passing a byte[] to JNI in my audio code since
AudioTrack.write() can't take a ByteBuffer anyway.
Reply all
Reply to author
Forward
0 new messages