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;