私は、バッファをmallocing(すなわち割り当て)しているネイティブコードを持っています。私はCanvas描画操作を使ってこのメモリに描画するのが好きです。 しかし、キャンバスコードはBitmapをバッキングプレーンとして使用しています。私はAndroidのビットマップでメモリのネイティブブロックをラップする方法があるかどうか疑問に思っています。ネイティブコードで作成したmallocedバッファを使用するビットマップを作成できますか?
おかげで、デフォルトで
Videoguy
私は、バッファをmallocing(すなわち割り当て)しているネイティブコードを持っています。私はCanvas描画操作を使ってこのメモリに描画するのが好きです。 しかし、キャンバスコードはBitmapをバッキングプレーンとして使用しています。私はAndroidのビットマップでメモリのネイティブブロックをラップする方法があるかどうか疑問に思っています。ネイティブコードで作成したmallocedバッファを使用するビットマップを作成できますか?
おかげで、デフォルトで
Videoguy
ビットマップuse native memory。
バッファからJAVAを渡し、ネイティブコードで埋めてCanvasでレンダリングすることができます。完了、完璧に動作します。例を追加して編集し
:
警告、Javaは、だから、メインのレンダリング部分は数行上記と呼ばれる先
/*
* Copyright (C) 2009 The Android Open Source Project
*/
package com.example.hellojni;
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.widget.Toast;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
import android.graphics.PixelFormat;
import java.nio.ByteBuffer;
public class HelloJni extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(new Panel(this));
}
public void onDestroy() {
super.onDestroy();
myEngineDestroy();
}
class Panel extends SurfaceView implements SurfaceHolder.Callback {
Bitmap renderbmp = null;
Paint paint = null;
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
getHolder().setFormat(PixelFormat.RGB_565);
setFocusable(true);
setFocusableInTouchMode(true);
}
@Override
public boolean onKeyDown(int i, KeyEvent event) {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if ((event.getAction() == MotionEvent.ACTION_DOWN) ||
(event.getAction() == MotionEvent.ACTION_MOVE))
{
if(myEngineMouseInput((int) event.getX(), (int) event.getY(), 0) == 1)
drawFrame();
return true;
}
return false;
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
if(renderbmp == null)
renderbmp = Bitmap.createBitmap(holder.getSurfaceFrame().right-holder.getSurfaceFrame().left, holder.getSurfaceFrame().bottom-holder.getSurfaceFrame().top,Bitmap.Config.RGB_565);
if(paint == null)
paint = new Paint(Paint.FILTER_BITMAP_FLAG);
myEngineInit(renderbmp, renderbmp.getWidth(), renderbmp.getHeight(), PixelFormat.RGB_565);
drawFrame();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
public void drawFrame() {
Canvas c;
c = getHolder().lockCanvas(null);
c.drawBitmap(renderbmp, 0, 0, paint);
if (c != null) getHolder().unlockCanvasAndPost(c);
}
}
/* A native method that is implemented by the
* 'hello-jni' native library, which is packaged
* with this application.
*/
public native void myEngineInit(Bitmap bmp, int w, int h, int pf);
public native int myEngineMouseInput(int x, int y, int mt);
public native void myEngineDestroy();
public native String unimplementedStringFromJNI();
static {
System.loadLibrary("hello-jni");
}
}
となりましたNDK側
/*
* Copyright (C) 2010 The Android Open Source Project
*/
#include <android_native_app_glue.h>
#include <errno.h>
#include <jni.h>
#include <sys/time.h>
#include <time.h>
#include <android/log.h>
#include <android/bitmap.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define LOG_TAG "myapp"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
/* Set to 1 to enable debug log traces. */
#define DEBUG 0
/* Return current time in milliseconds */
static double now_ms(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec*1000. + tv.tv_usec/1000.;
}
jobject jbmp = NULL;
ANativeWindow_Buffer draw_buffer = { 0 };
static void cleanup_draw_buffer(JNIEnv* env)
{
if(jbmp) {
AndroidBitmap_unlockPixels(env, jbmp);
}
draw_buffer.bits = 0;
}
static int init_draw_buffer(JNIEnv* env, jobject jbitmap, int width, int height)
{
int res = 0, ret;
LOGI("init_draw_buffer");
LOGI("window w:%d, h:%d, format: %d", width, height, 4);
if(draw_buffer.width != width ||
draw_buffer.height != height)
{
draw_buffer.width=width;
draw_buffer.height=height;
draw_buffer.stride = draw_buffer.width*2;
res = 1;
}
jbmp = NULL;
if ((ret = AndroidBitmap_lockPixels(env, jbitmap, &draw_buffer.bits)) < 0) {
LOGE("AndroidBitmap-lockPixels() failed ! error=%d", ret);
}
else {
LOGI("Successfully acquired bitmap pixels: %x", draw_buffer.bits);
jbmp = jbitmap;
}
return res;
}
/* simple stats management */
typedef struct {
double renderTime;
double frameTime;
} FrameStats;
#define MAX_FRAME_STATS 200
#define MAX_PERIOD_MS 1500
typedef struct {
double firstTime;
double lastTime;
double frameTime;
int firstFrame;
int numFrames;
FrameStats frames[ MAX_FRAME_STATS ];
} Stats;
static void
stats_init(Stats* s)
{
s->lastTime = now_ms();
s->firstTime = 0.;
s->firstFrame = 0;
s->numFrames = 0;
}
static void
stats_startFrame(Stats* s)
{
s->frameTime = now_ms();
}
static void
stats_endFrame(Stats* s)
{
double now = now_ms();
double renderTime = now - s->frameTime;
double frameTime = now - s->lastTime;
int nn;
if (now - s->firstTime >= MAX_PERIOD_MS) {
if (s->numFrames > 0) {
double minRender, maxRender, avgRender;
double minFrame, maxFrame, avgFrame;
int count;
nn = s->firstFrame;
minRender = maxRender = avgRender = s->frames[nn].renderTime;
minFrame = maxFrame = avgFrame = s->frames[nn].frameTime;
for (count = s->numFrames; count > 0; count--) {
nn += 1;
if (nn >= MAX_FRAME_STATS)
nn -= MAX_FRAME_STATS;
double render = s->frames[nn].renderTime;
if (render < minRender) minRender = render;
if (render > maxRender) maxRender = render;
double frame = s->frames[nn].frameTime;
if (frame < minFrame) minFrame = frame;
if (frame > maxFrame) maxFrame = frame;
avgRender += render;
avgFrame += frame;
}
avgRender /= s->numFrames;
avgFrame /= s->numFrames;
LOGI("frame/s (avg,min,max) = (%.1f,%.1f,%.1f) "
"render time ms (avg,min,max) = (%.1f,%.1f,%.1f)\n",
1000./avgFrame, 1000./maxFrame, 1000./minFrame,
avgRender, minRender, maxRender);
}
s->numFrames = 0;
s->firstFrame = 0;
s->firstTime = now;
}
nn = s->firstFrame + s->numFrames;
if (nn >= MAX_FRAME_STATS)
nn -= MAX_FRAME_STATS;
s->frames[nn].renderTime = renderTime;
s->frames[nn].frameTime = frameTime;
if (s->numFrames < MAX_FRAME_STATS) {
s->numFrames += 1;
} else {
s->firstFrame += 1;
if (s->firstFrame >= MAX_FRAME_STATS)
s->firstFrame -= MAX_FRAME_STATS;
}
s->lastTime = now;
}
// ----------------------------------------------------------------------
struct engine {
struct android_app* app;
Stats stats;
int animating;
};
void
Java_com_example_hellojni_HelloJni_myEngineDestroy(JNIEnv* env,
jobject thiz)
{
LOGI("Java_com_example_hellojni_HelloJni_myEngineDestroy");
cleanup_draw_buffer(env);
}
void
Java_com_example_hellojni_HelloJni_myEngineInit(JNIEnv* env,
jobject thiz, jobject jbitmap, int w, int h, int pf)
{
LOGI("Java_com_example_hellojni_HelloJni_myEngineInit");
init_draw_buffer(env, jbitmap, w, h);
}
jint
Java_com_example_hellojni_HelloJni_myEngineMouseInput(JNIEnv* env,
jobject thiz, int x, int y, int mt)
{
if(menuvisible)
// LOGI("Java_com_example_hellojni_HelloJni_myEngineMouseInput, x:%d y:%d mt:%d", x, y, mt);
return do_the_drawing_stuff(params_ommited); //drawing buffer is unsigned char *dest = draw_buffer.bits;
else
return 0;
}
を膨らま前述のように、バッファはdraw_buffer構造体にあります。
バッファ技法の通過を調べて、JNIインターフェイス経由でJAVAからCへのパスをトレースしてください。私は、変換なしでビットマップレンダリングの最終的な操作を行うように気をつけました。
私はベースとして例のいくつかの種類を取って、私はあなたが何ができるか:)
を得たことを新しいデバイス上で私の手を置くしたいとあなたは、一部を数え、そのフレームをOMMITでき介してバッファを渡すことですJNIをJavaに組み込み、そこからビットマップを作成します。 this pageを参照してください。次に、Canvas.setBitmapを使用してバッファに描画させることができます。
キャンバスに描画することは一度だけではありません。これは、タイマーのバックグラウンドスレッドから行われます。私はメモリをmallocするつもりはありません。メモリは代わりに私のプロセスにアドレスをマップし、レンダリングに使用します。別のプロセスでメモリマップを作成して、描画コードが変わってもバッファにアクセスできます。私は、JNIからBitmapオブジェクトで使用できるJavaへのバッファポインタをどのように渡すことができるのかよく分かりませんでした。 – videoguy
いくつかの例を教えてもらえますか? – videoguy
@ Ulterior..詳細な例をお忘れなく!私が探しているのは、Bitmapによって使用される内部バッファポインタを(mmap()の結果)ポインタに設定する方法です。 Bitmap_unlockPixels()は、私にとって役に立たないポインタを返します。私はまだJavaからレンダリングしたい。 – videoguy
私が探していた素晴らしい例です。ありがとう! – vitakot