从 NDK 中获取 SurfaceTexture 的 GL 上下文

Grabbing SurfaceTexture's GL context from NDK

用途: 我正在使用 SurfaceTexture 来显示相机预览,并且需要通过从 NDK 获取 GL 上下文在表面上绘制。我选择了 SurfaceTexture 方法,因为我可以避免相机帧缓冲区的手动从 java 传递到 NDK,以节省一些性能。

public class MainActivity extends Activity implements SurfaceTextureListener {

private Camera mCamera;
private TextureView mTextureView;

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

    mTextureView = new TextureView(this);
    mTextureView.setSurfaceTextureListener(this);

    setContentView(mTextureView);
}

@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
    mCamera = Camera.open();
    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 在内部使用 GL 功能来绘制上下文。从 NDK 获取默认显示失败并出现 BAD_DISPLAY 错误。

EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

当然,我可以初始化一个新的 GL 上下文并进行绘图,但我仍然希望在后台显示 java 代码中的纹理。

问题: 使用 SurfaceTexture 时是否可以从 NDK 中获取 GL 上下文? 可能我必须在 GLSurfaceView 上使用,从 java 代码手动初始化 GL 上下文并从 NDK 中获取它?

你的问题对我来说并不完全有意义,所以让我列出一些事情。

  • SurfaceTexture 不绘制任何东西。当 Camera 作为生产者连接时,SurfaceTexture 接收 YUV 帧,并使用 EGL 函数将其设置为 "external" 纹理。然后您可以使用 GLES 渲染该纹理。

  • EGL 上下文一次可以 "current" 在一个线程中。指向当前上下文的指针保存在本机线程本地存储中。 Java 语言 GLES 绑定是本机代码的薄包装,因此在使用 GLES 时,Java 和 C++ 在概念上几乎没有区别。

  • SurfaceTexture 的纹理将与对象创建时的当前上下文相关联,但您可以使用 attach/detach 调用将其切换到不同的上下文。您不能 "grab" SurfaceTexture 的 EGL 上下文,但您可以告诉它您希望它使用哪一个。

  • SurfaceTexture(和一般的 Surface)只能有一个生产者。您不能将相机帧发送到您正在使用 GLES 渲染的表面。您可以在它们之间来回切换,但通常最好使用两个不同的 Surface 对象。

  • TextureView 是具有嵌入式 SurfaceTexture 的视图。当被要求重绘时,它使用 GLES 从纹理渲染(这就是为什么如果禁用硬件渲染你根本看不到任何东西)。

如果我没有正确理解你的问题,我认为你想要做的是:

  • 将相机输出发送到在渲染器线程上创建的新 SurfaceTexture。
  • 为 TextureView 的 SurfaceTexture 创建一个 EGLSurface。
  • 使用 GLES 渲染到 TextureView,使用来自相机的纹理作为样本源。添加您想要的任何其他 GLES 渲染。

可以在 Grafika 中找到各种示例,例如"texture from camera" Activity.