前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何使用TextureView+OpenGL绘制相机预览

如何使用TextureView+OpenGL绘制相机预览

作者头像
雪月清
发布2020-06-23 16:16:22
2.7K0
发布2020-06-23 16:16:22
举报

使用Camera2 API实现相机预览样板代码太多了,偷一波懒,CV大法发动。。。

Google官方的Camera2BasicKotlin工程到手(该工程使用TextureView显示相机预览)

TextureView显示相机预览

Camera2启动相机预览需要三个步骤:

打开Camera--创建Session--启动预览

在创建Session的时候,传入的surface关联了textureView持有的SurfaceTexture:

val texture = mTextureView!!.surfaceTexture
// We configure the size of default buffer to be the size of camera preview we want.
texture!!.setDefaultBufferSize(mPreviewSize!!.width, mPreviewSize!!.height)
//This is the output Surface we need to start preview.
val surface = Surface(texture)
// Here, we create a CameraCaptureSession for camera preview.
mCameraDevice!!.createCaptureSession(Arrays.asList(surface, mImageReader!!.surface),
        object : CameraCaptureSession.StateCallback() {
              // ...
        }, null)

这样相机预览会不停的更新到这个surface上,最后显示到屏幕上(至于是如何显示到window上的,此处不细究

)

关联OpenGL

  1. 创建EGL环境,绑定输出到textureView持有的SurfaceTexture上;
  2. 创建Session的时候传递一个关联了OES纹理的surface,当预览数据更新时,将数据更新到纹理上;
  3. GL操作OES纹理,绘制到绑定的输出即可.

1. 创建EGl环境

EGL的创建参考GLSurfaceVIew内部定义的EglHelper类

// 1. Get an EGL instance.
mEgl = EGLContext.getEGL() as EGL10

// 2. Get to the default display
mEglDisplay = mEgl!!.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)

// 3. Initialize display
if (!mEgl!!.eglInitialize(mEglDisplay, version)) {
    throw RuntimeException("eglInitialize failed! " + mEgl!!.eglGetError())
}

// 4. Create an EGL context.
mEglContext = mEgl!!.eglCreateContext(mEglDisplay, mEglConfig[0], EGL10.EGL_NO_CONTEXT, contextAttributes)

// 5. Create an EGL surface we can render into.
mEglSurface = mEgl!!.eglCreateWindowSurface(mEglDisplay, mEglConfig[0], textureView.surfaceTexture, null)

// 6. Before we can issue GL commands, we need to make sure
//   the context is current and bound to a surface.
if (!mEgl!!.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
    throw RuntimeException("eglMakeCurrent failed! " + mEgl!!.eglGetError())
}

2. 配置Session

首先需要创建一个OES纹理,因为SurfaceTexture的构造需要它:

fun createOESTextureObject(): Int {
    val tex = IntArray(1)
    GLES20.glGenTextures(1, tex, 0)
    if (tex[0] == 0) {
        throw RuntimeException("create oes texture failed")
    }

    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex[0])
    GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 
              GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST.toFloat())
    GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 
              GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR.toFloat())
    GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
              GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE.toFloat())
    GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 
              GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE.toFloat())
    GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0)

    return tex[0]
}

然后构造Surface,并配置到Camera中:

val surfaceTexture = SurfaceTexture(oesId)
val surface = Surface(surfaceTexture)
mCameraDevice!!.createCaptureSession(...)

3. 绘制

当SurfaceTexture的onFrameAvailable回调,也就是有新的预览数据生成时,将图像数据更新到OES纹理上,然后使用GL采样纹理绘制即可

// Update image starem to texture
surfaceTexture!!.updateTexImage()

// Update matrix
surfaceTexture!!.getTransformMatrix(mTransformMatrix)

// draw
mEgl!!.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)
mCameraRender!!.drawTexture(mTransformMatrix, mOesTextureId)
mEgl!!.eglSwapBuffers(mEglDisplay, mEglSurface)

Demo

当TextureView引入GL环境后,我们就可以添加一些有趣的东西了,比如引入一个简单的粒子系统:

传送门:

https://github.com/sifutang/Camera2BasicKotlin.git

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 雪月清的随笔 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档