ijkplayer添加滤镜java版

上一篇是c代码版,想想还是写个java版,毕竟在java上进行很多操作比用c代码编写再编译来的方便很多,比如读取图片,添加gif之类的。

效果就不演示了,和上一篇一样我只加了个黑白滤镜,参考的还是这篇让IjkPlayer支持插入自定义的GPU滤镜,可能是版本问题吧,有些方法是不一样的,我的ijkplayer版本是0.8.4,开始改代码

ijkmedia/ijksdl/gles2/internal.h的IJK_GLES2_Renderer结构体内添加

typedef struct IJK_GLES2_Renderer
{
    ...//省略代码
    int has_filter;
    void (* func_onCreated)(void);
    void (* func_onSizeChanged)(int width,int height);
    void (* func_onDrawFrame)(int textureId);
    void (* func_onTexcoords)(float *texcoords);
    void (* func_onVertices)(float *vertices);
    void (* func_onRelease)(void);

    int view_width;
    int view_height;

    GLuint frame_buffers[1];
    GLuint frame_textures[1];

    GLfloat texcoords_test[8];

    GLfloat vertices_test[8];

   
} IJK_GLES2_Renderer;
ijkmedia/ijksdl/ijksdl_vout.h的SDL_Vout和SDL_VoutOverlay结构体内添加

struct SDL_VoutOverlay {
    ...//省略代码
    int has_filter;
    void (* func_onCreated)(void);
    void (* func_onSizeChanged)(int width,int height);
    void (* func_onDrawFrame)(int textureId);
    void (* func_onTexcoords)(float *texcoords);
    void (* func_onVertices)(float *vertices);
    void (* func_onRelease)(void);

};
struct SDL_Vout {
    ...//省略代码
    int has_filter;
    void (* func_onCreated)(void);
    void (* func_onSizeChanged)(int width,int height);
    void (* func_onDrawFrame)(int textureId);
    void (* func_onTexcoords)(float *texcoords);
    void (* func_onVertices)(float *vertices);
    void (* func_onRelease)(void);

};
ijkmedia/ijkplayer/android/ijkplayer_android.h添加函数

void ijkmp_android_set_filter(IjkMediaPlayer *mp,int has_filter,void *onCreated,void *onSizeChanged,void *onDrawFrame,void *onTexcoords,void *onVertices,void *onRelease);
ijkmedia/ijkplayer/android/ijkplayer_android.c内添加函数

void ijkmp_android_set_filter(IjkMediaPlayer *mp,int has_filter,void *onCreated,void *onSizeChanged,void *onDrawFrame,void *onTexcoords,void *onVertices,void *onRelease){
    mp->ffplayer->vout->has_filter = has_filter;
    if(has_filter == 1){
        mp->ffplayer->vout->func_onCreated=onCreated;
        mp->ffplayer->vout->func_onSizeChanged=onSizeChanged;
        mp->ffplayer->vout->func_onDrawFrame=onDrawFrame;
        mp->ffplayer->vout->func_onTexcoords=onTexcoords;
        mp->ffplayer->vout->func_onVertices=onVertices;
        mp->ffplayer->vout->func_onRelease=onRelease;
    }

}
ijkmedia/ijksdl/android/ijksdl_vout_android_nativewindow.c的func_create_overlay()函数内添加

static SDL_VoutOverlay *func_create_overlay(int width, int height, int frame_format, SDL_Vout *vout)
{
    SDL_LockMutex(vout->mutex);
    SDL_VoutOverlay *overlay = func_create_overlay_l(width, height, frame_format, vout);


    overlay->has_filter=vout->has_filter;
    overlay->func_onCreated=vout->func_onCreated;
    overlay->func_onSizeChanged=vout->func_onSizeChanged;
    overlay->func_onDrawFrame=vout->func_onDrawFrame;
    overlay->func_onTexcoords=vout->func_onTexcoords;
    overlay->func_onVertices=vout->func_onVertices;
    overlay->func_onRelease=vout->func_onRelease;


    SDL_UnlockMutex(vout->mutex);
    return overlay;
}
ijkmedia/ijksdl/gles2/renderer.c的IJK_GLES2_Renderer_create()函数内添加

IJK_GLES2_Renderer *IJK_GLES2_Renderer_create(SDL_VoutOverlay *overlay)
{
    ...//省略代码
    renderer->has_filter=overlay->has_filter;
    renderer->func_onCreated=overlay->func_onCreated;
    renderer->func_onSizeChanged=overlay->func_onSizeChanged;
    renderer->func_onDrawFrame=overlay->func_onDrawFrame;
    renderer->func_onTexcoords=overlay->func_onTexcoords;
    renderer->func_onVertices=overlay->func_onVertices;
    renderer->func_onRelease=overlay->func_onRelease;

    return renderer;
}
然后在 ijkmedia/ijkplayer/android/ijkplayer_jni.c内添加代码

static JNIEnv * mEnv;
static jmethodID onCreatedMethod;
static jmethodID onSizeChangedMethod;
static jmethodID onDrawFrameMethod;
static jmethodID onTexcoordsMethod;
static jmethodID onVerticesMethod;
static jmethodID onReleaseMethod;
void onCreated(){
    if(!mEnv){
        (*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
        jclass filterClass=(*mEnv)->GetObjectClass(mEnv,mFilter);
        onCreatedMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onCreated","()V");
        onSizeChangedMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onSizeChanged","(II)V");
        onDrawFrameMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onDrawFrame","(I)V");
        onTexcoordsMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onTexcoords","([F)V");
        onVerticesMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onVertices","([F)V");
        onReleaseMethod=(*mEnv)->GetMethodID(mEnv,filterClass,"onRelease","()V");
        (*g_jvm)->DetachCurrentThread(g_jvm);
    }
    if(onCreatedMethod){
        (*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
        (*mEnv)->CallVoidMethod(mEnv,mFilter,onCreatedMethod);
        (*g_jvm)->DetachCurrentThread(g_jvm);
    }
}

void onSizeChanged(int width,int height){
    if(onSizeChangedMethod){
        (*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
        (*mEnv)->CallVoidMethod(mEnv,mFilter,onSizeChangedMethod,width,height);
        (*g_jvm)->DetachCurrentThread(g_jvm);
    }
}

void onDrawFrame(int textureId){
    if(onDrawFrameMethod){
        (*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
        (*mEnv)->CallVoidMethod(mEnv,mFilter,onDrawFrameMethod,textureId);
        (*g_jvm)->DetachCurrentThread(g_jvm);
    }
}
void onTexcoords(float *texcoords){
    if(onTexcoordsMethod){
        (*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
        jfloatArray array = (*mEnv)->NewFloatArray(mEnv,8);
        (*mEnv)->SetFloatArrayRegion(mEnv,array, 0, 8, texcoords);
        (*mEnv)->CallVoidMethod(mEnv,mFilter,onTexcoordsMethod,array);
        (*mEnv)->DeleteLocalRef(mEnv, array);
        (*g_jvm)->DetachCurrentThread(g_jvm);
    }
}
void onVertices(float *vertices){
    if(onVerticesMethod){
        (*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
        jfloatArray array = (*mEnv)->NewFloatArray(mEnv,8);
        (*mEnv)->SetFloatArrayRegion(mEnv,array, 0, 8, vertices);
        (*mEnv)->CallVoidMethod(mEnv,mFilter,onVerticesMethod,array);
        (*mEnv)->DeleteLocalRef(mEnv, array);
        (*g_jvm)->DetachCurrentThread(g_jvm);
    }
}
void onRelease(){
    if(onReleaseMethod){
        (*g_jvm)->AttachCurrentThread(g_jvm,&mEnv,NULL);
        (*mEnv)->CallVoidMethod(mEnv,mFilter,onReleaseMethod);
        (*g_jvm)->DetachCurrentThread(g_jvm);
    }

}
static void IjkMediaPlayer_native_setGLFilter(JNIEnv *env,jobject thiz,jobject filter)
{
    if(mFilter){
        (*env)->DeleteGlobalRef(env,mFilter);
    }
    IjkMediaPlayer *mp = jni_get_media_player(env, thiz);

    if(filter!=NULL){
        mFilter=(*env)->NewGlobalRef(env,filter);
        ijkmp_android_set_filter(mp,1,onCreated,onSizeChanged,onDrawFrame,onTexcoords,onVertices,onRelease);
    }else{
        ijkmp_android_set_filter(mp,0,NULL,NULL,NULL,NULL,NULL,NULL);
    }

}
在g_methods[]内添加

{ "_setGLFilter",           "(Ltv/danmaku/ijk/media/player/IjkFilter;)V", (void *) IjkMediaPlayer_native_setGLFilter },
在函数IjkMediaPlayer_release()内添加

if(mFilter){
    (*env)->DeleteGlobalRef(env,mFilter);
    mFilter=NULL;
}

好了,接下来就是改ijkmedia/ijksdl/gles2/renderer.c的代码了,从上到下把要修改的地方都说一下

在IJK_GLES2_Renderer_reset()函数内添加

void IJK_GLES2_Renderer_reset(IJK_GLES2_Renderer *renderer)
{
    ...// 省略代码
    if(renderer->frame_textures){
        glDeleteTextures(1, renderer->frame_textures);
        renderer->frame_textures[0] = 0;
    }
    if(renderer->frame_buffers){
        glDeleteBuffers(1,renderer->frame_buffers);
        renderer->frame_buffers[0] = 0;
    }
    if(renderer->has_filter){
        renderer->func_onRelease();
    }
}
在IJK_GLES2_Renderer_create_base()内添加

IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_base(const char *fragment_shader_source)
{
    ...//省略代码
    renderer->texcoords_test[0] = 0.0f;
    renderer->texcoords_test[1] = 1.0f;
    renderer->texcoords_test[2] = 1.0f;
    renderer->texcoords_test[3] = 1.0f;
    renderer->texcoords_test[4] = 0.0f;
    renderer->texcoords_test[5] = 0.0f;
    renderer->texcoords_test[6] = 1.0f;
    renderer->texcoords_test[7] = 0.0f;



    renderer->vertices_test[0] = -1.0f;
    renderer->vertices_test[1] = -1.0f;
    renderer->vertices_test[2] =  1.0f;
    renderer->vertices_test[3] = -1.0f;
    renderer->vertices_test[4] = -1.0f;
    renderer->vertices_test[5] =  1.0f;
    renderer->vertices_test[6] =  1.0f;
    renderer->vertices_test[7] =  1.0f;

    return renderer;
    ...//省略代码
    return NULL;
}
在IJK_GLES2_Renderer_Vertices_apply()添加

static void IJK_GLES2_Renderer_Vertices_apply(IJK_GLES2_Renderer *renderer)
{
    ...//省略代码
    if(renderer->has_filter){
        renderer->func_onVertices(renderer->vertices);
    }

}
修改IJK_GLES2_Renderer_Vertices_reloadVertex()

static void IJK_GLES2_Renderer_Vertices_reloadVertex(IJK_GLES2_Renderer *renderer)
{
    glVertexAttribPointer(renderer->av4_position, 2, GL_FLOAT, GL_FALSE, 0, renderer->vertices_test);    IJK_GLES2_checkError_TRACE("glVertexAttribPointer(av2_texcoord)");
    glEnableVertexAttribArray(renderer->av4_position);                                                   IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(av2_texcoord)");
}
在IJK_GLES2_Renderer_TexCoords_cropRight()添加

static void IJK_GLES2_Renderer_TexCoords_cropRight(IJK_GLES2_Renderer *renderer, GLfloat cropRight)
{
    ...//省略代码
    if(renderer->has_filter){
        renderer->func_onTexcoords(renderer->texcoords);
    }
}
修改IJK_GLES2_Renderer_TexCoords_reloadVertex()

static void IJK_GLES2_Renderer_TexCoords_reloadVertex(IJK_GLES2_Renderer *renderer)
{
    glVertexAttribPointer(renderer->av2_texcoord, 2, GL_FLOAT, GL_FALSE, 0, renderer->texcoords_test);   IJK_GLES2_checkError_TRACE("glVertexAttribPointer(av2_texcoord)");
    glEnableVertexAttribArray(renderer->av2_texcoord);                                              IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(av2_texcoord)");
}
还是那句我忘了IJK_GLES2_Renderer_use()内改了什么就直接贴全部代码

GLboolean IJK_GLES2_Renderer_use(IJK_GLES2_Renderer *renderer)
{
    if (!renderer)
        return GL_FALSE;

    assert(renderer->func_use);
    if (!renderer->func_use(renderer))
        return GL_FALSE;

    IJK_GLES2_Renderer_TexCoords_reset(renderer);

    IJK_GLES2_Renderer_Vertices_reset(renderer);

    return GL_TRUE;
}
差点忘了IJK_GLES2_Renderer_set_view_size()了, ijkmedia/ijksdl/ijksdl_gles2.h内添加函数

void IJK_GLES2_Renderer_set_view_size(IJK_GLES2_Renderer *renderer,int width,int height);
在ijkmedia/ijksdl/ijksdl_egl.c的IJK_EGL_prepareRenderer()内添加代码

static EGLBoolean IJK_EGL_prepareRenderer(IJK_EGL* egl, SDL_VoutOverlay *overlay)
{
    ...//省略代码
    IJK_GLES2_Renderer_set_view_size(opaque->renderer,egl->width, egl->height);
    return EGL_TRUE;
}
ijkmedia/ijksdl/gles2/renderer.c内添加

void IJK_GLES2_Renderer_set_view_size(IJK_GLES2_Renderer *renderer,int width,int height){
    renderer->view_width = width;
    renderer->view_height = height;
}
回到 renderer.c,最后改IJK_GLES2_Renderer_renderOverlay()

GLboolean IJK_GLES2_Renderer_renderOverlay(IJK_GLES2_Renderer *renderer, SDL_VoutOverlay *overlay)
{
    GLsizei visible_width  = renderer->frame_width;
    GLsizei visible_height = renderer->frame_height;
    if (overlay) {
        visible_width  = overlay->w;
        visible_height = overlay->h;
        if (renderer->frame_width   != visible_width    ||
            renderer->frame_height  != visible_height   ||
            renderer->frame_sar_num != overlay->sar_num ||
            renderer->frame_sar_den != overlay->sar_den) {

            renderer->frame_width   = visible_width;
            renderer->frame_height  = visible_height;
            renderer->frame_sar_num = overlay->sar_num;
            renderer->frame_sar_den = overlay->sar_den;

            renderer->vertices_changed = 1;
        }

        renderer->last_buffer_width = renderer->func_getBufferWidth(renderer, overlay);

        if (!renderer->func_uploadTexture(renderer, overlay))
            return GL_FALSE;
    } else {
        // NULL overlay means force reload vertice
        renderer->vertices_changed = 1;
    }



    GLsizei buffer_width = renderer->last_buffer_width;
    if (renderer->vertices_changed ||
        (buffer_width > 0 &&
         buffer_width > visible_width &&
         buffer_width != renderer->buffer_width &&
         visible_width != renderer->visible_width)){


        renderer->vertices_changed = 0;

        IJK_GLES2_Renderer_Vertices_apply(renderer);


        renderer->buffer_width  = buffer_width;
        renderer->visible_width = visible_width;

        GLsizei padding_pixels     = buffer_width - visible_width;
        GLfloat padding_normalized = ((GLfloat)padding_pixels) / buffer_width;

        IJK_GLES2_Renderer_TexCoords_reset(renderer);
        IJK_GLES2_Renderer_TexCoords_cropRight(renderer, padding_normalized);
    }



    if (!renderer || !renderer->func_uploadTexture)
        return GL_FALSE;
    if(renderer->has_filter&&!renderer->frame_buffers[0]&&renderer->frame_width>0&&renderer->frame_height>0){

        glGenTextures(1,renderer->frame_textures);
        glBindTexture(GL_TEXTURE_2D,renderer->frame_textures[0]);
        glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,renderer->frame_width,renderer->frame_height,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glBindTexture(GL_TEXTURE_2D,0);


        glGenFramebuffers(1,renderer->frame_buffers);
        glBindFramebuffer(GL_FRAMEBUFFER,renderer->frame_buffers[0]);
        glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,renderer->frame_textures[0],0);

        glBindFramebuffer(GL_FRAMEBUFFER,0);
        renderer->func_onCreated();
        renderer->func_onSizeChanged(renderer->view_width, renderer->view_height);
    }

    if(renderer->has_filter&&renderer->frame_buffers[0]){
        glBindFramebuffer(GL_FRAMEBUFFER,renderer->frame_buffers[0]);
    }


    renderer->func_use(renderer);

    glViewport(0, 0, renderer->frame_width, renderer->frame_height);  IJK_GLES2_checkError_TRACE("glViewport");


    glClear(GL_COLOR_BUFFER_BIT);               IJK_GLES2_checkError_TRACE("glClear");


    IJK_GLES_Matrix modelViewProj;
    IJK_GLES2_loadOrtho(&modelViewProj, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
    glUniformMatrix4fv(renderer->um4_mvp, 1, GL_FALSE, modelViewProj.m);                    IJK_GLES2_checkError_TRACE("glUniformMatrix4fv(um4_mvp)");

    IJK_GLES2_Renderer_TexCoords_reloadVertex(renderer);
    IJK_GLES2_Renderer_Vertices_reloadVertex(renderer);


    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);      IJK_GLES2_checkError_TRACE("glDrawArrays");

    if(renderer->has_filter&&renderer->frame_buffers[0]){
        glBindFramebuffer(GL_FRAMEBUFFER,0);
        renderer->func_onDrawFrame(renderer->frame_textures[0]);
    }

    return GL_TRUE;
}
好了,可能忘了一些代码,我会在最后放上源码,可以下载来看看

接下来就是改java代码了,java还是很简单的,在tv/danmaku/ijk/media/player文件夹下添加个类

public interface IjkFilter {
    void onCreated();
    void onSizeChanged(int width,int height);
    void onDrawFrame(int textureId);
    void onTexcoords(float[] texcoords);
    void onVertices(float[] vertices);
    void onRelease();
}
在IjkMediaPlayer.java内添加

public void setFilter(IjkFilter filter){
    _setGLFilter(filter);
}
private native void _setGLFilter(IjkFilter filter);
好了,这样就可以实现滤镜了,用法和GLSurfaceView.Renderer一样,贴我的实现代码,先贴 shader代码

bitmap_vertext_shader.glsl

precision highp float;
varying   highp vec2 vTexCoord;
attribute highp vec4 aPosition;
attribute highp vec2 aTexCoord;

void main()
{
    vTexCoord = vec2(aTexCoord.x,1.0-aTexCoord.y);
    gl_Position = aPosition;
}
bitmap_fragment_sharder.glsl

precision highp float;
varying   highp vec2 vTexCoord;
uniform   lowp  sampler2D sTexture;
void main()
{
    lowp    vec3 rgb = texture2D(sTexture, vTexCoord).rgb;
    gl_FragColor = vec4(0.299*rgb.r+0.587*rgb.g+0.114*rgb.b);
}
建一个读取program的类

ShaderUtils.java

public class ShaderUtils {
    private static final String TAG = "ShaderUtils";

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

    public static 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;
    }


    public static 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;
    }

    public static String readRawTextFile(Context context, int resId) {
        InputStream inputStream = context.getResources().openRawResource(resId);
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }
            reader.close();
            return sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}
然后是我的滤镜实现类

GLRenderer.java

public class GLRenderer implements IjkFilter {
    private Context context;

    private FloatBuffer vertexBuffer;
    private FloatBuffer textureVertexBuffer;

    private int programId = 0;


    private int aPositionHandle;
    private int uTextureSamplerHandle;
    private int aTextureCoordHandle;



    public GLRenderer(Context context){
        this.context = context;
        final float[] vertexData = {
                -1.0f, -1.0f,
                1.0f, -1.0f,
                -1.0f, 1.0f,
                1.0f, 1.0f
        };

        final float[] textureVertexData = {
                0.0f, 1.0f,
                1.0f, 1.0f,
                0.0f, 0.0f,
                1.0f, 0.0f
        };

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

        textureVertexBuffer = ByteBuffer.allocateDirect(textureVertexData.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(textureVertexData);
        textureVertexBuffer.position(0);
    }



    @Override
    public void onCreated() {
        String vertexShader = ShaderUtils.readRawTextFile(context, R.raw.bitmap_vertext_shader);
        String fragmentShader = ShaderUtils.readRawTextFile(context, R.raw.bitmap_fragment_sharder);

        programId = ShaderUtils.createProgram(vertexShader, fragmentShader);
        aPositionHandle = GLES20.glGetAttribLocation(programId, "aPosition");
        uTextureSamplerHandle = GLES20.glGetUniformLocation(programId, "sTexture");
        aTextureCoordHandle = GLES20.glGetAttribLocation(programId, "aTexCoord");
    }
    private Rect rect = new Rect();
    @Override
    public void onSizeChanged(int width, int height) {
        rect.left = 0;
        rect.top = 0;
        rect.right = width;
        rect.bottom = height;
    }

    @Override
    public void onDrawFrame(int textureId) {
        GLES20.glUseProgram(programId);
        GLES20.glViewport(0,0,rect.right,rect.bottom);
        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

        GLES20.glEnableVertexAttribArray(aPositionHandle);
        GLES20.glVertexAttribPointer(aPositionHandle, 2, GLES20.GL_FLOAT, false,
                8, vertexBuffer);

        GLES20.glEnableVertexAttribArray(aTextureCoordHandle);
        GLES20.glVertexAttribPointer(aTextureCoordHandle, 2, GLES20.GL_FLOAT, false, 8, textureVertexBuffer);
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textureId);
        GLES20.glUniform1i(uTextureSamplerHandle, 0);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    }

    public void onTexcoords(float[] texcoords){
        textureVertexBuffer.clear();
        textureVertexBuffer.put(texcoords);
        textureVertexBuffer.position(0);
    }
    public void onVertices(float[] vertices){
        vertexBuffer.clear();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);
    }
    public void onRelease(){
        if(programId != 0){
            GLES20.glDeleteProgram(programId);
        }
    }

}

最后在IjkMediaPlayer初始化后调用setFilter函数

GLRenderer renderer = new GLRenderer(getContext());
ijkMediaPlayer.setFilter(renderer);
同样的要开启opengl渲染

ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", "fcc-_es2");
源码: 百度云,里面也有.so和.jar文件,不过还是推荐自己修改编译,我只是简单的测试几下,应该bug还挺多

密码:26dk

用官方的列子测试了几下,像onRelease()都不会调用,也不知道ijkplayer是怎么释放的,看来还是要研究研究

ijkplayer添加滤镜c版


猜你喜欢

转载自blog.csdn.net/u010302327/article/details/79259661