GPUImage

1,990 阅读4分钟

1. 简介

GPUImage 是一个开源的处理图片、实时视频流、视频文件的第三方库,同时支持 Mac OSiOS ,最低支持 iOS 4.0, 接口封装简单易用,里面内置了大量的滤镜供我们使用,当然也支持自定义滤镜,以及多种滤镜组合使用来完成对应的需求,目前共有 3 个版本:

  • 基于 OpenGL ES 的使用 Objective-C 封装的第一版:GPUImage
  • 基于 OpenGL ES 的使用 Swift 封装的第二版: GPUImage2
  • 基于 Metal 的使用 Swift 封装的第三版:GPUImage3

2. 特点

  • 源代码开源,实现透明,可定制化程度比较高。

  • 丰富的输入组件

    • 静态图片
    • 相机拍摄的照片
    • 视频(实时视频流和视频文件)
    • OpenGL 纹理
    • 二进制数据
    • UIElement(UIView,CALayer)
  • 大量的内置滤镜

    • 颜色处理类,31 个滤镜(亮度、色度、饱和度、对比度...)
    • 图像处理类,40 个滤镜(放射变换、裁剪、高斯模糊、毛玻璃效果...)
    • 颜色混合类,29 个滤镜(差异混合、透明度混合、遮罩混合...)
    • 视觉效果类,25 个滤镜(像素化、素描、浮雕、鱼眼...)
  • 丰富的输出组件

    • UIView
    • 视频文件
    • 纹理
    • 二进制数据
  • 灵活的滤镜链,滤镜效果之间可以互相串联、关联

  • 接口简单易用,把滤镜和 OpenGL 其他资源(contextprogramframeBuffer)都做了统一的封装,并且内置了一个 cache 模块实现了 frameBuffer 的复用。

  • 线程安全,GPUImage 创建了专门的 contextQueue,所有的滤镜都会在这个队列里处理。

  • 轻松实现自定义滤镜效果,无需关注 OpenGL 上下文环境的搭建以及渲染流程,专注于实现核心效果算法即可。

3. 滤镜处理流程

3.1 滤镜起点

  • GPUImagePicture

    处理静态图片,先解压图片,拿到解压后的位图,然后加载纹理,最后使用着色器程序对纹理进行处理。

  • GPUImageRawDataInput

    拿到二进制数据使用 CoreGraphics 绘制位图,然后加载纹理,最后使用着色器程序对纹理进行处理。

  • GPUImageTextureInput

    直接使用着色器程序对纹理进行处理。

  • GPUImageUIElement

    不管是 UIView 还是 CALayer,最终都会使用都会调用 [layer renderInContext:imageContext] 方法,绘制成位图,然后加载纹理,最后使用着色器程序对纹理进行处理。

  • GPUImageMovie

    拿到视频文件,使用 AVAssertReader 逐帧读取视频,将每一帧画面转为纹理,最后使用着色器程序对纹理进行处理。

  • GPUImageVideoCamera

    借助 AVFoundation 录制视频,在代理方法 -(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 拿到 CMSampleBufferRef,调用CMSampleBufferGetImageBuffer获取 CVImageBufferRef,然后将其转为纹理,最后使用着色器程序对纹理进行处理。

  • GPUImageStillCamera

    GPUImageStillCamera 继承自 GPUImageVideoCamera, 处理流程和GPUImageVideoCamera一样。

3.2 滤镜终点

  • GPUImageMovieWriter

    使用 AVAssetWriter 把录制的视频写入指定的文件中。

  • GPUImageRawDataOutput

    从帧缓冲区 framebuffer 获取 CVPixelBufferRef 数据,然后调用CVPixelBufferGetBaseAddress(renderTarget)得到二进制数据 GLubyte

  • GPUImageTextureOutput

    直接输出纹理,这个在使用滤镜链的时候用到。

  • GPUImageView

    GPUImageView 继承自 UIView,但是他的 layerClassCAEAGLLayer,借助于 OpenGLcontextCAEAGLLayer,将内容输出显示出来。

4. 核心类分析

4.1 GPUImageContext

GPUImageContextGPUImageOpenGL ES上下文的封装,添加了GPUImage相关的上下文,比如说Program的使用缓存,处理队列,CV纹理缓存等。

4.2 GLProgram

GLProgramGPUImageOpenGL ESprogram 封装,根据顶点、片元着色器源文件或者字符串生成对应的着色器程序,编译一下,然后 attachprogram 上面,然后 link program,成功以后就可以 user program 了。创建了针对 attributeuniform 的数据创建了对应的数组,方便在使用滤镜的时候进行数据绑定。

4.3 GPUImageFramebuffer

GPUImageFramebuffer是GPUImageOpenGL ESframeBuffer 封装,负责处理帧缓冲区里面的操作,生成顶点坐标数据,将顶点数据从 CPU 拷贝到 GPU 的显存中,并且生成纹理,设置纹理的放大缩小过滤方式(GL_TEXTURE_MIN_FILTERGL_TEXTURE_MAG_FILTER)以及环绕方式(GL_TEXTURE_WRAP_SGL_TEXTURE_WRAP_T),如果使用 mipmap,还需要处理 mipmap 相关设置。默认不使用 mipmap

4.4 GPUImageFramebufferCache

GPUImageFramebufferCacheGPUImageFrameBuffer的管理类,使用 NSMutableDictionary 缓存 GPUImageFrameBuffer,并且在收到内存警告的时候清空缓存。

5. 不足之处

  • 不支持人脸检测,二维码条形码识别,iOS 系统的 CoreImage 是支持人脸检测的。
  • 对应大图的处理会导致图像质量损失,GPUImage 在纹理大小超过 4096 * 4096 的时候,会自动压缩成支持的最大尺寸纹理的图像,然后再进行进一步处理。

6. 工作流程图

GPUImage 工作流程图