java - 在 CardboardView 上显示的 YUV 视频

标签 java android opengl-es glsurfaceview google-cardboard

我正在尝试修改 WebRTC Android http://webrtc.org/native-code/android/将视频流显示到 Google CardboardView 中。在 SurfaceViewRenderer.java 和 GlRectDrawer.java来源,他们使用这些顶点和 fragment 着色器:

private static final String VERTEX_SHADER_STRING =
    "varying vec2 interp_tc;\n"
  + "attribute vec4 in_pos;\n"
  + "attribute vec4 in_tc;\n"
  + "\n"
  + "uniform mat4 texMatrix;\n"
  + "\n"
  + "void main() {\n"
  + "    gl_Position = in_pos;\n"
  + "    interp_tc = (texMatrix * in_tc).xy;\n"
  + "}\n";


private static final String YUV_FRAGMENT_SHADER_STRING =
    "precision mediump float;\n"
  + "varying vec2 interp_tc;\n"
  + "\n"
  + "uniform sampler2D y_tex;\n"
  + "uniform sampler2D u_tex;\n"
  + "uniform sampler2D v_tex;\n"
  + "\n"
  + "void main() {\n"
  // CSC according to http://www.fourcc.org/fccyvrgb.php
  + "  float y = texture2D(y_tex, interp_tc).r;\n"
  + "  float u = texture2D(u_tex, interp_tc).r - 0.5;\n"
  + "  float v = texture2D(v_tex, interp_tc).r - 0.5;\n"
  + "  gl_FragColor = vec4(y + 1.403 * v, "
  + "                      y - 0.344 * u - 0.714 * v, "
  + "                      y + 1.77 * u, 1);\n"
  + "}\n";

而且看起来只是简单地画了一个矩形框

所以我认为它也适用于 CardboardView。但它在 VR 模式下不能像这样正确绘制:

enter image description here

我在禁用 VR 模式时检查它是否正确绘制

以下代码是我的 onDrawEye() 方法中的实际绘制代码。我只是简单地改编SurfaceViewRenderer.java代码

// Fetch and render |pendingFrame|.
    final VideoRenderer.I420Frame frame;

    synchronized (frameLock) {
        if (pendingFrame == null) {
            return;
        }
        frame = pendingFrame;
        pendingFrame = null;
    }

    final long startTimeNs = System.nanoTime();
    final float[] texMatrix;

    synchronized (layoutLock) {
        final float[] rotatedSamplingMatrix = RendererCommon.rotateTextureMatrix(frame.samplingMatrix, frame.rotationDegree);
        final float[] layoutMatrix = RendererCommon.getLayoutMatrix(mirror, frameAspectRatio(), (float) layoutWidth / layoutHeight);
        texMatrix = RendererCommon.multiplyMatrices(rotatedSamplingMatrix, layoutMatrix);
    }

     GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    if (frame.yuvFrame) {
        // Make sure YUV textures are allocated.
        if (yuvTextures == null) {
            yuvTextures = new int[3];
            for (int i = 0; i < 3; i++)  {
                yuvTextures[i] = createTexture(GLES20.GL_TEXTURE_2D);
            }
        }

        drawer.uploadYuvData(
                yuvTextures, frame.width, frame.height, frame.yuvStrides, frame.yuvPlanes);
        drawer.drawYuv(yuvTextures, texMatrix);
    } else {
        drawer.drawOes(frame.textureId, texMatrix);
    }

    VideoRenderer.renderFrameDone(frame);

    synchronized (statisticsLock) {
        if (framesRendered == 0) {
            firstFrameTimeNs = startTimeNs;
        }
        ++framesRendered;
        renderTimeNs += (System.nanoTime() - startTimeNs);
        if (framesRendered % 300 == 0) {
            logStatistics();
        }
    }

我仍然无法弄清楚是什么原因。我该如何解决? 提前致谢。

编辑:它似乎只正确绘制了第一个(?)帧,然后像上图一样在没有纹理的情况下绘制。

最佳答案

使用 OpenGL 跟踪器后,我找到了解决方案。其实很简单。

每次在 GlRectDrawer.java 中调用 drawYuv() 时,它都会准备着色器并设置顶点属性,即顶点和纹理坐标。当在 CardboardView 的 onDrawEye() 中调用它时,CardboardView 会使用其他着色器和顶点属性进行失真校正。

对于下一帧,要设置的顶点属性与 drawYuv() 中的相同。原始 GlRectDrawer.java 源代码不会在每次调用中设置顶点数据所以我只是简单地再次设置顶点数据。

关于java - 在 CardboardView 上显示的 YUV 视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34427483/

相关文章:

java - Swagger2 - 找不到用于 GET 的处理程序

java - Opencv java接口(interface)没有 "VideoWriter"类

android - Galaxy Tab 10.1 可用屏幕分辨率(- 菜单栏)

android - 如何为结果启动谷歌地图

opengl-es - mipmap 纹理显示错误

java - 生成 Mandelbrot 分形时如何设置 c 的值?

java - 获取超过 25 个帖子 RestFb 时出现异常

java - 聊天应用程序中的反向分页不起作用

iphone - Iphone 上的 OpenGL ES - 显示和旋转 3D 对象

android - 如何在 opengl es 3+ 中获取屏幕外帧缓冲区内底层对象的像素颜色?