Applying Effects on Video being Played

10,725

I have solved the issue and i am posting the answer in case anyone else is also looking for a way to apply different Filters on their video.

After being pointed out in the right direction by Lunero and Fadden i am now able to apply almost all EffectFactory effects to the video being played. Though these effects are only meant for preview purpose and do not change the original video but still they do the job for me.

What i did was that I changed the FragmentShaders code that was applied to the video being rendered and i was able to achieve different effects.

Here is the code for some 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";

Negative 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 = (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 without any Effect

enter image description here

Video with Black and White Effect

Black and White Effect

Video with Negative Effect

Negative Effect

If you like to apply more effects then i suggest you look at VidEffects on github. It will help you apply many different effects on your video.

Share:
10,725

Related videos on Youtube

Sheraz Ahmad Khilji
Author by

Sheraz Ahmad Khilji

I am an Android Developer and android can be a pain in the ass but what can i say, It's tough love so there will always be hurdles. So don't worry if you face those hurdles because i am here to help you overcome them. So Lets Get on with it \m/_

Updated on July 10, 2022

Comments

  • Sheraz Ahmad Khilji
    Sheraz Ahmad Khilji almost 2 years

    I am new to the world of Open Gl and I have googled a lot but i am unable to find a way to implement Effects on a video being played. After some research i have finally found a class that can be used to play video on a GLSurfaceView. And i know from Google documentation and that we can apply effects on a video.

    By following this post i was able to successfully apply effects on bitmaps. Now i want to do that for my video so any help or pointers is appreciated.

    Here is the VideoSurfaceView that i am using to Render Video that is being played

    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.
    

    And Here is my 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();
        }
    }
    
    • Lunero
      Lunero over 8 years
      I think you have to modify the fragment shader to achieve effects on the video. Try adding some value in this line " gl_FragColor = texture2D(sTexture, vTextureCoord) + <add some float>;\n" To understand the whole thing you need some understanding of Fragment and Vertex shaders.
    • fadden
      fadden over 8 years
      The documentation for Effect shows it being applied to a GLES texture. You would need to send the video output to a SurfaceTexture, execute the Effect on that texture, and then render the texture for display. You could, for example, take the "texture from Camera" activity from Grafika and add the Effect to draw(). github.com/google/grafika/blob/master/src/com/android/grafik‌​a/…
  • M.S.
    M.S. about 8 years
    Thanks. Any idea on how your code might be altered to apply multiple shaders in succession?
  • Mayank Sugandhi
    Mayank Sugandhi almost 8 years
    @SherazAhmadKhilji how to save this videos in sdcard after apply effect?
  • Chirag Shah
    Chirag Shah over 7 years
    @MayankSugandhi, any success for saving video?It will help me too.
  • Chirag Shah
    Chirag Shah over 7 years
    @SherazAhmadKhilji, any success for saving video?It will help me too.
  • Arati PAtel
    Arati PAtel about 7 years
    how to save video after applying effects?
  • Firdosh
    Firdosh about 7 years
    How to save and Share Video in sdcard after apply effect?
  • Rafael Sanches
    Rafael Sanches about 7 years
    another person needing to save the video. we've seen the FBO from the graphika, but not sure it makes sense
  • Harsh Bhavsar
    Harsh Bhavsar almost 6 years
    any 1 get effect expect sepia and grayscale for video filters?
  • Amrut Bidri
    Amrut Bidri almost 5 years
    How to blur and greyscale effect both at the same time? Is it possible to apply 2 effects at same time?