美文网首页待学习
架构7--SurfaceTexture

架构7--SurfaceTexture

作者: uin_sisyphus | 来源:发表于2017-11-03 17:33 被阅读0次

转自:https://source.android.com/devices/graphics/?hl=zh-cn

SurfaceTexture

SurfaceTexture 类是在 Android 3.0 中推出的。就像 SurfaceView 是 Surface 和 View 的组合一样,SurfaceTexture 是 Surface 和 GLES 纹理的粗略组合(包含几个注意事项)。

当您创建 SurfaceTexture 时,会创建一个应用是其消耗方的 BufferQueue。如果生产方将新的缓冲区加入队列,您的应用便会通过回调 (onFrameAvailable()) 获得通知。应用调用updateTexImage()(这会释放先前保留的缓冲区),从队列中获取新的缓冲区,然后发出一些 EGL 调用,让缓冲区可作为外部纹理供 GLES 使用。

外部纹理

外部纹理 (GL_TEXTURE_EXTERNAL_OES) 与 GLES (GL_TEXTURE_2D) 创建的纹理并不完全相同:您对渲染器的配置必须有所不同,而且有一些操作是不能对外部纹理执行的。关键是,您可以直接从 BufferQueue 接收到的数据中渲染纹理多边形。gralloc 支持各种格式,因此我们需要保证缓冲区中数据的格式是 GLES 可以识别的格式。为此,当 SurfaceTexture 创建 BufferQueue 时,它将消耗方用法标记设置为GRALLOC_USAGE_HW_TEXTURE,确保由 gralloc 创建的缓冲区均可供 GLES 使用。

由于 SurfaceTexture 会与 EGL 上下文交互,因此您必须小心地从正确的会话中调用其方法(详见类文档)。

时间戳和转换

如果您深入阅读类文档,您会看到两个奇怪的调用。一个调用会检索时间戳,而另一个调用是转换矩阵,每个调用的值都通过事先调用updateTexImage()来设置。事实证明,BufferQueue 不只是向消耗方传递缓冲区句柄。每个缓冲区都附有时间戳和转换参数。

提供转换是为了提高效率。在某些情况下,源数据可能以错误的方向传递给消耗方;但是,我们可以按照数据的当前方向发送数据并使用转换对其进行更正,而不是在发送数据之前对其进行旋转。在使用数据时,转换矩阵可以与其他转换合并,从而最大限度降低开销。

时间戳对于某些缓冲区来源非常有用。例如,假设您将生产方接口连接到相机的输出端(使用setPreviewTexture())。要创建视频,您需要为每个帧设置演示时间戳;不过您需要根据截取帧的时间(而不是应用收到缓冲区的时间)来设置该时间戳。随缓冲区提供的时间戳由相机代码设置,从而获得一系列更一致的时间戳。

SurfaceTexture 和 Surface

如果仔细观察 API,您会发现应用只能通过一种方式来创建简单 Surface,即通过将 SurfaceTexture 作为唯一参数的构造函数来创建。(在 API 11 之前,根本没有用于 Surface 的公开构造函数。)如果将 SurfaceTexture 视为 Surface 和纹理的组合,这看起来可能有点落后。

深入来看,SurfaceTexture 称为 GLConsumer,它更准确地反映了其作为 BufferQueue 的所有方和消耗方的角色。从 SurfaceTexture 创建 Surface 时,您所做的是创建一个表示 SurfaceTexture 的 BufferQueue 生产方端的对象。

案例研究:Grafika 的连续拍摄

相机可以提供一个适合作为电影进行录制的帧流。要在屏幕上显示它,您可以创建一个 SurfaceView,将 Surface 传递给setPreviewDisplay(),然后让生产方(相机)和消耗方 (SurfaceFlinger) 完成所有工作。要录制视频,您可以使用 MediaCodec 的createInputSurface()创建一个 Surface,将其传递给相机,然后便可高枕无忧了。若要边显示边录制,您必须使用更多内容。

在录制视频时,连续拍摄 Activity 会显示相机录制的视频。在这种情况下,已编码的视频将写入内存中的环形缓冲区,该缓冲区可随时保存到磁盘。实现起来非常简单,只要您跟踪所有内容所在的位置即可。

该流程涉及三个 BufferQueue,分别是由应用、SurfaceFlinger 和 mediaserver 所创建:

应用。该应用使用 SurfaceTexture 从相机接收帧,并将其转换为外部 GLES 纹理。

SurfaceFlinger。该应用声明一个我们用来显示帧的 SurfaceView。

MediaServer。您可以使用输入 Surface 配置 MediaCodec 编码器,以创建视频。


图 1.Grafika 的连续拍摄 Activity。箭头指示相机的数据传输路径,BufferQueue 则用颜色标示(生产方为青色,消耗方为绿色)。

已编码的 H.264 视频在应用进程中进入 RAM 中的环形缓冲区,并在点击拍摄按钮时使用 MediaMuxer 类写入到磁盘上的 MP4 文件中。

三个 BufferQueue 都在应用中通过单个 EGL 上下文处理,且 GLES 操作在 UI 线程上执行。通常,不鼓励在 UI 线程上执行 SurfaceView 渲染,但是由于我们执行的是由 GLES 驱动程序异步处理的简单操作,因此没有问题。(如果视频编码器锁定,并且我们阻止尝试将缓冲区移出队列,该应用便会停止响应。而此时,我们无论怎样操作都可能会失败。)对已编码数据的处理(管理环形缓冲区并将其写入磁盘)是在单独的线程中执行的。

大部分配置是在 SurfaceView 的surfaceCreated()回调中进行的。系统会创建 EGLContext,并为显示设备和视频编码器创建 EGLSurface。当新的帧到达时,我们会告知 SurfaceTexture 去获取它,并将其作为 GLES 纹理进行提供,然后使用 GLES 命令在每个 EGLSurface 上渲染它(从 SurfaceTexture 转发转换和时间戳)。编码器线程从 MediaCodec 拉取编码的输出内容,并将其存储在内存中。

安全纹理视频播放

Android 7.0 支持对受保护的视频内容进行 GPU 后处理。这允许将 GPU 用于复杂的非线性视频效果(例如扭曲),将受保护的视频内容映射到纹理,以用于常规图形场景(例如,使用 OpenGL ES)和虚拟现实 (VR)。

图 2.安全纹理视频播放 

使用以下两个扩展程序实现支持:

EGL 扩展程序(EGL_EXT_protected_content)。允许创建受保护的 GL 上下文和 Surface,它们都可以对受保护的内容进行操作。

GLES 扩展程序(GL_EXT_protected_textures)。允许将纹理标记为受保护,以便它们可以用作帧缓冲区纹理附件。

Android 7.0 还会更新 SurfaceTexture 和 ACodec (libstagefright.so),这样一来,即使窗口 Surface 没有加入窗口编写器(例如 SurfaceFlinger)的队列,也允许发送受保护的内容,并且提供受保护的视频 Surface 以在受保护的上下文中使用。该操作通过在受保护的上下文(由 ACodec 验证)中创建的 Surface 上设置正确的受保护消耗方位 (GRALLOC_USAGE_PROTECTED) 来完成。

这些更改可使以下对象受益:应用开发者,他们可以创建应用来执行增强的视频效果,或在 GL 中(例如在 VR 中)使用受保护的内容来应用视频纹理;最终用户,他们可以在 GL 环境中(例如在 VR 中)查看高价值的视频内容(如电影和电视节目);以及原始设备制造商 (OEM),他们可通过增加设备功能(例如在 VR 中观看高清电影)提高产品销量。新的 EGL 和 GLES 扩展程序可以由系统芯片 (SoC) 提供商和其他供应商使用,目前是在 Nexus 6P 中使用的 Qualcomm MSM8994 SoC 芯片组上实现。

安全纹理视频播放为在 OpenGL ES 环境中进行强大的 DRM 实现奠定了基础。如果没有诸如 Widevine 级别 1 这样的强大 DRM 实现,许多内容提供商将不允许在 OpenGL ES 环境中渲染其高价值内容,从而阻止重要的 VR 用例(例如在 VR 中观看受 DRM 保护的内容)。

AOSP 包括用于安全纹理视频播放的框架代码;驱动程序支持取决于供应商。设备实现人员必须实现EGL_EXT_protected_content和GL_EXT_protected_textures extensions。使用您自己的编解码器库(替代 libstagefright)时,请注意,只要消耗方用法位包含GRALLOC_USAGE_PROTECTED,/frameworks/av/media/libstagefright/SurfaceUtils.cpp中的更改便会允许将标记为GRALLOC_USAGE_PROTECTED的缓冲区发送到 ANativeWindow,即便 ANativeWindow 没有直接加入窗口编写器的队列也可以。有关实现扩展程序的详细文档,请参见 Khronos 注册表(EGL_EXT_protected_contentGL_EXT_protected_textures)。

设备实现人员可能还需要进行硬件更改,才能确保映射到 GPU 的受保护内存仍受保护,且不可由未受保护的代码读取。

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 3.0 License, and code samples are licensed under theApache 2.0 License. For details, see ourSite Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 九月 13, 2017.

相关文章

网友评论

    本文标题:架构7--SurfaceTexture

    本文链接:https://www.haomeiwen.com/subject/jhatmxtx.html