Android(安卓)OpenGl展示视频内容
16lz
2022-04-16
Android中OpenGL展示视频内容和预览摄像头数据用的纹理ID都是GLES11Ext.GL_TEXTURE_EXTERNAL_OES,所以可以直接按照上一篇的预览Camera基础之上,继承OesFilter,共用同一个GlSurfaceView,根据新生成的纹理ID创建SurfaceTexture绘画即可。
class CodecRender(val surface: CodecSurface) : GLSurfaceView.Renderer { private val TAG: String = "CodecRender" var textureId: Int = 0; private var filter: OesFilter? = null private var videoFilter: VideoFilter? = null var surfaceTexture: SurfaceTexture? = null private var cameraId: Int = 0; private var listener: SurfaceTexture.OnFrameAvailableListener? = null private var screenWidth: Int = 0 private var screenHight: Int = 0 private var videoWidth: Int = 400 private var videoHeight: Int = 400 init { filter = OesFilter() videoFilter = VideoFilter(surface)//将surface传入方便刷新和引用context获取本地视频数据,setOnFrameAvailableListener如果不在创建后设置会出现无法监听的问题 } override fun onDrawFrame(gl: GL10?) { GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f) GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT) surfaceTexture!!.updateTexImage() GLES20.glViewport(0, 0, screenWidth, screenHight); if (cameraUtil!!.isOpenFinish) { filter!!.drawFrame() } GLES20.glViewport(0, screenHight - videoHeight, videoWidth, videoHeight);//将视频置于左上角 //绘制视频 videoFilter!!.updateTexImage() videoFilter!!.drawFrame() } override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) { screenWidth = width screenHight = height GLES20.glViewport(0, 0, width, height); } override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) { textureId = filter!!.createTextureId() surfaceTexture = SurfaceTexture(textureId) surfaceTexture!!.setOnFrameAvailableListener { surface!!.requestRender() } cameraUtil!!.setTexture(surfaceTexture!!) setCameraId(cameraId); filter!!.setTextureId(textureId) filter!!.create() //绘制视频 videoFilter!!.createTextureView() } public fun setCameraId(id: Int) { cameraId = id; filter!!.setCoodData(cameraId) cameraUtil!!.open(cameraId.toString()) } private var cameraUtil: CameraUtil? = null public fun release() { surfaceTexture?.setOnFrameAvailableListener(null) surfaceTexture?.release() surfaceTexture = null cameraUtil!!.close() videoFilter?.close() } public fun setFrameListener(listener: SurfaceTexture.OnFrameAvailableListener) { this.listener = listener; } init { cameraUtil = CameraUtil(surface.context) }}
public open class OesFilter { private val TAG: String = "OesFilter" private var positionFloat: FloatBuffer? = null private var coodFloat: FloatBuffer? = null private var glHPosition: Int = 0 private var glHCoordinate: Int = 0 private var glHTexture: Int = 0 private var mHCoord: Int = 0 private var mHMatrix: Int = 0 public var coordinate: FloatArray = floatArrayOf( 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f ) private var textureId: Int = 0 private var programsId: Int = 0 private val vertexPosition = floatArrayOf( -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f ) public open fun create() { val frag_id = createShader(fragmentShaderCode, GLES20.GL_FRAGMENT_SHADER) val vertex_id = createShader(vertexShaderCode, GLES20.GL_VERTEX_SHADER) programsId = GLES20.glCreateProgram(); GLES20.glAttachShader(programsId, frag_id) GLES20.glAttachShader(programsId, vertex_id) GLES20.glLinkProgram(programsId) val linkState = IntArray(1) GLES20.glGetProgramiv(programsId, GLES20.GL_LINK_STATUS, linkState, 0) LogUtil.e(TAG, "state=${linkState[0]} programsId=$programsId") if (linkState[0] == 0) { LogUtil.e( TAG, "Could not link program: " ) LogUtil.e( TAG, GLES20.glGetProgramInfoLog(programsId) ) GLES20.glDeleteProgram(programsId) programsId = 0; } } private fun userProgram(programsId: Int) { GLES20.glUseProgram(programsId) var bb: ByteBuffer = ByteBuffer.allocateDirect(vertexPosition.size * 4) bb.order(ByteOrder.nativeOrder()) positionFloat = bb.asFloatBuffer() positionFloat!!.put(vertexPosition) positionFloat!!.position(0) var cbb: ByteBuffer = ByteBuffer.allocateDirect(coordinate!!.size * 4) cbb.order(ByteOrder.nativeOrder()) coodFloat = cbb.asFloatBuffer() coodFloat!!.put(coordinate) coodFloat!!.position(0) glHPosition = GLES20.glGetAttribLocation(programsId, "vPosition") glHCoordinate = GLES20.glGetAttribLocation(programsId, "vTextureCoordinate") glHTexture = GLES20.glGetUniformLocation(programsId, "vTexture") mHCoord = GLES20.glGetAttribLocation(programsId, "vCoord") mHMatrix = GLES20.glGetUniformLocation(programsId, "vMatrix") } public fun createTextureId(): Int { val texture = IntArray(1) GLES20.glGenTextures(1, texture, 0) GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texture[0]) GLES20.glTexParameterf( GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR.toFloat() ) GLES20.glTexParameterf( GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR.toFloat() ) GLES20.glTexParameterf( GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE.toFloat() ) GLES20.glTexParameterf( GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE.toFloat() ) return texture[0] } public fun setTextureId(id: Int) { textureId = id } private fun createShader(str: String, style: Int): Int { val shader: Int = GLES20.glCreateShader(style); GLES20.glShaderSource(shader, str) GLES20.glCompileShader(shader) val state = IntArray(1) GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, state, 0) if (state[0] == 0) { LogUtil.e(TAG, "Could not compile shader " + shader + ":"); LogUtil.e(TAG, " " + GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader) throw IllegalStateException("Could not compile shader") } return shader; } private val vertexShaderCode = "attribute vec4 vPosition;" + "attribute vec2 vCoord;" + "varying vec2 vTextureCoordinate;" + "uniform mat4 vMatrix;" + "void main() {" + " gl_Position = vMatrix*vPosition;" + "vTextureCoordinate = vCoord;" + "}" private val fragmentShaderCode = "#extension GL_OES_EGL_image_external : require\r\n" + "precision mediump float;" + "varying vec2 vTextureCoordinate;" + "uniform samplerExternalOES vTexture;" + "void main() {" + " gl_FragColor = texture2D(vTexture, vTextureCoordinate);" + "}" private val matrix: FloatArray = LogUtil.getOriginalMatrix() public fun drawFrame() { userProgram(programsId) GLES20.glEnableVertexAttribArray(glHPosition) GLES20.glEnableVertexAttribArray(mHCoord) GLES20.glActiveTexture(GLES20.GL_TEXTURE0) GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId) GLES20.glUniform1i(glHTexture, 0) GLES20.glVertexAttribPointer(glHPosition, 2, GLES20.GL_FLOAT, false, 0, positionFloat) GLES20.glVertexAttribPointer(mHCoord, 2, GLES20.GL_FLOAT, false, 0, coodFloat) GLES20.glUniformMatrix4fv(mHMatrix, 1, false, matrix, 0) GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4) GLES20.glDisableVertexAttribArray(glHPosition) GLES20.glDisableVertexAttribArray(mHCoord) } public fun setCoodData(cameraId: Int) { coordinate = if (cameraId == 0) {//后置摄像头 floatArrayOf( 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f ) } else {//前置摄像头 floatArrayOf( 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f ) } }}
class VideoFilter(val surface: CodecSurface) : OesFilter() { private var mediaPlayer: MediaPlayer? = null private var surfaceTexture: SurfaceTexture? = null init { mediaPlayer = MediaPlayer() } fun createTextureView() { create() val id = createTextureId() surfaceTexture = SurfaceTexture(id) coordinate = floatArrayOf( 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f ) setTextureId(id) surfaceTexture!!.setOnFrameAvailableListener { surface.requestRender() } play() } fun updateTexImage() { surfaceTexture!!.updateTexImage() } private fun play() { try { mediaPlayer!!.setSurface(Surface(surfaceTexture)) var fd = FileDescriptor() mediaPlayer!!.reset() mediaPlayer!!.isLooping = true var afd = surface.resources.openRawResourceFd(R.raw.test); mediaPlayer!!.setDataSource(afd.fileDescriptor, afd.startOffset, afd.length) mediaPlayer!!.setOnPreparedListener { mp -> mp.start() } mediaPlayer!!.prepareAsync() } catch (e: Exception) { e.printStackTrace() } } public fun close() { Thread { try { mediaPlayer?.let { if (it.isPlaying) { it.pause() it.stop() } it.release() } mediaPlayer = null } catch (e: Exception) { } }.start() }}
更多相关文章
- android支持的视频音频硬解码器
- Android(安卓)VideoView简单播放视频
- Android(安卓)仿秒拍,微信录制短视频
- android_camera
- 【备忘】2016最新独家老罗Android视频教程第二季 下载
- Android(安卓)关于获取摄像头帧数据
- Android(安卓)VideoView简单播放视频
- android camera(二):摄像头工作原理、s5PV310 摄像头接口(CAMIF)
- 【Android(安卓)开源系列】之视频处理框架