0

我正在为希望解压缩数据块的 Android 编写本机代码。我正在从本机 JNI 函数调用 Java 方法。这个 Java 方法调用 BitmapFactory,然后尝试分配一些内存:

int[] pixels = new int[width * height];

当程序似乎崩溃或停止或其他情况时,给我“spin on suspend”,然后在 VM 关闭之前在 logcat 中喷出很多东西。

只是为了在深入了解细节之前给出大图,我试图将压缩图像的字节数组转换为width*height*bpp未压缩的图像以返回给本机代码。我正在尝试使用 Android Java BitmapFactory 进行似乎可以正常工作的解压缩。压缩的字节块是之前加载到本机代码中的 JPG 或 PNG 图像(在我的系统中无法从磁盘读取)。

序列有点复杂,我不确定什么是相关的,所以我会全部说出来: class MyRenderer implements GLSurfaceView.Renderer方法onSurfaceCreated调用原生init(),它在MyRenderer 类中定义:

static {System.loadLibrary("glprog");
}
public native void init(int dummy_variable);

在本机代码中,这是调用的函数:

JNIEXPORT void JNICALL Java_com_pitransviewersingleimageres_MyRenderer_init(JNIEnv * env, jobject obj,  jint dummy_variable) {
glprog_init(dummy_variable);
}

然后调用另一个本机函数char glprog_init(int dummy_variable),该函数本身调用本机 wrapper_uncompress_image_by_os(overlay_compressed_data,overlay_compressed_data_len,... 这是本机函数:

char wrapper_uncompress_image_by_os(unsigned char *compressed_data, int compressed_len,                     //input compressed data
                                char *data_name_string, char *suffix,                                   //name and type
                                int slot_num)  {
jstring jnamestring = (*preset_env)->NewStringUTF(preset_env,data_name_string);
jstring jsuffix = (*preset_env)->NewStringUTF(preset_env,suffix);
//create byte[] and copy data in
jbyteArray retArray = (*preset_env)->NewByteArray(preset_env, compressed_len);
if(retArray==NULL) {__android_log_write(ANDROID_LOG_INFO, "NATIVE","ERROR wrapper_uncompress_image_by_os: calling NewByteArray()");return-1;}
jbyte *javaptr = (*preset_env)->GetPrimitiveArrayCritical(preset_env, (jarray)retArray, 0);
if(javaptr==NULL) {__android_log_write(ANDROID_LOG_INFO, "NATIVE","ERROR wrapper_uncompress_image_by_os: calling GetPrimitiveArrayCritical()");return-1;}
memcpy(javaptr,compressed_data,compressed_len); 
(*preset_env)->ReleasePrimitiveArrayCritical(preset_env, retArray, javaptr, 0);

if((preset_javaobject!=NULL)&&(preset_method_id_convertimagefromnative!=NULL))
   {
   jthrowable exception;
   //call java function
   (*preset_env)->CallVoidMethod(preset_env,     preset_javaobject,preset_method_id_convertimagefromnative, 
                             retArray,compressed_len,
                             jnamestring,jsuffix,slot_num);

它调用了与nativeconvertImageFromNative()相同的 Java 类中的方法。 MyRendererinit()

   public void convertImageFromNative(final byte[] data, int data_len, final String data_name_string, final String suffix, final int slot_num) {
    //writeFile(data,data_name_string);
    Bitmap bitmapqq=bytes2bitmap(data);

}

到目前为止,这似乎有效,如果我取消注释writeFile()它会将所有数据正常写入我的 SD 卡。我有问题是在里面bytes2bitmap()

可以在“常规”Java 中调用该类bytes2bitmap(),但是当从本机调用的 this 调用时,它会在该int[] pixels = new int[width * height];行崩溃。

所以最后这里是导致崩溃的代码:

Bitmap bytes2bitmap(byte[] bytes) {
    Log.d("startup", "Entered MyRenderer.bytes2bitmap()");
    BitmapFactory.Options opt = new BitmapFactory.Options(); 
    opt.inDither = true; 
    opt.inPreferredConfig = Bitmap.Config.ARGB_8888; 
    Bitmap bitmap=BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt);
    if(bitmap==null) Log.d("running", "ERROR: GLESActivity.java: BitmapFactory() returns null");
    int width = bitmap.getWidth(); 
    int height = bitmap.getHeight(); 
    bytes=null;   //not sure if I should be freeing memory here, but it seems to work
    int[] pixels = new int[width * height];    //crash happens here
    //crashes before doing the following
    bitmap.getPixels(pixels, 0, width, 0, 0, width, height); 
    pixels=null;
    return bitmap;
}

我还没有完成将未压缩的数据正确地传递回本机代码的部分,但我认为我应该首先解决这个问题。

我可以在本机代码中创建一个int[]数组来传递,问题是我不知道未压缩的图像大小。

在此先感谢,马克

4

1 回答 1

1

我解决了我的问题,这是我没有显示的代码中的错误。

问题出(*preset_env)->CallVoidMethod(preset_env, preset_javaobject,preset_method_id_convertimagefromnative,在本机代码中的调用中。变量 preset_env、_javaobject、_method_id_ 设置不正确。我在启动时将它们设置一次,以便以后使用本机函数 _setupnative2java() 重新使用。我的项目中有三个课程。我的错误是从我的第一个 Activity 类调用 _setupnative2java(),而不是实际包含 java 方法 bytes2bitmap() 的 MyRenderer 类。在调试过程中,我将这个函数的另一个副本放在第一个同名的 Activity 类中。所以它有点工作,但它的指针是错误的。奇怪的是,对 MyRenderer 的修改和 logcat 调用会起作用。

我实际上确实从 MyRenderer 类中调用了它,但是从带有 instancename.MyRenderer.setupnative2java 的启动 Activity 类中调用它。但也许因为它是从另一个类调用的,所以它没有获取 MyRenderer 的指针。另外,我不确定 MyRenderer 到底是如何“初始化”的。如果您为此花费了脑力,我深表歉意。

void Java_com_pitransviewersingleimageres_MyRenderer_setupnative2java(JNIEnv* env, jobject,javaThis, jint unused_variable) 
    {
    jthrowable exception;
    jclass class_id;
    preset_env=env;
    preset_javaobject=javaThis;
    class_id = (*env)->GetObjectClass(env, javaThis);
    if(class_id!=NULL)
       {
       preset_method_id_convertimagefromnative = (*env)->GetMethodID(env, class_id, "convertImageFromNative", "([BILjava/lang/String;Ljava/lang/String;I)V");  
       }
...
于 2012-09-15T19:04:18.347 回答