Android OpenGl展示视频内容

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()
    }

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值