#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