SurfaceTexture

文章介绍了如何使用SurfaceTexture从图像流中捕获帧作为OpenGLES纹理,包括创建、更新、绑定、回调机制以及注意事项。SurfaceTexture提供了一种将帧传递给OpenGL上下文的高效方式,支持多种应用场景,如Camera、MediaCodec等。

SurfaceTexture

从图像流中捕获帧作为OpenGL ES纹理。

图像流可以来自相机预览或视频解码。从SurfaceTexture创建的纹理对象可用作API的输出目标,包括Camera、MediaCodec、MediaPlayer和Allocation。调用updateTexImage()时,指定SurfaceTexture创建时的纹理对象的内容将更新为图像流中最新的图像。这可能会导致一些帧被跳过。SurfaceTexture还可以用作旧API中指定输出目标的SurfaceHolder的替代品。这样做会将图像流中的所有帧发送到SurfaceTexture对象,而不是设备的显示器。

通常的模式是使用SurfaceTexture将帧呈现到TextureView上;但是,使用纹理对象并不需要TextureView。纹理对象可以作为OpenGL ES着色器的一部分使用。

在从纹理中取样时,应首先使用通过getTransformMatrix(float[])查询的矩阵转换纹理坐标。变换矩阵可能每次调用updateTexImage()时都会发生变化,因此每次更新纹理图像时都应重新查询。该矩阵将传统的2D OpenGL ES纹理坐标列向量(形式为(s,t,0,1),其中s和t在包括区间[0,1])转换为流式纹理中的适当采样位置。该变换补偿了图像流源的任何属性,使其与传统的OpenGL ES纹理不同。例如,可以通过使用查询的矩阵转换列向量(0,0,0,1)从图像的左下角采样,而可以通过使用转换(1,1,0,1)从图像的右上角采样。

纹理对象使用GL_TEXTURE_EXTERNAL_OES纹理目标,该目标由GL_OES_EGL_image_external OpenGL ES扩展定义。这限制了纹理的使用方式。每次绑定纹理时,它必须绑定到GL_TEXTURE_EXTERNAL_OES目标而不是GL_TEXTURE_2D目标。此外,任何OpenGL ES 2.0着色器从纹理中取样时必须使用该扩展声明其使用,例如使用“#extension GL_OES_EGL_image_external : require”指令。这样的着色器还必须使用samplerExternalOES GLSL采样器类型访问纹理。

SurfaceTexture对象可以在任何线程上创建。只有包含纹理对象的OpenGL ES上下文的线程才能调用updateTexImage()。帧可用回调在任意线程上调用,因此除非特别注意,否则不应直接从回调中调用updateTexImage()。

内部类


interface    SurfaceTexture.OnFrameAvailableListener
用于通知新的流帧可用的回调接口。

class    SurfaceTexture.OutOfResourcesException
此类已在API级别19中被弃用。不再抛出。现在使用Surface.OutOfResourcesException。

公共构造函数


SurfaceTexture(int texName)
构造一个新的SurfaceTexture以将图像流传输到给定的OpenGL纹理。

SurfaceTexture(int texName, boolean singleBufferMode)
构造一个新的SurfaceTexture以将图像流传输到给定的OpenGL纹理,并指定是否使用单缓冲模式。

SurfaceTexture(boolean singleBufferMode)
构造一个新的SurfaceTexture以将图像流传输到给定的OpenGL纹理,并指定是否使用单缓冲模式。如果未指定纹理名称,则会自动创建一个新的纹理。

公共方法

void attachToGLContext(int texName)
将 SurfaceTexture 附加到当前线程的 OpenGL ES 上下文中,使用指定的纹理名称。

void detachFromGLContext()
将 SurfaceTexture 从拥有 OpenGL ES 纹理对象的 OpenGL ES 上下文中分离。

int getDataSpace()
检索与纹理图像关联的数据空间。

long getTimestamp()
检索与纹理图像关联的时间戳,该时间戳由最近一次调用 updateTexImage() 方法设置。

void getTransformMatrix(float[] mtx)
检索与纹理图像关联的 4x4 纹理坐标变换矩阵,该矩阵由最近一次调用 updateTexImage() 方法设置。

boolean isReleased()
返回 SurfaceTexture 是否已释放。

void release()
释放所有缓冲区并将 SurfaceTexture 置于“废弃”状态。

void releaseTexImage()
释放纹理内容。

void setDefaultBufferSize(int width, int height)
设置图像缓冲区的默认大小。

void setOnFrameAvailableListener(SurfaceTexture.OnFrameAvailableListener listener, Handler handler)
注册回调函数,在新的图像帧可用于 SurfaceTexture 时调用。

void setOnFrameAvailableListener(SurfaceTexture.OnFrameAvailableListener listener)
注册回调函数,在新的图像帧可用于 SurfaceTexture 时调用。

void updateTexImage()
将纹理图像更新为图像流中最近的帧。

### SurfaceTexture 使用指南与示例代码 `SurfaceTexture` 是 Android 提供的一个类,用于将图像流(如相机预览或视频解码)转换为 OpenGL 纹理。它广泛应用于需要对图像流进行处理的场景,例如相机预览、视频播放和实时图像处理。 #### 基本原理 `SurfaceTexture` 通过将图像数据作为纹理提供给 OpenGL,允许开发者直接操作图像流。当图像流更新时,`SurfaceTexture` 会通过回调通知开发者,开发者可以在回调中更新纹理并进行渲染。这种方式使得图像处理更加灵活,并支持复杂的图形操作。 #### 创建与初始化 要使用 `SurfaceTexture`,首先需要创建一个实例,并将其与 `TextureView` 或其他支持纹理的视图结合使用。以下是一个简单的初始化示例: ```java // 获取 TextureView 的 SurfaceTexture SurfaceTexture surfaceTexture = textureView.getSurfaceTexture(); // 创建一个新的 SurfaceTexture 实例 SurfaceTexture newSurfaceTexture = new SurfaceTexture(surfaceTexture); // 将新的 SurfaceTexture 设置回 TextureView textureView.setSurfaceTexture(newSurfaceTexture); ``` #### 绑定到相机预览 在相机应用中,`SurfaceTexture` 常用于接收相机预览数据。以下是如何将 `SurfaceTexture` 与相机预览结合使用的示例: ```java // 创建一个 SurfaceTexture SurfaceTexture surfaceTexture = new SurfaceTexture(textureView.getSurfaceTexture()); textureView.setSurfaceTexture(surfaceTexture); // 创建一个 Surface 对象 Surface surface = new Surface(surfaceTexture); // 配置相机预览会话 Preview preview = new Preview.Builder().build(); preview.setSurfaceProvider(previewView.createSurfaceProvider()); ``` #### 处理图像流更新 当图像流更新时,`SurfaceTexture` 会触发 `onFrameAvailable` 回调。开发者可以在该回调中更新纹理并进行渲染: ```java surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { @Override public void onFrameAvailable(SurfaceTexture surfaceTexture) { // 更新纹理 surfaceTexture.updateTexImage(); // 获取纹理矩阵 float[] textureMatrix = new float[16]; surfaceTexture.getTransformMatrix(textureMatrix); // 在此处进行渲染操作 renderFrame(); } }, null); ``` #### 示例代码 以下是一个完整的示例,展示如何在 `TextureView` 中使用 `SurfaceTexture` 来显示相机预览: ```java public class CameraPreviewActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener { private TextureView textureView; private Camera camera; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); textureView = new TextureView(this); textureView.setSurfaceTextureListener(this); setContentView(textureView); } @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { try { // 打开相机 camera = Camera.open(); // 创建 Surface Surface surface = new Surface(surfaceTexture); // 设置预览显示 camera.setPreviewDisplay(surface); // 开始预览 camera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) { // 处理大小变化 } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { // 释放相机资源 if (camera != null) { camera.stopPreview(); camera.release(); camera = null; } return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { // 每次纹理更新时调用 } } ``` #### 注意事项 - **生命周期管理**:确保在适当的生命周期阶段释放 `SurfaceTexture` 和相关资源,避免内存泄漏。 - **性能优化**:由于 `SurfaceTexture` 可能引入一定的延迟和性能开销,建议在不需要时及时释放资源。 - **线程安全**:`SurfaceTexture` 的某些操作可能需要在特定线程中执行,确保线程安全。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值