ijkplayer添加滤镜c版

最近在研究ijkplayer 源码,刚开始的时候看的有点眼晕,这个嵌套在那个里,那个又嵌套在这个里,特别是java文件是用c代码生成的,熟悉一些了,感觉对自己还是很有帮助的,言归正传。

去网上搜了下ijkplayer添加滤镜只找到这篇让IjkPlayer支持插入自定义的GPU滤镜参考了一下,他的是在c层使用opengl的fbo得到视频纹理再把纹理传到java层进行操作,可能我和他的ijkplayer版本不一样,虽然成功了可是加了很多他那篇文章里没有的代码,也熟悉了ijkplayer源码,既然他是在java层来进行操作,那我就在c层来实现滤镜吧,思路一样也是用fbo,可能我的方法在其他版本不适用所以说一下我的ijkplayer版本0.8.4,先看我实现的效果


当然这是简单的黑白滤镜,既然想添加滤镜,那就要添加shader代码,ijkplayer的shader代码都在ijkmedia/ijksdl/gles2/fsh文件夹下边,可以直接进行更改,不过每个文件都要改很麻烦,所以新建一个,我就随便建一个,在ijkmedia/ijksdl/gles2下边新建了个test_opengl.c文件,添加代码

#include "internal.h"
static const char g_shader[] = IJK_GLES_STRING(
    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);
    }
);
const char *IJK_GLES2_getFragmentShader_test()
{
    return g_shader;
}
static const char v_shader[] = IJK_GLES_STRING(
    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;
    }
);

const char *IJK_GLES2_getVertexShader_test()
{
    return v_shader;
}
这是我的黑白滤镜shader,然后在ijkmedia/ijksdl/gles2/internal.h内添加函数

const char *IJK_GLES2_getFragmentShader_test();
const char *IJK_GLES2_getVertexShader_test();
新建的文件要编译进去,修改ijkmedia/ijksdl/Android.mk添加新建文件

LOCAL_SRC_FILES += gles2/test_opengl.c

保存后开始修改代码,主要修改的都是ijkmedia/ijksdl/gles2文件夹下边的代码

先修改renderer_rgb.c,renderer_yuv420p.c,renderer_yuv420sp.c,renderer_yuv420sp_vtb.m,renderer_yuv444p10le.c的代码

只是简单的修改初始化纹理代码比如把renderer_yuv420p.c的yuv420p_use函数内代码

if (0 == renderer->plane_textures[0])
    glGenTextures(3, renderer->plane_textures);

for (int i = 0; i < 3; ++i) {
    glActiveTexture(GL_TEXTURE0 + i);
    glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);

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

    glUniform1i(renderer->us2_sampler[i], i);
}
改成

if (0 == renderer->plane_textures[0]){
    glGenTextures(3, renderer->plane_textures);
    for (int i = 0; i < 3; ++i) {
        glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);

        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);
    }
}

for (int i = 0; i < 3; ++i) {
    glActiveTexture(GL_TEXTURE0 + i);
    glBindTexture(GL_TEXTURE_2D, renderer->plane_textures[i]);
    glUniform1i(renderer->us2_sampler[i], i);
}
其他的也这样改,初始化一次因为这个函数要调用很多次,再修改internal.h代码,在IJK_GLES2_Renderer结构体内添加代码

typedef struct IJK_GLES2_Renderer
{
    ...//省略代码

    int view_width;
    int view_height;

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

    GLuint program_test;
    GLuint vertex_shader_test;
    GLuint fragment_shader_test;
    GLuint position_test;
    GLuint texcoord_test;
    GLuint sampler_test;
    GLfloat texcoords_test[8];

    GLfloat vertices_test[8];


} IJK_GLES2_Renderer;

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了,而且是大改

先补完上边的最后一步,在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;
}
初始化program_test等参数

IJK_GLES2_Renderer *IJK_GLES2_Renderer_create_base(const char *fragment_shader_source)
{
    ...//省略代码

    renderer->vertex_shader_test = IJK_GLES2_loadShader(GL_VERTEX_SHADER, IJK_GLES2_getVertexShader_test());
    if (!renderer->vertex_shader_test)
        goto fail;

    renderer->fragment_shader_test = IJK_GLES2_loadShader(GL_FRAGMENT_SHADER, IJK_GLES2_getFragmentShader_test());
    if (!renderer->fragment_shader_test)
        goto fail;

    renderer->program_test = glCreateProgram();                          IJK_GLES2_checkError("glCreateProgram");
    if (!renderer->program_test)
        goto fail;

    glAttachShader(renderer->program_test, renderer->vertex_shader_test);     IJK_GLES2_checkError("glAttachShader(vertex)");
    glAttachShader(renderer->program_test, renderer->fragment_shader_test);   IJK_GLES2_checkError("glAttachShader(fragment)");
    glLinkProgram(renderer->program_test);                               IJK_GLES2_checkError("glLinkProgram");
    GLint link_status_test = GL_FALSE;
    glGetProgramiv(renderer->program_test, GL_LINK_STATUS, &link_status_test);
    if (!link_status_test)
        goto fail;

    renderer->position_test = glGetAttribLocation(renderer->program_test, "aPosition");                IJK_GLES2_checkError_TRACE("glGetAttribLocation(aPosition)");
    renderer->texcoord_test = glGetAttribLocation(renderer->program_test, "aTexCoord");                IJK_GLES2_checkError_TRACE("glGetAttribLocation(aTexCoord)");
    renderer->sampler_test  = glGetUniformLocation(renderer->program_test, "sTexture");                IJK_GLES2_checkError_TRACE("glGetUniformLocation(sTexture)");



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

释放

void IJK_GLES2_Renderer_reset(IJK_GLES2_Renderer *renderer)
{
    ...//省略代码
    if (renderer->vertex_shader_test)
        glDeleteShader(renderer->vertex_shader_test);
    if (renderer->fragment_shader_test)
        glDeleteShader(renderer->fragment_shader_test);
    if (renderer->program_test)
        glDeleteProgram(renderer->program_test);

    if(renderer->frame_textures)
        glDeleteTextures(1, renderer->frame_textures);
    if(renderer->frame_buffers)
        glDeleteBuffers(1,renderer->frame_buffers);
}
修改IJK_GLES2_Renderer_Vertices_reloadVertex和IJK_GLES2_Renderer_TexCoords_reloadVertex函数

static void IJK_GLES2_Renderer_Vertices_reloadVertex(IJK_GLES2_Renderer *renderer)
{
    //glVertexAttribPointer(renderer->av4_position, 2, GL_FLOAT, GL_FALSE, 0, renderer->vertices);    IJK_GLES2_checkError_TRACE("glVertexAttribPointer(av2_texcoord)");
    //glEnableVertexAttribArray(renderer->av4_position);                                      IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(av2_texcoord)");

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

static void IJK_GLES2_Renderer_TexCoords_reloadVertex(IJK_GLES2_Renderer *renderer)
{
    //glVertexAttribPointer(renderer->av2_texcoord, 2, GL_FLOAT, GL_FALSE, 0, renderer->texcoords);   IJK_GLES2_checkError_TRACE("glVertexAttribPointer(av2_texcoord)");
    //glEnableVertexAttribArray(renderer->av2_texcoord);                                              IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(av2_texcoord)");

    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_renderOverlay函数,也是用opengl的fbo所以有些代码直接复制了上面那篇博文的

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->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);
    }

    if(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->frame_buffers[0]){
        glBindFramebuffer(GL_FRAMEBUFFER,0);
    }


    glUseProgram(renderer->program_test);            IJK_GLES2_checkError_TRACE("glUseProgram");
    glViewport(0, 0, renderer->view_width, renderer->view_height);  IJK_GLES2_checkError_TRACE("glViewport");
    glClear(GL_COLOR_BUFFER_BIT);               IJK_GLES2_checkError_TRACE("glClear");
    glClearColor(1.0f,1.0f,0.0f,1.0f);
    glVertexAttribPointer(renderer->texcoord_test, 2, GL_FLOAT, GL_FALSE, 0, renderer->texcoords);   IJK_GLES2_checkError_TRACE("glVertexAttribPointer(texcoord_test)");
    glEnableVertexAttribArray(renderer->texcoord_test);                                              IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(texcoord_test)");

    glVertexAttribPointer(renderer->position_test, 2, GL_FLOAT, GL_FALSE, 0, renderer->vertices);    IJK_GLES2_checkError_TRACE("glVertexAttribPointer(position_test)");
    glEnableVertexAttribArray(renderer->position_test);                                      IJK_GLES2_checkError_TRACE("glEnableVertexAttribArray(position_test)");

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,renderer->frame_textures[0]);
    glUniform1i(renderer->sampler_test, 0);


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


    return GL_TRUE;
}

修修改改可能有些忘记写了,如果觉得我的文章有点乱的话就直接下载我的代码研究研究自己编译一下看看
密码:r6ec

还要说一下ijkplayer默认是不开启opengl渲染的要在例子的java代码中修改

//                    String pixelFormat = mSettings.getPixelFormat();
//                    if (TextUtils.isEmpty(pixelFormat)) {
//                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
//                    } else {
//                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", pixelFormat);
//                    }
                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", "fcc-_es2");
这样ijkplayer就开启了opengl渲染




猜你喜欢

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