2015-08-04 16 views
22

Tôi mới đến với thế giới của Open Gl và tôi đã googled rất nhiều nhưng tôi không thể tìm thấy cách để triển khai Effects trên video đang được phát. Sau khi một số nghiên cứu tôi cuối cùng đã tìm thấy một class có thể được sử dụng để phát video trên GLSurfaceView. Và tôi biết từ Google documentation và chúng tôi có thể áp dụng hiệu ứng trên video.Áp dụng hiệu ứng trên video đang được chơi

Bằng cách thực hiện theo đây post tôi đã có thể áp dụng thành công hiệu ứng trên bitmap. Bây giờ tôi muốn làm điều đó cho video của tôi để bất kỳ trợ giúp hoặc con trỏ được đánh giá cao.

Here là VideoSurfaceView mà tôi đang sử dụng để Render video đang được chơi

package me.crossle.demo.surfacetexture; 

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.annotation.SuppressLint; 
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; 

@SuppressLint("ViewConstructor") 
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; 
     } 

     @Override 
     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(); 

     } 

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

     } 

     @Override 
     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); 
      mMediaPlayer.setScreenOnWhilePlaying(true); 
      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. 

Và đây là MainActivity tôi

package me.crossle.demo.surfacetexture; 

import java.io.File; 

import android.app.Activity; 
import android.content.res.AssetFileDescriptor; 
import android.content.res.Resources; 
import android.media.MediaPlayer; 
import android.os.Bundle; 
import android.os.Environment; 
import android.util.Log; 

public class MainActivity extends Activity { 

    private static final String TAG = "MainActivity"; 

    protected Resources mResources; 

    private VideoSurfaceView mVideoView = null; 
    private MediaPlayer mMediaPlayer = null; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     mResources = getResources(); 
     mMediaPlayer = new MediaPlayer(); 

     try { 
      File dir = Environment 
        .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); 

      File file = new File(dir, 
        "video.mp4"); 
      mMediaPlayer.setDataSource(file.getAbsolutePath()); 

     } catch (Exception e) { 
      Log.e(TAG, e.getMessage(), e); 
     } 

     mVideoView = new VideoSurfaceView(this, mMediaPlayer); 
     setContentView(mVideoView); 

    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     mVideoView.onResume(); 
    } 
} 
+1

tải lên bản trình diễn sẽ giúp phân tích vấn đề của bạn. –

+1

Đó là toàn bộ mã. Tôi chỉ cần biết nơi tôi có thể áp dụng hiệu ứng trong toàn bộ mã số –

+2

Tôi nghĩ rằng bạn phải sửa đổi trình đổ bóng phân đoạn để đạt được hiệu ứng trên video.Hãy thử thêm một số giá trị trong dòng này "gl_FragColor = texture2D (sTexture, vTextureCoord) + ; \ n" Để hiểu toàn bộ điều bạn cần một số hiểu biết về các trình đổ bóng Fragment và Vertex. – Lunero

Trả lời

25

tôi đã giải quyết được vấn đề này và tôi đang đăng câu trả lời trong trường hợp bất kỳ ai khác cũng đang tìm cách áp dụng các Bộ lọc khác nhau trên video của họ.

Sau khi được chỉ ra đúng hướng bởi LuneroFadden tôi hiện có thể áp dụng hầu như tất cả các hiệu ứng EffectFactory cho video đang phát. Mặc dù các hiệu ứng này chỉ dành cho mục đích xem trước không thay đổi video gốc nhưng vẫn thực hiện công việc cho tôi.

Điều tôi đã làm là tôi đã thay đổi mã FragmentShaders đã được áp dụng cho video đang được hiển thị và tôi có thể đạt được các hiệu ứng khác nhau.

Đây là mã cho một số fragmentShaders.

Black and White Effect

String fragmentShader = "#extension GL_OES_EGL_image_external : require\n" 
       + "precision mediump float;\n" 
       + "varying vec2 vTextureCoord;\n" 
       + "uniform samplerExternalOES sTexture;\n" 
       + "void main() {\n" 
       + " vec4 color = texture2D(sTexture, vTextureCoord);\n" 
       + " float colorR = (color.r + color.g + color.b)/3.0;\n" 
       + " float colorG = (color.r + color.g + color.b)/3.0;\n" 
       + " float colorB = (color.r + color.g + color.b)/3.0;\n" 
       + " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n" 
       + "}\n"; 

tác động tiêu cực

String fragmentShader = "#extension GL_OES_EGL_image_external : require\n" 
       + "precision mediump float;\n" 
       + "varying vec2 vTextureCoord;\n" 
       + "uniform samplerExternalOES sTexture;\n" 
       + "void main() {\n" 
       + " vec4 color = texture2D(sTexture, vTextureCoord);\n" 
       + " float colorR = (1.0 - color.r)/1.0;\n" 
       + " float colorG = (1.0 - color.g)/1.0;\n" 
       + " float colorB = (1.0 - color.b)/1.0;\n" 
       + " gl_FragColor = vec4(colorR, colorG, colorB, color.a);\n" 
       + "}\n"; 

Original video mà không cần bất kỳ hiệu ứng

enter image description here

video với Black and White Effect

Black and White Effect

video với hiệu ứng âm

Negative Effect

Nếu bạn muốn áp dụng hiệu ứng hơn sau đó tôi đề nghị bạn nhìn vào VidEffects trên github. Nó sẽ giúp bạn áp dụng nhiều hiệu ứng khác nhau cho video của bạn.

+0

Cảm ơn. Bất kỳ ý tưởng về cách mã của bạn có thể được thay đổi để áp dụng nhiều shaders liên tiếp? – Michael

+0

@Michael Một cách để làm điều đó là bằng cách gọi phương thức 'mVideoView.init (mMediaPlayer, DuotoneEffect (Color.YELLOW, Color.RED));' bất cứ khi nào bạn muốn thay đổi hiệu ứng. –

+2

@SherazAhmadKhilji làm thế nào để lưu video này trong sdcard sau khi áp dụng hiệu lực? –

Các vấn đề liên quan