使用Camera2 API实现相机预览样板代码太多了,偷一波懒,CV大法发动。。。
Google官方的Camera2BasicKotlin工程到手(该工程使用TextureView显示相机预览)
TextureView显示相机预览
Camera2启动相机预览需要三个步骤:
打开Camera--创建Session--启动预览
在创建Session的时候,传入的surface关联了textureView持有的SurfaceTexture:
代码语言:javascript复制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
- 创建EGL环境,绑定输出到textureView持有的SurfaceTexture上;
- 创建Session的时候传递一个关联了OES纹理的surface,当预览数据更新时,将数据更新到纹理上;
- GL操作OES纹理,绘制到绑定的输出即可.
1. 创建EGl环境
EGL的创建参考GLSurfaceVIew内部定义的EglHelper类
代码语言:javascript复制// 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的构造需要它:
代码语言:javascript复制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中:
代码语言:javascript复制val surfaceTexture = SurfaceTexture(oesId)
val surface = Surface(surfaceTexture)
mCameraDevice!!.createCaptureSession(...)
3. 绘制
当SurfaceTexture的onFrameAvailable回调,也就是有新的预览数据生成时,将图像数据更新到OES纹理上,然后使用GL采样纹理绘制即可
代码语言:javascript复制// 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