美文网首页
GPUImage源码分析(四):GPUImageTwoInput

GPUImage源码分析(四):GPUImageTwoInput

作者: 奔向火星005 | 来源:发表于2018-12-27 18:11 被阅读0次

    GPUImageTwoInputFilter是一个可以同时有两个输入的filter,可以做混合,滤镜等特效。类图如下:


    由图可见,GPUImageTwoInputFilter继承自GPUImageFilter, 它本身有一个secondInputFramebuffer, 加上它的父类GPUImageFilter的firstInputFramebuffer,一共有两个输入的Framebuffer,如

    GPUImageTwoInputFilter* twoInputFilter;
    [filter1 twoInputFilter atTextureLocation:0];
    [filter2 twoInputFilter atTextureLocation:1];
    

    后,会将filter1和filter2的outputframebuffer,赋给twoInputFilter的firstInputFramebuffer和secondInputFramebuffer,如下图:


    我们再看下GPUImageTwoInputFilter的newFrameReadyAtTime函数的实现:

    - (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
    {
        //以防重复渲染
        if (hasReceivedFirstFrame && hasReceivedSecondFrame) {
            return;
        }
        
        BOOL updatedMovieFrameOppositeStillImage = NO;
        
        //根据textureIndex判断是第一个还是第二个framebuffer到来
        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)  //当两个intputFramebuffer都到来时
        {
            CMTime passOnFrameTime = (!CMTIME_IS_INDEFINITE(firstFrameTime)) ? firstFrameTime : secondFrameTime;
            
            //内部会调用GPUImageTwoInputFilter或它子类的renderToTextureWithVertices
            [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;
        }
    }
    

    在看下renderToTextureWithVertices的实现,

    - (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
    {
        if (self.preventRendering)
        {
            [firstInputFramebuffer unlock];
            [secondInputFramebuffer unlock];
            return;
        }
        
        [GPUImageContext setActiveShaderProgram:filterProgram];
        
        //创建outputFramebuffer
        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);
        
        //绑定firstInputFramebuffer的纹理到纹理单元2上
        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, [firstInputFramebuffer texture]);
        glUniform1i(filterInputTextureUniform, 2); //对应片元着色器的inputImageTexture采样器,把它设为2
        
        //绑定secondInputFramebuffer的纹理到纹理单元3上
        glActiveTexture(GL_TEXTURE3);
        glBindTexture(GL_TEXTURE_2D, [secondInputFramebuffer texture]);
        glUniform1i(filterInputTextureUniform2, 3);  //对应片元着色器的inputImageTexture2采样器,把它设为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);
        }
    }
    

    代码挺简单,不再赘述。

    GPUImageTwoPassFilter相当于把两个filter串联起来,它的类图如下:


    GPUImageTwoPassFilter.png

    它内部的套路如下图:


    它的renderToTextureWithVertices源码如下:

    - (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
    {
        if (self.preventRendering)
        {
            [firstInputFramebuffer unlock];
            return;
        }
        
        [GPUImageContext setActiveShaderProgram:filterProgram];
        
        outputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
        [outputFramebuffer activateFramebuffer];
        
        [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);
        
        glVertexAttribPointer(filterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
        glVertexAttribPointer(filterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, textureCoordinates);
        
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        
        [firstInputFramebuffer unlock];
        firstInputFramebuffer = nil;
    
        // Run the second stage of the two-pass filter
        secondOutputFramebuffer = [[GPUImageContext sharedFramebufferCache] fetchFramebufferForSize:[self sizeOfFBO] textureOptions:self.outputTextureOptions onlyTexture:NO];
        [secondOutputFramebuffer activateFramebuffer];
        [GPUImageContext setActiveShaderProgram:secondFilterProgram];
        if (usingNextFrameForImageCapture)
        {
            [secondOutputFramebuffer lock];
        }
    
        [self setUniformsForProgramAtIndex:1];
        
        glActiveTexture(GL_TEXTURE3);
        glBindTexture(GL_TEXTURE_2D, [outputFramebuffer texture]);
        glVertexAttribPointer(secondFilterTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:kGPUImageNoRotation]);
        
        glUniform1i(secondFilterInputTextureUniform, 3);
        
        glVertexAttribPointer(secondFilterPositionAttribute, 2, GL_FLOAT, 0, 0, vertices);
    
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
    
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        [outputFramebuffer unlock];
        outputFramebuffer = nil;
        
        if (usingNextFrameForImageCapture)
        {
            dispatch_semaphore_signal(imageCaptureSemaphore);
        }
    }
    

    代码挺简单,不再赘述。

    相关文章

      网友评论

          本文标题:GPUImage源码分析(四):GPUImageTwoInput

          本文链接:https://www.haomeiwen.com/subject/rneklqtx.html