GPUImage源碼分析與使用(一) GPUImage簡介 GPUImage框架 GPUImage基類的具體介紹

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個,最終處理的都是紋理

  1. GPUImageVideoCamera(正在錄製的視頻)
  2. GPUImageStillCamera(拍攝的照片)
  3. GPUImagePicture(靜態圖片)
  4. GPUImageMovie(一段視頻)
  5. GPUImageMovieComposition
  6. GPUImageTextureInput(紋理)
  7. GPUImageRawDataOutput(二進制數據)
  8. GPUImageUIElement(UIView/UILayer)
  9. GPUImageColorConversion

Pipeline(管道)

  1. GPUImageFilterPipeline

Filters(過濾器/濾鏡)

  1. Base基類
  • GPUImageFilter,所有Filter父類
  • GPUImageTwoInputFilter
  • GPUImageThreeInputFilter
  • GPUImageFourInputFilter
  • GPUImageTwoPassFilter
  • GPUImageTwoPassTextureSamplingFilter
  • GPUImageFilterGroup
  • GPUImage3x3TextureSamplingFilter
  • GPUImageTwoInputCrossTextureSamplingFilter
  • GPUImageBuffer

內置濾鏡

  1. Color processing(色彩處理)

  2. Image processing(圖像處理)

  3. Blends(混合)

  4. Effects(效果)

Outputs(輸出)

4種輸出結果

  1. GPUImageView
  2. GPUImageMovieWriter
  3. GPUImageTextureOutput
  4. GPUImageRawDataOutput

SupportFrameworks

  1. CoreMedia.framework
  2. CoreVideo.framework
  3. OpenGL ES.framework(1.0和2.0使用,3.0使用Metal)
  4. QuartzCore.framework
  5. AV Foundation.framework(捕捉視頻)

GPUImage類的介紹

  1. GLProgram,shader管理,編譯鏈接
  2. GPUImageContext,OpenGL Context管理
  3. GPUImageFramebuffer和GPUImageFramebufferCache,buffer管理
  4. Source,數據源
  5. Pipeline,處理管道
  6. Filters,濾鏡組合
  7. Outputs,輸出組件

圖片處理示例

  1. 飽和度濾鏡
  • 原圖->GPUImagePicture->GPUImageSaturationFilter(飽和度濾鏡)->GPUImageView->添加濾鏡後的圖片
  • 處理流程跟OpenGl ES 一樣,只是更具有封裝性

GPUImage基類的具體介紹

GPUImage.h

GPUImage所有需要使用到的類的聲明基本上都在這裏了。

GLProgram

shader管理

GLProgram.h

  1. 變量聲明,全局變量聲明
{
    NSMutableArray  *attributes; //屬性
    NSMutableArray  *uniforms; //通道
    GLuint          program,
    vertShader,  //頂點着色器
    fragShader;  //片元着色器
}
  1. 屬性聲明,記錄編譯信息等
@property(readwrite, nonatomic) BOOL initialized;
//編譯信息記錄
@property(readwrite, copy, nonatomic) NSString *vertexShaderLog;
@property(readwrite, copy, nonatomic) NSString *fragmentShaderLog;
@property(readwrite, copy, nonatomic) NSString *programLog;
  1. 初始化,三種初始化方法,第一種是主要方法
/*
 傳入頂點着色器代碼和片元着色器代碼
 可以傳入字符串類型,也可以傳入文件類型,比如以.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;
  1. 添加attribute
- (void)addAttribute:(NSString *)attributeName;
  1. attribute和uniform的獲取
//獲得attribute
- (GLuint)attributeIndex:(NSString *)attributeName;
//獲得uniform
- (GLuint)uniformIndex:(NSString *)uniformName;
  1. program操作
- (BOOL)link;
- (void)use;
- (void)validate;

GLProgram.m

  1. 初始化方法,後兩種初始化方法都是在獲取到本地文件路徑後讀取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;
}
  1. 着色器編譯方法
- (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;
}
  1. 添加屬性addAttribute,使用函數glBindAttribLocation
- (void)addAttribute:(NSString *)attributeName
{
    if (![attributes containsObject:attributeName])
    {
        [attributes addObject:attributeName];
        //glBindAttribLocation函數添加addattribute
        glBindAttribLocation(program, 
                             (GLuint)[attributes indexOfObject:attributeName],
                             [attributeName UTF8String]);
    }
}
  1. 獲取attribute和uniform
- (GLuint)attributeIndex:(NSString *)attributeName
{
    return (GLuint)[attributes indexOfObject:attributeName];
}
- (GLuint)uniformIndex:(NSString *)uniformName
{
    return glGetUniformLocation(program, [uniformName UTF8String]);
}
  1. 鏈接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;
}
  1. 使用和銷燬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);
    }   
}
  1. dealloc,刪除着色器和program
- (void)dealloc
{
    if (vertShader)
        glDeleteShader(vertShader);
        
    if (fragShader)
        glDeleteShader(fragShader);
    
    if (program)
        glDeleteProgram(program);
       
}

GPUImageContext

GPUImage會有很多context,需要GPUImageContext進行context管理

GLProgramGPUImageContext 不需要使用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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章