GPUImage的filter 响应处理链 的理解笔记
GPUImage的filter的textures处理链式结构
两个最重要的的地方:
最重要的一个类GPUImageOutput(所有的filter的父类,其他也有继承它的,如GPUImageUIElement,UIKit元素通过CG转gles贴图 等等);
协议(或者接口)GPUImageInput。
继承GPUImageOutput且遵循GPUImageInput的filter,处理完成后输出又可以作为下一个filter的输入。
@protocol GPUImageInput <NSObject>
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex;
- (NSInteger)nextAvailableTextureIndex;
- (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
- (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
- (CGSize)maximumOutputSize;
- (void)endProcessing;
- (BOOL)shouldIgnoreUpdatesToThisTarget;
- (BOOL)enabled;
- (BOOL)wantsMonochromeInput;
- (void)setCurrentlyReceivingMonochromeInput:(BOOL)newValue;
@end
GPUImageFramebuffer
framebuffer的封装类,根据onlyGenerateTexture 判断 只生成纹理 或 framebuffer;摘自 - (void)generateFramebuffer;
只生成纹理的情况典型:GPUImageUIElement,GPUImageVideoCamera等等;
生成framebuffer,判断是否支持快速上传纹理数据(其实是判断CVOpenGLESTextureCacheCreate是否可用)
- 如果支持快速上传纹理,CVPixelBufferCreate生成renderTarget,CVOpenGLESTextureCacheCreateTextureFromImage根据renderTarget(sourceImage)生成renderTexture,最后调用glFramebufferTexture2D将framebuffer和renderTexture绑定在一块,framebuffer输出到texture(注:framebuffer也可以绑定到renderBuffer,也常称为colorbuffer,renderbuffer直接显示在CALayer上了;绑定在texture上通常作为中间值);
- 如果不支持;先generate texture,再绑定,glTexImage2D上传数据到GPU,最后调用glFramebufferTexture2D将framebuffer和texture绑定在一块;
GPUImageFramebuffer中的- (CGImageRef)newCGImageFromFramebufferContents;,用于从framebuffer中取出图像数据生成CGImageRef;
CGDataProviderRef dataProvider = NULL;
if ([GPUImageContext supportsFastTextureUpload])
{
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
NSUInteger paddedWidthOfImage = CVPixelBufferGetBytesPerRow(renderTarget) / 4.0; //字节对齐后的图片占用宽度可能要大
NSUInteger paddedBytesForImage = paddedWidthOfImage * (int)_size.height * ;
glFinish(); //强制提交前面调用的gl指令到GPU硬件,阻塞调用
CFRetain(renderTarget); //防止出现野指针,在回调中释放 I need to retain the pixel buffer here and release in the data source callback to prevent its bytes from being prematurely deallocated during a photo write operation
[self lockForReading];
rawImagePixels = (GLubyte *)CVPixelBufferGetBaseAddress(renderTarget);
dataProvider = CGDataProviderCreateWithData((__bridge_retained void*)self, rawImagePixels, paddedBytesForImage, dataProviderUnlockCallback); //全局的framebuffercache强引用当前自身,防止framebuffer在切换时出现问题
[[GPUImageContext sharedFramebufferCache] addFramebufferToActiveImageCaptureList:self]; // In case the framebuffer is swapped out on the filter, need to have a strong reference to it somewhere for it to hang on while the image is in existence
#else
#endif
}
else
{
[self activateFramebuffer];
rawImagePixels = (GLubyte *)malloc(totalBytesForImage);
glReadPixels(, , (int)_size.width, (int)_size.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels); //阻塞调用,直接从framebuffer中读取image 原始数据
dataProvider = CGDataProviderCreateWithData(NULL, rawImagePixels, totalBytesForImage, dataProviderReleaseCallback);
[self unlock]; // Don't need to keep this around anymore
}
最后CGImageCreate生成图片返回。
GPUImageOutput
类的说明其实已经很明了,视频采集,拍照等都是以它为基类,同一套路:源(视频,静态图)上传图片帧给OpenGL ES作为textures,这些textures作为下一个filter的输入,形成处理texture的链式结构。
/** GPUImage's base source object Images or frames of video are uploaded from source objects, which are subclasses of GPUImageOutput. These include: - GPUImageVideoCamera (for live video from an iOS camera)
- GPUImageStillCamera (for taking photos with the camera)
- GPUImagePicture (for still images)
- GPUImageMovie (for movies) Source objects upload still image frames to OpenGL ES as textures, then hand those textures off to the next objects in the processing chain.
*/
类中工具函数runSynchronouslyOnContextQueue等,通过dispatch_get_specific防止死锁,注意不要用dispatch_get_current_queue;
通过对三个典型类的作用解读,分别为 (GPUImagePicture)source->(GPUImageFilter)filter->(GPUImageView)output,形成处理链式结构,当然还有其他的pipeline。
1,GPUImagePicture
GPUImagePicture只继承GPUImageOutput,专门用作读取输入数据,上传GPU,交个链条下一步GPUImageFilter处理。
初始化initWithCGImage:读取CGImageRef数据,判断是否需要CG的辅助来处理图片数据,如需要CG,固定套路(包含解压图片语义)CGBitmapContextCreate–>CGContextDrawImage;不需要的情况,CGImageGetDataProvider–>CGDataProviderCopyData–>CFDataGetBytePtr获取原始数据, 最后通过调用glTexImage2D上传imageData到当前outputFramebuffer 的GPU texture;
处理图片processImageWithCompletionHandler:根据addTarget加入的所有target(即链条结构中间的filter),逐个setInputFramebuffer设置当前outputFramebuffer中processed texture为下一步filter的输入;
newFrameReadyAtTime 通知各个加入的target处理数据。
2,GPUImageFilter
GPUImageFilter(实际开发中通常用到它的子类)继承GPUImageOutput,同时遵循GPUImageInput 协议,类的说明如下
/** GPUImage's base filter class Filters and other subsequent elements in the chain conform to the GPUImageInput protocol,
which lets them take in the supplied or processed texture from the previous link in the chain and do something with it.
Objects one step further down the chain are considered targets,
and processing can be branched by adding multiple targets to a single output or filter.
*/
GPUImageFilter中 setInputFramebuffer (GPUImageInput协议方法)简单地赋值 ;
- (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex;
{
firstInputFramebuffer = newInputFramebuffer;
[firstInputFramebuffer lock];
}
然后调用newFrameReadyAtTime;
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
{
static const GLfloat imageVertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
}; //顶点数据,两个三角形组成texture区域
[self renderToTextureWithVertices:imageVertices textureCoordinates:[[self class] textureCoordinatesForRotation:inputRotation]]; [self informTargetsAboutNewFrameAtTime:frameTime];
}
激活该filter中的 filterProgram(已经attach过 顶点shader 和 片元shader),然后绑定输入的texture并渲染。
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
{
if (self.preventRendering)
{
[firstInputFramebuffer unlock];
return;
} [GPUImageContext setActiveShaderProgram:filterProgram];
/**
* 从GPUImageFrameBufferCache中取出可重用的outputFramebuffer
*
**/
outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
[outputFramebuffer activateFramebuffer];
if (usingNextFrameForImageCapture)
{
[outputFramebuffer lock];
} [self setUniformsForProgramAtIndex:]; glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
glClear(GL_COLOR_BUFFER_BIT); glActiveTexture(GL_TEXTURE2); //选择GL_TEXTURE2
glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]); //绑定当前输入的framebuffer中的texture glUniform1i(filterInputTextureUniform, );
//分别设置顶点shader中的顶点数据,和将来用于片元shader中的texture坐标数据
glVertexAttribPointer(filterPositionAttribute, , GL_FLOAT, , , vertices);
glVertexAttribPointer(filterTextureCoordinateAttribute, , GL_FLOAT, , , textureCoordinates); glDrawArrays(GL_TRIANGLE_STRIP, , ); [firstInputFramebuffer unlock]; if (usingNextFrameForImageCapture)
{
dispatch_semaphore_signal(imageCaptureSemaphore);
}
}
informTargetsAboutNewFrameAtTime 中轮询两次当前的target,第一次大致还是调用父类的setInputFramebufferForTarget(父类GPUImageOutput),第二次继续newFrameReadyAtTime,又回到了从source添加target的原点。
3,GPUImageView
作为最终的输出target只实现了GPUImageInput的协议,只能接受source或者filter传过来的数据,不再作为输出了;
其中的setInputFramebuffer 和 newFrameReadyAtTime和filter中处理如出一辙,但是加了一个调用;如下,正如开头提到的framebuffer也可以绑定到renderBuffer,也常称为colorbuffer,renderbuffer直接显示在CAEAGLLayer上了;最终通过设置屏幕大小的缓冲区,直接显示在手机屏幕上。
- (void)presentFramebuffer;
{
glBindRenderbuffer(GL_RENDERBUFFER, displayRenderbuffer);
[[GPUImageContext sharedImageProcessingContext] presentBufferForDisplay];
}
其中的displayRenderBuffer通过createDisplayFramebuffer方法创建,都是些模板代码,没什么可记录的。
小结
GPUImage的代码结构可谓是链式处理结构的典范,很值得学习;本文只记录了processing chain(source->filter–>filter…->output)的数据流向,很多细节以后再记录。
参考
GPUImage源码:https://github.com/BradLarson/GPUImage
GPUImage的filter 响应处理链 的理解笔记的更多相关文章
- 由浅入深讲解责任链模式,理解Tomcat的Filter过滤器
本文将从简单的场景引入, 逐步优化, 最后给出具体的责任链设计模式实现. 场景引入 首先我们考虑这样一个场景: 论坛上用户要发帖子, 但是用户的想法是丰富多变的, 他们可能正常地发帖, 可能会在网页中 ...
- Filter体现职责链模式
1. 前言 Filter—Filter 技术是servlet2.3 新增加的功能.完成的流程:对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后 ...
- 谈谈我对 js原型链的理解
想要学习 “原型链” 必须要认识什么是 “原型” 和 “原型链” 先理解一下普通的继承和原型的区别,下面写一段js代码来帮助理解: var Animal = function(){ // 动物抽象类 ...
- javascript原型与原型链个人理解
想了解原型和原型链,我觉得首先我们得知道javascript里有一个Object 与 Function,它俩都是构造函数,当然函数也是一个对象.我们打印Object 与 Function看一下, co ...
- 蒟蒻的长链剖分学习笔记(例题:HOTEL加强版、重建计划)
长链剖分学习笔记 说到树的链剖,大多数人都会首先想到重链剖分.的确,目前重链剖分在OI中有更加多样化的应用,但它大多时候是替代不了长链剖分的. 重链剖分是把size最大的儿子当成重儿子,顾名思义长链剖 ...
- batch normalization学习理解笔记
batch normalization学习理解笔记 最近在Andrew Ng课程中学到了Batch Normalization相关内容,通过查阅资料和原始paper,基本上弄懂了一些算法的细节部分,现 ...
- Filter的过滤链理解
一.Filter过滤链 web.xml配置了filter过滤器,在容器启动的时候执行了init()方法进行了初始化,然后在容器关闭的时候执行了destroy()方法销毁过滤器,在每次服务器接受请求的时 ...
- Filter技术+职责链模式
Filter是一个过滤器,存在Webclient与请求的资源之间.这里的资源能够说是jsp或servlet.它的作用就是在请求达到资源之前,先对请求进行预处理.而且也能够对servlet处理后的res ...
- 响应式设计:理解设备像素,CSS像素和屏幕分辨率
概述 屏幕分辨率.设备像素和CSS像素这些术语,在非常多语境下,是可互换的,但也因此easy在有差异的地方引起混淆,实际上它们是不同的概念. 屏幕分辨率和设备像素是物理概念,而CSS像素是WEB编程的 ...
随机推荐
- 数据结构与算法(c++)——跳跃表(skip list)
今天要介绍一个这样的数据结构: 单向链接 有序保存 支持添加.删除和检索操作 链表的元素查询接近线性时间 ——跳跃表 Skip List 一.普通链表 对于普通链接来说,越靠前的节点检索的时间花费越低 ...
- Android Gradle manifestPlaceholders 占位符详解
Android Gradle manifestPlaceholders 占位符详解 在实际项目中,AndroidManifest里十几个地方的值是需要动态的改变(生成apk文件的时候).如果每次去改也 ...
- 使用validator-api来验证spring-boot的参数
作为服务端开发,验证前端传入的参数的合法性是一个必不可少的步骤,但是验证参数是一个基本上是一个体力活,而且冗余代码繁多,也影响代码的可阅读性,所以有没有一个比较优雅的方式来解决这个问题? 这么简单的问 ...
- MySQL之改_update
MySQL增删改查之改_update UPDATE语句 进行数据记录的更新. 1.更新单个表中的值 语法: UPDATE [IGNORE] table_reference SET col_name1= ...
- Hadoop安全机制之令牌
介绍 Hadoop中的安全机制包括认证和授权.而Hadoop RPC中采用SASL(Simple Authentication and Security Layer,简单认证和安全层)进行安全认证,具 ...
- Python中的支持向量机SVM的使用(有实例)
除了在Matlab中使用PRTools工具箱中的svm算法,Python中一样可以使用支持向量机做分类.因为Python中的sklearn也集成了SVM算法. 一.简要介绍一下sklearn Scik ...
- react+redux+generation-modation脚手架添加一个todolist
当我遇到问题: 要沉着冷静. 要管理好时间. 别被bug或error搞的不高兴,要高兴,又有煅炼思维的机会了. 要思考这是为什么? 要搞清楚问题的本质. 要探究问题,探究数据的流动. TodoList ...
- Pycharm实用技巧汇总
Pycharm中输入 a = list 按住Command点鼠标左键,即可查看该类下的所有用法,如下图 获取类中有哪些成员
- 《JavaScript权威指南》学习——js闭包
序:闭包这个玩意啊~在很多没有代码块的语言中都会出现,已经成为大多程序员入门的一道坎,闭包让很多程序员觉得晦涩(事实上百度一下这个名词,真的说的很晦涩啊亲==|||),我第一次知道闭包这个名词是从&l ...
- LESS的一点自己的理解(2)
上次写的一点居然忘了保存了,虽然说编辑器有自动保存的功能,但是昨天写的依然找不到了,/(ㄒoㄒ)/~~那好吧,重新开始写. 1.上篇写到了Mixins(混入),如果你仔细看了上面的例子,你就会发现其实 ...