(原)android-as_video_player中的OpenGLES视频显示
1,SurfaceView和OpenGLES
surfaceView = (SurfaceView) findViewById(R.id.gl_surface_view); surfaceView.getLayoutParams().height =screenWidth; SurfaceHolder mSurfaceHolder = surfaceView.getHolder(); mSurfaceHolder.addCallback(previewCallback);
private Callback previewCallback = new Callback() { public void surfaceCreated(SurfaceHolder holder) { //这里先创建一个播放器对象,然后调用播放器的初始化函数 playerController.init(path, surfaceHolder.getSurface(), width, height,new OnInitializedCallback()) } }
而在播放器对象中,我们是先从surface对象拿到ANativeWindow对象,然后在后文中就会用这个ANativeWindow对象跟opengles相关内容结合。
//这里会先根据上层的surface对象拿到ndk层的窗口对象ANativeWindow window = ANativeWindow_fromSurface(env, surface); //往下传递,将这个窗口对象 videoPlayerController->onSurfaceCreated(window, width, height);
接着我们跳过中间无关的内容,我们看看是如何利用这个window对象的.
bool VideoOutput::createEGLContext(ANativeWindow* window) { //创建一个EGL对象 eglCore = new EGLCore(); //这里是创建一个egl共享上下文,并初始化相关东西,我们等会分析 bool ret = eglCore->initWithSharedContext(); //在底层会根据相关参数,创建一个eglsurface this->createWindowSurface(window); //连接 EGLContext 和 EGLSurface eglCore->doneCurrent(); }
接下来的内容,更多的涉及到egl相关的内容了。
2,什么是 EGL?
EGL 是 OpenGL ES 渲染 API 和本地窗口系统(native platform window system)之间的一个中间接口层,它主要由系统制造商实现。EGL提供如下机制:
-
与设备的原生窗口系统通信
-
查询绘图表面的可用类型和配置
-
创建绘图表面
-
在OpenGL ES 和其他图形渲染API之间同步渲染
-
管理纹理贴图等渲染资源
为了让OpenGL ES能够绘制在当前设备上,我们需要EGL作为OpenGL ES与设备的桥梁。
2.1,使用EGL绘图的基本步骤
-
Display(EGLDisplay) 是对实际显示设备的抽象。
-
Surface(EGLSurface)是对用来存储图像的内存区域
-
FrameBuffer 的抽象,包括 Color Buffer, Stencil Buffer ,Depth Buffer。
-
Context (EGLContext) 存储 OpenGL ES绘图的一些状态信息。
使用EGL的绘图的一般步骤:
-
获取 EGL Display 对象:eglGetDisplay()
-
初始化与 EGLDisplay 之间的连接:eglInitialize()
-
获取 EGLConfig 对象:eglChooseConfig()
-
创建 EGLContext 实例:eglCreateContext()
-
创建 EGLSurface 实例:eglCreateWindowSurface()
-
连接 EGLContext 和 EGLSurface:eglMakeCurrent()
-
使用 OpenGL ES API 绘制图形:gl_*()
-
切换 front buffer 和 back buffer 送显:eglSwapBuffer()
-
断开并释放与 EGLSurface 关联的 EGLContext 对象:eglRelease()
-
删除 EGLSurface 对象
-
删除 EGLContext 对象
-
终止与 EGLDisplay 之间的连接
3,接着上面的代码,继续分析我们的egl和opengles的相关代码
bool EGLCore::initWithSharedContext(){ //这里初始化一个共享的context,所谓的共享,其实就是底层使用的单例模式,创建了一个EglShareContext //然后在这个单例对象中存储了一个EGLContext sharedContext;对象,这里就是返回这个对象,实际上 EGLContext context = EglShareContext::getSharedContext(); //也是对上面的context在初始化一次,感觉两次初始化的内容其实都是一样,所以这个地方就不再贴了 return init(context); }
而在EglShareContext的初始化中,也是初始化egl相关内容:
void EglShareContext::init() { sharedContext = EGL_NO_CONTEXT; EGLint numConfigs; sharedDisplay = EGL_NO_DISPLAY; EGLConfig config; const EGLint attribs[] = { EGL_BUFFER_SIZE, 32, EGL_ALPHA_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_NONE }; //获取egl的默认显示对象 if ((sharedDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) { } //初始化和display对象之间连接的相关egl实现版本信息 if (!eglInitialize(sharedDisplay, 0, 0)) { } //选择config if (!eglChooseConfig(sharedDisplay, attribs, &config, 1, &numConfigs)) { } //创建一个共享contex上下文对象 EGLint eglContextAttributes[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; if (!(sharedContext = eglCreateContext(sharedDisplay, config, NULL == sharedContext ? EGL_NO_CONTEXT : sharedContext, eglContextAttributes))) { } }
接着我们走到VideoOutput::createWindowSurface(ANativeWindow* window)函数,我们看下源码:
void VideoOutput::createWindowSurface(ANativeWindow* window) { this->surfaceWindow = window; if(NULL!=eglCore){ //根据窗口对象window,display,以及display的config等信息来创建一个eglsurface的渲染表面对象 renderTexSurface = eglCore->createWindowSurface(window); if (renderTexSurface != NULL){ //这里是对当前的display和context所连接surface对象,即渲染表面 //eglMakeCurrent(display, eglSurface, eglSurface, context); eglCore->makeCurrent(renderTexSurface); //然后这里就是创建一个opengl es相关内容的对象了,在这个对象内部,实现opengles相关的渲染操作 //例如shader的加载,编译,连接,以及纹理加载,渲染等等都在这个对象里面操作 renderer = new VideoGLSurfaceRender(); if(NULL!=renderer){ bool isGLViewInitialized = renderer->init(screenWidth, screenHeight); if (!isGLViewInitialized) { } else { surfaceExists = true; forceGetFrame = true; } } } } }
转载请注明出处:https://www.cnblogs.com/lihaiping/p/opengles.html