Android 通过片段着色器将YUV转换为RGB

Android 通过片段着色器将YUV转换为RGB,android,opengl-es,camera,shader,fragment-shader,Android,Opengl Es,Camera,Shader,Fragment Shader,我有一个在Android中从YUV格式转换为RGB格式的相机预览问题。转换的目的是应用一些效果。我尝试通过片段着色器进行转换,因为通过本机代码进行转换的速度很慢(大约14fps)。我使用的参考文献是。我尝试将此代码移植到Android平台,但结果是黑绿色矩形。但是,通过我得到的输出,我可以看到一些形式。你能帮我解决这个问题吗。我相信这是一个普遍存在的问题:将效果应用于相机预览。我还提供了一个指向我的测试项目的链接:。 非常感谢。 更新: 这是我的预览帧方法: 这就是我如何在onDrawFr

我有一个在Android中从YUV格式转换为RGB格式的相机预览问题。转换的目的是应用一些效果。我尝试通过片段着色器进行转换,因为通过本机代码进行转换的速度很慢(大约14fps)。我使用的参考文献是。我尝试将此代码移植到Android平台,但结果是黑绿色矩形。但是,通过我得到的输出,我可以看到一些形式。你能帮我解决这个问题吗。我相信这是一个普遍存在的问题:将效果应用于相机预览。我还提供了一个指向我的测试项目的链接:。 非常感谢。
更新:
这是我的预览帧方法:

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

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

\ifdef glu
高精度浮点;
#恩迪夫
可变矢量2 v_texCoord;
均匀的y_纹理;
均匀的二维u_纹理;
均匀的二维v_纹理;
void main()
{   
浮动nx,ny,r,g,b,y,u,v;
nx=v_texCoord.x;
ny=v_texCoord.y;
y=纹理2d(y_纹理,v_texCoord).r;
u=纹理2d(u_纹理,v_texCoord).r;
v=纹理2d(v_纹理,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);
}

不确定您是否已解决此问题。我的答案是

  • 默认情况下,摄影机输出为NV12,但在片段着色器YUV到RGB中,您使用的是YV12->RGB。 你必须这样做
    setPreviewFormat(ImageFormat.YV12),或者可以使用其他着色器
  • 有3种纹理,请确保您做到了

    GLES20.glActiveTexture(GLES20.GL_TEXTURE2)
    
    GLES20.glBindTexture(GLES20.GL\u TEXTURE\u 2D,mutextRename)

    在调用任何glTexImage2D之前。和glTexSubImage2D

  • 还可以对每一帧使用glTexSubImage2D,并对glTexImage2D使用一次

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

    System.arraycopy(数据,U_索引,uData,0,长度4*2)

    应该是
    System.arraycopy(数据,U_索引,uData,0,长度_4)
    在代码中相应地更改大小


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


    祝你好运

    我不知道你的问题是否解决了

    我使用了你的代码,并在此模式下解决了问题

    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);
    }   
    

    }

    要获得最快、最优化的方式,只需使用通用GL扩展即可

    //Fragment Shader
    #extension GL_OES_EGL_image_external : require
    uniform samplerExternalOES u_Texture;
    
    而不是在爪哇

    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);
    
    颜色转换已经为您完成。 您可以在片段着色器中执行任何您想要的操作


    希望这能为您的研究节省一些时间。

    我将解决方案表单应用于问题中共享的项目,并获得了一个工作项目。如果您像我一样搜索通过片段着色器进行YUV到RGB转换的教程代码,您只需执行以下步骤即可获得一个工作示例

  • 下载项目并解压缩
  • 将文件GLRenderer.javares/raw/f_convert.glsl完全替换为下面共享的代码
  • 在Eclipse中打开项目,或
  • 问题中有关守则的主要问题如下:

  • GLES20.glActiveTexture(GLES20.GL_TEXTURE1),yBuffer未传递给GL
  • YUV数据采用YUV-NV21格式,并且u_纹理和v_纹理未在着色器中正确传递和处理。有关更多信息,请参阅
  • 现在更正代码:请将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);
    }
    
    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);
        }
    
    }
    
    #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);
    }