在CardboardView

时间:2015-12-23 02:05:21

标签: java android opengl-es glsurfaceview google-cardboard

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

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。但它不能像VRMode那样正确绘制:

enter image description here

当我禁用VRmode

时,我检查了它是否正确绘制

以下代码是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();
        }
    }

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

编辑:它似乎只能正确绘制第一个(?)帧,然后绘制没有像上图所示的纹理。

1 个答案:

答案 0 :(得分:0)

使用OpenGL跟踪器后,我找到了一个解决方案。实际上这很简单。

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

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