rosu alin
rosu alin

Reputation: 5830

I'm trying to modify a byte array and send it from c++ to java via the JNI

This is my function:

void FrameReceived(int width, int height, const char *rawImageBytes, int size, jboolean remote)
{

if(size == 0)
    return;

jboolean isAttached;
JNIEnv *env;
jint jParticipant;
jint jWidth;
jint jHeight;
jbyte *jRawImageBytes;
jbyte *modifiedRawImageBytes;
jbyteArray Array;

env = getJniEnv(&isAttached);

if (env == NULL)
    goto FAIL0;
//LOGE(".... **** ....TRYING TO FIND CALLBACK");
if(remote)
{
    if(frameReceivedRemoteMethod == NULL)
        frameReceivedRemoteMethod = getApplicationJniMethodId(env, applicationJniObj, "vidyoConferenceFrameReceivedRemoteCallback", "(III[B)V");

    if (frameReceivedRemoteMethod == NULL) {
        //LOGE(".... **** ....CALLBACK NOT FOUND");
        goto FAIL1;
    }
}
else
{
    if(frameReceivedMethod == NULL)
        frameReceivedMethod = getApplicationJniMethodId(env, applicationJniObj, "vidyoConferenceFrameReceivedCallback", "(III[B)V");

    if (frameReceivedMethod == NULL) {
        //LOGE(".... **** ....CALLBACK NOT FOUND");
        goto FAIL1;
    }
}

jWidth = width;
jHeight = height;
LOGI("FrameReceived will reach here 1");

jRawImageBytes = (*env)->NewByteArray(env, size);
LOGI("FrameReceived will reach here 2");
(*env)->SetByteArrayRegion(env, jRawImageBytes, 0, size, rawImageBytes);
LOGI("FrameReceived will reach here 3");
//TODO will transform to NV21 in ndk (faster)
modifiedRawImageBytes = (*env)->NewByteArray(env, size);
LOGI("FrameReceived will reach here 4");
jint sizeWH = width * height;
jint quarter = sizeWH/4;
jint v0 = sizeWH + quarter;
LOGI("FrameReceived will reach here 5");
for (int u = sizeWH, v = v0, o = sizeWH; u < v0; u++, v++, o += 2) {
    modifiedRawImageBytes[o] = jRawImageBytes[v]; // For NV21, V first
    modifiedRawImageBytes[o + 1] = jRawImageBytes[u]; // For NV21, U second
}
LOGI("FrameReceived will reach here 6");
(*env)->SetByteArrayRegion(env, Array, 0, size, modifiedRawImageBytes);
LOGI("FrameReceived will reach here 7");

//LOGE(".... **** ....CALLBACK BEING CALLED");
if(remote)
{
    (*env)->CallVoidMethod(env, applicationJniObj, frameReceivedRemoteMethod, 0, jWidth, jHeight, Array);
}
else
{
    (*env)->CallVoidMethod(env, applicationJniObj, frameReceivedMethod, 0, jWidth, jHeight, Array);
}
//LOGE(".... **** ....CALLBACK CALLED");

(*env)->DeleteLocalRef(env, jRawImageBytes);

if (isAttached)
{
    (*global_vm)->DetachCurrentThread(global_vm);
}
//LOGE("FrameReceived End");
return;
FAIL1:
if (isAttached)
{
    (*global_vm)->DetachCurrentThread(global_vm);
}
FAIL0:
//LOGE("FrameReceived FAILED");
return;
}

And It will always crash at after this LOG: LOGI("FrameReceived will reach here 5"); in the FOR loop. What am I doing wrong here? This is what I am trying to achieve in the NDK:

public byte[] I420toNV21(final byte[] input, byte[] output, final int width, final int height) { if (output == null) { output = new byte[input.length]; } final int size = width * height; final int quarter = size / 4; final int v0 = size + quarter;

    System.arraycopy(input, 0, output, 0, size); // Y is same

    for (int u = size, v = v0, o = size; u < v0; u++, v++, o += 2) {
        output[o] = input[v]; // For NV21, V first
        output[o + 1] = input[u]; // For NV21, U second
    }
    return output;
}

So I can send the corect format byte array to java. and not have to do this method in my java code. Why can't it add the value in the for loop to by byte array?

Upvotes: 0

Views: 795

Answers (1)

rosu alin
rosu alin

Reputation: 5830

So in order to do this, I changed a bit the logic. Having the char *rawImageBytes, and it's size. Instead of dirrectly creating a jbyteArray. I will alloc space for another char array. and I will copy the memory from the first one, in the second. Then I call the for Loop, in order to modify what I need, and only after that, I will create the jbyteArray:

char *modifiedRawImageBytes = malloc(size);
memcpy(modifiedRawImageBytes, rawImageBytes, size);
jint sizeWH = width * height;
jint quarter = sizeWH/4;
jint v0 = sizeWH + quarter;
for (int u = sizeWH, v = v0, o = sizeWH; u < v0; u++, v++, o += 2) {
        modifiedRawImageBytes[o] = rawImageBytes[v]; // For NV21, V first
        modifiedRawImageBytes[o + 1] = rawImageBytes[u]; // For NV21, U second
}
jWidth = width;
jHeight = height;

jRawImageBytes = (*env)->NewByteArray(env, size);
(*env)->SetByteArrayRegion(env, jRawImageBytes, 0, size, modifiedRawImageBytes);

Upvotes: 0

Related Questions