Android NDK圖形API篇

Android NDK圖形API篇
前言
我們知道,在遊戲和多媒體領域,圖形和圖像的處理速度和性能至關重要,在Java層處理圖形、圖像速度又比較慢,不能滿足實際的需要,這時候我們就可以藉助原生圖形API來讓自己的遊戲和多媒體應用表現更出色。

本篇重點介紹原生圖形API的相關知識,並通過一些示例,讓大家更好的掌握原生圖形API的相關知識。

原生圖形API
原生圖形API的種類
l  JNI圖形API也叫位圖API

l  Open GL ES API

l  原生Window API

JNI圖形API也叫位圖API
需要引用的頭文件
#include <android/bitmap.h>

需要引用的so庫
jnigraphics.so

JNI圖形API函數解析
獲取Bitmap對象信息
int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, AndroidBitmapInfo*info);

enum AndroidBitmapFormat {
    ANDROID_BITMAP_FORMAT_NONE      = 0,
    ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
    ANDROID_BITMAP_FORMAT_RGB_565   = 4,
    ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
    ANDROID_BITMAP_FORMAT_A_8       = 8,
};

typedef struct {
    uint32_t    width;
    uint32_t    height;
    uint32_t    stride;
    int32_t     format;
    uint32_t    flags;      // 0 for now
} AndroidBitmapInfo;
 

函數解析

env,指JNIEnv結構體指針

jbitmap,指android的Bitmap對象

info,指AndroidBitmapInfo結構體指針

如果函數調用成功,返回0,否則返回-1

示例代碼

AndroidBitmapInfo info;
int result=AndroidBitmap_getInfo(env,bitmap,&info);
鎖定Bitmap像素緩存
int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr);
函數解析

env,指JNIEnv結構體指針

jbitmap,指android的Bitmap對象

addrPtr,指指向jbitmap對象的像素數據指針

如果函數調用成功,返回0,否則返回-1

示例代碼

int32_t *buffer=0;
result=AndroidBitmap_lockPixels(env,bitmap,(void**)&buffer);

解鎖Bitmap像素緩存
int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
函數解析

env,指JNIEnv結構體指針

jbitmap,指android的Bitmap對象

如果函數調用成功,返回0,否則返回-1

示例代碼

AndroidBitmap_unlockPixels(env,bitmap);

JNI圖形API示例
extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_render(JNIEnv* env, jobject thiz,jobject bitmap,jobject bitmap2){
    int32_t *buffer=0;
    AndroidBitmapInfo info;
    int result=AndroidBitmap_getInfo(env,bitmap,&info);

    result=AndroidBitmap_lockPixels(env,bitmap,(void**)&buffer);

    int32_t *data=0;
   result=AndroidBitmap_lockPixels(env,bitmap2,(void**)&data);
    long len= sizeof(int)*info.width*info.height;
    //memcpy(buffer,data,len);
    memmove(buffer,data,len);
    AndroidBitmap_unlockPixels(env,bitmap2);
   AndroidBitmap_unlockPixels(env,bitmap);
}

其中bitmap是一個動態生成的bitmap,沒有位圖數據,bitmap2是一個真實的圖像bitmap,這個例子要做的就是把bitmap2的位圖數據複製到bitmap的位圖數據所指向的地址空間裏面。

Open GL ES API
需要引用的頭文件
Open GL ES 1.x頭文件

#include <GLES/gl.h>

#include <GLES/glext.h>

Open GL ES 2.x頭文件

#include <GLES2/gl2.h>

#include <GLES2/gl2ext.h>

需要引用的so庫
Open GL ES 1.x庫文件

GLESV1_CM.so

Open GL ES 2.x庫文件

GLESv2.so

GLSurfaceView
如果原生代碼需要使用Open GL ES的相關函數來進行view的渲染,在android端需要使用GLSurfaceView進顯示渲染後的內容

Open GL ES API函數解析
關於Open GL ES API,由於這個函數庫比較大,涉及的函數比較多,請大家參考專業的Open GL ES相關的書籍,這裏就不再介紹了。

Open GL ES API示例
請大家參考Open GL ES的相關書箱或者官方教程

原生Window API
需要引用的頭文件
#include <android/native_window.h>

#include<android/native_window_jni.h>

需要引用的so庫
android.so

原生Window API函數解析
從Surface對象中檢索原生Window
ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);

函數解析

env,指JNIEnv結構體的指針

suerface,指向android的Surface對象

如果函數調用成功,返回指向ANativeWindow的指針,否則返回NULL

獲取原生Window實例中的引用
void ANativeWindow_acquire(ANativeWindow* window);

函數解析

window,指通過ANativeWindow_fromSurface函數獲取的ANativeWindow指針

這個函數的功能就是防止引用的surface對象被刪除,獲取一個指向surface對象的引用

釋放原生Window實例中的引用
void ANativeWindow_release(ANativeWindow* window);

函數解析

window,指通過ANativeWindow_fromSurface函數獲取的ANativeWindow指針

這個函數的功能就是釋放通過ANativeWindow_acquire函數獲取的surface對象的引用

檢索原生Window的信息
獲取原生window的寬度
int32_t ANativeWindow_getWidth(ANativeWindow* window);

函數解析

window,指通過ANativeWindow_fromSurface函數獲取的ANativeWindow指針

如果調用成功,返回原生window的寬度,否則返回-1

獲取原生window的高度
int32_t ANativeWindow_getHeight(ANativeWindow* window);

函數解析

window,指通過ANativeWindow_fromSurface函數獲取的ANativeWindow指針

如果調用成功,返回原生window的高度,否則返回-1

獲取原生window的像素格式
int32_t ANativeWindow_getFormat(ANativeWindow* window);

函數解析

window,指通過ANativeWindow_fromSurface函數獲取的ANativeWindow指針

如果函數調用成功,返回原生window的像素格式,否則返回-1

設置原生window緩衝區的幾何形狀
int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
        int32_t width, int32_t height,int32_t format);

函數解析

window,指通過ANativeWindow_fromSurface函數獲取的ANativeWindow指針

width,設置原生window的寬度

height,設置原生window的高度

format,設置原生window的像素格式

如果函數調用成功,返回0,否則,返回-1

鎖定原生Window的緩衝區
typedef struct ANativeWindow_Buffer {
    // The number ofpixels that are show horizontally.
    int32_t width;

    // The number ofpixels that are shown vertically.
    int32_t height;

    // The number of*pixels* that a line in the buffer takes in
    // memory.  This may be >= width.
    int32_t stride;

    // The format of thebuffer.  One of WINDOW_FORMAT_*
    int32_t format;

    // The actual bits.
    void* bits;
    
    // Do not touch.
    uint32_t reserved[6];
} ANativeWindow_Buffer;

 

int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer*outBuffer,
        ARect* inOutDirtyBounds);

函數解析

window,指通過ANativeWindow_fromSurface函數獲取的ANativeWindow指針

outBuffer,指向ANativeWindow_Buffer結構體的指針,

inOutDirtyBounds,指向ARect結構體的指針,這個參數爲可選參數

如果函數調用成功,返回0,否則,返回-1

釋放原生Window的緩衝區
int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);

函數解析

window,指通過ANativeWindow_fromSurface函數獲取的ANativeWindow指針

如果函數調用成功,返回0,否則,返回-1

SurfaceView
在android層要想使用原生windowAPI,我們需要使用SurfaceView來和原生windowAPI配置,我們可以通過SurfaceView來獲取原生windowAPI需要的surface對象

原生Window API示例
extern "C"
JNIEXPORT void JNICALL
Java_com_kgdwbb_jnistudy_MainActivity_render2(JNIEnv* env, jobject thiz,jobject surface,jobject bitmap){
    AndroidBitmapInfo info;
   AndroidBitmap_getInfo(env,bitmap,&info);
    int dataLen= sizeof(int) * info.width *info.height;

    char *data=NULL;
    AndroidBitmap_lockPixels(env,bitmap,(void**)&data);
    AndroidBitmap_unlockPixels(env,bitmap);

    ANativeWindow *window=ANativeWindow_fromSurface(env,surface);
//    intwidth=ANativeWindow_getWidth(window);
//    intheight=ANativeWindow_getHeight(window);
//    intformat=ANativeWindow_getFormat(window);
//   ANativeWindow_setBuffersGeometry(window,width,height,format);

    ANativeWindow_acquire(window);

    ANativeWindow_BufferwindowBuffer;
   ANativeWindow_lock(window,&windowBuffer,NULL);

    dataLen= sizeof(int)*windowBuffer.width*windowBuffer.height;

    if (windowBuffer.bits != NULL) {
        //memcpy(windowBuffer.bits,data, dataLen);
        if (windowBuffer.width == windowBuffer.stride) {
            memcpy(windowBuffer.bits, data, dataLen);
        } else {
            int offset=windowBuffer.stride-windowBuffer.width;
            for (int ii=0; ii <windowBuffer.height*2; ii++) {
                char *srcPointer = data+ windowBuffer.width * ii*2;
                char *dstPointer = ((char *)windowBuffer.bits) + windowBuffer.stride * ii*2;

                memcpy(dstPointer,srcPointer, windowBuffer.stride*2);
            }
        }
    }

    ANativeWindow_release(window);

    ANativeWindow_unlockAndPost(window);
}

結束語
本篇介紹了android NDK三種原生圖形API,各有所長,大家可以根據需要來選用,對於最強大最複雜的Open GL ES的內容,本篇暫時不作深入介紹,有興趣的同學可以參考其它Open GL ES的專業書籍或教程來系統的學習。

Android NDK提供的這三種強大的圖形API,讓我們可以在遊戲和多媒體領域充分發揮我們所長,設計和開發中精美的作品。

本篇文章只是拋磚引玉,大家如果想在圖形圖像領域有所成就,僅僅學習本篇文章是遠遠不夠的。大家還需要在圖形圖像領域進行更深入的學習和研究。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章