1. 程式人生 > >android jni 用c++使用opengles和egl實現離屏渲染

android jni 用c++使用opengles和egl實現離屏渲染

最近在做視訊有關的東西,用開源的ffmpeg解碼視訊,在通過opengl渲染出來,因為有使用到egl就試了試離屏渲染

EGLConfig eglConf;
EGLSurface eglSurface;
EGLContext eglCtx;
EGLDisplay eglDisp;

egl用到的就是這四個

先初始化

EGLint configSpec[] = { EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE };
EGLint surfaceAttr[] = {
        EGL_WIDTH
, width, EGL_HEIGHT, height, EGL_NONE }; eglDisp = eglGetDisplay(EGL_DEFAULT_DISPLAY); EGLint eglMajVers, eglMinVers; EGLint numConfigs; eglInitialize(eglDisp, &eglMajVers, &eglMinVers); eglChooseConfig(eglDisp, configSpec, &eglConf, 1, &numConfigs); eglSurface = eglCreatePbufferSurface(eglDisp
, eglConf, surfaceAttr); const EGLint ctxAttr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; eglCtx = eglCreateContext(eglDisp, eglConf,EGL_NO_CONTEXT, ctxAttr);

上邊的width和height是模擬視窗的寬高 最好和圖片的比例一致,不然轉成圖片會拉伸

eglMakeCurrent(eglDisp, eglSurface, eglSurface, eglCtx);

設定顯示的視窗,前一個視窗是顯示視窗,後一個是寫入視窗,通過呼叫這個來切換視窗

然後可以用opengl 進行畫圖了

畫完後呼叫一下

eglSwapBuffers(eglDisp, eglSurface);

把東西顯示在視窗上

最後加個釋放

eglMakeCurrent(eglDisp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroyContext(eglDisp, eglCtx);
eglDestroySurface(eglDisp, eglSurface);
eglTerminate(eglDisp);
eglDisp = EGL_NO_DISPLAY;
eglSurface = EGL_NO_SURFACE;
eglCtx = EGL_NO_CONTEXT;

試了試雙屏切換

glViewport(0, 0, w, h);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
eglSwapBuffers(eglDisp, eglSurface);
jclass jcl = env->GetObjectClass(ob);
jmethodID mid = env->GetMethodID(jcl, "getBitmap", "(II)V");
env->CallVoidMethod(ob, mid,w,h);

第一次是離屏渲染,渲染完成後呼叫java程式碼把圖片顯示出來

public void getBitmap(int width,int height){
    IntBuffer RGBABuffer = IntBuffer.allocate(width * height);
RGBABuffer.position(0);
GLES20.glReadPixels(0, 0, width, height,GLES20.GL_RGBA,GLES20.GL_UNSIGNED_BYTE,RGBABuffer);
    int[] pixls = RGBABuffer.array();
    for (int y = 0; y < height / 2; y++) {
        for (int x = 0; x < width; x++) {
            int pos1 = y * width + x;
            int pos2 = (height - 1 - y) * width + x;
            int tmp = pixls[pos1];
pixls[pos1] = (pixls[pos2] & 0xFF00FF00) | ((pixls[pos2] >> 16) & 0xff) | ((pixls[pos2] << 16) & 0x00ff0000); // ABGR->ARGB
pixls[pos2] = (tmp & 0xFF00FF00) | ((tmp >> 16) & 0xff) | ((tmp << 16) & 0x00ff0000);
}
    }
    if (height % 2 == 1) { // 中間一行
for (int x = 0; x < width; x++) {
            int pos = (height / 2 + 1) * width + x;
pixls[pos] = (pixls[pos] & 0xFF00FF00) | ((pixls[pos] >> 16) & 0xff) | ((pixls[pos] << 16) & 0x00ff0000);
}
    }
    final Bitmap modelBitmap = Bitmap.createBitmap(pixls, width, height, Bitmap.Config.ARGB_8888);
runOnUiThread(new Runnable() {
        @Override
public void run() {
            ImageView imageView = (ImageView) findViewById(R.id.iv_opengl);
imageView.setImageBitmap(modelBitmap);
}
    });
}

然後切換

eglMakeCurrent(eglDisp, eglWindow, eglSurface, eglCtx);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(left, top, viewWidth, viewHeight);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
eglSwapBuffers(eglDisp, eglWindow);

切換的時候要再先清屏在畫,不然兩個紋理會重疊