Java Forum / General / December 2005
Making and Returning Java Byte Arrays in C++ via JNI (Help! Please!)
res7cxbi@verizon.net - 16 Dec 2005 06:14 GMT How do you make java byte arrays, fill them with values, and return them in c++? I have no clue where to start. The JNI Tutorial a at Java's website isn't much help because it doesn't really explain how to make new jarrays. Any tips, how-tos and example code are welcome! (And can anybody please explain me what's jsize? Is it just another integer?)
Jean-Francois Briere - 16 Dec 2005 07:12 GMT To create a new jbytearray of size 32:
jbytearray bArray = env->NewByteArray(32);
jsize == jint jint is platform dependent (it's long on 32 bits Windows for instance).
You should check the specification to help you. http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/jniTOC.html
Regards
res7cxbi@verizon.net - 16 Dec 2005 07:33 GMT Thanks - this is a huge start for me
how do you fill it with values though...?
Thanks (Again)
res7cxbi@verizon.net - 16 Dec 2005 08:30 GMT Let me clarify my last reply...
How do you fill the jbyteArray with values from a BYTE* array (which is native)?
Gordon Beaton - 16 Dec 2005 09:11 GMT > How do you fill the jbyteArray with values from a BYTE* array (which > is native)? Using one of these mechanisms:
- SetByteArrayRegion()
- use GetByteArrayElements(), modify the local copy using "normal" assignment, then use ReleaseByteArrayElements() to propagate your changes back to the Java array.
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
Chris Uppal - 16 Dec 2005 09:10 GMT > how do you fill it with values though...? You should find the JNI book helpful. Downloadable from:
http://java.sun.com/docs/books/jni/index.html
See especially section 3.3, "Accessing Arrays".
-- chris
res7cxbi@verizon.net - 16 Dec 2005 09:52 GMT Thanks guys, it works except for one thing.... The VM crashes!!!
This is the most interesting problem ever encountered. I've tested each line one by one and after that I've found out that the lines that are commented out is the code that is causing the VM to crash
All the other code works perfectly. But the loop that copies the contents of the buffer retrieved by GetSample() (a method implemented by me) into the jbyte array completely screws up everything
More interestingly, this method works for the first 2 invocations if compiled with the for loop then crashes!
Compile w/o the loop method works perfectly
Im just as confused as you are
That loop is crucial because it is what fills the arrays! Or is there a workaround?
Here's the code for it... it completely stumped me... any ideas are highly appreciated!
JNIEXPORT jbyteArray JNICALL Java_SomeClass_readNextArray (JNIEnv *env, jobject obj) { BYTE *buffer = NULL; DWORD bufferlen = 0; GetSample(&buffer, &bufferlen); jbyteArray bArray = env->NewByteArray( bufferlen ); jbyte *jBytes = env->GetByteArrayElements( bArray, 0); //Problem Code!!! //for(DWORD i = 0; i < bufferlen; i++) { // jBytes[i] = buffer[i]; //} env->ReleaseByteArrayElements( bArray, jBytes, 0); return bArray; }
res7cxbi@verizon.net - 16 Dec 2005 10:01 GMT Actually it might be a problem with the GetSample() implementation. Time to check it out...... keep you guys updated
res7cxbi@verizon.net - 16 Dec 2005 10:18 GMT If this helps, this is the error:
# # An unexpected error has been detected by HotSpot Virtual Machine: # # EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x10001640, pid=3212, tid=3068 # # Java VM: Java HotSpot(TM) Client VM (1.5.0_04-b05 mixed mode, sharing) # Problematic frame: # C [ArrayReaderTest.dll+0x1640] # # An error report file with more information is saved as hs_err_pid3212.log # # If you would like to submit a bug report, please visit: # http://java.sun.com/webapps/bugreport/crash.jsp #
res7cxbi@verizon.net - 16 Dec 2005 10:21 GMT Nope... GetSample() is fine
Gordon Beaton - 16 Dec 2005 10:48 GMT > Nope... GetSample() is fine When everything is fine but your code is still crashing, then your definition of "fine" needs adjusting.
Aside from your neglect to check return values (as Chris already pointed out) there is nothing inherently wrong with the native code you posted.
What do buffer and bufferlen contain after calling GetSample()? Are you sure that the length is correct for the given buffer?
What happens if you completely remove the call to GetSample(), and do something like this instead (just to test):
BYTE buffer[] = { 1, 2, 3, 4, 5 }; DWORD bufferlen = 5;
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
res7cxbi@verizon.net - 16 Dec 2005 11:00 GMT works perfectly... hey now that's even more interesting...
the buffer contains PCM audio data as unsigned bytes (i believe) the buffer is usually somewhere in the 50,000 elements at any one time
res7cxbi@verizon.net - 16 Dec 2005 11:02 GMT Sorry my last post was supposed to go right after Gordon's Post...
Gordon Beaton - 16 Dec 2005 11:30 GMT > works perfectly... hey now that's even more interesting... So I suggest you look more closely at GetSample(). Does bufferlen agree with buffer? Is the buffer allocated dynamically? If so, shouldn't you free it at some point?
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
Chris Uppal - 16 Dec 2005 10:18 GMT > The VM crashes!!! Not quite the right way to put it. The correct expression is "My code crashes, taking the JVM with it!!!".
> jbyteArray bArray = env->NewByteArray( bufferlen ); > jbyte *jBytes = env->GetByteArrayElements( bArray, 0); Never omit error-checking in JNI code. NEVER.
Other than that nothing obvious leaps out at me. Possibly the error is elsewhere in your code. Are you /certain/ that GetSample() works, and returns the correct values in buffer and bufferlen ? Where does the "buffer" come from, is it malloc()/new()-ed ? If so then where's the corresponding free()/delete[] ?
-- chris
res7cxbi@verizon.net - 16 Dec 2005 10:32 GMT The "buffer" comes from an INSSBuffer which comes from the IWMSyncReader in the Windows Media Format SDK. I want to pass samples to my java app
res7cxbi@verizon.net - 16 Dec 2005 10:55 GMT Im running out of time... i'll just set up a buffer in the native code and have individual elements passed to the java app by native methods and have a for loop to reconstruct the array... really, can't figure this out...
Do you guys think there's a performance penalty for java repeatly asking for the next individual element or is it more favorable passing the entire array to the java app?
Gordon Beaton - 16 Dec 2005 11:28 GMT > Do you guys think there's a performance penalty for java repeatly > asking for the next individual element or is it more favorable passing > the entire array to the java app? Crossing the JNI boundary is expensive. Return the whole array!
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
Gordon Beaton - 16 Dec 2005 11:51 GMT > jbyte *jBytes = env->GetByteArrayElements( bArray, 0); > //Problem Code!!! > //for(DWORD i = 0; i < bufferlen; i++) { > // jBytes[i] = buffer[i]; > //} > env->ReleaseByteArrayElements( bArray, jBytes, 0); Not that this has anything to do with your problem, but you can replace all of the above code (two calls to Set/GetByteArrayElements and the intervening loop) with a single call to SetByteArrayRegion.
As an added bonus, SetByteArrayRegion likely uses a more efficient mechanism to transfer the data.
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
Roedy Green - 16 Dec 2005 09:30 GMT >How do you make java byte arrays, fill them with values, and return >them in c++? I have no clue where to start. to initialise arrays see http://mindprod.com/jgloss/gotchas.html#ARRAY
passing arrays back and forth to C++ is tricky. You need a text book to explain it all. See http://mindprod.com/jgloss/jni.html to get started.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Gordon Beaton - 16 Dec 2005 18:19 GMT > passing arrays back and forth to C++ is tricky. You need a text book > to explain it all. No it's not and no you don't.
If you have a moderate grasp of C or C++, then it's just an API like any other. If you don't, then you probably shouldn't be using JNI.
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
Roedy Green - 17 Dec 2005 03:14 GMT >If you have a moderate grasp of C or C++, then it's just an API like >any other. If you don't, then you probably shouldn't be using JNI. It the time I was learning, it was an unusually poorly documented API without any sample code or tutorials. It all made sense once I got a text book that showed some sample code.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
res7cxbi@verizon.net - 17 Dec 2005 18:11 GMT PROBLEM SOLVED!!!
I simply memcpy'd twice on some temporary BYTE*s then copy them into jbyte using a for loop
BYTE* tempMem; DWORD len = 0; hr = inssBuffer->GetBufferAndLength(&tempMem, &len); BYTE* tempMem2 = new BYTE[len]; jbyteArray bArray = env->NewByteArray( len); jbyte *jBytes = env->GetByteArrayElements( bArray, 0); if(hr == S_OK) { memcpy(tempMem2, tempMem, len); for(DWORD i = 0; i < len; i++) { jBytes[i] = tempMem2[i]; } } //then clean up (cleanup code ommited for clarity env->ReleaseByteArrayElements( bArray, jBytes, 0); return bArray;
so now i am able to return the entire array
This works perfectly this time. Thanks for all who tried to help me. It is very much appreciated - thaks for reminding me to put in error-checking code and giving me some ways to test it out and giving me tips
Thank you all again!
res7cxbi@verizon.net - 17 Dec 2005 18:15 GMT Sorry, i copy and pasted the code all wrong
BYTE* tempMem; BYTE* tempBuffer; DWORD len = 0; hr = inssBuffer->GetBufferAndLength(&tempBuffer, &len); BYTE* tempMem2 = new BYTE[len]; jbyteArray bArray = env->NewByteArray( len); jbyte *jBytes = env->GetByteArrayElements( bArray, 0); if(hr == S_OK) { memcpy(tempMem, tempBuffer, len); memcpy(tempMem2, tempMem, len); for(DWORD i = 0; i < len; i++) { jBytes[i] = tempMem2[i]; }
}
Gordon Beaton - 17 Dec 2005 18:39 GMT > Sorry, i copy and pasted the code all wrong > [quoted text clipped - 12 lines] > } > } I hate to disappoint you, but I don't believe for a moment that copying the data twice with memcpy (and a *third* time in the loop!) actually solves anything:
http://catb.org/~esr/jargon/html/C/cargo-cult-programming.html
Also, where do you initialize tempMem? Where do you free tempMem2?
/gordon
 Signature [ do not email me copies of your followups ] g o r d o n + n e w s @ b a l d e r 1 3 . s e
res7cxbi@verizon.net - 31 Dec 2005 07:47 GMT Hey this is an interesting:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4418152
Maybe take a look at that
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|