架构7--SurfaceTexture

转自: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.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容