GPUImage简介
- GPUImage是链式编程,可以处理图片和视频,支持iOS和Mac。
- GPUImage1.0和2.0是基于 OpenGL ES 封装,1.0是OC版本,2.0是swift版本,3.0是基于Metal的swift版本。
- AVFoundation在GPUImage框架中是用来捕捉视频的
CoreImage与GPUImage的对比
- CoreImage是Apple原生的图片视频处理框架
- 两者都是基于OpenGL ES封装的框架,在性能上没有太大区别
GPUImage的优势
- 在iOS4.0和5.0低版本上GPUImage会比CoreImage表现更好
- GPUImage在视频滤镜处理上会比CoreImage表现更好
- GPUImage是开源框架,支持自定义滤镜
- GPUImage源码开源,会比CoreImage更易于使用
CoreImage的优势
- CoreImage是官方框架,使用方便,不需要担心维护问题,第三方框架会有停止更新维护的情况
- 还支持CPU渲染
- 与Metal、spriteKit、SceneKit、Core Animation等官方框架能更好的配合使用
- 支持人脸识别功能,但是识别功能不是很强大
- 支持对大图进行处理,GPU的纹理限制是4096*4096,对于超出限制的图片,GPUImage会压缩处理导致损失图片质量,CoreImage会把图片拆解成小图处理
GPUImage的特性
- 有丰富的输入组件,可以处理图片、纹理、视频、二进制数据、UIElement(UIView、CALayer),可以使用GPUImage拍照、处理纹理图片、给视频或拍摄中的视频添加滤镜、添加水印可以使用UIElement
- 集成了很多内置滤镜:
- 颜色类有亮度、饱和度、色度、对比度、白平衡等;
- 图像类有仿射变换、裁剪、高斯模糊、毛玻璃等;
- 颜色混合类有透明度混合、纹理混合;
- 效果类有素描、像素画、旋涡等
- 有很多输出组件,输出方式有UIView、视频文件、纹理、二进制数据等
- 灵活的滤镜链,模块化功能
GPUImage框架
Source(来源)
GPUImageOutput,常用的为前4个,最终处理的都是纹理
- GPUImageVideoCamera(正在录制的视频)
- GPUImageStillCamera(拍摄的照片)
- GPUImagePicture(静态图片)
- GPUImageMovie(一段视频)
- GPUImageMovieComposition
- GPUImageTextureInput(纹理)
- GPUImageRawDataOutput(二进制数据)
- GPUImageUIElement(UIView/UILayer)
- GPUImageColorConversion
Pipeline(管道)
- GPUImageFilterPipeline
Filters(过滤器/滤镜)
- Base基类
- GPUImageFilter,所有Filter父类
- GPUImageTwoInputFilter
- GPUImageThreeInputFilter
- GPUImageFourInputFilter
- GPUImageTwoPassFilter
- GPUImageTwoPassTextureSamplingFilter
- GPUImageFilterGroup
- GPUImage3x3TextureSamplingFilter
- GPUImageTwoInputCrossTextureSamplingFilter
- GPUImageBuffer
内置滤镜
Color processing(色彩处理)
Image processing(图像处理)
Blends(混合)
Effects(效果)
Outputs(输出)
4种输出结果
- GPUImageView
- GPUImageMovieWriter
- GPUImageTextureOutput
- GPUImageRawDataOutput
SupportFrameworks
- CoreMedia.framework
- CoreVideo.framework
- OpenGL ES.framework(1.0和2.0使用,3.0使用Metal)
- QuartzCore.framework
- AV Foundation.framework(捕捉视频)
GPUImage类的介绍
- GLProgram,shader管理,编译链接
- GPUImageContext,OpenGL Context管理
- GPUImageFramebuffer和GPUImageFramebufferCache,buffer管理
- Source,数据源
- Pipeline,处理管道
- Filters,滤镜组合
- Outputs,输出组件
图片处理示例
- 饱和度滤镜
- 原图->GPUImagePicture->GPUImageSaturationFilter(饱和度滤镜)->GPUImageView->添加滤镜后的图片
- 处理流程跟OpenGl ES 一样,只是更具有封装性
GPUImage基类的具体介绍
GPUImage.h
GPUImage所有需要使用到的类的声明基本上都在这里了。
GLProgram
shader管理
GLProgram.h
- 变量声明,全局变量声明
{
NSMutableArray *attributes; //属性
NSMutableArray *uniforms; //通道
GLuint program,
vertShader, //顶点着色器
fragShader; //片元着色器
}
- 属性声明,记录编译信息等
@property(readwrite, nonatomic) BOOL initialized;
//编译信息记录
@property(readwrite, copy, nonatomic) NSString *vertexShaderLog;
@property(readwrite, copy, nonatomic) NSString *fragmentShaderLog;
@property(readwrite, copy, nonatomic) NSString *programLog;
- 初始化,三种初始化方法,第一种是主要方法
/*
传入顶点着色器代码和片元着色器代码
可以传入字符串类型,也可以传入文件类型,比如以.vsh/.fsh/.glsl等为后缀等命名的文件
GPUImage里自定义滤镜基本都是使用字符串类型
*/
- (id)initWithVertexShaderString:(NSString *)vShaderString
fragmentShaderString:(NSString *)fShaderString;
- (id)initWithVertexShaderString:(NSString *)vShaderString
fragmentShaderFilename:(NSString *)fShaderFilename;
- (id)initWithVertexShaderFilename:(NSString *)vShaderFilename
fragmentShaderFilename:(NSString *)fShaderFilename;
- 添加attribute
- (void)addAttribute:(NSString *)attributeName;
- attribute和uniform的获取
//获得attribute
- (GLuint)attributeIndex:(NSString *)attributeName;
//获得uniform
- (GLuint)uniformIndex:(NSString *)uniformName;
- program操作
- (BOOL)link;
- (void)use;
- (void)validate;
GLProgram.m
- 初始化方法,后两种初始化方法都是在获取到本地文件路径后读取glsl字符串,然后调用第一种方法
//传入顶点着色器和片元着色器进行初始化
- (id)initWithVertexShaderString:(NSString *)vShaderString
fragmentShaderString:(NSString *)fShaderString;
{
if ((self = [super init]))
{
_initialized = NO;
attributes = [[NSMutableArray alloc] init];
uniforms = [[NSMutableArray alloc] init];
program = glCreateProgram();
//拿到着色器代码进行编译
if (![self compileShader:&vertShader
type:GL_VERTEX_SHADER
string:vShaderString])
{
NSLog(@"Failed to compile vertex shader");
}
// Create and compile fragment shader
if (![self compileShader:&fragShader
type:GL_FRAGMENT_SHADER
string:fShaderString])
{
NSLog(@"Failed to compile fragment shader");
}
//着色器编译后附着到program
glAttachShader(program, vertShader);
glAttachShader(program, fragShader);
}
return self;
}
- 着色器编译方法
- (BOOL)compileShader:(GLuint *)shader
type:(GLenum)type
string:(NSString *)shaderString
{
// CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
GLint status;
const GLchar *source;
//拿到source
source =
(GLchar *)[shaderString UTF8String];
if (!source)
{
NSLog(@"Failed to load vertex shader");
return NO;
}
//创建着色器
*shader = glCreateShader(type);
glShaderSource(*shader, 1, &source, NULL);
glCompileShader(*shader);
//获取shader信息
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE)
{
GLint logLength;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0)
{
GLchar *log = (GLchar *)malloc(logLength);
glGetShaderInfoLog(*shader, logLength, &logLength, log);
if (shader == &vertShader)
{
self.vertexShaderLog = [NSString stringWithFormat:@"%s", log];
}
else
{
self.fragmentShaderLog = [NSString stringWithFormat:@"%s", log];
}
free(log);
}
}
// CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);
// NSLog(@"Compiled in %f ms", linkTime * 1000.0);
return status == GL_TRUE;
}
- 添加属性addAttribute,使用函数glBindAttribLocation
- (void)addAttribute:(NSString *)attributeName
{
if (![attributes containsObject:attributeName])
{
[attributes addObject:attributeName];
//glBindAttribLocation函数添加addattribute
glBindAttribLocation(program,
(GLuint)[attributes indexOfObject:attributeName],
[attributeName UTF8String]);
}
}
- 获取attribute和uniform
- (GLuint)attributeIndex:(NSString *)attributeName
{
return (GLuint)[attributes indexOfObject:attributeName];
}
- (GLuint)uniformIndex:(NSString *)uniformName
{
return glGetUniformLocation(program, [uniformName UTF8String]);
}
- 链接program
- (BOOL)link
{
// CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
GLint status;
//链接Program
glLinkProgram(program);
//获取link状态
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
return NO;
//link成功之后删除着色器,从program中去着色器信息
if (vertShader)
{
glDeleteShader(vertShader);
vertShader = 0;
}
if (fragShader)
{
glDeleteShader(fragShader);
fragShader = 0;
}
self.initialized = YES;
// CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);
// NSLog(@"Linked in %f ms", linkTime * 1000.0);
return YES;
}
- 使用和销毁program
- (void)use
{
glUseProgram(program);
}
- (void)validate;
{
GLint logLength;
glValidateProgram(program);
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0)
{
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(program, logLength, &logLength, log);
self.programLog = [NSString stringWithFormat:@"%s", log];
free(log);
}
}
- dealloc,删除着色器和program
- (void)dealloc
{
if (vertShader)
glDeleteShader(vertShader);
if (fragShader)
glDeleteShader(fragShader);
if (program)
glDeleteProgram(program);
}
GPUImageContext
GPUImage会有很多context,需要GPUImageContext进行context管理
GLProgram 和 GPUImageContext 不需要使用GPUImage的开发者更改和直接使用,这是GPUImage框架本身使用的
GPUImageFramebuffer/GPUImageFramebufferCache
Framebuffer的管理
//开辟Framebuffer
// Initialization and teardown
- (id)initWithSize:(CGSize)framebufferSize;
- (id)initWithSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)fboTextureOptions onlyTexture:(BOOL)onlyGenerateTexture;
- (id)initWithSize:(CGSize)framebufferSize overriddenTexture:(GLuint)inputTexture;