Android-as_video_player 中的 OpenGLES 视频显示
1,SurfaceView 和 OpenGLES
先从 java 的上层代码入手:
- 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
- Windows = ANativeWindow_fromSurface(env, surface);
- // 往下传递, 将这个窗口对象
- videoPlayerController->onSurfaceCreated(Windows, width, height);
接着我们跳过中间无关的内容, 我们看看是如何利用这个 Windows 对象的.
- bool VideoOutput::createEGLContext(ANativeWindow* Windows) {
- // 创建一个 EGL 对象
- eglCore = new EGLCore();
- // 这里是创建一个 egl 共享上下文, 并初始化相关东西, 我们等会分析
- bool ret = eglCore->initWithSharedContext();
- // 在底层会根据相关参数, 创建一个 eglsurface
- this->createWindowSurface(Windows);
- // 连接 EGLContext 和 EGLSurface
- eglCore->doneCurrent();
- }
接下来的内容, 更多的涉及到 egl 相关的内容了.
2, 什么是 EGL?
EGL 是 OpenGL ES 渲染 API 和本地窗口系统 (native platform Windows 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* Windows)函数, 我们看下源码:
- void VideoOutput::createWindowSurface(ANativeWindow* Windows) {
- this->surfaceWindow = Windows;
- if(NULL!=eglCore){
- // 根据窗口对象 Windows,display, 以及 display 的 config 等信息来创建一个 eglsurface 的渲染表面对象
- renderTexSurface = eglCore->createWindowSurface(Windows);
- 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;
- }
- }
- }
- }
- }
来源: http://www.bubuko.com/infodetail-3371703.html