AVPlayer和GPUImagede学习

GPUImage(三):视频滤镜GPUImageFilter高阶

2017-11-01  本文已影响47人  sellse

GPUImage(一):视频采集GPUImageVideoCamera介绍了GPUImage视频采集类
GPUImage(二):视频滤镜GPUImageFilter基础篇介绍了GPUImage滤镜的一些简单用法和片段着色器的基本使用。
本篇继续探索GPUImageFilter类的具体实现,相对于基础篇较为抽象。

GPUImageFilter3个主要职责

GPUImageFilter .m文件开头定义了一个顶点着色器kGPUImageVertexShaderString和一个直通片元着色器kGPUImagePassthroughFragmentShaderString,用于初始化一个标准的GPUImageFilter,会被重写。

初始化方法

1. -(id)init;//调用2
2. -(id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString;//调用4,是上文GPUImageSaturationFilter调用的方法
3. -(id)initWithFragmentShaderFromFile:(NSString *)fragmentShaderFilename;//从文件找查找`.fsh`文件并调用2
4. -(id)initWithVertexShaderFromString:(NSString *)vertexShaderString fragmentShaderFromString:(NSString *)fragmentShaderString;//**最终都会调用这个方法**

在4初始化方法中,调用在父类GPUImageOutput中定义的方法
void runSynchronouslyOnVideoProcessingQueue(void (^block)(void))做一系列操作:

runSynchronouslyOnVideoProcessingQueue(^{
        [GPUImageContext useImageProcessingContext];//得到上下环境
        filterProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:vertexShaderString fragmentShaderString:fragmentShaderString];//openGL源程序
        if (!filterProgram.initialized){
            [self initializeAttributes]; //初始化shader属性,调用了初始化shader属性的方法
            if (![filterProgram link]) {
                NSString *progLog = [filterProgram programLog];//源程序调试log
                NSLog(@"Program link log: %@", progLog);
                NSString *fragLog = [filterProgram fragmentShaderLog];//片段着色器调试log
                NSLog(@"Fragment shader compile log: %@", fragLog);
                NSString *vertLog = [filterProgram vertexShaderLog];//顶点着色器调试log
                NSLog(@"Vertex shader compile log: %@", vertLog);
                filterProgram = nil;
                NSAssert(NO, @"Filter shader link failed");
            }
        }
        filterPositionAttribute = [filterProgram attributeIndex:@"position"];//得到顶点属性
        filterTextureCoordinateAttribute = [filterProgram attributeIndex:@"inputTextureCoordinate"];//得到纹理属性
        filterInputTextureUniform = [filterProgram uniformIndex:@"inputImageTexture"]; // This does assume a name of "inputImageTexture" for the fragment shader //得到纹理常量
        
        [GPUImageContext setActiveShaderProgram:filterProgram];//运行源程序
        
        glEnableVertexAttribArray(filterPositionAttribute);  //开启顶点坐标数组
        glEnableVertexAttribArray(filterTextureCoordinateAttribute);    //开启纹理坐标数组
    });

其中,glEnableVertexAttribArray函数:把顶点属性位置值作为它的参数,启用在着色器中找到的属性位置

GPUImageFilter init.png

静态图片处理Still image processing
重写父类两个静态图片处理方法(这一块讲解有待丰富)

最为核心的部分:渲染方法

+ (const GLfloat *)textureCoordinatesForRotation:(GPUImageRotationMode)rotationMode;
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
- (void)informTargetsAboutNewFrameAtTime:(CMTime)frameTime;
- (CGSize)outputFrameSize;//上边这个方法调用

这几个方法的作用分别是:

其中,第二个方法最为核心,展开来讲
两个GPUImageFramebuffer对象:
firstInputFramebuffer:输入纹理。先加锁,输入纹理使用完毕后解锁。在调用这个解锁之前必须确定之前已经调用加锁,否则会报错。
outputFramebuffer:输出纹理,
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
绑定输入纹理

glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
    
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

绑定顶点和纹理坐标并绘制图元
这几个方法都是被GPUImageInput代理方法调用的,都在- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;中完成调用。

输入参数
目测大概有近20个输入参数方法,这些函数是设置GLSL里面的变量,就不一一说了。

GPUImageInput代理方法
GPUImageInput代理定义在GPUImageContext中,后续再说。

开篇说,GPUImageFilter的第三个职责是绘制图元到特定的帧缓存,帧缓存是什么,下文说。

上一篇 下一篇

猜你喜欢

热点阅读