开发一个完整iOS直播app——GPUImage渲染底层实现-opengl

简介:

一、前言

  本篇主要讲解GPUImage底层是如何渲染的,GPUImage底层使用的是OPENGL,操控GPU来实现屏幕展示

  由于网上OpenGL实战资料特别少,官方文档对一些方法也是解释不清楚,避免广大同学再次爬坑,本篇讲解了不少OpenGL的知识,并且还讲解了花了大量时间解决bug的注意点,曾经因为对glDrawArrays这个方法不熟悉,遇上Bug,晚上熬到凌晨四点都没解决,还是第二天中午解决的。

  如果喜欢我的文章,可以关注我微博:袁峥Seemygo,也可以来小码哥,了解下我们的iOS培训课程。后续还会更新更多内容,有任何问题,欢迎关注微,信号“小码哥订阅号”。

  二、GPUImageVideoCamera

  • 可以捕获采集的视频数据

  • 关键是捕获到一帧一帧视频数据如何展示?

  • 通过这个方法可以获取采集的视频数据

  • 采集视频注意点:要设置采集竖屏,否则获取的数据是横屏

  • 通过AVCaptureConnection就可以设置

  三、自定义OpenGLView渲染视频

  暴露一个接口,获取采集到的帧数据,然后把帧数据传递给渲染View,展示出来

  四、利用OpenGL渲染帧数据并显示

  • 导入头文件#import <GLKit/GLKit.h>,GLKit.h底层使用了OpenGLES,导入它,相当于自动导入了OpenGLES

  • 步骤

    • 01-自定义图层类型

    • 02-初始化CAEAGLLayer图层属性

    • 03-创建EAGLContext

    • 04-创建渲染缓冲区

    • 05-创建帧缓冲区

    • 06-创建着色器

    • 07-创建着色器程序

    • 08-创建纹理对象

    • 09-YUV转RGB绘制纹理

    • 10-渲染缓冲区到屏幕

    • 11-清理内存

  01-自定义图层类型

  • 为什么要自定义图层类型CAEAGLLayer? CAEAGLLayer是OpenGL专门用来渲染的图层,使用OpenGL必须使用这个图层

  02-初始化CAEAGLLayer图层属性

  • 1.不透明度(opaque)=YES,CALayer默认是透明的,透明性能不好,最好设置为不透明.

  • 2.设置绘图属性

    • kEAGLDrawablePropertyRetainedBacking :NO (告诉CoreAnimation不要试图保留任何以前绘制的图像留作以后重用)

    • kEAGLDrawablePropertyColorFormat :kEAGLColorFormatRGBA8 (告诉CoreAnimation用8位来保存RGBA的值)

  • 其实设置不设置都无所谓,默认也是这个值,只不过GPUImage设置了

  03-创建EAGLContext

  • 需要将它设置为当前context,所有的OpenGL ES渲染默认渲染到当前上下文

  • EAGLContext管理所有使用OpenGL ES进行描绘的状态,命令以及资源信息,要绘制东西,必须要有上下文,跟图形上下文类似。

  • 当你创建一个EAGLContext,你要声明你要用哪个version的API。这里,我们选择OpenGL ES 2.0

  04-创建渲染缓冲区

  • 有了上下文,openGL还需要在一块buffer进行描绘,这块buffer就是RenderBuffer

  • OpenGLES 总共有三大不同用途的color buffer,depth buffer 和 stencil buffer.

  • 最基本的是color buffer,创建它就好了

  函数glGenRenderbuffers

  • 它是为renderbuffer(渲染缓存)申请一个id(名字),创建渲染缓存

  • 参数n表示申请生成renderbuffer的个数

  • 参数renderbuffers返回分配给renderbuffer(渲染缓存)的id

      。 注意:返回的id不会为0,id 0 是OpenGL ES保留的,我们也不能使用id 为0的renderbuffer(渲染缓存)。

  函数glBindRenderbuffer

  • 告诉OpenGL:我在后面引用GL_RENDERBUFFER的地方,其实是引用_colorRenderBuffer

  • 参数target必须为GL_RENDERBUFFER

  • 参数renderbuffer就是使用glGenRenderbuffers生成的id

      。 当指定id的renderbuffer第一次被设置为当前renderbuffer时,会初始化该 renderbuffer对象,其初始值为:

  • 函数renderbufferStorage

  • 把渲染缓存(renderbuffer)绑定到渲染图层(CAEAGLLayer)上,并为它分配一个共享内存。

  • 参数target,为哪个renderbuffer分配存储空间

  • 参数drawable,绑定在哪个渲染图层,会根据渲染图层里的绘图属性生成共享内存。

  实战代码

  05-创建帧缓冲区

  • 它相当于buffer(color, depth, stencil)的管理者,三大buffer可以附加到一个framebuffer上

  • 本质是把framebuffer内容渲染到屏幕

  函数glFramebufferRenderbuffer

  • 该函数是将相关buffer()三大buffer之一)attach到framebuffer上,就会自动把渲染缓存的内容填充到帧缓存,在由帧缓存渲染到屏幕

  • 参数target,哪个帧缓存

  • 参数attachment是指定renderbuffer被装配到那个装配点上,其值是GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT中的一个,分别对应 color,depth和 stencil三大buffer。

  • renderbuffertarget:哪个渲染缓存

  • renderbuffer渲染缓存id

  06-创建着色器

  着色器

  • 什么是着色器? 通常用来处理纹理对象,并且把处理好的纹理对象渲染到帧缓存上,从而显示到屏幕上。

  • 提取纹理信息,可以处理顶点坐标空间转换,纹理色彩度调整(滤镜效果)等操作。

  • 着色器分为顶点着色器,片段着色器

    • 顶点着色器用来确定图形形状

    • 片段着色器用来确定图形渲染颜色

  • 步骤: 1.编辑着色器代码 2.创建着色器 3.编译着色器

  • 只要创建一次,可以在一开始的时候创建

      着色器代码

  • 实战代码

  07-创建着色器程序

  • 步骤: 1.创建程序 2.贴上顶点和片段着色器 3.绑定attribute属性 4.连接程序 5.绑定uniform属性 6.运行程序

  • 注意点:第3步和第5步,绑定属性,必须有顺序,否则绑定不成功,造成黑屏

  08-创建纹理对象

  纹理

  • 采集的是一张一张的图片,可以把图片转换为OpenGL中的纹理, 然后再把纹理画到OpenGL的上下文中

  • 什么是纹理?一个纹理其实就是一幅图像。

  • 纹理映射,我们可以把这幅图像的整体或部分贴到我们先前用顶点勾画出的物体上去.

  • 比如绘制一面砖墙,就可以用一幅真实的砖墙图像或照片作为纹理贴到一个矩形上,这样,一面逼真的砖墙就画好了。如果不用纹理映射的方法,则墙上的每一块砖都必须作为一个独立的多边形来画。另外,纹理映射能够保证在变换多边形时,多边形上的纹理图案也随之变化。

  • 纹理映射是一个相当复杂的过程,基本步骤如下:

    • 1)激活纹理单元、2)创建纹理 、3)绑定纹理 、4)设置滤波

  • 注意:纹理映射只能在RGBA方式下执行

  函数glTexParameter

  • 控制滤波,滤波就是去除没用的信息,保留有用的信息

  • 一般来说,纹理图像为正方形或长方形。但当它映射到一个多边形或曲面上并变换到屏幕坐标时,纹理的单个纹素很少对应于屏幕图像上的像素。根据所用变换和所用纹理映射,屏幕上单个象素可以对应于一个纹素的一小部分(即放大)或一大批纹素(即缩小)

  • 固定写法

  函数glPixelStorei

  • 设置像素存储方式

  • pname:像素存储方式名

  • 一种是 GL_PACK_ALIGNMENT用于将像素数据打包,一般用于压缩。

  • 另一种是GL_UNPACK_ALIGNMENT,用于将像素数据解包,一般生成纹理对象,就需要用到解包.

  • param:用于指定存储器中每个像素行有多少个字节对齐。这个数值一般是1、2、4或8,

      一般填1,一个像素对应一个字节;

  函数CVOpenGLESTextureCacheCreateTextureFromImage

  • 根据图片生成纹理

  • 参数allocator kCFAllocatorDefault,默认分配内存

  • 参数textureCache 纹理缓存

  • 参数sourceImage 图片

  • 参数textureAttributes NULL

  • 参数target , GL_TEXTURE_2D(创建2维纹理对象)

  • 参数internalFormat GL_LUMINANCE,亮度格式

  • 参数width 图片宽

  • 参数height 图片高

  • 参数format GL_LUMINANCE 亮度格式

  • 参数type 图片类型 GL_UNSIGNED_BYTE

  • 参数planeIndex 0,切面角标,表示第0个切面

  • 参数textureOut 输出的纹理对象

  实战代码

  09-YUV转RGB绘制纹理

  • 纹理映射只能在RGBA方式下执行

  • 而采集的是YUV,所以需要把YUV 转换 为 RGBA,

  • 本质其实就是改下矩阵结构

  • 注意点(熬夜凌晨的bug):glDrawArrays如果要绘制着色器上的点和片段,必须和着色器赋值代码放在一个代码块中,否则找不到绘制的信息,就绘制不上去,造成屏幕黑屏

  • 之前是把glDrawArrays和YUV转RGB方法分开,就一直黑屏.

  函数glUniform1i

  • 指定着色器中亮度纹理对应哪一层纹理单元

  • 参数location:着色器中纹理坐标

  • 参数x:指定那一层纹理

  函数glEnableVertexAttribArray

  • 开启顶点属性数组,只有开启顶点属性,才能给顶点属性信息赋值

  函数glVertexAttribPointer

  • 设置顶点着色器属性,描述属性的基本信息

  • 参数indx:属性ID,给哪个属性描述信息

  • 参数size:顶点属性由几个值组成,这个值必须位1,2,3或4;

  • 参数type:表示属性的数据类型

  • 参数normalized:GL_FALSE表示不要将数据类型标准化

  • 参数stride 表示数组中每个元素的长度;

  • 参数ptr 表示数组的首地址

  函数glBindAttribLocation

  • 给属性绑定ID,通过ID获取属性,方便以后使用

  • 参数program 程序

  • 参数index 属性ID

  • 参数name 属性名称

  函数glDrawArrays

  • 作用:使用当前激活的顶点着色器的顶点数据和片段着色器数据来绘制基本图形

  • mode:绘制方式 一般使用GL_TRIANGLE_STRIP,三角形绘制法

  • first:从数组中哪个顶点开始绘制,一般为0

  • count:数组中顶点数量,在定义顶点着色器的时候,就定义过了,比如vec4,表示4个顶点

  • 注意点,如果要绘制着色器上的点和片段,必须和着色器赋值代码放在一个代码块中,否则找不到绘制的信息,就绘制不上去,造成屏幕黑屏。

  实战代码

  请点击此处输入图片描述请点击此处输入图片描述

  10-渲染缓冲区到屏幕

  • 注意点:必须设置窗口尺寸glViewport

  • 注意点:渲染代码必须调用[EAGLContext setCurrentContext:_context]

  • 原因:因为是多线程,每一个线程都有一个上下文,只要在一个上下文绘制就好,设置线程的上下文为我们自己的上下文,就能绘制在一起了,否则会黑屏.

  • 注意点:每次创建纹理前,先把之前的纹理引用清空[self cleanUpTextures],否则卡顿

      函数glViewport

  • 设置OpenGL渲染窗口的尺寸大小,一般跟图层尺寸一样.

  • 注意:在我们绘制之前还有一件重要的事情要做,我们必须告诉OpenGL渲染窗口的尺寸大小

      方法presentRenderbuffer

  • 是将指定renderbuffer呈现在屏幕上

  实战代码

  11-清理内存

  • 注意:只要有Ref结尾的,都需要自己手动管理,清空

  函数glClearColor

  • 设置一个RGB颜色和透明度,接下来会用这个颜色涂满全屏.

  函数glClear

  • 用来指定要用清屏颜色来清除由mask指定的buffer,mask可以是 GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT的自由组合。

  • 在这里我们只使用到 color buffer,所以清除的就是 clolor buffer。

  • GPUImage工作原理

  • GPUImage最关键在于GPUImageFramebuffer这个类,这个类会保存当前处理好的图片信息。

  • GPUImage是通过一个链条处理图片,每个链条通过target连接,每个target处理完图片后,会生成一个GPUImageFramebuffer对象,并且把图片信息保存到GPUImageFramebuffer。

  • 这样比如targetA处理好,要处理targetB,就会先取出targetA的图片,然后targetB在targetA的图片基础上在进行处理.
















本文转自ljianbing51CTO博客,原文链接:http://blog.51cto.com/ljianbing/1921654  ,如需转载请自行联系原作者

相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
3天前
|
供应链 搜索推荐 API
1688APP原数据API接口的开发、应用与收益(一篇文章全明白)
1688作为全球知名的B2B电商平台,通过开放的原数据API接口,为开发者提供了丰富的数据资源,涵盖商品信息、交易数据、店铺信息、物流信息和用户信息等。本文将深入探讨1688 APP原数据API接口的开发、应用及其带来的商业收益,包括提升流量、优化库存管理、增强用户体验等方面。
25 6
|
4天前
|
机器学习/深度学习 前端开发 算法
婚恋交友系统平台 相亲交友平台系统 婚恋交友系统APP 婚恋系统源码 婚恋交友平台开发流程 婚恋交友系统架构设计 婚恋交友系统前端/后端开发 婚恋交友系统匹配推荐算法优化
婚恋交友系统平台通过线上互动帮助单身男女找到合适伴侣,提供用户注册、个人资料填写、匹配推荐、实时聊天、社区互动等功能。开发流程包括需求分析、技术选型、系统架构设计、功能实现、测试优化和上线运维。匹配推荐算法优化是核心,通过用户行为数据分析和机器学习提高匹配准确性。
24 3
|
10天前
|
移动开发 小程序 PHP
校园圈子论坛系统采取的PHP语音和uni账号开发的小程序APP公众号H5是否只需要4800元?是的,就是只需要4800元
关于校园圈子论坛系统采用PHP语言和uni-app开发的小程序、APP、公众号和H5是否仅需4800元这个问题,实际上很难给出一个确定的答案。这个价格可能受到多种因素的影响
40 8
|
6天前
|
人工智能 小程序 数据处理
uni-app开发AI康复锻炼小程序,帮助肢体受伤患者康复!
近期,多家康复机构咨询AI运动识别插件是否适用于肢力运动受限患者的康复锻炼。本文介绍该插件在康复锻炼中的应用场景,包括康复运动指导、运动记录、恢复程度记录及过程监测。插件集成了人体检测、姿态识别等功能,支持微信小程序平台,使用便捷,安全可靠,帮助康复治疗更加高效精准。
|
25天前
|
传感器 iOS开发 UED
探索iOS生态系统:从App Store优化到用户体验提升
本文旨在深入探讨iOS生态系统的多个方面,特别是如何通过App Store优化(ASO)和改进用户体验来提升应用的市场表现。不同于常规摘要仅概述文章内容的方式,我们将直接进入主题,首先介绍ASO的重要性及其对开发者的意义;接着分析当前iOS平台上用户行为的变化趋势以及这些变化如何影响应用程序的设计思路;最后提出几点实用建议帮助开发者更好地适应市场环境,增强自身竞争力。
|
27天前
|
人工智能 小程序 搜索推荐
uni app下开发AI运动小程序解决方案
本文介绍了在小程序中实现AI运动识别的解决方案。该方案依托于UNI平台,通过高效便捷的插件形式,实现包括相机抽帧控制、人体识别、姿态识别等在内的多项功能,无需依赖后台服务器,大幅提高识别效率和用户体验。方案内置多种运动模式,支持自定义扩展,适用于AI健身、云上赛事、AI体测等多场景,适合新开发和存量改造项目。
|
1月前
|
设计模式 Swift iOS开发
探索iOS开发:从基础到高级,打造你的第一款App
【10月更文挑战第40天】在这个数字时代,掌握移动应用开发已成为许多技术爱好者的梦想。本文将带你走进iOS开发的世界,从最基础的概念出发,逐步深入到高级功能实现,最终指导你完成自己的第一款App。无论你是编程新手还是有志于扩展技能的开发者,这篇文章都将为你提供一条清晰的学习路径。让我们一起开始这段旅程吧!
|
1月前
|
小程序 数据挖掘 UED
开发1个上门家政小程序APP系统,都有哪些功能?
在快节奏的现代生活中,家政服务已成为许多家庭的必需品。针对传统家政服务存在的问题,如服务质量不稳定、价格不透明等,我们历时两年开发了一套全新的上门家政系统。该系统通过完善信用体系、提供奖励机制、优化复购体验、多渠道推广和多样化盈利模式,解决了私单、复购、推广和盈利四大痛点,全面提升了服务质量和用户体验,旨在成为家政行业的领导者。
|
1月前
|
机器人
布谷直播App系统源码开发之后台管理功能详解
直播系统开发搭建管理后台功能详解!
|
2月前
|
NoSQL PHP Redis
布谷语音app源码服务器环境配置及技术开发语言
布谷语音app源码服务器环境配置及技术语言研发。。
下一篇
DataWorks