概括
- 使用 ByteBuffer.allocateDirect(someBufferSize) 在 Java 中创建称为缓冲区的 ByteBuffer
- 用数据填充缓冲区
- 将缓冲区作为作业对象传递给 C++ - jbuffer
- 使用 env->GetDirectBufferAddress(jbuffer) 获取缓冲区直接指针
- 在 C++ 端处理缓冲区数据。如何防止 GC 清理我们的缓冲区,否则它永远不会发生?
- 工作完成——我们现在不需要 jbuffer。
- 释放jbuffer?free(jbuffer) - 将引发无效地址错误
长部分
我使用下一个代码通过 Java AssetManager 加载 PNG 文件,以使用它们创建 Open GL ES 2.0 纹理。
Java端PNG类
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++ 端 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;
}
然后使用 png 创建纹理
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);
}
那么在 C++ 端使用它的直接指针后如何释放字节缓冲区呢?它是直接分配的(如 malloc - 在本机端)并且必须被释放,否则我会得到 OutOfMemory 错误。