2015-05-04 7 views
13

Próbuję przechwycić wideo i wyświetlić go na ekranie, ustawiając teksturę Open GL ES na androida surfaceTexture. Nie mogę używać TextureView i implementować SurfaceTextureListener zgodnie z this tutorial, ponieważ używam Google Cardboard.Używanie strumienia wideo jako otwartej tekstury GL ES 2.0

Podążałem za the Android documentation o tym, jak zainicjować Open GL ES 2.0 i użyć go, a także this tutorial na teksturowaniu.

Łącząc 2, otrzymuję pusty ekran i od czasu do czasu otrzymuję <core_glBindTexture:572>: GL_INVALID_OPERATION w oknie konsoli.

Przytłoczony tak wieloma nowymi koncepcjami, których nie znam, nie jestem w stanie debugować lub po prostu zrozumieć, czy te dwie metody mogą być używane w ten sposób. Oto mój kod rysunkowy, jest on inicjowany w klasie onSurfaceCreated() klasy MainActivity i jest rysowany od onEyeDraw(), który jest funkcją rysowania kartonu.

package com.example.rich.test3; 

import android.hardware.Camera; 
import android.opengl.GLES20; 
import android.view.TextureView; 

import java.nio.ShortBuffer; 
import java.nio.FloatBuffer; 
import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 

/** 
* Created by rich on 03/05/2015. 
*/ 
public class Square { 

private java.nio.FloatBuffer vertexBuffer; 
private java.nio.ShortBuffer drawListBuffer; 
private final java.nio.FloatBuffer mCubeTextureCoordinates; 

float color[] = { 1.f, 1.f, 1.f, 1.0f }; 

private final String vertexShaderCode = 
     "attribute vec4 vPosition;" + 
     "attribute vec2 a_TexCoordinate;" + 
     "varying vec2 v_TexCoordinate;" + 
       "void main() {" + 
       " gl_Position = vPosition;" + 
       " v_TexCoordinate = a_TexCoordinate;" + 
       "}"; 

private final String fragmentShaderCode = 
     "precision mediump float;" + 
       "uniform vec4 vColor;" + 
       "uniform sampler2D u_Texture;" + 
       "varying vec2 v_TexCoordinate;" + 
       "void main() {" + 
       "gl_FragColor = (texture2D(u_Texture, v_TexCoordinate));" + 
       "}"; 

// number of coordinates per vertex in this array 
static final int COORDS_PER_VERTEX = 3; 
static float squareCoords[] = { 
     -0.5f, -0.5f, 0.0f, // bottom left 
     0.5f, -0.5f, 0.0f, // bottom right 
     -0.5f, 0.5f, 0.0f, // top left 
     0.5f, 0.5f, 0.0f}; // top right 

private short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices 

private int mProgram; 

private int mPositionHandle; 
private int mColorHandle; 
private int mTextureUniformHandle; 
private int mTextureCoordinateHandle; 
private final int mTextureCoordinateDataSize = 2; 

private final int vertexCount = squareCoords.length/COORDS_PER_VERTEX; 
private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex 

private int mTextureDataHandle; 

float textureCoordinates[] = 
     {0.0f, 1.0f, 
     1.0f, 1.0f, 
     0.0f, 0.0f, 
     1.0f, 0.0f }; 

Camera _camera; 
TextureView _textureView; 
int[] textures; 
android.graphics.SurfaceTexture _surface; 

public Square() 
{ 
    ByteBuffer bb = ByteBuffer.allocateDirect(
      // (# of coordinate values * 4 bytes per float) 
      squareCoords.length * 4); 
    bb.order(ByteOrder.nativeOrder()); 
    vertexBuffer = bb.asFloatBuffer(); 
    vertexBuffer.put(squareCoords); 
    vertexBuffer.position(0); 

    // initialize byte buffer for the draw list 
    ByteBuffer dlb = ByteBuffer.allocateDirect(
      // (# of coordinate values * 2 bytes per short) 
      drawOrder.length * 2); 
    dlb.order(ByteOrder.nativeOrder()); 
    drawListBuffer = dlb.asShortBuffer(); 
    drawListBuffer.put(drawOrder); 
    drawListBuffer.position(0); 

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

    // create empty OpenGL ES Program 
    mProgram = GLES20.glCreateProgram(); 

    textures = new int[1]; 
    GLES20.glGenTextures(1, textures, 0); 

    _surface = new android.graphics.SurfaceTexture(textures[0]); 
    _camera = Camera.open(); 
    Camera.Size previewSize = _camera.getParameters().getPreviewSize(); 

    try 
    { 
     _camera.setPreviewTexture(_surface); 
    } 
    catch (java.io.IOException ex) 
    { 
     // Console.writeLine (ex.Message); 
    } 

    final int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); 
    GLES20.glShaderSource(vertexShaderHandle, vertexShaderCode); 
    GLES20.glCompileShader(vertexShaderHandle); 
    final int[] compileStatus = new int[1]; 
    GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 
    if (compileStatus[0] == 0) 
    { 
     //do check here 
    } 

    final int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER); 
    GLES20.glShaderSource(fragmentShaderHandle, fragmentShaderCode); 
    GLES20.glCompileShader(fragmentShaderHandle); 
    GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 
    if (compileStatus[0] == 0) 
    { 
     //do check here 
    } 

    GLES20.glAttachShader(mProgram, vertexShaderHandle); 
    GLES20.glAttachShader(mProgram, fragmentShaderHandle); 
    GLES20.glBindAttribLocation(mProgram, 0, "a_Position"); 
    GLES20.glBindAttribLocation(mProgram, 0, "a_TexCoordinate"); 

    GLES20.glLinkProgram(mProgram); 
    final int[] linkStatus = new int[1]; 
    GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0); 
    if (linkStatus[0] == 0) 
    { 
     //do check here 
    } 

    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); 
    mTextureDataHandle = textures[0]; 

    // Set filtering 
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 
} 

public void draw() 
{ 
    _surface.updateTexImage(); 
    GLES20.glUseProgram(mProgram); 

    mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture"); 
    mPositionHandle = GLES20.glGetAttribLocation(mProgram, "a_Position"); 
    mColorHandle = GLES20.glGetAttribLocation(mProgram, "a_Color"); 
    mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate"); 

    GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle); 

    GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, 
      GLES20.GL_FLOAT, false, 
      vertexStride, vertexBuffer); 
    GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 
      0, mCubeTextureCoordinates); 

    GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle); 
    GLES20.glEnableVertexAttribArray(mPositionHandle); 
    GLES20.glUniform1i(mTextureUniformHandle, 0); 

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount); 
    GLES20.glDisableVertexAttribArray(mPositionHandle); 
} 

} 
+0

Znalazłeś https://github.com/google/grafika? Aktywność "tekstury z kamery" prawdopodobnie robi większość tego, co chcesz. – fadden

Odpowiedz

7

Podczas renderowania obiektu SurfaceTexture tekstury, trzeba używać target GL_TEXTURE_EXTERNAL_OES Tekstura:

Przedmiotem tekstury używa cel tekstury GL_TEXTURE_EXTERNAL_OES, który jest zdefiniowany przez rozszerzenie GL_OES_EGL_image_external OpenGL ES. Ogranicza to sposób wykorzystania tekstury. Za każdym razem, gdy tekst jest powiązany, musi być powiązany z celem GL_TEXTURE_EXTERNAL_OES, a nie z GL_TEXTURE_2D. Ponadto dowolny moduł cieniujący OpenGL ES 2.0, który pobiera próbki z tekstury, musi zadeklarować użycie tego rozszerzenia przy użyciu, na przykład, dyrektywy "#extension GL_OES_EGL_image_external: require". Takie shadery muszą również uzyskać dostęp do tekstury za pomocą samplera samplerExternalOES GLSL.

Więc trzeba zmienić fragment shader takiego, dodając oświadczenie #extension i deklarując swoją teksturę mundur jak samplerExternalOES:

private final String fragmentShaderCode = 
    "#extension GL_OES_EGL_image_external : require\n" + 
    "precision mediump float;" + 
    "uniform vec4 vColor;" + 
    "uniform samplerExternalOES u_Texture;" + 
    "varying vec2 v_TexCoordinate;" + 
    "void main() {" + 
      "gl_FragColor = (texture2D(u_Texture, v_TexCoordinate));" + 
    "}"; 

także w funkcji draw(), wiążą teksturę tak:

GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureDataHandle); 
+0

po prostu miał okazję wypróbować i uzyskać W/Adreno-ES20: : GL_INVALID_OPERATION –

+1

Możesz dostać ten błąd, jeśli wiążesz różne cele: https://www.khronos.org/opengles/sdk/ docs/man/xhtml/glBindTexture.xml nazywacie glBindTexture w konstruktorze, a także w draw(), zmień to, aby dobrze wykorzystać GLES11Ext.GL_TEXTURE_EXTERNAL_OES oraz – samgak

+0

. Teraz dostaję ten błąd W/Adreno-ES20: : GL_INVALID_VALUE. google nic nie wymyśli. czy widzisz coś, co może być przyczyną tego? –

3

Nie można użyć normalnej tekstury do renderowania podglądu kamery lub wideo, należy użyć rozszerzenia GL_TEXTURE_EXTERNAL_OES. Miałem ten sam problem i znalazłem kompletne działające rozwiązanie na Github. Nazwa projektu to android_instacam.

znajdziesz kod źródłowy do nauki. Jeśli chcesz zobaczyć to w akcji bezpośrednio na urządzeniu, po prostu wejdź do sklepu Play here.

+0

dzięki za link, wygląda bardzo podobnie do tego, co robię. –

Powiązane problemy