android jni 用c++使用opengles和egl實現離屏渲染
阿新 • • 發佈:2019-01-03
最近在做視訊有關的東西,用開源的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);
切換的時候要再先清屏在畫,不然兩個紋理會重疊