如何在CameraX 1.3-beta01中使用CameraEffect实现录像特效?
使用CameraX 1.3-beta01的CameraEffect实现录像特效
CameraX 1.3-beta01新增的CameraEffect类支持为录像添加基于OpenGL的特效,以下是具体实现步骤:
1. 自定义CameraEffect子类(核心逻辑)
你需要继承CameraEffect并指定TARGET_VIDEO_CAPTURE目标,然后在关键生命周期方法中管理OpenGL资源,在onDrawFrame中实现特效逻辑。以灰度滤镜为例:
class GrayScaleEffect : CameraEffect(TARGET_VIDEO_CAPTURE) { private var glProgram: Int = 0 private var positionHandle: Int = 0 private var textureHandle: Int = 0 override fun onAttach(context: Context, cameraInfo: CameraInfo) { // 初始化OpenGL着色器程序 val vertexShader = """ attribute vec4 aPosition; attribute vec2 aTextureCoord; varying vec2 vTextureCoord; void main() { gl_Position = aPosition; vTextureCoord = aTextureCoord; } """.trimIndent() val fragmentShader = """ precision mediump float; varying vec2 vTextureCoord; uniform sampler2D uTexture; void main() { vec4 color = texture2D(uTexture, vTextureCoord); float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); gl_FragColor = vec4(gray, gray, gray, color.a); } """.trimIndent() glProgram = createGlProgram(vertexShader, fragmentShader) positionHandle = GLES20.glGetAttribLocation(glProgram, "aPosition") textureHandle = GLES20.glGetUniformLocation(glProgram, "uTexture") } override fun onDetach(context: Context) { // 释放OpenGL资源,避免内存泄漏 GLES20.glDeleteProgram(glProgram) } override fun onDrawFrame(frame: Frame) { // 绑定输入纹理(CameraX传递的摄像头帧数据) GLES20.glActiveTexture(GLES20.GL_TEXTURE0) GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frame.texture) // 使用自定义着色器程序 GLES20.glUseProgram(glProgram) // 设置顶点坐标(CameraX提供默认的全屏顶点数组) GLES20.glEnableVertexAttribArray(positionHandle) GLES20.glVertexAttribPointer(positionHandle, 2, GLES20.GL_FLOAT, false, 0, frame.vertexArray) // 传递纹理采样器参数 GLES20.glUniform1i(textureHandle, 0) // 绘制处理后的帧 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4) // 解绑资源 GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0) GLES20.glDisableVertexAttribArray(positionHandle) } // 辅助方法:创建并链接OpenGL程序 private fun createGlProgram(vertexShader: String, fragmentShader: String): Int { val vertex = loadShader(GLES20.GL_VERTEX_SHADER, vertexShader) val fragment = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader) val program = GLES20.glCreateProgram() GLES20.glAttachShader(program, vertex) GLES20.glAttachShader(program, fragment) GLES20.glLinkProgram(program) // 可添加链接状态检查,排查程序创建失败问题 return program } // 辅助方法:加载并编译着色器 private fun loadShader(type: Int, shaderCode: String): Int { val shader = GLES20.glCreateShader(type) GLES20.glShaderSource(shader, shaderCode) GLES20.glCompileShader(shader) // 可添加编译状态检查,排查着色器语法错误 return shader } }
2. 将特效绑定到VideoCapture
创建VideoCapture实例后,通过VideoCapture.withEffects()方法将自定义特效绑定,再关联到CameraX的生命周期:
// 初始化默认VideoCapture实例 val videoCapture = VideoCapture.Builder.DEFAULT.build() // 实例化自定义特效 val grayScaleEffect = GrayScaleEffect() // 选择后置摄像头 val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA // 绑定生命周期与CameraX用例,添加特效 cameraProvider.bindToLifecycle( lifecycleOwner, cameraSelector, VideoCapture.withEffects(videoCapture, listOf(grayScaleEffect)) )
3. 关键注意事项
- 权限要求:必须申请
CAMERA和RECORD_AUDIO运行时权限,否则无法启动录像。 - OpenGL版本:
CameraEffect基于GLES 2.0,确保设备支持该版本(绝大多数现代Android设备都满足)。 - 性能优化:复杂的着色器逻辑可能降低录像帧率,建议在目标设备上测试,必要时简化Shader代码或使用硬件加速优化。
- Frame数据使用:
Frame类提供的texture(输入纹理ID)、vertexArray(顶点坐标)、textureCoordArray(纹理坐标)是处理帧的核心数据,无需自行生成。
内容的提问来源于stack exchange,提问作者Buntupana
相关产品推荐
相关产品推荐

