データのブロックを解凍したいAndroid用のネイティブコードを書いています。ネイティブ JNI 関数から Java メソッドを呼び出しています。この Java メソッドは BitmapFactory を呼び出し、次のようにメモリを割り当てようとします。
int[] pixels = new int[width * height];
プログラムがクラッシュしたり、停止したりしたように見えて、「一時停止中のスピン」が発生し、その後、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);
nativeを呼び出した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 から呼び出すことができますが、ネイティブから呼び出される 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[]
て渡すことができましたが、問題は、圧縮されていない画像のサイズがわからないことです。
前もってありがとう、マーク