0

我试图转换这个 Java 代码:

// http://www.stanford.edu/class/ee368/Android/index.html  
// Source: http://www.stanford.edu/class/ee368/Android/HelloViewfinder/Project.zip
private void decodeYUV420RGB(int[] rgb, byte[] yuv420sp, int width, int height) {
     Convert YUV to RGB
    final int frameSize = width * height;
    for (int j = 0, yp = 0; j < height; j++) {
        int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
        for (int i = 0; i < width; i++, yp++) {
            int y = (0xff & ((int) yuv420sp[yp])) - 16;
            if (y < 0) y = 0;
            if ((i & 1) == 0) {
                v = (0xff & yuv420sp[uvp++]) - 128;
                u = (0xff & yuv420sp[uvp++]) - 128;
            }

            int y1192 = 1192 * y;
            int r = (y1192 + 1634 * v);
            int g = (y1192 - 833 * v - 400 * u);
            int b = (y1192 + 2066 * u);

            if (r < 0) r = 0; else if (r > 262143) r = 262143;
            if (g < 0) g = 0; else if (g > 262143) g = 262143;
            if (b < 0) b = 0; else if (b > 262143) b = 262143;

            rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
        }
    }
}

就是这样称呼的:

//byte[] mYUVData; int[] mRGBData;
decodeYUV420RGB(mRGBData, mYUVData, mImageWidth, mImageHeight);

到这个 C 代码:

#include <string.h>
#include <jni.h>

jint*
Java_com_camera_DrawOnTop_decodeYUV420RGB565(JNIEnv* env, jobject  thiz, jintArray rgb, jbyteArray yuv420sp, jint width, jint height)
{
 jbyte* yuv420spc = (*env)->GetByteArrayElements(env, yuv420sp, NULL);
 jint*  rgbc      = (*env)->GetIntArrayElements(env, rgb, NULL);

    int frameSize = width * height;
    int j;
    int i;
    int yp;
    for (j = 0, yp = 0; j < height; j++) {
        int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
        for (i = 0; i < width; i++, yp++) {
            int y = (0xff & ((int) yuv420spc[yp])) - 16;
            if (y < 0) y = 0;
            if ((i & 1) == 0) {
                v = (0xff & yuv420spc[uvp++]) - 128;
                u = (0xff & yuv420spc[uvp++]) - 128;
            }

            int y1192 = 1192 * y;
            int r = (y1192 + 1634 * v);
            int g = (y1192 - 833 * v - 400 * u);
            int b = (y1192 + 2066 * u);

            if (r < 0) r = 0; else if (r > 262143) r = 262143;
            if (g < 0) g = 0; else if (g > 262143) g = 262143;
            if (b < 0) b = 0; else if (b > 262143) b = 262143;

            rgbc[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
        }
    }

(*env)->ReleaseByteArrayElements(env, yuv420sp, yuv420spc, 0 );
(*env)->ReleaseIntArrayElements(env, rgb, rgbc, 0 );
return rgbc;

}

并通过 JNI 调用它:

//int[] mRGBData; int [] tmpData = {1,2,3};
mRGBData = decodeYUV420RGB565(tmpData, mYUVData, mImageWidth, mImageHeight);

但是在上述调用之后程序会中断运行。我现在不知道如何使用 JNI 进行引用调用,所以我只使用 tmpData 来获取数据,但通过等号将真实数据返回给 mRGBData。

我的 C 代码有什么问题,所以它在运行时中断?

我有什么要改变的,以便它像原始代码一样使用参考(不带等号)?

4

3 回答 3

1

您应该为您的 JNI 函数提供一个大小正确的 RGB 数组(即w*h),以及一个大小和结构正确的 YUV 数组(w*h*3/2,带有w*h 亮度字节(Y),后跟(w/2)*(h/2)色度UV )字节。如果您提供大小为 3 的rgb数组,则调用将崩溃,如您的代码片段中所示。

另请注意,您正在构建一个 rgb565 数组。它的元素可能是 short 类型(16 位)而不是 int (32 位)。

于 2013-05-13T10:11:22.790 回答
0

我将代码更改为:

爪哇:

native void decodeYUV420RGB565(ByteBuffer rgb, byte[] yuv420sp, int width, int height); 
//There's no allocateDirect for IntBuffer so I have to use ByteBuffer
//although mRGBData is an int array
//allocateDirect(mRGBData.length * 4) because mRGBData is an int array
ByteBuffer mTempData = ByteBuffer.allocateDirect(mRGBData.length*4);
decodeYUV420RGB565(mTempData, mYUVData, mImageWidth, mImageHeight);
mRGBData = mTempData.asIntBuffer().array();
mTempData.clear();

C:

void Java_com_camera_DrawOnTop_decodeYUV420RGB565(JNIEnv* env, jobject thiz, jintArray rgb, jbyteArray yuv420sp, jint width, jint height)
{
 jbyte* yuv420spc = (*env)->GetByteArrayElements(env, yuv420sp, NULL);
 jint*  rgbc      = (*env)->GetDirectBufferAddress(env, thiz);

 //...conversion code as above...

 (*env)->ReleaseByteArrayElements(env, yuv420sp, yuv420spc, 0 );
 (*env)->ReleaseIntArrayElements(env, rgb, rgbc, 0 );

但我有同样的问题:当我调用 decodeYUV420RGB565(mTempData, mYUVData, mImageWidth, mImageHeight) 时代码崩溃。我要在代码中更改什么?

于 2013-05-13T16:05:56.363 回答
0

GetByteArrayElements() 在 C 端创建一个数组,您填充该数组,然后释放,然后返回给 Java,Java 获取指向释放内存的指针。如果您想真正将数据传递到 Java 端,您需要创建一个新的 Java 数组对象并将其返回。或者,在 Java 端创建新对象并将其传递给 C 代码进行修改。我发现后者通常更容易。我通常在 Java 端创建一个 DirectByteBuffer 并将其传递给本机函数,让本机函数调用 GetDirectBufferAddress 并写入其中。

例如,请参阅我的 PD ojrandlib JNI 代码:https ://github.com/lcrocker/ojrandlib/tree/master/source/java/com/onejoker/randlib

于 2013-05-12T22:58:00.800 回答