2014-11-02 120 views
0

我正在使用Java側直接nio緩衝區,它保存位圖中的像素數據並將其作爲gl紋理在NDK側使用。基本上我無法在c/C++ gl draw調用中正確讀取Java nio緩衝區像素。使用Java nio bytebuffer進行紋理圖像的Android NDK gl

似乎填充有關於Java側像素Java.ByteBuffer不與NDK側GL這需要無符號字節直接兼容(Java字節顯然是32位)

因此單個白色像素的Java側面:

int size = 1; 
ByteBuffer vv = ByteBuffer.allocateDirect(size_t*4); 
vv.order(ByteOrder.nativeOrder()); 
vv.put((byte)255); // R 
vv.put((byte)255); // G 
vv.put((byte)255); // B 
vv.put((byte)255); // A 
vv.position(0); 
... //code to send the buffer address to JNI/NDK gl side 
... // 

將在NDK側繪製爲黑色像素;

我意識到這個緩衝區的實際無符號字節值可能是負的 - 我該如何糾正。 另外 - 一旦我解決了這個問題,我需要轉換byte [],它是從Java端的位圖導出的圖像數據,用於NDK側紋理。

提前致謝!

+0

從您的本機代碼執行十六進制緩衝區轉儲以確保像素數據實際到達那裏。 – fadden 2014-11-03 16:12:20

回答

0

Java中的第一個「字節」是8位(有符號)而不是32位。 我不使用nio.ByteBufffer(雖然可以)。 byte []數組的工作更好,更簡單。

在AndroidBitmap.java

public class AndroidBitmap { 

    public static native void updateBitmap(android.graphics.Bitmap bitmap, byte[] data, int w, int h, int bpp); 

} 

在AndroidBitmap.c

jboolean Java_jni_AndroidBitmap_updateBitmap(JNIEnv* env, jobject that, jobject bitmap, jbyteArray data, jint w, jint h, jint bpp) { 

    jbyte* a = (*env)->GetByteArrayElements(env, data, NULL); 
    jsize bytes = (*env)->GetArrayLength(env, data); 

    AndroidBitmapInfo info = {0}; 
    int r = AndroidBitmap_getInfo(env, bitmap, &info); 
    if (r != 0) { 
     // … "AndroidBitmap_getInfo() failed ! error=%d", r 
     return false; 
    } 
    int width = info.width; 
    int height = info.height; 
    if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888 && info.format != ANDROID_BITMAP_FORMAT_A_8) { 
     // "Bitmap format is not RGBA_8888 or A_8" 
     return false; 
    } 
    int bytesPerPixel = info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ? 4 : 1; 
    void* pixels = null; 
    r = AndroidBitmap_lockPixels(env, bitmap, &pixels); 
    if (r != 0) { 
     // ..."AndroidBitmap_lockPixels() failed ! error=%d", r 
     return false; 
    } 
    if (w == width && h == height && bytesPerPixel == bpp) { 
     memcpy(pixels, a, width * height * bytesPerPixel); 
    } else if (bytesPerPixel == 4 && bpp == 1) { 
     grayscaleToRGBA(pixels, &info, data, w, h); 
    } else { 
     assertion(bytesPerPixel == 4 && bpp == 1, "only grayscale -> RGBA is supported bytesPerPixel=%d bpp=%d", bytesPerPixel, bpp); 
    } 
    AndroidBitmap_unlockPixels(env, bitmap); 
    (*env)->ReleaseByteArrayElements(env, data, a, 0); 
    return true; 
} 

希望這有助於。

+0

感謝您在Java中對8位和32位字節的說明。如果我跟蹤我提供的樣本 - 所有值都是-1。我確實需要傳遞nio緩衝區的內存地址,而不是實際的像素。該緩衝區在java上更新,我需要NDK端直接訪問它。我正在使用相同的機制來非常快速地從Java端(float,int等)共享數據,但不是字節圖像數據。 – narkis 2014-11-02 23:29:05

+0

byte [],ByteBuffer和直接ByteBuffer的性能特徵可能不同。請參閱http://developer.android.com/training/articles/perf-jni.html#faq_sharing – fadden 2014-11-03 16:14:06

+0

1.在現實生活中,字節[]永遠不會被VM複製。 Android上的nio.ByteBuffer.put()相對於[i] = v而言非常昂貴; (可以通過批量操作來減輕) 2.在實際項目中,我甚至沒有封送byte []數組。我在jni端返回地址做了malloc(),返回地址爲64位java長,並且具有memset,memget,memcpy jni ops來處理暴露給java端的數據。由malloc()分配的內存保證保持原位(不會被GC移動)並且可以快速訪問。您還可以在進程之間共享該內存。 3.我最近的測量顯示,Java調用比C調用貴15倍 – Leo 2014-11-04 21:00:47