2015-08-04 6 views
22

Я новичок в мире Open Gl, и у меня много googled, но я не могу найти способ реализовать Effects на воспроизводимом видео. После некоторых исследований я наконец нашел class, который можно использовать для воспроизведения видео на GLSurfaceView. И я знаю от Google documentation и что мы можем применять эффекты к видео.Применение эффектов для воспроизводимого видео

После этого post я смог успешно применить эффекты к растровым изображениям. Теперь я хочу сделать это для своего видео, поэтому любая помощь или указатели оцениваются.

Here является VideoSurfaceView, что я использую для рендеринга видео, которую играют

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. 

И вот мой MainActivity

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

Загрузка демонстрации поможет проанализировать вашу проблему. –

+1

Вот и весь код. Мне просто нужно знать, где я могу применять эффекты во всем коде –

+2

Думаю, вам нужно изменить шейдер фрагмента для достижения эффектов на видео.Попробуйте добавить некоторое значение в эту строку «gl_FragColor = texture2D (sTexture, vTextureCoord) + <добавить некоторый float>; \ n" Чтобы понять все, вам нужно некоторое понимание шейдеров Фрагмента и Вершины. – Lunero

ответ

25

Я решил эту проблему, и я отправляю ответ в Если кто-то еще ищет способ применения разных фильтров на своем видео.

После того, как указали в нужном направлении на Lunero и Fadden, теперь я могу применить практически все эффекты EffectFactory к воспроизводимому видео. Хотя эти эффекты предназначены только для Цель предварительного просмотра и не изменяют оригинальное видео, но все же они выполняют эту работу для меня.

Что я сделал, так это то, что я изменил код FragmentShaders, который был применен к визуализируемому видео, и я смог добиться различных эффектов.

Вот код для некоторых fragmentShaders.

Черно-белого эффект

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

Отрицательного эффект

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

Оригинальное видео без эффекта

enter image description here

Видео с черно-белый эффект

Black and White Effect

видео с отрицательным эффектом

Negative Effect

Если вы хотите применить несколько эффектов, то я предлагаю вам взглянуть на VidEffects на GitHub. Это поможет вам применить много разных эффектов к вашему видео.

+0

Спасибо. Любая идея о том, как ваш код может быть изменен для одновременного применения нескольких шейдеров? – Michael

+0

@Michael. Один из способов сделать это - вызвать метод mVideoView.init (mMediaPlayer, новый метод DuotoneEffect (Color.YELLOW, Color.RED)), когда вы хотите изменить эффекты. –

+2

@SherazAhmadKhilji Как сохранить это видео в sdcard после применения эффекта? –

Смежные вопросы