Android播放器之SurfaceView与GLSurfaceView

本文详细介绍了Android中SurfaceView和GLSurfaceView的工作原理及使用方法,对比了两者之间的区别,包括它们如何用于屏幕绘制、OpenGL渲染以及各自的特点。

先看Surface

Surface的官方介绍:Handle onto a raw buffer that is being managed by the screen compositor,Surface是一个raw buffer的句柄,通过它在raw buffer上进行绘制,可以通过Surface获得一个Canvas。

Canvas canvas = mSurface.lockCanvas(null);
mSurface.unlockCanvasAndPost(canvas);

SurfaceView

SurfaceView对Surface进行了一次封装,它内部帮我们管理了一个Surface。我们使用SurfaceView其实最终都是获取到这个Surface去绘制,可参看官方解释:

Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen

The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it. This can be used to place overlays such as buttons on top of the Surface, though note however that it can have an impact on performance since a full alpha-blended composite will be performed each time the Surface changes.

The transparent region that makes the surface visible is based on the layout positions in the view hierarchy. If the post-layout transform properties are used to draw a sibling view on top of the SurfaceView, the view may not be properly composited with the surface.

Access to the underlying surface is provided via the SurfaceHolder interface, which can be retrieved by calling getHolder().

The Surface will be created for you while the SurfaceView's window is visible; you should implement SurfaceHolder.Callback#surfaceCreated and SurfaceHolder.Callback#surfaceDestroyed to discover when the Surface is created and destroyed as the window is shown and hidden.

One of the purposes of this class is to provide a surface in which a secondary thread can render into the screen. If you are going to use it this way, you need to be aware of some threading semantics:

绘制过程:

  • 通过SurfaceHolder.getSurface可以获取到Surface;
  • 通过Surface.lockCanvas可以获取到Surface的Canvas;
  • 使用Canvas绘制图像;
  • 使用Surface.unlockCanvasAndPost可以释放Canvas。

GLSurfaceView

GLSurfaceView继承自SurfaceView,对SurfaceView又做了一次封装,方便我们在安卓中使用OpenGL。

GLSurfaceView提供了以下特性:

  • 提供并且管理一个独立的Surface;
  • 提供并且管理一个EGL display,它能让opengl把内容渲染到上述的Surface上;
  • 支持用户自定义渲染器(Render),通过setRenderer设置一个自定义的Renderer;
  • 让渲染器在独立的GLThread线程里运作,和UI线程分离;
  • 支持按需渲染(on-demand)和连续渲染(continuous)两种模式;
  • GPU加速:GLSurfaceView的效率是SurfaceView的30倍以上,SurfaceView使用画布进行绘制,GLSurfaceView利用GPU加速提高了绘制效率;
  • View的绘制onDraw(Canvas canvas)使用Skia渲染引擎渲染,而GLSurfaceView的渲染器Renderer的onDrawFrame(GL10 gl)使用opengl绘制引擎进行渲染。

参看官方解释:

An implementation of SurfaceView that uses the dedicated surface for displaying OpenGL rendering.

A GLSurfaceView provides the following features:

  • Manages a surface, which is a special piece of memory that can be composited into the Android view system.
  • Manages an EGL display, which enables OpenGL to render into a surface.
  • Accepts a user-provided Renderer object that does the actual rendering.
  • Renders on a dedicated thread to decouple rendering performance from the UI thread.
  • Supports both on-demand and continuous rendering.
  • Optionally wraps, traces, and/or error-checks the renderer's OpenGL calls.

总结

除了上述区别外,SurfaceView通用性更好,GLSurfaceView渲染更细腻,如果想让普通的SurfaceView渲染效果更好,可以加抗锯齿效果,不过抗锯齿效果会有一定的性能消耗,硬解码设置surface模式的话,直接用普通的SurfaceView。

一般兼容性比较好的播放器,会同时支持SurfaceView和GLSurfaceView两种模式供用户根据实际场景选择,以大牛直播SDK(Github)的Android平台RTSP和RTMP播放端为例:

    /* Create rendering */
    private boolean CreateView() {

        if (sSurfaceView == null) {

            Log.i(TAG, "CreateView..");

            String manufacturer = Build.MANUFACTURER;
            Log.i(TAG, "CreateView, current manufacturer: " + manufacturer);

            if (is_enable_hardware_render_mode) {
                //hardware render模式,第二个参数设置为false
                sSurfaceView = NTRenderer.CreateRenderer(this, false);
            } else {
                //这个字符串可以自己定义,例如判断华为就填写huawei,魅族就填写meizu
                if ("huawei".equalsIgnoreCase(manufacturer)) {
                    sSurfaceView = NTRenderer.CreateRenderer(this, true);
                } else {
                    /*
                     * useOpenGLES2: If with true: Check if system supports openGLES, if
                     * supported, it will choose openGLES. If with false: it will set
                     * with default surfaceView;
                     */
                    sSurfaceView = NTRenderer.CreateRenderer(this, true);
                }
            }
        }

        if (sSurfaceView == null) {
            Log.i(TAG, "Create render failed..");
            return false;
        }

        if (is_enable_hardware_render_mode) {
            SurfaceHolder surfaceHolder = sSurfaceView.getHolder();
            if (surfaceHolder == null) {
                Log.e(TAG, "CreateView, surfaceHolder with null..");
            }
            surfaceHolder.addCallback(this);
        }

        return true;
    }

感兴趣的开发者可以参考官方文档。

<think> 我们正在详细比较TextureView、SurfaceViewGLSurfaceView。根据用户提供的引用和之前的对话历史,我们可以总结如下: 1. **继承关系**: - View:所有UI组件的基类。 - SurfaceView:继承自View,但拥有独立的绘制表面(Surface),在独立线程中绘制。 - GLSurfaceView:继承自SurfaceView,专门为OpenGL ES渲染设计,内置了OpenGL ES的上下文管理。 - TextureView:继承自View,没有独立的Surface,而是通过SurfaceTexture将图像流转换为OpenGL纹理,然后作为普通View进行合成。 2. **核心差异**: - **SurfaceView**: - 拥有独立的Surface,由SurfaceFlinger直接合成到屏幕上,不参View树的普通绘制流程。 - 优点:性能高,延迟低,适合高频刷新(如视频播放、相机预览)。 - 缺点:在7.0以下版本,进行缩放、旋转等变换时可能出现黑边;不能很好地支持View的动画(因为独立于View层级)。 - **TextureView**: - 使用主窗口的Surface,通过SurfaceTexture将图像流转换为OpenGL纹理,然后作为普通View进行绘制。 - 优点:可以像普通View一样进行变换(旋转、缩放、平移)和动画,且不会出现黑边。 - 缺点:需要额外的纹理转换,导致延迟增加(通常多1-3帧),内存消耗较高,且强制要求硬件加速。 - **GLSurfaceView**: - 是SurfaceView的子类,专门用于OpenGL ES渲染。 - 优点:提供了OpenGL ES的上下文管理,简化了OpenGL的使用,适合3D图形和复杂特效。 - 缺点:由于使用OpenGL,需要处理OpenGL特有的问题(如上下文丢失等)。 3. **使用场景**: - **SurfaceView**:适用于对性能要求高、需要独立线程绘制的场景,如游戏、视频播放、相机预览(高帧率)。 - **TextureView**:适用于需要普通View混合、需要动画效果的场景,如动态滤镜、小窗播放等。 - **GLSurfaceView**:适用于需要OpenGL渲染的场景,如3D游戏、复杂特效、图像处理(如滤镜)。 4. **技术细节**: - **SurfaceView**:通过`SurfaceHolder`获取Surface,可以在非UI线程绘制。 - **TextureView**:通过`SurfaceTextureListener`监听SurfaceTexture的准备状态,然后通过`SurfaceTexture`获取Surface进行绘制,最后作为纹理在View的draw过程中合成。 - **GLSurfaceView**:通过`GLSurfaceView.Renderer`接口,在独立线程中进行OpenGL渲染。 5. **系统版本的影响**: - Android 7.0+:SurfaceView引入了同步Surface生命周期(`SURFACE_LIFECYCLE_SYNCHRONIZED`),解决了变换时的黑边问题,性能进一步提升。 - Android 5.0+:TextureView的渲染可以在渲染线程进行,降低了主线程压力。 根据以上分析,我们可以整理成表格形式,并给出详细说明。 注意:由于用户要求使用LaTeX格式的数学公式,虽然本问题不涉及数学公式,但我们在适当的地方(如性能指标)可以使用LaTeX来表示一些数值关系。另外,需要生成相关问题。 下面开始组织回答。 </think>### TextureView、SurfaceView GLSurfaceView 区别详解 以下是三者在渲染机制、性能特性和适用场景的核心对比: --- #### **1. 核心继承关系** ```mermaid graph TD A[View] --> B[SurfaceView] B --> C[GLSurfaceView] A --> D[TextureView] ``` - **View**:所有 UI 组件的基类,主线程绘制 - **SurfaceView**:**独立绘制线程**,直接访问硬件层(SurfaceFlinger 合成) - **GLSurfaceView**:SurfaceView 子类,**内置 OpenGL ES 渲染管线** - **TextureView**:基于 **SurfaceTexture 的纹理渲染**,参 View 层级合成[^4] --- #### **2. 核心特性对比** | **特性** | SurfaceView | GLSurfaceView | TextureView | |----------------------|------------------------------|-----------------------------|------------------------------| | **渲染线程** | 自定义线程 | 专用 OpenGL 线程 | 主线程或渲染线程 | | **内存开销** | 低 (直接显存) | 中 (GPU 资源) | 高 (纹理缓冲 + GPU 内存) | | **延迟** | ≤1帧 | 1-2帧 | 2-3帧 | | **动画支持** | ❌ 无变形动画 | ✅ 3D 变形 | ✅ 2D 变形 (缩放/旋转) | | **图层合成** | 系统级叠加 (SurfaceFlinger) | 系统级叠加 + OpenGL | View 层级 GPU 合成 | | **适用帧率** | >60 FPS | 30-60 FPS | <30 FPS | > **性能公式** > 纹理转换延迟:$$ \Delta t_{\text{texture}} = t_{\text{copy}} + t_{\text{GPU}} $$ > 其中 $t_{\text{copy}}$ 为内存拷贝耗时,$t_{\text{GPU}}$ 为纹理处理耗时[^1] --- #### **3. 技术原理差异** 1. **SurfaceView** - 通过 `SurfaceHolder` 获取独立 Surface - 像素数据直接推送至硬件合成器 - **优势**:零拷贝传输,适用于高帧率场景 ```java surfaceHolder.lockCanvas(); // 获取画布 // 绘制操作... surfaceHolder.unlockCanvasAndPost(canvas); // 提交帧 ``` 2. **GLSurfaceView** - 扩展 `SurfaceView` 的 OpenGL 实现 - 自动管理 EGL 上下文和渲染线程 - **核心接口**:`GLSurfaceView.Renderer` ```java public class MyRenderer implements GLSurfaceView.Renderer { @Override public void onDrawFrame(GL10 gl) { gl.glClear(GL10.GL_COLOR_BUFFER_BIT); // OpenGL 绘制 } } ``` 3. **TextureView** - 通过 `SurfaceTexture` 将图像流转为 OpenGL 纹理 - 作为普通 View 参合成 ```java textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int w, int h) { // 纹理就绪后获取Surface Surface texSurface = new Surface(surface); } }); ``` --- #### **4. 适用场景推荐** | **场景** | 推荐方案 | 原因 | |-------------------------|-------------------|----------------------------------------------------------------------| | 游戏渲染 (>60fps) | ✅ SurfaceView | 独立线程避免卡顿,直接硬件合成 | | 3D模型/AR渲染 | ✅ GLSurfaceView | 原生OpenGL支持,复杂光照处理 | | 视频编辑 (滤镜+变形) | ✅ TextureView | 完美支持GPU滤镜链和2D变形 | | 相机预览 (高帧率) | ✅ SurfaceView | 低延迟确保实时性 (Android Camera2 默认方案) | | 动态UI叠加 (弹幕/贴纸) | ✅ TextureView | 普通View层级混合 | --- #### **5. 典型问题优化** 1. **SurfaceView 黑边问题** (Android 7.0以下) ```java // 启用同步生命周期 (API 24+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { surfaceView.setSurfaceLifecycle(SurfaceView.SURFACE_LIFECYCLE_SYNCHRONIZED); } ``` 2. **TextureView 内存泄漏预防** ```java @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { surface.release(); // 手动释放纹理资源 return true; } ``` 3. **GLSurfaceView 渲染线程阻塞** ```java glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); // 避免onDemand模式卡顿 ``` > **设计哲学差异**: > - SurfaceView/GLSurfaceView:**优先性能**(牺牲动画灵活性) > - TextureView:**优先兼容性**(牺牲渲染效率)[^2] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值