【十三】【vlc-anroid】EGL OpenGL模块组件加载源码实现分析

由第十二章节分析,可知,vlc使用OpenGL加载时,android端会加载【“opengl”】名的组件模块。
如下找到该组件声明:

// 【vlc/modules/video_output/opengl/egl.c】

vlc_module_begin ()
    set_shortname (N_("EGL"))
    set_description (N_("EGL extension for OpenGL"))
    set_category (CAT_VIDEO)
    set_subcategory (SUBCAT_VIDEO_VOUT)
    // android端加载的是该模块
    set_capability ("opengl", 50)
    set_callbacks (OpenGL, Close)
    add_shortcut ("egl")

    add_submodule ()
    set_capability ("opengl es2", 50)
    set_callbacks (OpenGLES2, Close)
    add_shortcut ("egl")

vlc_module_end ()

1、组件初始化入口OpenGL:

// 【vlc/modules/video_output/opengl/egl.c】
static int OpenGL (vlc_object_t *obj)
{
    // GL API的设置
    static const struct gl_api api = {
        "OpenGL", EGL_OPENGL_API, 4, EGL_OPENGL_BIT,
        { EGL_NONE },
    };
    return Open (obj, &api);
}

// 【vlc/modules/video_output/opengl/egl.c】
/**
 * Probe EGL display availability
 */
static int Open (vlc_object_t *obj, const struct gl_api *api)
{
    vlc_gl_t *gl = (vlc_gl_t *)obj;
    vlc_gl_sys_t *sys = malloc(sizeof (*sys));
    if (unlikely(sys == NULL))
        return VLC_ENOMEM;

    gl->sys = sys;
    sys->display = EGL_NO_DISPLAY;
    sys->surface = EGL_NO_SURFACE;
    sys->context = EGL_NO_CONTEXT;
    sys->eglCreateImageKHR = NULL;
    sys->eglDestroyImageKHR = NULL;

    // 十二章中传入的window对象
    vout_window_t *wnd = gl->surface;
    // 创建EGLSurface对象的方法指针,该方法最终调用了【eglCreateWindowSurface】方法创建GL的Surface对象
    EGLSurface (*createSurface)(EGLDisplay, EGLConfig, void *, const EGLint *)
        = CreateWindowSurface;
    void *window;

#ifdef USE_PLATFORM_X11
 // ... 省略部分代码,此处为适配其他系统处理

#elif defined (USE_PLATFORM_ANDROID)
    if (wnd->type != VOUT_WINDOW_TYPE_ANDROID_NATIVE)
        goto error;

    // 创建android native window/Surface对象
    // 【主要是从java层Surface中获取对应的native window对象】
    // 见第十章2.2小节分析 TODO
    ANativeWindow *anw =
        AWindowHandler_getANativeWindow(wnd->handle.anativewindow,
                                        AWindow_Video);
    if (anw == NULL)
        goto error;
    window = &anw;
# if defined (__ANDROID__) || defined (ANDROID)
    // 调用android接口获取安卓底层EGLDisplay对象
    sys->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
# endif

#endif

    if (sys->display == EGL_NO_DISPLAY)
        goto error;

    // 调用EGL display展示相关方法进行初始化处理
    /* Initialize EGL display */
    EGLint major, minor;
    if (eglInitialize(sys->display, &major, &minor) != EGL_TRUE)
        goto error;
    msg_Dbg(obj, "EGL version %s by %s",
            eglQueryString(sys->display, EGL_VERSION),
            eglQueryString(sys->display, EGL_VENDOR));

    const char *ext = eglQueryString(sys->display, EGL_EXTENSIONS);
    if (*ext)
        msg_Dbg(obj, " extensions: %s", ext);

    if (major != 1 || minor < api->min_minor
     || !CheckAPI(sys->display, api->name))
    {
        msg_Err(obj, "cannot select %s API", api->name);
        goto error;
    }

    // 设置EGL配置参数bit大小
    const EGLint conf_attr[] = {
        EGL_RED_SIZE, 5,
        EGL_GREEN_SIZE, 5,
        EGL_BLUE_SIZE, 5,
        EGL_RENDERABLE_TYPE, api->render_bit,
        EGL_NONE
    };
    EGLConfig cfgv[1];
    EGLint cfgc;

    if (eglChooseConfig(sys->display, conf_attr, cfgv, 1, &cfgc) != EGL_TRUE
     || cfgc == 0)
    {
        msg_Err (obj, "cannot choose EGL configuration");
        goto error;
    }

    // 调用上面定义的【createSurface】方法指针局部变量,创建绘制Surface对象
    /* Create a drawing surface */
    sys->surface = createSurface(sys->display, cfgv[0], window, NULL);
    if (sys->surface == EGL_NO_SURFACE)
    {
        msg_Err (obj, "cannot create EGL window surface");
        goto error;
    }

    if (eglBindAPI (api->api) != EGL_TRUE)
    {
        msg_Err (obj, "cannot bind EGL API");
        goto error;
    }

    // 调用的是android底层egl接口
    EGLContext ctx = eglCreateContext(sys->display, cfgv[0], EGL_NO_CONTEXT,
                                      api->attr);
    if (ctx == EGL_NO_CONTEXT)
    {
        msg_Err (obj, "cannot create EGL context");
        goto error;
    }
    sys->context = ctx;

    // 设置OpenGL的调用方法指针回调
    /* Initialize OpenGL callbacks */
    gl->ext = VLC_GL_EXT_EGL;
    // 见第2小节分析
    gl->makeCurrent = MakeCurrent;
    // 与【MakeCurrent】相反,释放当前OpenGL的加载
    gl->releaseCurrent = ReleaseCurrent;
    // 该方法实现在安卓端为空实现,功能是给【WAYLAND】图像渲染系统使用的
    gl->resize = Resize;
    // 最终调用了egl接口【eglSwapBuffers】,
    // 该方法实现如其名就是交换缓冲区buffer,即queue和dequeue过程
    gl->swap = SwapBuffers;
    // 最终调用的是egl接口【eglGetProcAddress】获取其传入接口名是否支持的地址
    gl->getProcAddress = GetSymbol;
    // 调用了egl接口【eglQueryString】查询egl配置属性等
    gl->egl.queryString = QueryString;

    // 调用的是android底层egl接口 图像2D纹理处理
    sys->eglCreateImageKHR = (void *)eglGetProcAddress("eglCreateImageKHR");
    sys->eglDestroyImageKHR = (void *)eglGetProcAddress("eglDestroyImageKHR");
    if (sys->eglCreateImageKHR != NULL && sys->eglDestroyImageKHR != NULL)
    {
        // 图像2D纹理处理方法指针赋值调用
        // 该方法实现为:最后调用了【sys->eglCreateImageKHR】即上面赋值的【eglCreateImageKHR】方法指针,
        // 也就是说若egl实现支持该接口功能则会执行该功能
        gl->egl.createImageKHR = CreateImageKHR;
        gl->egl.destroyImageKHR = DestroyImageKHR;
    }

    return VLC_SUCCESS;

error:
    Close (obj);
    return VLC_EGENERIC;
}

2、MakeCurrent实现分析:

static int MakeCurrent (vlc_gl_t *gl)
{
    vlc_gl_sys_t *sys = gl->sys;

    // 调用android EGL接口
    // 在完成EGL的初始化之后,需要通过eglMakeCurrent()函数来将当前的上下文切换,
    // 这样opengl的函数才能启动作用.
    // 该接口将申请到的display,draw(surface)和 context进行了绑定。也就是说,
    // 在context下的OpenGLAPI指令将draw(surface)作为其渲染最终目的地。
    // 而display作为draw(surface)的前端显示。调用后,当前线程使用的EGLContex为context。
    if (eglMakeCurrent (sys->display, sys->surface, sys->surface,
                        sys->context) != EGL_TRUE)
        return VLC_EGENERIC;
    return VLC_SUCCESS;
}

你可能感兴趣的:(【vlc-android】,【音视频】,vlc,opengl)