I have a very large char buffer in C and need to copy some part of it to a Java array.
Specifically, I need the elements starting at 16,384 and ending at 32000. How can I do this?
Initially I tried this:
jbyte * bytes = (* env) -> GetByteArrayElements (env, array, NULL);
memmove (bytes, (jbyte *) buffer, buffer_size);
(* Env) -> ReleaseByteArrayElements (env, array, (jbyte *) bytes, 0);
(* Env) -> CallStaticVoidMethod (env, cls, mid, buffer_size);
But with this code the entire buffer is transmitted, and it is very big (more than 40 MB). I need only a small part of buffer.
EDIT:
Thank you very much, but your version is not quite working. I applied it as follows:
memmove (array, (jbyte *) (buffer + numbers), 16385);
in the buffer – at each iteration is copied to the “buffer” new 16384 bytes.
such figures in the amount of buffer and numbers, respectively:
16384 – 0
32,768 – 16,385
49152 – 32769
65536 – 49153
81,920 – 65,537
98,304 – 81,921
Ie at each iteration by turns in the “numbers” of right-hand column.
As a result, – bytes are copied are not always successful. the first iteration is always successful. Further, by turns both successful and unsuccessful. memtcpy gives the same result. What will advise? How to solve the problem?
EDIT2:
My code:
JNIEXPORT jint work (JNIEnv * env, jobject obj, jbyteArray array)
{
int argc;
char * args [3];
char * argv [3];
argv [1] = "Music/Tg.mp3";
argv [2] = "testwavS3.flac";
argc = 3;
sox_effects_chain_t * chain;
sox_effect_t * e;
static sox_format_t * in, * out; / * input and output files * /
char * buffer;
size_t buffer_size;
size_t number_read;
/ * All libSoX applications must start by initialising the SoX library * /
sox_init ();
/ * Open the input file (with default parameters) * /
in = sox_open_read (argv [1], NULL, NULL, NULL);
# Define MAX_SAMPLES (size_t) 8192
__android_log_write (ANDROID_LOG_ERROR, "Read", "Haha");
sox_sample_t samples [MAX_SAMPLES]; / * Temporary store whilst copying. * /
jclass cls;
jmethodID mid, mid2;
cls = (* env) -> GetObjectClass (env, obj);
mid = (* env) -> GetStaticMethodID (env, cls, "testt",
"(I) V");
jbyteArray bytearrayBuffer = (* env) -> NewByteArray (env, & in-> signal.length); / / construct a new byte array
out = sox_open_memstream_write (& buffer, & buffer_size, & in-> signal, NULL, "sox", NULL);
int numbers = 0;
in-> encoding.bits_per_sample = 16;
out-> encoding.bits_per_sample = 16;
(* Env) -> GetByteArrayElements (env, array, NULL);
while (number_read = sox_read (in, samples, MAX_SAMPLES)) {
sox_write (out, samples, number_read);
memmove (array, (jbyte *) (buffer + numbers), (buffer_size-numbers));
numbers + = buffer_size-numbers;
(* Env) -> CallStaticVoidMethod (env, cls, mid, buffer_size);
}
sox_close (out);
sox_close (in);
# If! Defined FIXED_BUFFER
free (buffer);
# Endif
}
using SoX to decode the audio and give buffer in Java.
Why not just:
with appropriate changes to the target Java array, and appropriate bounds checking of the C++ buffer.
As an aside: My C/C++ is rusty, but is not
memcpymore efficient thanmemmoveif you know you don’t have overlapping memory?Edit 2011-06-13
Looking over the full function that you posted, it’s still not entirely clear what you are really intending to do. However, I can see several potential problems in what is posted, not the least of which is that it appears it should not compile. I will leave you to follow up on these observations and either correct the code or rule them out (recall it’s been a while since I coded C full-time, so I may not be entirely accurate in every observation).
JNIEnv *env, but several of the JNI calls use(*Env)instead of*env– if this compiles at all, it’s probably a mistake, and even if the pointer happens to be valid, it’s horrible form – use the environment pointer passed in the function call.sox_open_memstream_writeallocatesbuffer, the pointer is not valid.bytearrayBufferis constructed but never used.free(buffer)releases memory that was never allocated.memmovetoarraywhich is a jbyteArray and is not a pointer returned from locking the array for read/write from JNI (using, e.g.GetByteArrayElements). I would have expect a point cast warning from the C compiler.(*Env) -> GetByteArrayElements (env, array, NULL);is not being used; therefore you have no valid pointer to the array contents, and you have leaked memory since the Java array is not released usingReleaseByteArrayElements.numbersseems illogical; the first time through the value will be 0, then next time through it will bebuffer_size, and after that it will be indexing off the end of the buffer.(*Env) -> CallStaticVoidMethod (env, cls, mid, buffer_size);does not appear to be able to anything useful. If it’s meant to tell Java about the buffer size, then either return the value or create a Java array size of exactly that size.Apart from the Java array being incorrectly accessed, I think the heart of your problem could be that you need:
instead of
assuming the buffer is created by
sox_open_memstream_writeand is created large enough to write the entire output (which seems nonsensical since the structure of the API would seem to indicate reading chunks of input and writing processed output to a temporary output buffer which output buffer is being reused for each write.Maybe the loop should be something like:
(PS: Please stop emailing me – I will respond here when and if I feel like it)