2012-02-21 22 views
16

需要幫助Android。如何播放視頻上表面(OpenGL的)

  1. 如何在Android中播放視頻上Surface(OpenGL)? 我試着在mySurfaceView extends SurfaceView播放視頻,幫助方法setSurface()MediaPlayer

    SurfaceTexture mTexture = new SurfaceTexture(texture_id); 
    Surface mSurface = new Surface(mTexture); 
    MediaPlayer mp = new MediaPlayer(); 
    mp.setSurface(mSurface); 
    

我只拿到了播放音頻 - 視頻不是在玩。

  1. 如何讓視頻緩衝區發送到OpenGL
  2. 如何播放視頻GLTexture
+0

可能重複[如何在Android上的OpenGL播放視頻?](http://stackoverflow.com/questions/9363162/how-to-play-video-in-opengl-on-android) – Bart 2012-02-21 10:11:20

+1

@Bart'這個問題是由其作者自願刪除的,就是它所說的。 – SERPRO 2012-02-21 10:51:24

+0

@SERPRO然後他在提出這個問題之後這樣做,它基本上是一樣的。 – Bart 2012-02-21 12:20:39

回答

1

我猜你不行。至少這就是我發現的。 我的計劃是在播放視頻時有某種OpenGL場景(文本標記)。 由於android使用硬件解碼來顯示視頻,因此不會使用OpenGL完成。我也嘗試使用ffmpeg在OpenGL中播放視頻,但是我發現,沒有我嘗試過的設備,性能足以通過ffmpeg進行SW解碼。

所以我不得不使用VideoView來顯示我的視頻並將GLSurfaceView放在上面,以查看我的報價文本。 但是你必須讓GLSurfaceView變得像半透明一樣在ApiDemos中完成'TranslucentGLSurfaceViewActivity'。

我意識到的另一件事:如果你把一個GLSurfaceView放在VideoView的頂部,你的fps會從60fps(opengl)大幅降低到30-40fps。 這適用於我測試的所有Android 2.x版本。 上週我有機會在Android 4上測試它,這一次我沒有在fps中分解。也許他們真的改進了ICS的圖形管道。

問候,-chris-

18

從Android源代碼...

import java.io.IOException; 
import java.nio.ByteBuffer; 
import java.nio.ByteOrder; 
import java.nio.FloatBuffer; 

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

import android.content.Context; 
import android.graphics.SurfaceTexture; 
import android.media.MediaPlayer; 
import android.opengl.GLES20; 
import android.opengl.GLSurfaceView; 
import android.opengl.Matrix; 
import android.util.Log; 
import android.view.Surface; 

class VideoSurfaceView extends GLSurfaceView { 

    VideoRender mRenderer; 
    private MediaPlayer mMediaPlayer = null; 

    public VideoSurfaceView(Context context, MediaPlayer mp) { 
     super(context); 

     setEGLContextClientVersion(2); 
     mMediaPlayer = mp; 
     mRenderer = new VideoRender(context); 
     setRenderer(mRenderer); 
    } 

    @Override 
    public void onResume() { 
     queueEvent(new Runnable(){ 
       public void run() { 
        mRenderer.setMediaPlayer(mMediaPlayer); 
       }}); 

     super.onResume(); 
    } 

    private static class VideoRender 
     implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener { 
     private static String TAG = "VideoRender"; 

     private static final int FLOAT_SIZE_BYTES = 4; 
     private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; 
     private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; 
     private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; 
     private final float[] mTriangleVerticesData = { 
      // X, Y, Z, U, V 
      -1.0f, -1.0f, 0, 0.f, 0.f, 
      1.0f, -1.0f, 0, 1.f, 0.f, 
      -1.0f, 1.0f, 0, 0.f, 1.f, 
      1.0f, 1.0f, 0, 1.f, 1.f, 
     }; 

     private FloatBuffer mTriangleVertices; 

     private final String mVertexShader = 
       "uniform mat4 uMVPMatrix;\n" + 
       "uniform mat4 uSTMatrix;\n" + 
       "attribute vec4 aPosition;\n" + 
       "attribute vec4 aTextureCoord;\n" + 
       "varying vec2 vTextureCoord;\n" + 
       "void main() {\n" + 
       " gl_Position = uMVPMatrix * aPosition;\n" + 
       " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" + 
       "}\n"; 

     private final String mFragmentShader = 
       "#extension GL_OES_EGL_image_external : require\n" + 
       "precision mediump float;\n" + 
       "varying vec2 vTextureCoord;\n" + 
       "uniform samplerExternalOES sTexture;\n" + 
       "void main() {\n" + 
       " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" + 
       "}\n"; 

     private float[] mMVPMatrix = new float[16]; 
     private float[] mSTMatrix = new float[16]; 

     private int mProgram; 
     private int mTextureID; 
     private int muMVPMatrixHandle; 
     private int muSTMatrixHandle; 
     private int maPositionHandle; 
     private int maTextureHandle; 

     private SurfaceTexture mSurface; 
     private boolean updateSurface = false; 

     private static int GL_TEXTURE_EXTERNAL_OES = 0x8D65; 

     private MediaPlayer mMediaPlayer; 

     public VideoRender(Context context) { 
      mTriangleVertices = ByteBuffer.allocateDirect(
       mTriangleVerticesData.length * FLOAT_SIZE_BYTES) 
        .order(ByteOrder.nativeOrder()).asFloatBuffer(); 
      mTriangleVertices.put(mTriangleVerticesData).position(0); 

      Matrix.setIdentityM(mSTMatrix, 0); 
     } 

     public void setMediaPlayer(MediaPlayer player) { 
      mMediaPlayer = player; 
     } 

     public void onDrawFrame(GL10 glUnused) { 
      synchronized(this) { 
       if (updateSurface) { 
        mSurface.updateTexImage(); 
        mSurface.getTransformMatrix(mSTMatrix); 
        updateSurface = false; 
       } 
      } 

      GLES20.glClearColor(0.0f, 1.0f, 0.0f, 1.0f); 
      GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT); 

      GLES20.glUseProgram(mProgram); 
      checkGlError("glUseProgram"); 

      GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 
      GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID); 

      mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); 
      GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, 
       TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); 
      checkGlError("glVertexAttribPointer maPosition"); 
      GLES20.glEnableVertexAttribArray(maPositionHandle); 
      checkGlError("glEnableVertexAttribArray maPositionHandle"); 

      mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); 
      GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT, false, 
       TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); 
      checkGlError("glVertexAttribPointer maTextureHandle"); 
      GLES20.glEnableVertexAttribArray(maTextureHandle); 
      checkGlError("glEnableVertexAttribArray maTextureHandle"); 

      Matrix.setIdentityM(mMVPMatrix, 0); 
      GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0); 
      GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0); 

      GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); 
      checkGlError("glDrawArrays"); 
      GLES20.glFinish(); 

     } 

     public void onSurfaceChanged(GL10 glUnused, int width, int height) { 

     } 

     public void onSurfaceCreated(GL10 glUnused, EGLConfig config) { 
      mProgram = createProgram(mVertexShader, mFragmentShader); 
      if (mProgram == 0) { 
       return; 
      } 
      maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); 
      checkGlError("glGetAttribLocation aPosition"); 
      if (maPositionHandle == -1) { 
       throw new RuntimeException("Could not get attrib location for aPosition"); 
      } 
      maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord"); 
      checkGlError("glGetAttribLocation aTextureCoord"); 
      if (maTextureHandle == -1) { 
       throw new RuntimeException("Could not get attrib location for aTextureCoord"); 
      } 

      muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); 
      checkGlError("glGetUniformLocation uMVPMatrix"); 
      if (muMVPMatrixHandle == -1) { 
       throw new RuntimeException("Could not get attrib location for uMVPMatrix"); 
      } 

      muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix"); 
      checkGlError("glGetUniformLocation uSTMatrix"); 
      if (muSTMatrixHandle == -1) { 
       throw new RuntimeException("Could not get attrib location for uSTMatrix"); 
      } 


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

      mTextureID = textures[0]; 
      GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID); 
      checkGlError("glBindTexture mTextureID"); 

      GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, 
            GLES20.GL_NEAREST); 
      GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, 
            GLES20.GL_LINEAR); 

      /* 
      * Create the SurfaceTexture that will feed this textureID, 
      * and pass it to the MediaPlayer 
      */ 
      mSurface = new SurfaceTexture(mTextureID); 
      mSurface.setOnFrameAvailableListener(this); 

      Surface surface = new Surface(mSurface); 
      mMediaPlayer.setSurface(surface); 
      surface.release(); 

      try { 
       mMediaPlayer.prepare(); 
      } catch (IOException t) { 
       Log.e(TAG, "media player prepare failed"); 
      } 

      synchronized(this) { 
       updateSurface = false; 
      } 

      mMediaPlayer.start(); 
     } 

     synchronized public void onFrameAvailable(SurfaceTexture surface) { 
      updateSurface = true; 
     } 

     private int loadShader(int shaderType, String source) { 
      int shader = GLES20.glCreateShader(shaderType); 
      if (shader != 0) { 
       GLES20.glShaderSource(shader, source); 
       GLES20.glCompileShader(shader); 
       int[] compiled = new int[1]; 
       GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); 
       if (compiled[0] == 0) { 
        Log.e(TAG, "Could not compile shader " + shaderType + ":"); 
        Log.e(TAG, GLES20.glGetShaderInfoLog(shader)); 
        GLES20.glDeleteShader(shader); 
        shader = 0; 
       } 
      } 
      return shader; 
     } 

     private int createProgram(String vertexSource, String fragmentSource) { 
      int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); 
      if (vertexShader == 0) { 
       return 0; 
      } 
      int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); 
      if (pixelShader == 0) { 
       return 0; 
      } 

      int program = GLES20.glCreateProgram(); 
      if (program != 0) { 
       GLES20.glAttachShader(program, vertexShader); 
       checkGlError("glAttachShader"); 
       GLES20.glAttachShader(program, pixelShader); 
       checkGlError("glAttachShader"); 
       GLES20.glLinkProgram(program); 
       int[] linkStatus = new int[1]; 
       GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); 
       if (linkStatus[0] != GLES20.GL_TRUE) { 
        Log.e(TAG, "Could not link program: "); 
        Log.e(TAG, GLES20.glGetProgramInfoLog(program)); 
        GLES20.glDeleteProgram(program); 
        program = 0; 
       } 
      } 
      return program; 
     } 

     private void checkGlError(String op) { 
      int error; 
      while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 
       Log.e(TAG, op + ": glError " + error); 
       throw new RuntimeException(op + ": glError " + error); 
      } 
     } 

    } // End of class VideoRender. 

} // End of class VideoSurfaceView. 
+0

在github上的演示https://github.com/crossle/MediaPlayerSurface – crossle 2014-03-09 07:36:39

+0

你能提供一個如何保持視頻寬高比的例子嗎?舉例來說,只有拉伸高度,但仍然保持縱橫比? – Florian 2014-03-10 10:21:02

+0

你可以看到https://github.com/yixia/VitamioBundle/blob/master/vitamio-sample/src/io/vov/vitamio/demo/VideoViewSubtitle.java – crossle 2014-03-10 10:23:17

0
mMediaPlayer.setSurface(new Surface(mSurfaceTexture)); 

您可以使用上面的代碼行超過您所需的表面紋理用它在你的mediaPlayerObject這是一個在您的表面視圖中應用紋理。

希望有所幫助。