前言
此博客的大部分内容来自我的毕业设计论文,因此语言上会偏正式一点,如果您有任何问题或建议,欢迎留言。在此感谢实验室的聂师兄,全景视频render部分的代码设计主要参考了他所编写的代码来完成,他对视频渲染过程的讲解也让我对此部分有了更好的理解!
为了能播放MEPG-DASH标准的视频,我使用了ExoPlayer作为播放器,而非之前的MediaPlayer
,如有需要,请参考,ExoPlayer播放器MPEG-DASH视频播放。
GLSurfaceView的使用介绍
针对VR视频的播放需求,由于需要使用OpenGL ES 来完成视频渲染工作,所以使用了GLSurfaceView。它是SurfaceView的实现,并使用特定的surface来展示OpenGL的渲染内容。它具有如下特点:
- 管理一个surface(一块可以组合进Android view系统的特殊内存);
- 管理EGL显示(即允许使用OpenGL进行渲染);
- 接受由用户提供的渲染器完成渲染工作;开启特定线程完成渲染;
- 支持按要求(on-demand rendering.)渲染和连续渲染(continuous rendering)两种模式。
这些特点都说明,GLSurfaceView很适合用来进行渲染工作。
GLSurfaceView的使用包含下面这几部分工作:
首先是初始化:即使用setRenderer(Renderer)来设置一个渲染器。具体的步骤为:
- 定制android.view.Surface:GLSurfaceView默认创建一个像素格式为PixelFormat.RGB_888的surface,根据具体的需求,可以选择需要的像素格式,如透明格式,则需要调用getHolder().setFormat(PixelFormat.TRANSLUCENT)来设置。
- 选择EGL配置:一个Android设备可能支持多种EGL配置,如通道(channels)数以及每个通道颜色位数不同则EGL配置也不同,所以,在渲染器之前必须指定EGL的配置。默认使用RGB通道和16位深度,在初始化GLSurfaceView时可以通过调用setEGLConfigChooser(EGLConfigChooser)方法来改变EGL配置。
- 调试选项(可选):可以通过调用setDebugFlags(int),和setGLWrapper(GLSurfaceView.GLWrapper)方法来指定GLSurfaceView的调试行为。
- 设置渲染器:初始化的最后一步是设置渲染器,通过调用setRenderer(GLSurfaceView.Renderer)来注册一个GLSurfaceView渲染器。真正的OpenGL渲染工作将由渲染器负责完成。
- 渲染模式:如在GLSurfaceView的特点中所介绍的,它支持按要求(on-demand rendering.)渲染和连续渲染(continuous rendering)两种模式,设定好渲染器,再使用setRenderMode(int)指定需要使用的渲染模式。
另外两个部分是Activity生命周期和事件处理。
Activity生命周期:GLSurfaceView会在Activity窗口暂停(pause)或恢复(resume)时会收到通知,并调用它的的onPause方法和 onResume方法。这是因为GLSurfaceView是一个重量级的控件,恢复和暂停渲染进程是为了使它能及时释放或重建OpenGL ES的资源。
事件处理:为了处理事件,和其他View的事件处理类似,即继承GLSurfaceView类并重载它的事件方法。事件处理过程中可能涉及到和渲染对象所在的渲染线程的通信,使用queueEvent(Runnable)可以简化这部分工作,当然也可以使用其他标准的进程通信机制中的方法。
VR视频的渲染
VR视频的渲染工作总结起来,主要是两大部分,一是球体的绘制,二是进行球体的纹理贴图工作。具体的实现细节较为复杂,如在完成贴图后,为了能让观众自由地切换视角,还需要使用投影和相机视图,并进行窗口裁剪等工作。VR全景视频完整的渲染播放流程如图1所示:
创建 GLSurfaceView 对象
在GLSurfaceView的使用介绍中提到真正的OpenGL渲染工作由渲染器来完成,而GLSurfaceView本身所做的工作并不多。根据Android官网的开发者指导,可以直接使用GLSurfaceView,但为了进行事件处理,本应用必须创建一个自己的MyGLSurfaceView,它继承自GLSurfaceView。
创建GLSurfaceView.Renderer类
GLSurfaceView.Renderer负责向GLSurfaceView的渲染工作,而渲染工作主要有下面这三个方法来完成:onSurfaceCreated():这个方法在GLSurfaceView被创建时,会调用一次,通常在这里进行一些初始化工作,如形状初始化,着色器的编译等;onDrawFrame():这个方法在每次绘制图像时被调用,绘制主要在这里完成; onSurfaceChanged():当几何图形发送改变时,会调用这个方法,如屏幕大小发生变化时。
本应用创建一个SphereVideoRenderer,它是GLSurfaceView.Renderer的实现。按照OpenGL ES 2.0可编程管线,绘制一个图形并最终展示在view(送入FrameBuffer中)的过程为:准备顶点(作为输入顶点着色器的顶点数据),顶点着色器处理,图元装配Primitive Assembly,光栅化(rasterizati