Я пишу собственный код для Android, где хочу распаковать блок данных. Я вызываю метод Java из собственной функции JNI. Этот метод Java вызывает BitmapFactory, а затем пытается выделить часть памяти с помощью:
int[] pixels = new int[width * height];
когда кажется, что программа дает сбой или зависает или что-то в этом роде, что дает мне "вращение при приостановке", за которым следует много извержений в 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)
которая сама вызывает нативную обертку_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);
Который вызывает метод convertImageFromNative()
в том же классе Java MyRenderer
, который вызывал родной init()
.
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()
.
Класс bytes2bitmap()
можно вызывать из «обычной» Java, но при вызове из этого, который вызывается из нативного, происходит сбой в строке 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[]
вниз в собственном коде, чтобы отказаться от него, проблема в том, что я не знаю размер несжатого изображения.
Заранее спасибо, Марк