TextureView中的surfaceTexture的作用

它是什么

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(float16) 提供采样矩阵,修正裁剪、旋转、Y 翻转等。

常见坑与优化

  1. 尺寸不匹配:没设 setDefaultBufferSize 易导致缩放模糊和额外带宽。

  2. 生命周期泄漏:离开页面未 release(),相机/解码器还在往无主的 Surface 写。

  3. 高刷新/高分辨率卡顿:TextureView 路径多一道应用端合成,4K60/高刷新机型建议评估 SurfaceView。

  4. 频繁重建:切旋转/多窗口导致 SurfaceTexture 重建,注意恢复播放器输出面。

  5. 截图/滤镜:如果要二次处理帧,可在 onSurfaceTextureUpdated 后做轻量工作,重活放到独立渲染线程。

一句话总结

SurfaceTexture 是把 BufferQueue 的图像缓冲"变成一张可采样的外部纹理" 的关键组件;在 TextureView 中,它让视频/相机帧像普通 View 一样参与 UI 动画与合成,从而兼顾渲染灵活性与较低的复制开销。

相关推荐
IT_陈寒34 分钟前
Vite的这个问题坑了我三天,原来如此解决!
前端·人工智能·后端
网易云信35 分钟前
大模型能上岗做销售吗?我们让 12 款国产模型交了 420 份作业
前端·后端
蜗牛互联网1 小时前
Python Agent工具调用的白名单、参数校验与审批门禁
java·服务器·前端·人工智能·后端·python
计算机魔术师1 小时前
Perplexity:每个 Project 都是一个 Git 仓库
前端
Andrew5511 小时前
让 AI 写页面不再“一眼假”:我把设计品味做成了一个 Claude Code Skill 流水线
前端
乐享qicheng1 小时前
14-AI智能管家JSBridge深度问答
前端
10年前端老司机2 小时前
我用 Vue3 + LangGraph 做了个心理咨询 AI,踩了 9 个坑后总结出来的实战经验
前端·langchain·agent
数据掘金2 小时前
A/B 实验分组参数回滚后还在生效?一次参数校验体系的重构复盘
前端
bmxy小明同学2 小时前
2026-10-09-token与成本
java·前端·数据库
neoooo3 小时前
🚀Claude Code 小技巧(二):找回会话,撤销修改
前端·人工智能·后端