SurfaceTexture源码分析

概述

SurfaceTexture,是Android3.0以后引入的,它对图像流的处理并不直接显示,而是转换为GL外部纹理,因此可用于图像流数据的二次处理,比如Camera滤镜、特效等。

分析源码

SurfaceTexture

java.lang.Object
↳ android.graphics.SurfaceTexture

public class SurfaceTexture {

 }
API 注释
  • Captures frames from an image stream as an OpenGL ES texture. 从图像流中捕获帧数据用作OpenGL ES的纹理。The image stream may come from either camera preview or video decode 其中这个图像流数据也可以是相机预览数据也可以是视频解码数据。
  • A SurfaceTexture may be used in place of a SurfaceHolder when specifying the output destination of a Camera or MediaPlayer object. 当输出目标指定为Camera或者MediaPlayer对象时候,可以使用SurfaceTexture来代替SurfaceHolder
  • Doing so will cause all the frames from the image stream to be sent to the SurfaceTexture object rather than to the device’s display. 如果这样做的话,image stream将把所有帧对象都传给了SurfaceTexture对象,而不是显示在设备上。

两个重要的方法

1. updateTexImage( )

    public void updateTexImage() {
        nativeUpdateTexImage();
    }
  • When updateTexImage() is called, the contents of the texture object specified when the SurfaceTexture was created are updated to contain the most recent image from the image stream.
  • 当updateTexImage()方法被调用的时候,SurfaceTexture对象所关联的OpenGL ES中纹理对象的内容将会被更新为image stream中最新的图片。
  • This may cause some frames of the stream to be skipped.
  • 也就是调用该方法可能会丢失帧数据。
  • SurfaceTexture objects may be created on any thread. updateTexImage() may only be called on the thread with the OpenGL ES context that contains the texture object.
  • SurfaceTexture对象可以再任何线程中创建,但是updateTexImage() 方法只能够在OpenGL Thread中被调用,一般情况下都是在onDrawFrame方法中调用updateTexImage() ,将数据绑定给OpenGL 对应的纹理对象。
  • 这里需要注意下,必须显示的调用这个方法,将最新的数据更新到OpenGL ES对应的纹理对象当中去,这样SurfaceTexture才有空间来获取下一帧的数据,不然就永远取不了下一帧数据。

2. getTransformMatrix(float[]).

 public void getTransformMatrix(float[] mtx) {
        // Note we intentionally don't check mtx for null, so this will result in a
        // NullPointerException. But it's safe because it happens before the call to native.
        if (mtx.length != 16) {
            throw new IllegalArgumentException();
        }
        nativeGetTransformMatrix(mtx);
    }
  • When sampling from the texture one should first transform the texture coordinates using the matrix queried via getTransformMatrix(float[])
  • 当从OpenGL ES纹理取样的时候,需要先调用getTransformMatrix()方法获取变换矩阵,来转换纹理坐标。
  • The transform matrix may change each time updateTexImage() is called, so it should be re-queried each time the texture image is updated.
  • 每次调用 updateTexImage()这个方法的时候,纹理坐标都有可能变换,所以每次texture image变化的时候,都需要获取一次新的变换矩阵,也就是每调用一次updateTexImage(),也必须要调用一次getTransformMatrix()。
  • This matrix transforms traditional 2D OpenGL ES texture coordinate column vectors of the form (s, t, 0, 1) where s and t are on the inclusive interval [0, 1] to the proper sampling location in the streamed texture
  • 也就是说这个方法是将2D OpenGL ES纹理坐标的列向量转化成纹理流中正确的采样位置 ,也就是使用这个矩阵获取正确的采样坐标
GL_TEXTURE_EXTERNAL_OES 纹理类型
  • The texture object uses the GL_TEXTURE_EXTERNAL_OES texture target, which is defined by the GL_OES_EGL_image_external OpenGL ES extension.
  • 在上面说过,updateTexImage()会将最新的图片更新到与SurfaceTexture相关联的OpenGL ES的纹理对象中,那么这个纹理对象所需要的类型就是GL_TEXTURE_EXTERNAL_OES这个类型,这个类型是OpenGL ES的扩展类型,所以这个需要使用额外扩展的采样器对这个纹理进行采样,在我的上上篇博客使用OpenGL显示摄像头里面的片元着色器部分对这个有相关使用。可以去看下

一个接口

SurfaceTexture.OnFrameAvailableListener
  • Callback interface for being notified that a new stream frame is available.
  • 当有新数据可用的时候,调用该方法
  • 当设置渲染器的模式为按需渲染的时候,可以在这个接口回调里面调用GLSurfaceView.requestRender()来进行渲染
  • 具体的实例应用都可以去看看我这篇使用OpenGL显示摄像头

小结

首先,SurfaceTexture从图像流(来自Camera预览、视频解码,GL绘制场景)中获取帧数据,然后使用updateTexImage()将最新的图像更新到SurfaceTexture所对应的GL纹理对象中去,由于SurfaceTexture很特殊,所以对应的OpenGL的纹理对象类型不是普通的sampler2D,而是GL_TEXTURE_EXTERNAL_OES。所以在OpenGL中对纹理进行操作的时候,采样器需要采用额外类型的采样器,另外我们需要通过getTransformMatrix()获取变换矩阵,通过矩阵变换获取到采样点真正的采样位置。

猜你喜欢

转载自blog.csdn.net/YuQing_Cat/article/details/83654295