通过 SurfaceTexture 在 GLSurfaceView 上显示相机流

Posted

技术标签:

【中文标题】通过 SurfaceTexture 在 GLSurfaceView 上显示相机流【英文标题】:Displaying the camera stream on a GLSurfaceView via SurfaceTexture 【发布时间】:2012-10-23 10:22:13 【问题描述】:

我正在尝试通过传输到 OpenGL ES 2.0 着色器的 SurfaceTexture 在 GLSurfaceView 中显示相机流。

我从这个post中获得灵感。

图像完整,但在我的平板电脑上显示不正确。 屏幕似乎分为 2x2 部分。图像显示在左上角,而其他三个部分是黑色的。

我怀疑问题出在我使用了here记录的序列返回的转换矩阵

updateTexImage();
getTransformMatrix(...);

我在顶点着色器中传输这个矩阵来为片段着色器生成纹理坐标。

顶点着色器:

attribute vec3 aPosition;
uniform mat4 uMvpTransform;
// Matrix retrieved by getTransformMatrix(...);
uniform mat4 uTexMatTransform;
varying vec2 vTexCoord;

void main(void)

  gl_Position = uMvpTransform *vec4(aPosition.xyz, 1);
  vec4 l_tex =  uTexMatTransform*vec4(aPosition.xyz, 1);
  vTexCoord=l_tex.xy;

片段着色器:

#extension GL_OES_EGL_image_external : require
varying mediump vec2 vTexCoord;
uniform samplerExternalOES uSampler; 

void main(void) 
 
    mediump vec4 l_tex = texture2D(uSampler, vTexCoord);
    gl_FragColor=l_tex;

纹理附加到以下正方形:

 // Image container
 GLfloat l_vertices[] = 
  -1.0f, 1.0f,  0.0f,
  -1.0f, -1.0f,  0.0f,
  1.0f,  -1.0f,  0.0f,
  1.0f,  1.0f,  0.0f ;

有人做过类似的事情吗?

2012 年 11 月 3 日编辑:

顶点着色器的修正:

attribute vec3 aPosition;
attribute vec2 aTexCoord;
uniform mat4 uMvpTransform;
// Matrix retrieved by getTransformMatrix(...);
uniform mat4 uTexMatTransform;
varying vec2 vTexCoord;

void main(void)

  gl_Position = uMvpTransform *vec4(aPosition.xyz, 1);
  vec4 l_tex =  uTexMatTransform*vec4(aTexCoord.xy,0, 1);
  vTexCoord=l_tex.xy;

与:

// Texture
GLfloat l_texCoord[] = 
   0.0f, 1.0f,
   0.0f, 0.0f,
   1.0f,  0.0f,
   1.0f,  1.0f

;

【问题讨论】:

【参考方案1】:

我已成功使用 SurfaceTexture 在自定义 opengl 纹理上绘制相机帧,而无需使用 android 提供的转换矩阵。

只需尝试像普通纹理绘制那样定义索引顶点和纹理。比如这个。

const GLfloat Vertices[] = 0.5, -0.5, 0,
                            0.5, 0.5, 0,
                           -0.5, 0.5, 0,
                           -0.5, -0.5, 0;

const GLubyte Indices[] =  0, 1, 2,
                            2, 3, 0 ;

const GLfloat Textures[] =  1.,0.,
                             0.,0.,
                             0.,1.,
                             1.,1. ;

您应该能够像使用普通纹理一样使用表面纹理。

如果您想要执行某种 3D 投影,请参阅good post,了解如何生成正确的 MVP 矩阵。您可以使用它与顶点着色器中的位置相乘。

【讨论】:

好建议。或者我可以将正确的纹理坐标发送到着色器。我更新了顶点着色器,以便它可以帮助其他人。 那我们为什么要提供变换矩阵呢? 参见 Fabien R 编辑的“Edited nov 3, 2012”。我正在添加一个简短的答案来解决这一点。【参考方案2】:

由于我有同样的问题,即使这个问题有点老了,可能值得详细说明一下“为什么使用变换矩阵”

转换矩阵映射 SurfaceTexture 使用的特定坐标集(或更可能 当前视频源 流式传输到 SurfaceTexture...) 到标准的 OpenGL 纹理坐标。

绝对应该使用它的原因是,尽管 Startibartfast 答案适用于一个或多个特定设置,并且可能很容易实现且很诱人,当运行相同的程序时,它可能会产生奇怪的可视化错误不同的设备,具体取决于每个平台的视频驱动程序实现。

例如,在我的例子中,变换矩阵只是将内容颠倒过来(我在 Nexus 7 上将 SurfaceTexture 与 MediaPlayer 结合使用),而不是 Fabien R 指出的结果。

在 2012 年 11 月 3 日的 Fabien R 编辑中指出了使用矩阵的正确方法,我报告了一些小修饰(如使用 st 索引),并进行了小修正int/float 不匹配:

attribute   vec2 uv;
varying     vec2 vTexCoord;
uniform     mat4 transformMatrix;

vTexCoord = (transformMatrix * vec4(uv, 0.0, 1.0)).st;

希望对你有帮助

【讨论】:

以上是关于通过 SurfaceTexture 在 GLSurfaceView 上显示相机流的主要内容,如果未能解决你的问题,请参考以下文章

Android:将 SurfaceTexture 附加到 FrameBuffer

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

音视频开发系列——详解Android SurfaceTexture

Android - 在 SurfaceTexture 上绘制 YouTube 视频

从 NDK 中获取 SurfaceTexture 的 GL 上下文

与 MediaPlayer 一起使用后如何清除 SurfaceTexture?