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

常见坑与优化

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

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

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

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

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

一句话总结

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

相关推荐
!win !9 小时前
不定高元素动画实现方案(下)
前端·javascript·css
Song5592 天前
elpis框架抽离并发布 SDK-NPM 包
前端
Mintopia2 天前
低代码平台如何集成 AIGC 技术?核心技术衔接点解析
前端·javascript·aigc
Mintopia2 天前
Next.js + AI-SDK + DeepSeek:3 分钟建设属于你的 AI 问答 Demo
前端·javascript·next.js
anyup2 天前
历时 10 天+,速度提升 20 倍,新文档正式上线!uView Pro 开源组件库体验再升级!
前端·typescript·uni-app
沉默王二2 天前
金山还是小米,谁才是雷军的亲儿子?附小米线下一面面经(八股盛宴)
后端·面试
_AaronWong2 天前
仿 ElementPlus 的函数式弹窗调用
前端·element
用户21411832636022 天前
AI 当 “牛马”!免费云服务器 + 开源插件,7×24 小时写小说,一晚交出 70 章长篇
前端
橙序员小站2 天前
搞定系统设计题:如何设计一个订单系统?
java·后端·面试
IT_陈寒2 天前
React 18新特性全解析:这5个隐藏API让你的性能飙升200%!
前端·人工智能·后端