一、创建OpenGL ES 环境
在清单中声明OpenGL ES
为了使您的应用程序能够使用OpenGL ES 2.0 API,您必须在清单中添加以下声明:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
构建GLSurfaceView对象
class MyGLSurfaceView(context: Context, attributeSet: AttributeSet?) : GLSurfaceView(context, attributeSet) {
companion object {
private const val TAG = "MyGLSurfaceView"
}
constructor(context: Context) : this(context, null)
private val renderer: MyGLRenderer
init {
// Create an OpenGL ES 2.0 context
setEGLContextClientVersion(2)
renderer = MyGLRenderer()
// Set the Renderer for drawing on the GLSurfaceView
setRenderer(renderer)
// Render the view only when there is a change in the drawing data
renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
}
/**
* 设置显示方向
* @param degrees 显示旋转角度(逆时针),有效值是(0, 90, 180, and 270.)
*/
fun setDisplayOrientation(degrees: Int) {
renderer.setDisplayOrientation(degrees)
}
/**
* 设置渲染的YUV数据的宽高
* @param width 宽度
* @param height 高度
*/
fun setYuvDataSize(width: Int, height: Int) {
Log.d(TAG, "setYuvDataSize $width * $height")
renderer.setYuvDataSize(width, height)
}
/**
* 填充预览YUV格式数据
* @param yuvData yuv格式的数据
* @param type YUV数据的格式 0 -> I420 1 -> NV12 2 -> NV21
*/
fun feedData(yuvData: ByteArray?, type: Int = 0) {
if (yuvData == null) {
return
}
renderer.feedData(yuvData, type)
// 请求渲染新的YUV数据
requestRender()
}
}
主要工作:
1、指定OpenGL ES Context版本
2、设置渲染的 Renderer
3、设定渲染模式为RENDERMODE_WHEN_DIRTY,只有在调用requestRender()后才触发redraw工作
4、传入YUV数据的宽度、高度
5、传输需要渲染的YUV格式的数据(I420、NV12、NV21)
构建Renderer类
class MyGLRenderer : GLSurfaceView.Renderer {
companion object {
private const val TAG = "MyGLRenderer"
}
private lateinit var mProgram: MyGLProgram
// GLSurfaceView宽度
private var mScreenWidth: Int = 0
// GLSurfaceView高度
private var mScreenHeight: Int = 0
// 预览YUV数据宽度
private var mVideoWidth: Int = 0
// 预览YUV数据高度
private var mVideoHeight: Int = 0
// vPMatrix is an abbreviation for "Model View Projection Matrix"
private val vPMatrix = FloatArray(16)
private val projectionMatrix = FloatArray(16)
private val viewMatrix = FloatArray(16)
// y分量数据
private var y: ByteBuffer = ByteBuffer.allocate(0)
// u分量数据
private var u: ByteBuffer = ByteBuffer.allocate(0)
// v分量数据
private var v: ByteBuffer = ByteBuffer.allocate(0)
// uv分量数据
private var uv: ByteBuffer = ByteBuffer.allocate(0)
// YUV数据格式 0 -> I420 1 -> NV12 2 -> NV21
private var type: Int = 0
// 标识GLSurfaceView是否准备好
private var hasVisibility = false
// Called once to set up the view's OpenGL ES environment.
override fun onSurfaceCreated(unused: GL10, config: EGLConfig) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
// 配置OpenGL ES 环境
mProgram = MyGLProgram()
}
// Called if the geometry of the view changes, for example when the device's screen orientation changes.
override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) {
GLES20.glViewport(0, 0, width, height)
mScreenWidth = width
mScreenHeight = height
mScreenWidth = width
mScreenHeight = height
val ratio: Float = width.toFloat() / height.toFloat()
// this projection matrix is applied to object coordinates
// in the onDrawFrame() method
Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f)
// Set the camera position (View matrix)
Matrix.setLookAtM(viewMatrix, 0, 0f, 0f, -3f, 0f, 0f, 0f, 1.0f, 0.0f, 0.0f)
if (mVideoWidth > 0 && mVideoHeight > 0) {
createBuffers(mVideoWidth, mVideoHeight)
}
hasVisibility = true
Log.d(TAG, "onSurfaceChanged width:$width * height:$height")
}
// Called for each redraw of the view.
override fun onDrawFrame(unused: GL10) {
synchronized(this) {
if (y.capac