摘要:二、现在我们有了frameBuffer和frameBufferTexture,接下来我们把Camera SurfaceTexture FBO中的数据绘制到这个frameBuffer中。从数据流方向来看,Camer SurfaceTexture从Camera中读取数据缓存到自己的FBO中,然后离屏FBO通过Camer SurfaceTexture的ID读取Camera FBO中的数据缓存到自己的内存中,在这里可以对这个FBO做各种处理,最后TextureView从离屏FBO的ID读取缓存的数据绘制到屏幕上。

封面出自: 板栗懒得很

 本章仅对部分代码进行讲解,以帮助读者更好的理解章节内容。本系列文章涉及的项目HardwareVideoCodec已经开源到Github,支持软编和硬编。使用它你可以很容易的实现任何分辨率的视频编码,无需关心摄像头预览大小。一切都如此简单。目前已迭代多个稳定版本,欢迎查阅学习和使用,如有BUG或建议,欢迎Issue。

  在第二章中,我们通过一个Camera SurfaceTexture纹理,把摄像头数据绘制到这个纹理上,同时TextureView的SurfaceTexture纹理通过id与第一个纹理关联起来,从而把摄像头画面直接绘制到屏幕上。

  对OpenGL有一定了解的人可能会知道,要使用OpenGL渲染各种好看的特效,FBO必不可少。通过FBO,我们可以先把摄像头数据绘制到Camera SurfaceTexture纹理上,然后把这个纹理数据再绘制到一个离屏的FBO,我们可以在这个FBO上做各种特效处理,处理完之后再把离屏FBO中的数据绘制到TextureView的SurfaceTexture纹理,也就是手机屏幕上。

滤镜绘制流程,从上图中我们不难看出:

  1. 两端的纹理都包含EGL环境,只有中间FBO没有,因为FBO只是作为缓存的作用,不跟任何设备有关联。

  2. 其实Camer SurfaceTexture也需要一个FBO,因为需要把摄像头数据缓存到这个FBO,那为什么TextureView却不需要呢,因为广义上来说,屏幕的缓存就是它的FBO。

  3. 从数据流方向来看,Camer SurfaceTexture从Camera中读取数据缓存到自己的FBO中,然后离屏FBO通过Camer SurfaceTexture的ID读取Camera FBO中的数据缓存到自己的内存中,在这里可以对这个FBO做各种处理,最后TextureView从离屏FBO的ID读取缓存的数据绘制到屏幕上。

 在前两章的基础上,我们已经有了Camera SurfaceTexture和TextureView SurfaceTexture,现在我们需要再加入一层离屏FBO。

一、向OpenGL申请FBO,frameBuffer和frameBufferTexture:

  1. frameBuffer指向OpenGL的一块内存。

  2. frameBufferTexture可以把frameBuffer中的数据作为一个纹理绑定到OpenGL。

open fun initFrameBuffer() {

val frameBuffer = IntArray(1)

val frameBufferTex = IntArray(1)

GLES20.glGenFramebuffers(1, frameBuffer, 0)

GLES20.glGenTextures(1, frameBufferTex, 0)

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameBufferTex[0])

GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null)

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,

GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR.toFloat())

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,

GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR.toFloat())

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,

GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE.toFloat())

GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,

GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE.toFloat())

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer[0])

GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, frameBufferTex[0], 0)

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0)

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0)

val error = GLES20.glGetError()

if (error != GLES20.GL_NO_ERROR) {

val msg = "initFrameBuffer: glError 0x" + Integer.toHexString(error)

debug_e(msg)

return

}

//FBO,通过这个往FBO内存中写入数据

frameBuffer = frameBuffer[0]

//FBO ID,通过这个从FBO的内存中读取数据

frameBufferTexture = frameBufferTex[0]

}

二、现在我们有了frameBuffer和frameBufferTexture,接下来我们把Camera SurfaceTexture FBO中的数据绘制到这个frameBuffer中。

private fun drawCamera() {

if (null != cameraWrapper.surfaceTexture) {

cameraSurfaceTexture?.updateTexImage()

cameraSurfaceTexture?.getTransformMatrix(transformMatrix)

}

cameraEgl?.makeCurrent()

GLES20.glViewport(0, 0, cameraPreviewHeight, cameraPreviewWidth)

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)

GLES20.glClearColor(0.3f, 0.3f, 0.3f, 0f)


GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer!!)

GLES20.glUseProgram(shaderProgram!!)

GLES20.glActiveTexture(GLES20.GL_TEXTURE0)

GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, cameraSurfaceTextureId)

GLES20.glUniform1i(uTextureLocation, 0)

enableVertex(aPositionLocation, aTextureCoordinateLocation, buffer!!, verticesBuffer!!)

GLES20.glUniformMatrix4fv(uTextureMatrix, 1, false, transformMatrix, 0)


drawer.draw()


GLES20.glFinish()

GLES20.glDisableVertexAttribArray(aPositionLocation)

GLES20.glDisableVertexAttribArray(aTextureCoordinateLocation)

GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_NONE)

GLES20.glUseProgram(GLES20.GL_NONE)

GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_NONE)

}

三、现在frameBuffer中已经有了数据,在这里可以运用OpenGL对数据进行处理,这里以简单的GreyFilter为例,这里就不贴具体代码了。

private fun drawFilter() {

synchronized(filterLock) {

if (null == filter) return

GLES20.glViewport(0, 0, parameter.video.width, parameter.video.height)

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)

filter?.drawTexture(null)

}

}

四、最后通过frameBufferTexture把数据绘制到屏幕。

fun drawScreen(){

screenWrapper?.egl?.makeCurrent()

//根据需要对画面进行裁剪

GLES20.glViewport(viewportX, viewportY, width, height)

GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)

GLES20.glClearColor(0.3f, 0.3f, 0.3f, 0f)

screenWrapper?.drawTexture(transformMatrix)

screenWrapper?.egl?.swapBuffers()

}

  以上就是本章关于OpenGL为Camera添加各种滤镜的所有内容,至于如何编写OpenGL Shape实现各种滤镜,由于内容比较多,以后有机会单独另开章节详细介绍。

本章知识点:

  1. FBO的使用。

  2. OpenGL纹理绘制的基本流程。

本章相关源码·HardwareVideoCodec项目:

  • DefaultRenderImpl

  • CameraTextureWrapper

  • GreyFilter

  • ScreenTextureWrappe

相关阅读:

如果你想要跟大家分享你的文章

欢迎投稿

相关文章