由第十二章节分析,可知,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;
}