Android中的ANativeWindow


ANativeWindow是什么

ANativeWindow是C/C++中定义的一个结构体,等同于Java中的Surface.

Android NDK中可以访问到ANativeWindow.

ANativeWindow中存放像素信息的结构是:ANativeWindow_Buffer:

typedef struct ANativeWindow_Buffer {
    /// The number of pixels that are shown horizontally.
    int32_t width;

    /// The number of pixels 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 the buffer. One of AHardwareBuffer_Format.
    int32_t format;

    /// The actual bits.
    void* bits;

    /// Do not touch.
    uint32_t reserved[6];
} ANativeWindow_Buffer;

主要API

  • 获取与surface对应的ANativeWindow

    ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
  • 保持/释放ANativeWindow对象的引用

    void ANativeWindow_acquire(ANativeWindow* window);
    
    void ANativeWindow_release(ANativeWindow* window);
  • 向buffer中写入数据并提交

    int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
            ARect* inOutDirtyBounds);
    
    // 这之间的代码可以执行一些向buffer中写入数据的操作
    
    int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
  • 获取Window Surface的信息:宽/高/像素格式

    int32_t ANativeWindow_getWidth(ANativeWindow* window);
    
    int32_t ANativeWindow_getHeight(ANativeWindow* window);
    
    int32_t ANativeWindow_getFormat(ANativeWindow* window);

    像素格式定义在AHARDWAREBUFFER_FORMAT_*

  • 改变Window Buffer的格式和大小

    int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
            int32_t width, int32_t height, int32_t format);

一般的流程

  1. 通过ANativeWindow_fromSurface获取与Surface对应的ANativeWindow对象
  2. ANativeWindow_setBuffersGeometry设置buffer的尺寸和格式
  3. ANativeWindow_acquire获取引用对象
  4. 利用ANativeWindow_lock/ANativeWindow_unlockAndPost与之间的绘制代码绘制图像
  5. ANativeWindow_release释放引用.

一个简单的例子

写个简单的例子:利用ANativeWindow绘制一个灰色的背景.

  • C++代码

    #include <jni.h>
    #include <string>
    #include <android/native_window.h>
    #include <android/native_window_jni.h>
    
    void drawColor(JNIEnv *env,jobject obj,jobject surface, jint colorARGB) {
        int alpha = colorARGB >> 24 & 0xFF;
        int red = colorARGB >> 16 & 0xFF;
        int green = colorARGB >> 8 & 0xFF;
        int blue = colorARGB & 0xFF;
    
        int colorABGR = alpha << 24 | (blue << 16) | (green << 8) | red;
    
        ANativeWindow *window = ANativeWindow_fromSurface(env,surface);
    
        int32_t result = ANativeWindow_setBuffersGeometry(window,640,640,AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
        if (result < 0){
            ANativeWindow_release(window);
            window = nullptr;
            return;
        }
        ANativeWindow_acquire(window);
        ANativeWindow_Buffer buffer;
        if (ANativeWindow_lock(window,&buffer, nullptr) < 0){
            ANativeWindow_release(window);
            window = nullptr;
            return;
        }
    
        auto *line = (uint32_t *) buffer.bits;
        for (int y = 0; y < buffer.height; ++y) {
            for (int x = 0; x < buffer.width; ++x) {
                line[x] = colorABGR;
            }
            line += buffer.stride;
        }
    
        if (ANativeWindow_unlockAndPost(window) < 0){
            return;
        }
    
        ANativeWindow_release(window);
    }
    
    extern "C"
    JNIEXPORT void JNICALL
    Java_com_jiangkang_androiddemos_MainActivity_drawColor(JNIEnv *env, jobject thiz, jobject surface,
                                                           jint color) {
        drawColor(env,thiz,surface,color);
    }
  • Activity代码

    import android.graphics.Color
    import android.os.Bundle
    import android.view.Surface
    import android.view.SurfaceHolder
    import androidx.appcompat.app.AppCompatActivity
    import kotlinx.android.synthetic.main.activity_main.*
    
    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            surface_view.holder.addCallback(object : SurfaceHolder.Callback2 {
                override fun surfaceRedrawNeeded(holder: SurfaceHolder?) {
                }
    
                override fun surfaceChanged(
                    holder: SurfaceHolder?,
                    format: Int,
                    width: Int,
                    height: Int
                ) {
                }
    
                override fun surfaceDestroyed(holder: SurfaceHolder?) {
                }
    
                override fun surfaceCreated(holder: SurfaceHolder?) {
                    holder?.let {
                        drawColor(it.surface, Color.GRAY)
                    }
                }
            })
        }
    
        external fun drawColor(surface: Surface, color: Int)
    
        companion object {
            init {
                System.loadLibrary("native-lib")
            }
        }
    }
    

总结

  1. Native层中的ANativeWindow对应Java层中的Surface,因此可以利用SurfaceView + ANativeWindow,用C++代码绘制屏幕;
  2. 在图像/视频处理中会利用到ANativeWindow,也可以与EGL,FFMPEG等结合使用
  3. Flutter Engine中正是通过 ANativeWindow才将Dart中的UI与Android中UI联系到一起的.

文章作者: 姜康
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 姜康 !
评论
  目录