9

我在将 Android 中的相机预览从 YUV 格式转换为 RGB 时遇到问题。转换的目的是应用一些效果。我尝试通过片段着色器进行转换,因为本机代码的转换速度很慢(大约 14fps)。我使用的参考是http://jyrom.tistory.com/m/post/view/id/187。我尝试将此代码移植到 Android 平台,但结果是黑绿色矩形。但是,我可以通过我得到的输出观看某种形式。你能不能帮我解决这个问题。我相信这是一个流行的问题:将效果应用于相机预览。我还提供了一个指向我的测试项目的链接:https ://dl.dropbox.com/u/12829395/application/FilterGL/FilterGL.zip 。谢谢你。
更新:
这是我的onPreviewFrame方法:

public void onPreviewFrame(byte[] data, Camera camera) {
    yBuffer.put(data);
    yBuffer.position(0);

    System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4 * 2);
    uBuffer.put(uData);
    uBuffer.position(0);

    System.arraycopy(data, V_INDEX, vData, 0, LENGTH_4);
    vBuffer.put(vData);
    vBuffer.position(0);
}

这就是我在onDrawFrame方法中将字节数组绑定到 OpenGL 纹理的方式:

    GLES20.glUniform1i(yTexture, 1);
    GLES20.glTexImage2D(   GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
            320, 240, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yBuffer);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

    GLES20.glUniform1i(uTexture, 2);
    GLES20.glTexImage2D(   GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
            160, 120, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, uBuffer);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

    GLES20.glUniform1i(vTexture, 3);
    GLES20.glTexImage2D(   GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
            160, 120, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, vBuffer);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

这是我的片段着色器代码:

#ifdef GL_ES
precision highp float;
#endif

varying vec2 v_texCoord;
uniform sampler2D y_texture;
uniform sampler2D u_texture;
uniform sampler2D v_texture;

void main()
{   
    float nx,ny,r,g,b,y,u,v;
    nx=v_texCoord.x;
    ny=v_texCoord.y;
    y=texture2D(y_texture,v_texCoord).r;
    u=texture2D(u_texture,v_texCoord).r;
    v=texture2D(v_texture,v_texCoord).r;

    y=1.1643*(y-0.0625);
    u=u-0.5;
    v=v-0.5;

    r=y+1.5958*v;
    g=y-0.39173*u-0.81290*v;
    b=y+2.017*u;

    gl_FragColor = vec4(r,g,b,1.0);
}
4

5 回答 5

4

不知道你的问题有没有解决。

我使用了你的代码,我在这种模式下解决了。

public class MyRenderer implements Renderer{
public static final int recWidth = Costanti.recWidth;
public static final int recHeight = Costanti.recHeight;

private static final int U_INDEX = recWidth*recHeight;
private static final int V_INDEX = recWidth*recHeight*5/4;
private static final int LENGTH = recWidth*recHeight;
private static final int LENGTH_4 = recWidth*recHeight/4;

private int previewFrameWidth = 256;
private int previewFrameHeight = 256;

private int[] yTextureNames;
private int[] uTextureNames;
private int[] vTextureNames;

private MainActivity activity;

private FloatBuffer mVertices;
private ShortBuffer mIndices;

private int mProgramObject;
private int mPositionLoc;
private int mTexCoordLoc;

private int yTexture;
private int uTexture;
private int vTexture;

private final float[] mVerticesData = { -1.f, 1.f, 0.0f, // Position 0
        0.0f, 0.0f, // TexCoord 0
        -1.f, -1.f, 0.0f, // Position 1
        0.0f, 1.0f, // TexCoord 1
        1.f, -1.f, 0.0f, // Position 2
        1.0f, 1.0f, // TexCoord 2
        1.f, 1.f, 0.0f, // Position 3
        1.0f, 0.0f // TexCoord 3
};
private final short[] mIndicesData = { 0, 1, 2, 0, 2, 3 };

private ByteBuffer yBuffer;
private ByteBuffer uBuffer;
private ByteBuffer vBuffer;

private IntBuffer frameBuffer;
private IntBuffer renderBuffer;
private IntBuffer parameterBufferWidth;
private IntBuffer parameterBufferHeigth;

byte[] ydata = new byte[LENGTH];
byte[] uData = new byte[LENGTH_4];
byte[] vData = new byte[LENGTH_4];

public MyRenderer(MainActivity activity) {
    this.activity = activity;

    mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();
    mVertices.put(mVerticesData).position(0);

    mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2)
            .order(ByteOrder.nativeOrder()).asShortBuffer();
    mIndices.put(mIndicesData).position(0);

    yBuffer = MyGraphUtils.makeByteBuffer(LENGTH);
    uBuffer = MyGraphUtils.makeByteBuffer(LENGTH_4/* * 2*/);
    vBuffer = MyGraphUtils.makeByteBuffer(LENGTH_4);
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
    GLES20.glActiveTexture(GLES20.GL_ACTIVE_TEXTURE);
    GLES20.glViewport(0, 0, width, height);
}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    Log.d("debug", "on surface created");
    // Define a simple shader program for our point.
    final String vShaderStr = readTextFileFromRawResource(activity, R.raw.v_simple);
    final String fShaderStr = readTextFileFromRawResource(activity, R.raw.f_convert);
    frameBuffer = IntBuffer.allocate(1);
    renderBuffer= IntBuffer.allocate(1);

    GLES20.glEnable(GLES20.GL_TEXTURE_2D);

    GLES20.glGenFramebuffers(1, frameBuffer);
    GLES20.glGenRenderbuffers(1, renderBuffer);
    GLES20.glActiveTexture(GLES20.GL_ACTIVE_TEXTURE);
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer.get(0));
    GLES20.glClear(0);
    GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, renderBuffer.get(0));     

    GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16,
                                 320, 240);

    parameterBufferHeigth = IntBuffer.allocate(1);
    parameterBufferWidth = IntBuffer.allocate(1);
    GLES20.glGetRenderbufferParameteriv(GLES20.GL_RENDERBUFFER, GLES20.GL_RENDERBUFFER_WIDTH, parameterBufferWidth);
    GLES20.glGetRenderbufferParameteriv(GLES20.GL_RENDERBUFFER, GLES20.GL_RENDERBUFFER_HEIGHT, parameterBufferHeigth);
    GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_RENDERBUFFER, renderBuffer.get(0));
    if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER)!=GLES20.GL_FRAMEBUFFER_COMPLETE){
        Log.d("debug", "gl frame buffer status != frame buffer complete");
    }
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    GLES20.glClear(0);

    mProgramObject = loadProgram(vShaderStr, fShaderStr);

    // Get the attribute locations
    mPositionLoc = GLES20.glGetAttribLocation(mProgramObject, "a_position");
    mTexCoordLoc = GLES20.glGetAttribLocation(mProgramObject, "a_texCoord");

    GLES20.glEnable(GLES20.GL_TEXTURE_2D);
    yTexture = GLES20.glGetUniformLocation(mProgramObject, "y_texture");
    yTextureNames = new int[1];
    GLES20.glGenTextures(1, yTextureNames, 0);
    int yTextureName = yTextureNames[0];

    GLES20.glEnable(GLES20.GL_TEXTURE_2D);
    uTexture = GLES20.glGetUniformLocation(mProgramObject, "u_texture");
    uTextureNames = new int[1];
    GLES20.glGenTextures(1, uTextureNames, 0);
    int uTextureName = uTextureNames[0];

    GLES20.glEnable(GLES20.GL_TEXTURE_2D);
    vTexture = GLES20.glGetUniformLocation(mProgramObject, "v_texture");
    vTextureNames = new int[1];
    GLES20.glGenTextures(1, vTextureNames, 0);
    int vTextureName = vTextureNames[0];

    GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
}

@Override
public final void onDrawFrame(GL10 gl) {
    Log.d("debug", "on Draw frame");
    // Clear the color buffer
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

    // Use the program object
    GLES20.glUseProgram(mProgramObject);

    // Load the vertex position
    mVertices.position(0);
    GLES20.glVertexAttribPointer(mPositionLoc, 3, GLES20.GL_FLOAT, false, 5*4, mVertices);
    // Load the texture coordinate
    mVertices.position(3);
    GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 5*4, mVertices);

    GLES20.glEnableVertexAttribArray(mPositionLoc);
    GLES20.glEnableVertexAttribArray(mTexCoordLoc);

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureNames[0]);
    GLES20.glTexImage2D(   GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
            320, 240, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yBuffer);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureNames[0]);
    GLES20.glUniform1i(yTexture, 0);

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uTextureNames[0]);
    GLES20.glTexImage2D(   GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
            160, 120, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, uBuffer);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE1+2);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uTextureNames[0]);
    GLES20.glUniform1i(uTexture, 2);

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, vTextureNames[0]);
    GLES20.glTexImage2D(   GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
            160, 120, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, vBuffer);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE1+1);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, vTextureNames[0]);
    GLES20.glUniform1i(vTexture, 1);

    GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices);
}



public void setPreviewFrameSize(int realWidth, int realHeight) {
    previewFrameHeight = realHeight;
    previewFrameWidth = realWidth;
}

public static String readTextFileFromRawResource(final Context context, final int resourceId) {
    final InputStream inputStream = context.getResources().openRawResource(resourceId);
    final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
    final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

    String nextLine;
    final StringBuilder body = new StringBuilder();

    try {
        while ((nextLine = bufferedReader.readLine()) != null) {
            body.append(nextLine);
            body.append('\n');
        }
    } catch (IOException e) {
        return null;
    }

    return body.toString();
}

public static int loadShader(int type, String shaderSrc) {
    int shader;
    int[] compiled = new int[1];

    // Create the shader object
    shader = GLES20.glCreateShader(type);
    if (shader == 0) {
        return 0;
    }
    // Load the shader source
    GLES20.glShaderSource(shader, shaderSrc);
    // Compile the shader
    GLES20.glCompileShader(shader);
    // Check the compile status
    GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);

    if (compiled[0] == 0) {
        Log.e("ESShader", GLES20.glGetShaderInfoLog(shader));
        GLES20.glDeleteShader(shader);
        return 0;
    }
    return shader;
}

public static int loadProgram(String vertShaderSrc, String fragShaderSrc) {
    int vertexShader;
    int fragmentShader;
    int programObject;
    int[] linked = new int[1];

    // Load the vertex/fragment shaders
    vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertShaderSrc);
    if (vertexShader == 0) {
        return 0;
    }

    fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragShaderSrc);
    if (fragmentShader == 0) {
        GLES20.glDeleteShader(vertexShader);
        return 0;
    }

    // Create the program object
    programObject = GLES20.glCreateProgram();

    if (programObject == 0) {
        return 0;
    }

    GLES20.glAttachShader(programObject, vertexShader);
    GLES20.glAttachShader(programObject, fragmentShader);

    // Link the program
    GLES20.glLinkProgram(programObject);

    // Check the link status
    GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linked, 0);

    if (linked[0] == 0) {
        Log.e("ESShader", "Error linking program:");
        Log.e("ESShader", GLES20.glGetProgramInfoLog(programObject));
        GLES20.glDeleteProgram(programObject);
        return 0;
    }

    // Free up no longer needed shader resources
    GLES20.glDeleteShader(vertexShader);
    GLES20.glDeleteShader(fragmentShader);

    return programObject;
}

@Override
public void onPreviewFrame(byte[] data, Camera camera) {

    System.arraycopy(data, 0, ydata, 0, LENGTH);
    yBuffer.put(ydata);
    yBuffer.position(0);

    System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4);
    uBuffer.put(uData);
    uBuffer.position(0);

    System.arraycopy(data, V_INDEX, vData, 0, LENGTH_4);
    vBuffer.put(vData);
    vBuffer.position(0);
}   

}

于 2013-07-12T13:10:52.777 回答
3

不确定您是否已经解决了这个问题。我的回答

  1. 默认情况下,相机输出为 NV12,但在片段着色器 YUV 到 RGB 中,您使用的是 YV12 -> RGB。您将不得不这样做 setPreviewFormat(ImageFormat.YV12);,或者可能会使用其他着色器
  2. 有 3 种纹理,请确保您这样做

    GLES20.glActiveTexture(GLES20.GL_TEXTURE2); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, muTextureName)

    在调用任何 glTexImage2D 之前。和 glTexSubImage2D

  3. 您还可以对每一帧使用 glTexSubImage2D 和 glTexImage2D 一次。

  4. U 和 V 的大小相同,至少对于 YV12,

    System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4 * 2);

    应该 System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4); 在代码中相应地更改大小。

于 2012-12-18T16:41:24.050 回答
2

对于最快和最优化的方式,只需使用常见的 GL 扩展

//Fragment Shader
#extension GL_OES_EGL_image_external : require
uniform samplerExternalOES u_Texture;

比在 Java 中

surfaceTexture = new SurfaceTexture(textureIDs[0]);
try {
   someCamera.setPreviewTexture(surfaceTexture);
} catch (IOException t) {
   Log.e(TAG, "Cannot set preview texture target!");
}

someCamera.startPreview();

private static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65;

在 Java GL 线程中

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureIDs[0]);
GLES20.glUniform1i(uTextureHandle, 0);

颜色转换已经为您完成。你可以在片段着色器中做任何你想做的事情。

希望这可以节省您的研究时间。

于 2014-03-19T13:06:28.327 回答
1

最后让您的项目显示相机预览。我发现了 2 个问题: 1. 在绑定和更改表面特征之前,您必须调用 GLES20.glActiveTexture(GLES20.surfacenumber); 2. 更重要和隐藏的问题是 GLES20.glTexImage2D() 不适用于宽度和高度,它们不是 2 的幂。加载大小为 1024X1024 的纹理后,应调用 GLES20.glTexSubImage2D()

祝你好运!

于 2013-03-04T19:05:28.447 回答
0

我应用了解决方案表格How to render Android's YUV-NV21 camera image on the background on libgdx with OpenGLES 2.0 real-time? 到问题中共享的项目并获得了一个工作项目。如果您像我一样寻找通过片段着色器进行 YUV 到 RGB 转换的教程代码,您可以简单地执行以下步骤来获得一个工作示例。

  1. 下载项目https://dl.dropbox.com/u/12829395/application/FilterGL/FilterGL.zip并解压缩。
  2. 用下面共享的代码完全替换文件GLRenderer.javares/raw/f_convert.glsl
  3. 在 Eclipse 中打开项目,或将项目导入 Android Studio

问题中代码的主要问题是:

  1. 没有GLES20.glActiveTexture(GLES20.GL_TEXTURE1); , yBuffer 没有传递给 GL。
  2. YUV 数据采用 YUV-NV21 格式,并且 u_texture 和 v_texture 未在着色器中正确传递和处理。有关更多信息,请参阅此帖子

现在更正的代码:请将GLRenderer.java替换为

package com.filtergl.shader;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;

public class GLRenderer
implements Renderer, PreviewCallback {
    private static final int LENGTH = 76800;
    private static final int LENGTH_2 = 38400;

    private ActivityFilterGL activity;

    private FloatBuffer mVertices;
    private ShortBuffer mIndices;

    private int previewFrameWidth = 256;
    private int previewFrameHeight = 256;
    private int mProgramObject;
    private int mPositionLoc;
    private int mTexCoordLoc;
//  private int mSamplerLoc;
    private int yTexture;
    private int uTexture;
    private int vTexture;

    private final float[] mVerticesData = { -1.f, 1.f, 0.0f, // Position 0
            0.0f, 0.0f, // TexCoord 0
            -1.f, -1.f, 0.0f, // Position 1
            0.0f, 1.0f, // TexCoord 1
            1.f, -1.f, 0.0f, // Position 2
            1.0f, 1.0f, // TexCoord 2
            1.f, 1.f, 0.0f, // Position 3
            1.0f, 0.0f // TexCoord 3
    };

    private final short[] mIndicesData = { 0, 1, 2, 0, 2, 3 };

    private ByteBuffer frameData = null;
    private ByteBuffer yBuffer;
    private ByteBuffer uBuffer;

    public GLRenderer(ActivityFilterGL activity) {
        this.activity = activity;

        mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        mVertices.put(mVerticesData).position(0);

        mIndices = ByteBuffer.allocateDirect(mIndicesData.length * 2)
                .order(ByteOrder.nativeOrder()).asShortBuffer();
        mIndices.put(mIndicesData).position(0);

        yBuffer = GraphicsUtil.makeByteBuffer(LENGTH);
        uBuffer = GraphicsUtil.makeByteBuffer(LENGTH_2);
    }

    @Override
    public final void onDrawFrame(GL10 gl) {
        // Clear the color buffer
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        // Use the program object
        GLES20.glUseProgram(mProgramObject);

        // Load the vertex position
        mVertices.position(0);
        GLES20.glVertexAttribPointer(mPositionLoc, 3, GLES20.GL_FLOAT, false, 5 * 4, mVertices);
        // Load the texture coordinate
        mVertices.position(3);
        GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 5 * 4, mVertices);

        GLES20.glEnableVertexAttribArray(mPositionLoc);
        GLES20.glEnableVertexAttribArray(mTexCoordLoc);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);

        GLES20.glUniform1i(yTexture, 1);
        GLES20.glTexImage2D(   GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE,
                320, 240, 0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, yBuffer);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE2);

        GLES20.glUniform1i(uTexture, 2);
        GLES20.glTexImage2D(   GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE_ALPHA,
                160, 120, 0, GLES20.GL_LUMINANCE_ALPHA, GLES20.GL_UNSIGNED_BYTE, uBuffer);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

        GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, mIndices);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

        // Define a simple shader program for our point.
        final String vShaderStr = readTextFileFromRawResource(activity, R.raw.v_simple);
        final String fShaderStr = readTextFileFromRawResource(activity, R.raw.f_convert);

        // Load the shaders and get a linked program object
        mProgramObject = loadProgram(vShaderStr, fShaderStr);

        // Get the attribute locations
        mPositionLoc = GLES20.glGetAttribLocation(mProgramObject, "a_position");
        mTexCoordLoc = GLES20.glGetAttribLocation(mProgramObject, "a_texCoord");

        GLES20.glEnable(GLES20.GL_TEXTURE_2D);
        yTexture = GLES20.glGetUniformLocation(mProgramObject, "y_texture");
        int[] yTextureNames = new int[1];
        GLES20.glGenTextures(1, yTextureNames, 0);
        int yTextureName = yTextureNames[0];
        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, yTextureName);

        GLES20.glEnable(GLES20.GL_TEXTURE_2D);
        uTexture = GLES20.glGetUniformLocation(mProgramObject, "u_texture");
        int[] uTextureNames = new int[1];
        GLES20.glGenTextures(1, uTextureNames, 0);
        int uTextureName = uTextureNames[0];
        GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, uTextureName);

        // Set the background clear color to black.
        GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
    }

    public void setPreviewFrameSize(int realWidth, int realHeight) {
        previewFrameHeight = realHeight;
        previewFrameWidth = realWidth;

//      frameData = GraphicsUtil.makeByteBuffer(previewFrameHeight * previewFrameWidth * 3);
    }

    public static String readTextFileFromRawResource(final Context context, final int resourceId) {
        final InputStream inputStream = context.getResources().openRawResource(resourceId);
        final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        final BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

        String nextLine;
        final StringBuilder body = new StringBuilder();

        try {
            while ((nextLine = bufferedReader.readLine()) != null) {
                body.append(nextLine);
                body.append('\n');
            }
        } catch (IOException e) {
            return null;
        }

        return body.toString();
    }

    public static int loadShader(int type, String shaderSrc) {
        int shader;
        int[] compiled = new int[1];

        // Create the shader object
        shader = GLES20.glCreateShader(type);
        if (shader == 0) {
            return 0;
        }
        // Load the shader source
        GLES20.glShaderSource(shader, shaderSrc);
        // Compile the shader
        GLES20.glCompileShader(shader);
        // Check the compile status
        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);

        if (compiled[0] == 0) {
            Log.e("ESShader", GLES20.glGetShaderInfoLog(shader));
            GLES20.glDeleteShader(shader);
            return 0;
        }
        return shader;
    }

    public static int loadProgram(String vertShaderSrc, String fragShaderSrc) {
        int vertexShader;
        int fragmentShader;
        int programObject;
        int[] linked = new int[1];

        // Load the vertex/fragment shaders
        vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertShaderSrc);
        if (vertexShader == 0) {
            return 0;
        }

        fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragShaderSrc);
        if (fragmentShader == 0) {
            GLES20.glDeleteShader(vertexShader);
            return 0;
        }

        // Create the program object
        programObject = GLES20.glCreateProgram();

        if (programObject == 0) {
            return 0;
        }

        GLES20.glAttachShader(programObject, vertexShader);
        GLES20.glAttachShader(programObject, fragmentShader);

        // Link the program
        GLES20.glLinkProgram(programObject);

        // Check the link status
        GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linked, 0);

        if (linked[0] == 0) {
            Log.e("ESShader", "Error linking program:");
            Log.e("ESShader", GLES20.glGetProgramInfoLog(programObject));
            GLES20.glDeleteProgram(programObject);
            return 0;
        }

        // Free up no longer needed shader resources
        GLES20.glDeleteShader(vertexShader);
        GLES20.glDeleteShader(fragmentShader);

        return programObject;
    }

    @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        yBuffer.put(data, 0, LENGTH);
        yBuffer.position(0);

        uBuffer.put(data, LENGTH, LENGTH/2);
        uBuffer.position(0);
    }

}

并将f_convert.glsl替换为

#ifdef GL_ES
precision highp float;
#endif

varying vec2 v_texCoord;
uniform sampler2D y_texture;
uniform sampler2D u_texture;

 void main()
{   
    float r, g, b, y, u, v;

    //We had put the Y values of each pixel to the R,G,B components by
    //GL_LUMINANCE, that's why we're pulling it from the R component,
    //we could also use G or B
    y = texture2D(y_texture, v_texCoord).r;

    //We had put the U and V values of each pixel to the A and R,G,B
    //components of the texture respectively using GL_LUMINANCE_ALPHA.
    //Since U,V bytes are interspread in the texture, this is probably
    //the fastest way to use them in the shader
    u = texture2D(u_texture, v_texCoord).a - 0.5;
    v = texture2D(u_texture, v_texCoord).r - 0.5;

    //The numbers are just YUV to RGB conversion constants
    r = y + 1.13983*v;
    g = y - 0.39465*u - 0.58060*v;
    b = y + 2.03211*u;

    gl_FragColor = vec4(r,g,b,1.0);
}
于 2016-10-19T09:55:49.283 回答