2012-08-26 23 views
8

Ho riscontrato un problema con la conversione dell'anteprima della videocamera in Android dal formato YUV a RGB. Lo scopo della conversione è applicare alcuni effetti. Provo a convertire da framment shader perché la conversione per codice nativo è lenta (circa 14fps). Il riferimento che ho usato è http://jyrom.tistory.com/m/post/view/id/187. Provo a portare questo codice alla piattaforma Android, ma il risultato sono rettangoli nero-verde. Ma posso vedere un po 'di forma attraverso l'output che ottengo. Potrebbe per favore cercare di aiutarmi a risolvere questo problema. Credo che questo sia un problema popolare: applicare effetti all'anteprima della fotocamera. Fornisco anche un collegamento al mio progetto per i test: https://dl.dropbox.com/u/12829395/application/FilterGL/FilterGL.zip. Grazie.
aggiornamento:
Questo è il mio onPreviewFrame metodo: Conversione da YUV a RGB con framment shader

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

Questo è come mi legano array di byte a OpenGL texture in onDrawFrame metodo:

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

E questo è il mio codice shader frammento:

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

risposta

3

Non so se avete già fissato questo problem.My risposta

  1. Per output predefinito fotocamera è NV12, ma nel frammento di shader YUV a RGB si utilizza YV12 -> RGB. Si dovrà fare setPreviewFormat(ImageFormat.YV12);, o può essere utilizzare qualche altro Shader
  2. Ci sono 3 texture, assicuratevi di fare

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

    prima di chiamare a qualsiasi glTexImage2D. e glTexSubImage2D

  3. È inoltre possibile utilizzare glTexSubImage2D con ogni frame e glTexImage2D una volta.

  4. dimensione di U e V è stesso, atleast per YV12,

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

    dovrebbe essere System.arraycopy(data, U_INDEX, uData, 0, LENGTH_4); modifica le dimensioni di conseguenza nel codice.

1

Infine, il progetto ha mostrato le anteprime delle telecamere. Ho trovato 2 problemi: 1. Prima di legare e modificare le caratteristiche della superficie, è necessario chiamare GLES20.glActiveTexture (GLES20.surfacenumber); 2. Il problema più importante e nascosto è che GLES20.glTexImage2D() non funziona con larghezza e altezza, che non sono potenza di 2 numeri. Dopo aver caricato la trama con le dimensioni, ad esempio 1024X1024, è necessario chiamare GLES20.glTexSubImage2D()

Buona fortuna!

2

Non so se hai risolto il tuo problema.

Ho usato il tuo codice e ho risolto in questa modalità.

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

}

1

Per il modo più veloce e ottimizzata, basta utilizzare il comune GL Estensione

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

Than in 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; 

In Java GL Discussione

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

La conversione del colore è già fatta per te. Puoi fare ciò che vuoi direttamente nello shader Fragment.

Speranza che ti fa risparmiare un po 'di tempo nella tua ricerca.

0

Ho applicato il modulo di soluzione How to render Android's YUV-NV21 camera image on the background in libgdx with OpenGLES 2.0 in real-time? al progetto condiviso nella domanda e ottenuto un progetto di lavoro. Se sei come me alla ricerca di un codice tutorial che comporti la conversione da YUV a RGB con framment shader, puoi semplicemente fare i seguenti passi per ottenere un esempio funzionante.

  1. Scaricare il progetto https://dl.dropbox.com/u/12829395/application/FilterGL/FilterGL.zip e decomprimere.
  2. Sostituisci file GLRenderer.java e res/raw/f_convert.glsl interamente dal codice condiviso di seguito.
  3. Aprire il progetto in Eclipse o import the project to Android Studio.

I temi principali del codice in questione sono:

  1. senza GLES20.glActiveTexture (GLES20.GL_TEXTURE1);, yBuffer non viene passato a GL.
  2. i dati YUV acquisiscono il formato YUV-NV21 e u_texture e v_texture non sono stati passati e gestiti correttamente nello shader. Fare riferimento a this post per ulteriori informazioni.

Ora il codice corretto: si prega di sostituire GLRenderer.java con

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

} 

e sostituire f_convert.glsl con

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