它是什么
SurfaceTexture 是一个"消费者 + 纹理桥接器" :
-
作为 BufferQueue 的消费者 接收图像缓冲(GraphicBuffer);
-
把最新一帧绑定成 OpenGL ES 的外部纹理(GL_TEXTURE_EXTERNAL_OES),供 GPU 采样;
-
同时可以从它生成一个 Surface (new Surface(surfaceTexture)),给相机、解码器、OpenGL 等 生产者 往里写帧。
TextureView 里它的作用(数据流)
TextureView 内部自带一个 SurfaceTexture,用来把外部视频帧/相机帧"喂"给自己绘制:
scss
Producer (Camera/MediaCodec/GL/CPU)
│ 写入
▼
Surface ──► BufferQueue ──► SurfaceTexture(Consumer)
│ updateTexImage()
▼
外部纹理(OES)
│ getTransformMatrix()
▼
TextureView 在 GPU 上采样并合成到 View 树
-
Producer:拿到 Surface 后持续输出帧;
-
SurfaceTexture:收到新帧后触发回调,TextureView 在下次绘制时调用 updateTexImage() 把"最新帧"绑定到纹理;
-
TextureView:作为普通 View 参与 UI 合成(支持平移、旋转、缩放、alpha、圆角裁剪、动画等),把那张外部纹理画进自己的内容里。
你能怎么用
典型做法是监听 SurfaceTextureListener,在可用时把 Surface 交给相机或播放器:
kotlin
textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(st: SurfaceTexture, width: Int, height: Int) {
// 建议把默认缓冲区尺寸设为 View 尺寸,避免缩放模糊
st.setDefaultBufferSize(width, height)
val surface = Surface(st)
// 交给 MediaPlayer / ExoPlayer / Camera / MediaCodec 作为输出面
player.setSurface(surface)
player.playWhenReady = true
}
override fun onSurfaceTextureSizeChanged(st: SurfaceTexture, w: Int, h: Int) {
st.setDefaultBufferSize(w, h) // 跟随尺寸变化
}
override fun onSurfaceTextureDestroyed(st: SurfaceTexture): Boolean {
// 返回 true 表示我们自己释放;false 表示交给系统
player.setSurface(null)
st.release()
return true
}
override fun onSurfaceTextureUpdated(st: SurfaceTexture) {
// 每帧更新回调,可做轻量统计或截图
}
}
要点
-
setDefaultBufferSize(w, h):让生产的帧分辨率匹配 View 大小,避免 GPU 额外缩放引起的模糊/开销。
-
Surface 生命周期:停止输出后及时 release();切后台或旋转屏幕会重建。
-
如自行用 GLES 渲染到这个纹理:配合 attachToGLContext / detachFromGLContext、updateTexImage()、getTransformMatrix()。
和 SurfaceView 的区别(何时选谁)
维度 | TextureView (基于 SurfaceTexture) | SurfaceView |
---|---|---|
合成位置 | 应用进程内作为普通 View 参与 UI 合成 | 系统合成器(SurfaceFlinger)直接合成,独立表面 |
变换/裁剪 | 支持(旋转/缩放/alpha/圆角/动画) | 受限,不易做 View 级别动画/裁剪 |
延迟/性能 | 多一道应用端合成,灵活换较低延迟的代价 | 路径更直接,低延迟、高性能(大分辨率/高帧率更有优势) |
叠放关系 | 与其他 View 可正确叠放 | Z 顺序独立,容易"盖在最上/下",与 View 叠放受限 |
典型场景 | 需要和 UI 动画、圆角、裁剪融合的预览/视频 | 追求极致性能/低延迟/4K 高帧率播放、相机取景 |
同步与时序
-
fence 同步 :Producer 写完 → queueBuffer 给到 BufferQueue;TextureView 绘制前调用 updateTexImage() 会等待写入完成的 acquire fence,保证采样的是"已就绪帧"。
-
变换矩阵:getTransformMatrix(float[16]) 提供采样矩阵,修正裁剪、旋转、Y 翻转等。
常见坑与优化
-
尺寸不匹配:没设 setDefaultBufferSize 易导致缩放模糊和额外带宽。
-
生命周期泄漏:离开页面未 release(),相机/解码器还在往无主的 Surface 写。
-
高刷新/高分辨率卡顿:TextureView 路径多一道应用端合成,4K60/高刷新机型建议评估 SurfaceView。
-
频繁重建:切旋转/多窗口导致 SurfaceTexture 重建,注意恢复播放器输出面。
-
截图/滤镜:如果要二次处理帧,可在 onSurfaceTextureUpdated 后做轻量工作,重活放到独立渲染线程。
一句话总结
SurfaceTexture 是把 BufferQueue 的图像缓冲"变成一张可采样的外部纹理" 的关键组件;在 TextureView 中,它让视频/相机帧像普通 View 一样参与 UI 动画与合成,从而兼顾渲染灵活性与较低的复制开销。