在 CardboardView 上显示的 YUV 视频
YUV video displaying on CardboardView
我正在尝试修改 WebRTC Android http://webrtc.org/native-code/android/ to display video stream into Google CardboardView. In SurfaceViewRenderer.java and GlRectDrawer.java 来源,他们使用这些顶点和片段着色器:
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 模式下不能像这样正确绘制:
我检查了它在禁用 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 源代码不会在每次调用时都设置顶点数据所以我只是简单地再次设置顶点数据。
我正在尝试修改 WebRTC Android http://webrtc.org/native-code/android/ to display video stream into Google CardboardView. In SurfaceViewRenderer.java and GlRectDrawer.java 来源,他们使用这些顶点和片段着色器:
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 模式下不能像这样正确绘制:
我检查了它在禁用 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 源代码不会在每次调用时都设置顶点数据所以我只是简单地再次设置顶点数据。