【Android 音视频开发打怪升级:OpenGL渲染视频画面篇】五、OpenGL FBO数据缓冲区

【声 明】

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

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

教程代码:【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视频编码

本文你可以了解到

本文将介绍如何使用FBO,FBO可以实现什么效果,以及如何在着色器中使用多个纹理单元。

先来看看利用FBO实现的灵魂出窍效果:

灵魂出窍

一、FBO与EGL的离屏渲染的区别

上一篇文章,讲解了如何使用EGL,并且提到EGL可以建立一个离屏渲染的缓冲区,这种离屏渲染的方式通常用于模拟整个渲染窗口,比如可以用于FFmpeg软编码,将显示在虚拟窗口中的画面编码成H264。

与此同时,OpenGL也提供另外一种离屏渲染方式,即FBO。FBO不仅可以实现离屏渲染整个OpenGL窗口,也可以用于处理碎片画面,即窗口中的小画面。

关于EGL的离屏渲染,将会在后面关于FFmpeg的文章中使用到,这里暂且不论。

而在视频编辑当中,FBO离屏渲染扮演着很重要的角色,许多的视频滤镜都会用到,接下来就来看看FBO如何使用吧。

二、FBO简介

OpenGL 在渲染到系统窗口之前,都会将数据送到 FBO 上,也就是说,FBO 其实一直在默默的为我们服务。
所以,OpenGL 在一开始就创建了一个默认的 FBO。

FBO:Frame Buffer Object,帧缓存对象。

从名字上看,往往很容易让人误解这是一个缓存空间,但实际上,FBO很重要的在最后面的Object上。这是一个缓存对象,包含了多个缓冲索引,分别为颜色缓冲(Color buffers), 深度缓冲(Depth buffer), 模板缓冲(Stencil buffer)

之所以说是缓冲索引,是因为FBO并不包含这些缓冲数据,仅仅保存了缓冲数据的索引地址。

FBO和这些缓冲区则通过附着点进行连接。

可以看到FBO中包含了:

1. 多个颜色附着点(GL_COLOR_ATTACHMENT0、GL_COLOR_ATTACHMENT1...)
2. 一个深度附着点(GL_DEPTH_ATTACHMENT)
3. 一个模板附着点(GL_STENCIL_ATTACHMENT)

可以划分为两类:

纹理附着(颜色附着):主要用于将颜色渲染到纹理中。

渲染缓冲对象RBO(Render Buffer Objecgt):主要用于渲染深度信息和模板信息。

在2D中,通常只用到了颜色附着,另外两种附着通常在3D渲染中使用。

上面说了,FBO可用于离屏渲染,下面就来看看如何通过FBO将画面渲染到一个“后台”的纹理中。

这里的后台,指不用于显示到窗口的纹理。

三、如何使用FBO

1. 新建纹理
fun createFBOTexture(width: Int, height: Int): IntArray {
   
    // 新建纹理ID
    val textures = IntArray(1)
    GLES20.glGenTextures(1, textures, 0)
    
    // 绑定纹理ID
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0])
    
    // 根据颜色参数,宽高等信息,为上面的纹理ID,生成一个2D纹理
    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height,
        0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null)
        
    // 设置纹理边缘参数
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST.toFloat())
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,GLES20.GL_LINEAR.toFloat())
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,GLES20.GL_CLAMP_TO_EDGE.toFloat())
    GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,GLES20.GL_CLAMP_TO_EDGE.toFloat())
    
    // 解绑纹理ID
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0)
    return textures
}

生成一个用于FBO的纹理和普通的纹理其实差不多。

首先,生成一个纹理ID,并绑定到OpenGL中。

其次,给这个纹理ID生成对应的纹理。

这里使用的是 GLES20.glTexImage2D ,在渲染图片纹理的时候,使用的是 GLUtils.texImage2D

关于创建纹理的宽高问题,这里说明一下:
FBO创建的是一个虚拟的窗口,所以,大小是可以根据自己的需求设置的,可以比实际系统窗口大。为了视频画面比例正常,可以把OpenGL的窗口宽高,以及纹理的宽高都设置为视频的宽高。因此,OpenGL在渲染的时候,我们也把无需再通过矩阵变换来矫正比例,直接拉伸就可以。

最后,设置纹理边缘参数,然后解绑。

2. 新建FrameBuffer
fun createFrameBuffer(): Int {
   
    val fbs = IntArray(1)
    GLES20.glGenFramebuffers(1, fbs, 0)
    return fbs[0]
}

新建FrameBuffer类似新建纹理ID,最后返回FBO索引

3. 绑定FBO
fun bindFBO(fb: Int, textureId: Int) {
   
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fb)
    GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
        GLES20.GL_TEXTURE_2D, textureId, 0)
}

先绑定上面创建的FBO,接着将FBO和上面创建的纹理通过颜色附着点 GLES20.GL_COLOR_ATTACHMENT0 绑定起来。

4. 解绑FBO
fun unbindFBO() {
   
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_NONE)
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0)
}

解绑FBO比较简单,其实就是将FBO绑定到默认的窗口上。

这里的 GLES20.GL_NONE 其实就是 0 ,也就是系统默认的窗口的 FBO 。

5. 删除FBO
fun deleteFBO(frame: IntArray, texture:IntArray) {
   
    //删除Frame Buffer
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_NONE)
    GLES20
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: OpenGLES 3.0是一个用于移动设备的图形渲染API,可以用来渲染3D图形和动画。要实现视频数据离屏渲染,可以按照以下步骤: 1.创建一个FBO(Frame Buffer Object)。FBO是一个特殊的OpenGL对象,它可以将渲染结果存储到一个纹理或者渲染缓冲区中。 2.创建一个纹理对象,用来存储渲染结果。将纹理对象作为FBO的颜色附件绑定到FBO上。 3.将FBO绑定到OpenGL上下文中。 4.创建一个渲染程序(Program),用于将视频数据渲染FBO中。该渲染程序应该包含一个顶点着色器(Vertex Shader)和一个片元着色器(Fragment Shader)。 5.将视频数据上传到纹理对象中。 6.设置顶点和纹理坐标,将视频数据渲染FBO中。 7.将FBOOpenGL上下文中解绑。 8.从纹理对象中获取渲染结果数据。 9.销毁FBO、纹理对象和渲染程序。 以上步骤需要使用OpenGL ES 3.0的相关函数和常量进行操作,具体实现可以参考OpenGL ES 3.0的相关文档和示例代码。 ### 回答2: OpenGLES(OpenGL for Embedded Systems)是一种针对嵌入式系统的2D和3D图形API。OpenGLES 3.0是OpenGLES的一个版本,它引入了更多的功能和更高的性能,以满足现代移动设备和嵌入式系统对图形渲染的需求。 要实现为视频数据进行离屏渲染,首先需要获取视频数据。可以通过各种方式获取视频数据,例如从文件中读取、网络传输等等。获取视频数据后,就可以进行渲染操作了。 接下来,需要创建一个离屏渲染的环境。在OpenGLES中,可以通过创建一个离屏帧缓冲对象(FBO)来实现离屏渲染。离屏帧缓冲对象可以将渲染结果存储在纹理或渲染缓冲中。 创建离屏帧缓冲对象后,需要将其绑定为当前的渲染目标。这样,所有的渲染操作将会在离屏帧缓冲对象中进行,而不是直接渲染屏幕上。可以使用glBindFramebuffer函数来绑定离屏帧缓冲对象。 一旦离屏帧缓冲对象被绑定,就可以通过OpenGL ES的渲染管线来进行渲染操作了。可以使用顶点缓冲对象、着色器程序和纹理等来设置渲染的属性和效果。可以使用glDrawArrays或glDrawElements函数来执行渲染操作。 渲染完成后,可以将离屏帧缓冲对象中的渲染结果存储在纹理中,或者将其拷贝到其他地方,例如内存或文件中。可以使用glFramebufferTexture2D或glReadPixels函数来实现这些操作。 最后,需要清除和释放离屏渲染所使用的资源,例如离屏帧缓冲对象、纹理和顶点缓冲对象等。可以使用glDeleteFramebuffers、glDeleteTextures和glDeleteBuffers函数来释放相应的资源。 通过以上步骤,就可以使用OpenGLES 3.0实现为视频数据进行离屏渲染。这样可以将渲染结果用于后续的处理、保存或显示等用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

开发的猫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值