Skip to content

Instantly share code, notes, and snippets.

@depthlove
Forked from georgmay/GPUImageFiveInputFilter.h
Created October 11, 2017 17:28
Show Gist options
  • Save depthlove/586eac10c37d106b710e8a0141478f7f to your computer and use it in GitHub Desktop.
Save depthlove/586eac10c37d106b710e8a0141478f7f to your computer and use it in GitHub Desktop.

Revisions

  1. George Mays created this gist Dec 13, 2014.
    19 changes: 19 additions & 0 deletions GPUImageFiveInputFilter.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,19 @@
    #import <GPUImage/GPUImage.h>
    #import "GPUImageFourInputFilter.h"

    @interface GPUImageFiveInputFilter : GPUImageFourInputFilter
    {
    GPUImageFramebuffer *fifthInputFramebuffer;

    GLint filterFifthTextureCoordinateAttribute;
    GLint filterInputTextureUniform5;
    GPUImageRotationMode inputRotation5;
    GLuint filterSourceTexture5;
    CMTime fifthFrameTime;

    BOOL hasSetFourthTexture, hasReceivedFifthFrame, fifthFrameWasVideo;
    BOOL fifthFrameCheckDisabled;
    }

    - (void)disableFifthFrameCheck;
    @end
    438 changes: 438 additions & 0 deletions GPUImageFiveInputFilter.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,438 @@
    #import "GPUImageFiveInputFilter.h"

    static NSString *const kGPUImageFiveInputTextureVertexShaderString = SHADER_STRING
    (
    attribute vec4 position;
    attribute vec4 inputTextureCoordinate;
    attribute vec4 inputTextureCoordinate2;
    attribute vec4 inputTextureCoordinate3;
    attribute vec4 inputTextureCoordinate4;
    attribute vec4 inputTextureCoordinate5;

    varying vec2 textureCoordinate;
    varying vec2 textureCoordinate2;
    varying vec2 textureCoordinate3;
    varying vec2 textureCoordinate4;
    varying vec2 textureCoordinate5;

    void main()
    {
    gl_Position = position;
    textureCoordinate = inputTextureCoordinate.xy;
    textureCoordinate2 = inputTextureCoordinate2.xy;
    textureCoordinate3 = inputTextureCoordinate3.xy;
    textureCoordinate4 = inputTextureCoordinate4.xy;
    textureCoordinate5 = inputTextureCoordinate5.xy;
    }
    );

    @implementation GPUImageFiveInputFilter

    #pragma mark -
    #pragma mark Initialization and teardown

    - (id)initWithFragmentShaderFromString:(NSString *)fragmentShaderString;
    {
    if (!(self = [self initWithVertexShaderFromString:kGPUImageFiveInputTextureVertexShaderString fragmentShaderFromString:fragmentShaderString]))
    {
    return nil;
    }

    return self;
    }

    - (id)initWithVertexShaderFromString:(NSString *)vertexShaderString fragmentShaderFromString:(NSString *)fragmentShaderString;
    {
    if (!(self = [super initWithVertexShaderFromString:vertexShaderString fragmentShaderFromString:fragmentShaderString]))
    {
    return nil;
    }

    inputRotation5 = kGPUImageNoRotation;

    hasSetFourthTexture = NO;

    hasReceivedFifthFrame = NO;
    fifthFrameWasVideo = NO;
    fifthFrameCheckDisabled = NO;

    fifthFrameTime = kCMTimeInvalid;

    runSynchronouslyOnVideoProcessingQueue(^{
    [GPUImageContext useImageProcessingContext];
    filterFifthTextureCoordinateAttribute = [filterProgram attributeIndex:@"inputTextureCoordinate5"];

    filterInputTextureUniform4 = [filterProgram uniformIndex:@"inputImageTexture5"]; // This does assume a name of "inputImageTexture5" for the fifth input texture in the fragment shader
    glEnableVertexAttribArray(filterFifthTextureCoordinateAttribute);
    });

    return self;
    }

    - (void)initializeAttributes;
    {
    [super initializeAttributes];
    [filterProgram addAttribute:@"inputTextureCoordinate5"];
    }

    - (void) disableFifthFrameCheck
    {
    fourthFrameCheckDisabled = YES;
    }

    #pragma mark -
    #pragma mark Rendering

    - (void)renderToTextureWithVertices:(const GLfloat *)vertices textureCoordinates:(const GLfloat *)textureCoordinates;
    {
    if (self.preventRendering)
    {
    [firstInputFramebuffer unlock];
    [secondInputFramebuffer unlock];
    [thirdInputFramebuffer unlock];
    [fourthInputFramebuffer unlock];
    [fifthInputFramebuffer 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);

    glActiveTexture(GL_TEXTURE4);
    glBindTexture(GL_TEXTURE_2D, [thirdInputFramebuffer texture]);
    glUniform1i(filterInputTextureUniform3, 4);

    glActiveTexture(GL_TEXTURE5);
    glBindTexture(GL_TEXTURE_2D, [fourthInputFramebuffer texture]);
    glUniform1i(filterInputTextureUniform4, 5);

    glActiveTexture(GL_TEXTURE6);
    glBindTexture(GL_TEXTURE_2D, [fifthInputFramebuffer texture]);
    glUniform1i(filterInputTextureUniform5, 6);

    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]);
    glVertexAttribPointer(filterThirdTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation3]);
    glVertexAttribPointer(filterFourthTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation4]);
    glVertexAttribPointer(filterFourthTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [[self class] textureCoordinatesForRotation:inputRotation5]);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    [firstInputFramebuffer unlock];
    [secondInputFramebuffer unlock];
    [thirdInputFramebuffer unlock];
    [fourthInputFramebuffer unlock];
    [fifthInputFramebuffer unlock];
    if (usingNextFrameForImageCapture)
    {
    dispatch_semaphore_signal(imageCaptureSemaphore);
    }
    }

    #pragma mark -
    #pragma mark GPUImageInput

    - (NSInteger)nextAvailableTextureIndex;
    {
    if(hasSetFourthTexture){
    return 4;
    }
    else if(hasSetThirdTexture){
    return 3;
    }
    else if (hasSetSecondTexture)
    {
    return 2;
    }
    else if (hasSetFirstTexture)
    {
    return 1;
    }
    else
    {
    return 0;
    }
    }

    - (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex;
    {
    if (textureIndex == 0)
    {
    firstInputFramebuffer = newInputFramebuffer;
    hasSetFirstTexture = YES;
    [firstInputFramebuffer lock];
    }
    else if (textureIndex == 1)
    {
    secondInputFramebuffer = newInputFramebuffer;
    //hasSetSecondTexture = YES;
    [secondInputFramebuffer lock];
    }
    else if(textureIndex == 2){
    thirdInputFramebuffer = newInputFramebuffer;
    [thirdInputFramebuffer lock];
    }
    else if (textureIndex == 3)
    {
    fourthInputFramebuffer = newInputFramebuffer;
    [fourthInputFramebuffer lock];
    }
    else if (textureIndex == 4)
    {
    fifthInputFramebuffer = newInputFramebuffer;
    [fifthInputFramebuffer lock];

    }
    }

    - (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
    {
    if (textureIndex == 0)
    {
    [super setInputSize:newSize atIndex:textureIndex];

    if (CGSizeEqualToSize(newSize, CGSizeZero))
    {
    hasSetFirstTexture = NO;
    }
    }
    else if (textureIndex == 1)
    {
    if (CGSizeEqualToSize(newSize, CGSizeZero))
    {
    hasSetSecondTexture = NO;
    }
    }
    else if(textureIndex == 2)
    {
    if (CGSizeEqualToSize(newSize, CGSizeZero)) {
    hasSetThirdTexture = NO;
    }
    }
    else if(textureIndex == 3)
    {
    if (CGSizeEqualToSize(newSize, CGSizeZero)) {
    hasSetFourthTexture = NO;
    }
    }
    }

    - (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
    {
    if (textureIndex == 0)
    {
    inputRotation = newInputRotation;
    }
    else if (textureIndex == 1)
    {
    inputRotation2 = newInputRotation;
    }
    else if (textureIndex == 2)
    {
    inputRotation3 = newInputRotation;
    }
    else if (textureIndex == 3)
    {
    inputRotation4 = newInputRotation;
    }
    else
    {
    inputRotation5 = newInputRotation;
    }
    }

    - (CGSize)rotatedSize:(CGSize)sizeToRotate forIndex:(NSInteger)textureIndex;
    {
    CGSize rotatedSize = sizeToRotate;

    GPUImageRotationMode rotationToCheck;
    if (textureIndex == 0)
    {
    rotationToCheck = inputRotation;
    }
    else if (textureIndex == 1)
    {
    rotationToCheck = inputRotation2;
    }
    else if (textureIndex == 2)
    {
    rotationToCheck = inputRotation3;
    }
    else if (textureIndex == 3)
    {
    rotationToCheck = inputRotation4;
    }
    else
    {
    rotationToCheck = inputRotation5;
    }

    if (GPUImageRotationSwapsWidthAndHeight(rotationToCheck))
    {
    rotatedSize.width = sizeToRotate.height;
    rotatedSize.height = sizeToRotate.width;
    }

    return rotatedSize;
    }

    - (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
    {
    // You can set up infinite update loops, so this helps to short circuit them
    if (hasReceivedFirstFrame && hasReceivedSecondFrame && hasReceivedThirdFrame && hasReceivedFourthFrame && hasReceivedFifthFrame)
    {
    return;
    }

    BOOL updatedMovieFrameOppositeStillImage = NO;

    if (textureIndex == 0)
    {
    hasReceivedFirstFrame = YES;
    firstFrameTime = frameTime;
    if (secondFrameCheckDisabled)
    {
    hasReceivedSecondFrame = YES;
    }
    if (thirdFrameCheckDisabled)
    {
    hasReceivedThirdFrame = YES;
    }
    if (fourthFrameCheckDisabled) {
    hasReceivedFourthFrame = YES;
    }
    if (fifthFrameCheckDisabled) {
    hasReceivedFifthFrame = YES;
    }

    if (!CMTIME_IS_INDEFINITE(frameTime))
    {
    if CMTIME_IS_INDEFINITE(secondFrameTime)
    {
    updatedMovieFrameOppositeStillImage = YES;
    }
    }
    }
    else if (textureIndex == 1)
    {
    hasReceivedSecondFrame = YES;
    secondFrameTime = frameTime;
    if (firstFrameCheckDisabled)
    {
    hasReceivedFirstFrame = YES;
    }
    if (thirdFrameCheckDisabled)
    {
    hasReceivedThirdFrame = YES;
    }
    if (fourthFrameCheckDisabled) {
    hasReceivedFourthFrame = YES;
    }
    if (fifthFrameCheckDisabled) {
    hasReceivedFifthFrame = YES;
    }

    if (!CMTIME_IS_INDEFINITE(frameTime))
    {
    if CMTIME_IS_INDEFINITE(firstFrameTime)
    {
    updatedMovieFrameOppositeStillImage = YES;
    }
    }
    }
    else if(textureIndex == 2)
    {
    hasReceivedThirdFrame = YES;
    thirdFrameTime = frameTime;
    if (firstFrameCheckDisabled)
    {
    hasReceivedFirstFrame = YES;
    }
    if (secondFrameCheckDisabled)
    {
    hasReceivedSecondFrame = YES;
    }

    if (fourthFrameCheckDisabled) {
    hasReceivedFourthFrame = YES;
    }
    if (fifthFrameCheckDisabled) {
    hasReceivedFifthFrame = YES;
    }

    if (!CMTIME_IS_INDEFINITE(frameTime))
    {
    if CMTIME_IS_INDEFINITE(firstFrameTime)
    {
    updatedMovieFrameOppositeStillImage = YES;
    }
    }
    }else
    {
    hasReceivedFourthFrame = YES;
    fourthFrameTime = frameTime;
    if (firstFrameCheckDisabled) {
    hasReceivedFirstFrame = YES;
    }

    if (secondFrameCheckDisabled) {
    hasReceivedSecondFrame = YES;
    }

    if (thirdFrameCheckDisabled) {
    hasReceivedThirdFrame = YES;
    }
    if (fifthFrameCheckDisabled) {
    hasReceivedFifthFrame = YES;
    }

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

    if ((hasReceivedFirstFrame && hasReceivedSecondFrame && hasReceivedThirdFrame && hasReceivedFourthFrame && hasReceivedFifthFrame) || updatedMovieFrameOppositeStillImage)
    {
    static const GLfloat imageVertices[] = {
    -1.0f, -1.0f,
    1.0f, -1.0f,
    -1.0f, 1.0f,
    1.0f, 1.0f,
    };

    [self renderToTextureWithVertices:imageVertices textureCoordinates:[[self class] textureCoordinatesForRotation:inputRotation]];

    [self informTargetsAboutNewFrameAtTime:frameTime];

    hasReceivedFirstFrame = NO;
    hasReceivedSecondFrame = NO;
    hasReceivedThirdFrame = NO;
    hasReceivedFourthFrame = NO;
    hasReceivedFifthFrame = NO;
    }
    }


    @end