GPUImage源码解读(二十)

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

GPUImageTwoInputFilter 可以接收两个帧缓存对象的输入。它的作用可以将两个帧缓存对象的输入合并成一个帧缓存对象的输出。它继承自GPUImageFilter,因此,可以方便在滤镜链中使用。
- 实例变量。GPUImageTwoInputFilter最主要的特点就是增加了secondInputFramebuffer这个接收第二个帧缓存对象的实例变量,同时,也增加了关于第二个帧缓存对象的其它相关参数

@interface GPUImageTwoInputFilter : GPUImageFilter
{
    // 与第二个帧缓存对象相关的参数
    GPUImageFramebuffer *secondInputFramebuffer;
    GLint filterSecondTextureCoordinateAttribute;
    GLint filterInputTextureUniform2;
    GPUImageRotationMode inputRotation2;
    CMTime firstFrameTime, secondFrameTime;

    // 控制两个帧缓存对象渲染的相关参数
    BOOL hasSetFirstTexture, hasReceivedFirstFrame, hasReceivedSecondFrame, firstFrameWasVideo, secondFrameWasVideo;
    BOOL firstFrameCheckDisabled, secondFrameCheckDisabled;
}

// 需不需要检查第一个纹理输入
- (void)disableFirstFrameCheck;
// 需不需要检查第二个纹理输入
- (void)disableSecondFrameCheck;
  • 初始化方法。初始化的时候可以不用指定顶点着色器,但是需要指定片段着色器。

// 指定fragmentShaderString来初始化
- (id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString;
{
    if (!(self = [self initWithVertexShaderFromString:kGPUImageTwoInputTextureVertexShaderString fragmentShaderFromString:fragmentShaderString]))
    {
        return nil;
    }

    return self;
}
// 指定vertexShaderString和fragmentShaderString来初始化
- (id)initWithVertexShaderFromString:(NSString *)vertexShaderString fragmentShaderFromString:(NSString *)fragmentShaderString;
{
    if (!(self = [super initWithVertexShaderFromString:vertexShaderString fragmentShaderFromString:fragmentShaderString]))
    {
        return nil;
    }
     // 相关变量初始化
    inputRotation2 = kGPUImageNoRotation;

    hasSetFirstTexture = NO;

    hasReceivedFirstFrame = NO;
    hasReceivedSecondFrame = NO;
    firstFrameWasVideo = NO;
    secondFrameWasVideo = NO;
    firstFrameCheckDisabled = NO;
    secondFrameCheckDisabled = NO;

    firstFrameTime = kCMTimeInvalid;
    secondFrameTime = kCMTimeInvalid;

    runSynchronouslyOnVideoProcessingQueue(^{
        [GPUImageContext useImageProcessingContext];
        // 获取第二个纹理坐标对象
        filterSecondTextureCoordinateAttribute = [filterProgram attributeIndex:@"inputTextureCoordinate2"];
        // 获取第二个纹理对象
        filterInputTextureUniform2 = [filterProgram uniformIndex:@"inputImageTexture2"]; // This does assume a name of "inputImageTexture2" for second input texture in the fragment shader
        glEnableVertexAttribArray(filterSecondTextureCoordinateAttribute);
    });

    return self;
}
  • 其它方法。GPUImageTwoInputFilter给出的方法比较少,但是这里有一些重写父类的方法是处理两个帧缓存对象输入的关键
// 增加方法
- (void)disableFirstFrameCheck;
- (void)disableSecondFrameCheck;
// 重写方法
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
- (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
{
    // You can set up infinite update loops, so this helps to short circuit them
    if (hasReceivedFirstFrame && hasReceivedSecondFrame)
    {
        return;
    }

    BOOL updatedMovieFrameOppositeStillImage = NO;
    // 处理第一个纹理对象
    if (textureIndex == 0)
    {
        hasReceivedFirstFrame = YES;
        firstFrameTime = frameTime;
         // 如果不检查第二个纹理输入,则直接默认已经接收了第二个纹理
        if (secondFrameCheckDisabled)
        {
            hasReceivedSecondFrame = YES;
        }

        if (!CMTIME_IS_INDEFINITE(frameTime))
        {
            if CMTIME_IS_INDEFINITE(secondFrameTime)
            {
                updatedMovieFrameOppositeStillImage = YES;
            }
        }
    }
    else
    {
        hasReceivedSecondFrame = YES;
        secondFrameTime = frameTime;
        // 如果不检查第一个纹理输入,则直接默认已经接收了第一个纹理
        if (firstFrameCheckDisabled)
        {
            hasReceivedFirstFrame = YES;
        }

        if (!CMTIME_IS_INDEFINITE(frameTime))
        {
            if CMTIME_IS_INDEFINITE(firstFrameTime)
            {
                updatedMovieFrameOppositeStillImage = YES;
            }
        }
    }

    // || (hasReceivedFirstFrame && secondFrameCheckDisabled) || (hasReceivedSecondFrame && firstFrameCheckDisabled)
     // 如果接收了两个纹理输入或者是有效帧,则渲染
    if ((hasReceivedFirstFrame && hasReceivedSecondFrame) || updatedMovieFrameOppositeStillImage)
    {
        CMTime passOnFrameTime = (!CMTIME_IS_INDEFINITE(firstFrameTime)) ? firstFrameTime : secondFrameTime;
        [super newFrameReadyAtTime:passOnFrameTime atIndex:0]; // Bugfix when trying to record: always use time from first input (unless indefinite, in which case use the second input)
        hasReceivedFirstFrame = NO;
        hasReceivedSecondFrame = NO;
    }
}

- (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
{
    if (self.preventRendering)
    {
        [firstInputFramebuffer unlock];
        [secondInputFramebuffer unlock];
        return;
    }

    [GPUImageContext setActiveShaderProgram:filterProgram];
    outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
    [outputFramebuffer activateFramebuffer];
    if (usingNextFrameForImageCapture)
    {
        [outputFramebuffer lock];
    }

    [self setUniformsForProgramAtIndex:0];

    glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
    glClear(GL_COLOR_BUFFER_BIT);

    // 激活第一个纹理
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
    glUniform1i(filterInputTextureUniform, 2);

   // 激活第二个纹理
    glActiveTexture(GL_TEXTURE3);
    glBindTexture(GL_TEXTURE_2D, [secondInputFramebuffer texture]);
    glUniform1i(filterInputTextureUniform2, 3);

    glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
      glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
    glVertexAttribPointer(filterSecondTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation2]);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    [firstInputFramebuffer unlock];
    [secondInputFramebuffer unlock];
    if (usingNextFrameForImageCapture)
    {
        dispatch_semaphore_signal(imageCaptureSemaphore);
    }
}
GPUImage写双输入的滤镜 今天主要来讲一下怎么用GPUImage来手撸一个双输入(blend)的滤镜,以及三输入的滤镜。 那么先说一下为什么要自己手撸多输入的滤镜: 双输入的滤镜其实是三输入(也就是多个输入端滤镜)的简单版,让大家比较容易上手。 在实际上写app的时候,往往一个滤镜效果是不能满足需求的,而像:0.5的亮度+0.87的透明度+柔光混合+RGB调整,这种分开做都比较简单,但是合并起来则会使代码变得超长超恶 阅读详情

相关推荐

GPUImage源码分析与使用()

有丰富的输入组件,可以处理图片、纹理、视频、二进制数据、UIElement(UIView、CALayer),可以使用GPUImage拍照、处理纹理图片、给视频或拍摄中的视频添加滤镜、添加水印可以使用UIElement。支持对大图进行处理,GPU的纹理限制是4096*4096,对于超出限制的图片,GPUImage会压缩处理导致损失图片质量,CoreImage会把图片拆解成小图处理。可以传入字符串类型,也可以传入文件类型,比如以.vsh/.fsh/.glsl等为后缀等命名的文件。

程序猿老樊的博客 1117

Android GPUImage源码分析(四) Lookup滤镜的使用

Android GPUImage源码分析(四) Lookup滤镜的使用 一、lookup滤镜输入双纹理输入滤镜 /**** * 双纹理输入滤镜 */ public class GPUImageTwoInputFilter extends GPUImageFilter { /**顶点坐标shader**/ private static final String VERTE...

1004

关于GPUImage 两路输入 其中一路为 GPUImagePicture 的 问题的详细解析

关于GPUImage 两路输入 其中一路为 GPUImagePicture 的 问题的详细解析情况1:GPUImagePicture -> 添加到1                                                 ->GPUImageTwoInputFilter 此时调用不会crashGPUImageMovie -> 添加到0在GPUIm...

jeffasd的专栏 1369

GPUImageMovieWriter录制视频问题

GPUImageMovieWriter录制视频问题 1、两个movie叠加的时候,每个movie解码出一帧都会走到GPUImageTwoInputFilter的newFrameReadyAtTime - (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex; {     // You ca

u011270282的专栏 5581

GPUImage源码解读(二十)

GPUImageLookupFilter GPUImageLookupFilter 是GPUImage中的颜色查找滤镜,在一般的相机应用中使用得最广泛,它的作用是通过颜色变换从而产生出新风格的图片,在philm项目中也有大量使用 LUT (Lookup Tables)即查找表 。LUT是个非常简单的数值转换表,不同的色彩输入数值“映射”到一套输出数值,用来改变图像的色彩。例如:红色在LUT中可...

Philm_iOS的博客 740

GPUImage源码解读(二十)

#GPUImageView 结构说明 . ├── GPUImage.xcodeproj │   ├── project.pbxproj │   ├── project.xcworkspace ├── GPUImageMac.xcodeproj │   ├── project.pbxproj │  

Philm_iOS的博客 458

GPUImage源码解读(二十)

GPUImageFilter GPUImageFilter 是GPUImage中很重要、很基础的类,它可以处理帧缓存对象的输入输出,但是对纹理并不添加任何特效,也就是说只是简单的让纹理通过。它更多的是作为其它滤镜的基类,一些具体的滤镜由它的子类去完成。同时它也只能处理单个帧缓存对象的输入,处理多个帧缓存对象的输入也是由它的子类去完成 向量定义 //在 GPUImage 中主要用到了3...

Philm_iOS的博客 485

GPUImage源码解读(二十)

GPUImageThreeInputFilter 可以接收三个帧缓存对象的输入。它的作用可以将三个帧缓存对象的输入合并成一个帧缓存对象的输出。它继承自GPUImageTwoInputFilter,与GPUImageTwoInputFilter类似,主要增加了第三个帧缓存对象处理的相关操作。 实例变量。主要增加了与第三个帧缓存对象相关的实例变量 “` @interface GPUImageT...

Philm_iOS的博客 397

GPUImage源码解读(二十)

GPUImageFourInputFilter 可以接收四个帧缓存对象的输入。它的作用可以将四个帧缓存对象的输入合并成一个帧缓存对象的输出。它继承自GPUImageThreeInputFilter,与GPUImageTwoInputFilterGPUImageThreeInputFilter类似,主要增加了第四个帧缓存对象处理的相关操作。 philm gpuimage 版本没有这个类 GPUI...

Philm_iOS的博客 420

GPUImage 源码分析

GPUImage源码解读 介绍 GitHub - cats-oss/android-gpuimage: Android filters based on OpenGL (idea from GPUImage for iOS) 做图片或者视频滤镜渲染,离不开 OpenGL,而在移动平台上最令人熟知的就是 GitHub - BradLarson/GPUImage2: GPUImage 2 is ...

crazy_jack 2149

iOS GPUImage研究总结

关于GPUImage 这里直接引用官方描述:GPUImage是使用GPU处理图像的、他可以对图片、实时画面、视频进行处理。他允许你自定义滤镜、支持iOS4.0。然而,目前缺乏核心形象的一些更高级的功能,比如面部检测。

Quinn's blog ! I'm glad to be here! 1万+

iOS GPUImage源码解读

前言 GPUImage是iOS上一个基于OpenGL进行图像处理的开源框架,内置大量滤镜,架构灵活,可以在其基础上很轻松地实现各种图像处理功能。本文主要向大家分享一下项目的核心架构、源码解读及使用心得。 GPUImage有哪些特性 丰富的输入组件 摄像头、图片、视频、OpenGL纹理、二进制数据、UIElement(UIView, CALayer) 大量现成的内置滤镜(4大类) 1). 颜...

majiakun1的专栏 3610

iOS开发——GPUImage源码解析

一、基本概念 GPUImage:一个开源的、基于openGL的图片或视频的处理框架,其本身内置了多达120多种常见的滤镜效果,并且支持照相机和摄像机的实时滤镜,并且能够自定义图像滤镜。同时也很方便在原有基础上加入自己的滤镜Filter,所有滤镜是基于opengl shader(着色器)实现的,所以滤镜效果图像处理是在GPU上实现的,处理效率比较高,在iPhone6及其以上手机,可以做到实时流...

weixin_30240349的博客 376

GPUImage源码解读()

导读: 系列文章会从结构到使用,细化到每一个变量, 使用方法全有对应 DEMO.也会有相对应的技术点扩展如(AVFoundation,OpenGL shader,CAEAGLLayer)等,目前是 Objective-C 版本的,后面会有Swift版本. GPUImage-Objective-C 官方源码 GPUImage-Swift 官方源码 GPUImage-Objective-C 添...

Philm_iOS的博客 798

c语言freeimage库文件,GPUImage源码解读之GLProgram

简述GLProgram是GPUImage中代表openGL ES 中的program,具有glprogram功能。其实是作者对OpenGL ES program的面向对象封装初始化- (id)initWithVertexShaderString:(NSString *)vShaderStringfragmentShaderString:(NSString *)fShaderString;- (id...

weixin_36176188的博客 303

GPUImage源码解读()

这篇文章主要是阅读GPUImage框架中的 GLProgram、GPUImageContext 两个重要类的源码。这两个类是 GPUImage 框架的基础,里面涉及的知识也有 OpenGL ES 基础 和 多线程 基础。以下是源码内容: GLProgram 一 GLProgram GLProgram专门处理OpenGL ES程序的创建等相关工作。 初始化方法,可以根据需要传入顶点着色...

Philm_iOS的博客 566

android 滤镜开源,Android_GPUImage 支持实时摄像头滤镜的GPUImage是iOS下一个开源的基于GPU的图像处理库 - 下载 - 搜珍网...

Android例子源码支持实时摄像头滤镜的GPUImage/Android例子源码支持实时摄像头滤镜的GPUImage/.gitignoreAndroid例子源码支持实时摄像头滤镜的GPUImage/library/Android例子源码支持实时摄像头滤镜的GPUImage/library/.classpathAndroid例子源码支持实时摄像头滤镜的GPUImage/library/.gitig...

weixin_36397146的博客 184

GPUImage源码解读之GLProgram

简述 GLProgram是GPUImage中代表openGL ES 中的program,具有glprogram功能。其实是作者对OpenGL ES program的面向对象封装 初始化 - (id)initWithVertexShaderString:(NSString *)vShaderString fragmentShaderString:(NSString *)fS...

weixin_30346033的博客 168

GPUImage源码解读()

GPUImageView 从名称就可以知道GPUImageView是GPUImage框架中显示图片相关的类。GPUImageView实现了GPUImageInput协议,从而可以知道它能够接受GPUImageFramebuffer的输入。因此,常常作为响应链的终端节点,用于显示处理后的帧缓存。 - 重写静态方法 返回 CAEAGLLayer GPUImageView 是UIView的子类...

Philm_iOS的博客 500
上一篇: GPUImage源码解读(十八)
下一篇: GPUImage源码解读(二十一)
Philm_iOS
博客等级 码龄8年 74粉丝 53原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值