美文网首页
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