SurfaceTexture详解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SurfaceTexture详解相关的知识,希望对你有一定的参考价值。

参考技术A 之前讲到了 flutter的Texture
SurfaceTexture 是 Surface 和 OpenGL ES (GLES) 纹理的组合。SurfaceTexture 用于提供输出到 GLES 纹理的 Surface
SurfaceTexture 包含一个 BufferQueue。当生产方将新的缓冲区排入队列时,onFrameAvailable() 回调会通知应用。然后,应用调用 updateTexImage(),这会释放先前占有的缓冲区,从队列中获取新缓冲区并执行 EGL 调用,从而使 GLES 可将此缓冲区作为外部纹理使用。

关键方法:
SurfaceTexture(int texName, boolean singleBufferMode)构造方法
setOnFrameAvailableListener 设置回调,当生产者准备好新的帧后会调用Listener
updateTexImage 更新texture到指定的GLESContext
detachFromGLContext
attachToGLContext
解绑/绑定 当前GLContext
getTransformMatrix 设置重采样纹理矩阵,当渲染的时候会用到这个数据
release() 完全释放 SufaceTexture的 buffers并且吧Surface状态置为abandoned

android-8.0.0_r1 源码解析:

GLConsumer参数解释:
bq是BufferQueue创建BufferConsumer
tex 表示要将图像流传输到的OpenGL ES纹理名称。
texTarget指定了哪个纹理将被绑定
useFenceSync表示是否需要同步访问缓冲区
可以从一个OpenGL ES上下文中分离GLConsumer,然后分别使用detachFromContext和attachToContext方法将GLConsumer附加到另一个上下文。
如果设置tex参数则会通过attachToContext将GLConsumer附加到OpenGL ES context中。
第一次调用updateTexImage才会绑定,之后所有对updateTexImage的调用必须使用相同的当前OpenGL ES context进行

acquireBufferLocked创建EglImage并设置到EglSlots中

updateAndReleaseLocked 更新 EglImage
createIfNeeded 如果EGLDisplay改变或者crop改变则会创建EglImage
bindToTextureTarget 将调用glEGLImageTargetTexture2DOES去绑定image到指定的目标纹理

这里创建EGLImageKHR,EGLImageKHR用于共享EGL资源

EGL的ShareContext是常见的共享上下文的方式(ios平台的EAGL叫ShareGroup)。

当share_context参数传入另一个EGL的context时,这两个EGLContext就可以共享纹理以及VBO等。
需要注意的是container objects不能被共享,比如:
Framebuffer objects
Vertex array objects
Transform feedback objects
Program pipeline objects

参考: https://wiki.jikexueyuan.com/project/deep-android-v1/classes.html
EGLImageKHR: https://www.khronos.org/registry/EGL/extensions/KHR/EGL_KHR_image_base.txt

Android TextureView+SurfaceTexture实现相机预览

AndroidManifest.xml

    <uses-permission android:name="android.permission.RECORD_AUDIO"/><!--音频录制权限-->
    <uses-permission android:name="android.permission.CAMERA"/><!--摄像头权限-->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><!--存储权限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

MainActivity .java

import android.Manifest;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.Gravity;
import android.view.TextureView;
import android.view.View;
import android.widget.FrameLayout;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import java.io.IOException;

public class MainActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener 
    private Camera mCamera;
    private TextureView mTextureView;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

        /**
         * 在 Android 6.0 以上需要动态添加权限
         */
        ActivityCompat.requestPermissions(this,
                new String[]Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO,
                100);

        mTextureView = new TextureView(this);
        mTextureView.setSurfaceTextureListener(this);
        mTextureView.setScaleX(-1f);
        setContentView(mTextureView);
    

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) 
        mCamera = Camera.open(1);
        Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
        mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
                previewSize.width, previewSize.height, Gravity.CENTER));

        try 
            mCamera.setPreviewTexture(surface);
         catch (IOException t) 
        

        mCamera.startPreview();

    

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) 
        // Ignored, the Camera does all the work for us
    

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) 
        mCamera.stopPreview();
        mCamera.release();
        return true;
    

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) 
        // Update your view here!
    

以上是关于SurfaceTexture详解的主要内容,如果未能解决你的问题,请参考以下文章

如何以类似于相机为 SurfaceTexture 生成帧的方式生成 YUVI420 帧到 SurfaceTexture?

SurfaceTexture.getTransformMatrix的返回值是啥意思,谁能解释一下?

从 NDK 中获取 SurfaceTexture 的 GL 上下文

Android - 在 SurfaceTexture 上绘制 YouTube 视频

Android:将 SurfaceTexture 附加到 FrameBuffer

通过 SurfaceTexture 在 GLSurfaceView 上显示相机流