【Android 音视频开发打怪升级:OpenGL渲染视频画面篇】三、OpenGL渲染多视频,实现画中画

本文介绍了如何在Android中使用OpenGL渲染多视频画面,实现画中画效果。通过OpenGL,不仅可以渲染单个视频,还可以进行画面的混合、缩放、移动等操作,为视频编辑提供了基础。文章详细讲解了如何实现多个纹理ID,通过调整顶点着色器和片元着色器实现半透明效果,以及如何进行画面的移动和缩放变换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【声 明】

首先,这一系列文章均基于自己的理解和实践,可能有不对的地方,欢迎大家指正。
其次,这是一个入门系列,涉及的知识也仅限于够用,深入的知识网上也有许许多多的博文供大家学习了。
最后,写文章过程中,会借鉴参考其他人分享的文章,会在文章最后列出,感谢这些作者的分享。

码字不易,转载请注明出处!

教程代码:【Github传送门
目录
一、Android音视频硬解码篇:
二、使用OpenGL渲染视频画面篇
三、Android FFmpeg音视频解码篇
  • 1,FFmpeg so库编译
  • 2,Android 引入FFmpeg
  • 3,Android FFmpeg视频解码播放
  • 4,Android FFmpeg+OpenSL ES音频解码播放
  • 5,Android FFmpeg+OpenGL ES播放视频
  • 6,Android FFmpeg简单合成MP4:视屏解封与重新封装
  • 7,Android FFmpeg视频编码

本文你可以了解到

渲染多视频画面,是实现音视频编辑的基础,本文将介绍如何将多个视频画面渲染到OpenGL中,以及如何对画面进行混合、缩放、移动等。

写在前面

距离上次更新已经有两个星期,由于这段时间事情比较多,还请各位关注本系列文章的小伙伴见谅,一有时间我会加紧码字,感谢大家的关注和督促。

下面就来看看如何在OpenGL中渲染多视频画面。

一、渲染多画面

上篇文章中,详细的讲解了如何通过OpenGL渲染视频画面,以及对视频画面进行比例矫正,基于前面系列文章中封装好的工具,可以非常容易地实现在OpenGL中渲染多个视频画面。

上文的OpenGL Render非常简单如下:

class SimpleRender(private val mDrawer: IDrawer): GLSurfaceView.Renderer {
   

    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
   
        GLES20.glClearColor(0f, 0f, 0f, 0f)
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
        mDrawer.setTextureID(OpenGLTools.createTextureIds(1)[0])
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
   
        GLES20.glViewport(0, 0, width, height)
        mDrawer.setWorldSize(width, height)
    }

    override fun onDrawFrame(gl: GL10?) {
   
        mDrawer.draw()
    }
}

只支持一个Drawer,这里改造一下,把Drawer修改为列表,以支持多个绘制器。

class SimpleRender: GLSurfaceView.Renderer {
   

    private val drawers = mutableListOf<IDrawer>()

    override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
   
        GLES20.glClearColor(0f, 0f, 0f, 0f)
        val textureIds = OpenGLTools.createTextureIds(drawers.size)
        for ((idx, drawer) in drawers.withIndex()) {
   
            drawer.setTextureID(textureIds[idx])
        }
    }

    override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
   
        GLES20.glViewport(0, 0, width, height)
        for (drawer in drawers) {
   
            drawer.setWorldSize(width, height)
        }
    }

    override fun onDrawFrame(gl: GL10?) {
   
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT)
        drawers.forEach {
   
            it.draw()
        }
    }

    fun addDrawer(drawer: IDrawer) {
   
        drawers.add(drawer)
    }
}

同样非常简单,

  1. 增加一个addDrawer方法,用来添加多个绘制器。
  2. 在onSurfaceCreated中为每个绘制器设置一个纹理ID。
  3. 在onSurfaceChanged中为每个绘制器设置显示区域宽高。
  4. 在onDrawFrame中,遍历所有绘制器,启动绘制。

接着,新建一个新页面,生成多个解码器和绘制器。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto">
    <android.opengl.GLSurfaceView
            android:id="@+id/gl_surface"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>
class MultiOpenGLPlayerActivity: AppCompatActivity() {
   
    private val path = Environment.getExternalStorageDirectory().absolutePath + "/mvtest.mp4"
    private val path2 = Environment.getExternalStorageDirectory().absolutePath + "/mvtest_2.mp4"

    private val render = SimpleRender()

    private val threadPool = Executors.newFixedThreadPool(10)

    override fun onCreate(savedInstanceState: Bundle?) {
   
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_opengl_player)
        initFirstVideo()
        initSecondVideo()
        initRender()
    }
    
    private fun initFirstVideo() {
   
        val drawer = VideoDrawer()
        drawer.setVideoSize(1920, 1080)
        drawer.getSurfaceTexture {
   
            initPlayer(path, Surface(it), true)
        }
        render.addDrawer(drawer)
    }

    private fun initSecondVideo() {
   
        val drawer = VideoDrawer()
        drawer.setVideoSize(1920, 1080)
        drawer.getSurfaceTexture {
   
            initPlayer(path2, Surface(it), false)
        }
        render.addDrawer(drawer)
    }

    private fun initPlayer(path: String, sf: Surface, withSound: Boolean) {
   
        val videoDecoder = VideoDecoder(path, null, sf)
        threadPool.execute(videoDecoder)
        videoDecoder.goOn()

        if (withSound) {
   
            val audioDecoder = AudioDecoder(path)
            threadPool.execute(audioDecoder)
            audioDecoder.goOn()
        }
    }
    
    private fun initRender() {
   
        gl_surface.setEGLContextClientVersion(2)
        gl_surface.setRenderer(render)
    }
}

代码比较简单,通过之前封装好的解码工具和绘制工具,添加了两个视频画面的渲染。

当然了,你可以添加更多的画面到OpenGL中渲染。
并且,你应该发现了,渲染多个视

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

开发的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值