Summary
- Create ByteBuffer in Java called buffer with ByteBuffer.allocateDirect(someBufferSize)
- Fill buffer with data
- Pass buffer to C++ as jobject - jbuffer
- Get buffer direct pointer with env->GetDirectBufferAddress(jbuffer)
- Work with buffer data on C++ side. How prevent GC to cleanup our buffer or it will never happen?
- Work done - we don't need jbuffer now.
- Release jbuffer? free(jbuffer) - will raise an invalid address error
Long part
I use next code to load PNG files with Java AssetManager to use them for Open GL ES 2.0 textures creation.
Java side PNG class
import java.nio.ByteBuffer;
import android.graphics.Bitmap;
public class PNG
{
private static final int BYTES_PER_PIXEL_PNG = 4;
private static final String LOG_TAG = "[PNG]";
public int width;
public int height;
public ByteBuffer pixels;
public PNG(Bitmap bitmap)
{
this.width = bitmap.getWidth();
this.height = bitmap.getHeight();
this.pixels = ByteBuffer.allocateDirect(this.width * this.height * BYTES_PER_PIXEL_PNG);
bitmap.copyPixelsToBuffer(this.pixels);
}
}
public static PNG loadPNG(String path)
{
InputStream is = null;
try
{
is = ASSETS_MANAGER.open(path);//get png file stream with AssetsManager instance
}
catch (IOException e)
{
Log.e(LOG_TAG, "Can't load png - " + path, e);
}
return new PNG(BitmapFactory.decodeStream(is));
}
C++ side PNG
typedef struct png
{
int width;
int height;
char* pixels;
} png;
png* load_png(const char* path)
{
png* res = (res*) malloc(sizeof(png);
...
jobject _png = env->CallStaticObjectMethod(get_java_lib_class(), get_method_id(JAVA_LIB_LOAD_PNG, JAVA_LIB_LOAD_PNG_SIGN), _path);//Calling loadPng() from Java, get PNG jobject
jobject _pixels = env->GetObjectField(_png, PNG_FIELDS->PNG_PIXELS_ID);//Getting pixels field from Java PNG jobject
res->pixels = (char*) env->GetDirectBufferAddress(_pixels);//Get direct pointer to our pixel data
//Cleanup
...
env->DeleteLocalRef(_png);
env->DeleteLocalRef(_pixels);
return res;
}
Then using png to create texture
void test_create_tex(const char* path)
{
...
png* source = load_png(path);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, source->width, source->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, source->pixels);
//We don't need source pixel data any more
//free(source->pixels);//INVALID HEAP ADDRESS (deadbaad)
free(source);
}
So how release byte buffer after using in C++ side with it's direct pointer? It is allocate directly (like malloc - on native side) and must be freed or i will get OutOfMemory error.