123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- #import "GPUImageView.h"
- #import <OpenGLES/EAGLDrawable.h>
- #import <QuartzCore/QuartzCore.h>
- #import "GPUImageContext.h"
- #import "GPUImageFilter.h"
- #import <AVFoundation/AVFoundation.h>
- #pragma mark -
- #pragma mark Private methods and instance variables
- @interface GPUImageView ()
- {
- GPUImageFramebuffer *inputFramebufferForDisplay;
- GLuint displayRenderbuffer, displayFramebuffer;
-
- GLProgram *displayProgram;
- GLint displayPositionAttribute, displayTextureCoordinateAttribute;
- GLint displayInputTextureUniform;
- CGSize inputImageSize;
- GLfloat imageVertices[8];
- GLfloat backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha;
- CGSize boundsSizeAtFrameBufferEpoch;
- }
- @property (assign, nonatomic) NSUInteger aspectRatio;
- // Initialization and teardown
- - (void)commonInit;
- // Managing the display FBOs
- - (void)createDisplayFramebuffer;
- - (void)destroyDisplayFramebuffer;
- // Handling fill mode
- - (void)recalculateViewGeometry;
- @end
- @implementation GPUImageView
- @synthesize aspectRatio;
- @synthesize sizeInPixels = _sizeInPixels;
- @synthesize fillMode = _fillMode;
- @synthesize enabled;
- #pragma mark -
- #pragma mark Initialization and teardown
- + (Class)layerClass
- {
- return [CAEAGLLayer class];
- }
- - (id)initWithFrame:(CGRect)frame
- {
- if (!(self = [super initWithFrame:frame]))
- {
- return nil;
- }
-
- [self commonInit];
-
- return self;
- }
- -(id)initWithCoder:(NSCoder *)coder
- {
- if (!(self = [super initWithCoder:coder]))
- {
- return nil;
- }
- [self commonInit];
- return self;
- }
- - (void)commonInit;
- {
- // Set scaling to account for Retina display
- if ([self respondsToSelector:@selector(setContentScaleFactor:)])
- {
- self.contentScaleFactor = [[UIScreen mainScreen] scale];
- }
- inputRotation = kGPUImageNoRotation;
- self.opaque = YES;
- self.hidden = NO;
- CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
- eaglLayer.opaque = YES;
- eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
- self.enabled = YES;
-
- runSynchronouslyOnVideoProcessingQueue(^{
- [GPUImageContext useImageProcessingContext];
-
- displayProgram = [[GPUImageContext sharedImageProcessingContext] programForVertexShaderString:kGPUImageVertexShaderString fragmentShaderString:kGPUImagePassthroughFragmentShaderString];
- if (!displayProgram.initialized)
- {
- [displayProgram addAttribute:@"position"];
- [displayProgram addAttribute:@"inputTextureCoordinate"];
-
- if (![displayProgram link])
- {
- NSString *progLog = [displayProgram programLog];
- NSLog(@"Program link log: %@", progLog);
- NSString *fragLog = [displayProgram fragmentShaderLog];
- NSLog(@"Fragment shader compile log: %@", fragLog);
- NSString *vertLog = [displayProgram vertexShaderLog];
- NSLog(@"Vertex shader compile log: %@", vertLog);
- displayProgram = nil;
- NSAssert(NO, @"Filter shader link failed");
- }
- }
-
- displayPositionAttribute = [displayProgram attributeIndex:@"position"];
- displayTextureCoordinateAttribute = [displayProgram attributeIndex:@"inputTextureCoordinate"];
- displayInputTextureUniform = [displayProgram uniformIndex:@"inputImageTexture"]; // This does assume a name of "inputTexture" for the fragment shader
- [GPUImageContext setActiveShaderProgram:displayProgram];
- glEnableVertexAttribArray(displayPositionAttribute);
- glEnableVertexAttribArray(displayTextureCoordinateAttribute);
-
- [self setBackgroundColorRed:0.0 green:0.0 blue:0.0 alpha:1.0];
- _fillMode = kGPUImageFillModePreserveAspectRatio;
- [self createDisplayFramebuffer];
- });
- }
- - (void)layoutSubviews {
- [super layoutSubviews];
-
- // The frame buffer needs to be trashed and re-created when the view size changes.
- if (!CGSizeEqualToSize(self.bounds.size, boundsSizeAtFrameBufferEpoch) &&
- !CGSizeEqualToSize(self.bounds.size, CGSizeZero)) {
- runSynchronouslyOnVideoProcessingQueue(^{
- [self destroyDisplayFramebuffer];
- [self createDisplayFramebuffer];
- [self recalculateViewGeometry];
- });
- }
- }
- - (void)dealloc
- {
- runSynchronouslyOnVideoProcessingQueue(^{
- [self destroyDisplayFramebuffer];
- });
- }
- #pragma mark -
- #pragma mark Managing the display FBOs
- - (void)createDisplayFramebuffer;
- {
- [GPUImageContext useImageProcessingContext];
-
- glGenFramebuffers(1, &displayFramebuffer);
- glBindFramebuffer(GL_FRAMEBUFFER, displayFramebuffer);
-
- glGenRenderbuffers(1, &displayRenderbuffer);
- glBindRenderbuffer(GL_RENDERBUFFER, displayRenderbuffer);
-
- [[[GPUImageContext sharedImageProcessingContext] context] renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
-
- GLint backingWidth, backingHeight;
- glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
- glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
-
- if ( (backingWidth == 0) || (backingHeight == 0) )
- {
- [self destroyDisplayFramebuffer];
- return;
- }
-
- _sizeInPixels.width = (CGFloat)backingWidth;
- _sizeInPixels.height = (CGFloat)backingHeight;
- // NSLog(@"Backing width: %d, height: %d", backingWidth, backingHeight);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, displayRenderbuffer);
-
- GLuint framebufferCreationStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- NSAssert(framebufferCreationStatus == GL_FRAMEBUFFER_COMPLETE, @"Failure with display framebuffer generation for display of size: %f, %f", self.bounds.size.width, self.bounds.size.height);
- boundsSizeAtFrameBufferEpoch = self.bounds.size;
- }
- - (void)destroyDisplayFramebuffer;
- {
- [GPUImageContext useImageProcessingContext];
- if (displayFramebuffer)
- {
- glDeleteFramebuffers(1, &displayFramebuffer);
- displayFramebuffer = 0;
- }
-
- if (displayRenderbuffer)
- {
- glDeleteRenderbuffers(1, &displayRenderbuffer);
- displayRenderbuffer = 0;
- }
- }
- - (void)setDisplayFramebuffer;
- {
- if (!displayFramebuffer)
- {
- [self createDisplayFramebuffer];
- }
-
- glBindFramebuffer(GL_FRAMEBUFFER, displayFramebuffer);
-
- glViewport(0, 0, (GLint)_sizeInPixels.width, (GLint)_sizeInPixels.height);
- }
- - (void)presentFramebuffer;
- {
- glBindRenderbuffer(GL_RENDERBUFFER, displayRenderbuffer);
- [[GPUImageContext sharedImageProcessingContext] presentBufferForDisplay];
- }
- #pragma mark -
- #pragma mark Handling fill mode
- - (void)recalculateViewGeometry;
- {
- runSynchronouslyOnVideoProcessingQueue(^{
- CGFloat heightScaling, widthScaling;
-
- CGSize currentViewSize = self.bounds.size;
-
- // CGFloat imageAspectRatio = inputImageSize.width / inputImageSize.height;
- // CGFloat viewAspectRatio = currentViewSize.width / currentViewSize.height;
-
- CGRect insetRect = AVMakeRectWithAspectRatioInsideRect(inputImageSize, self.bounds);
-
- switch(_fillMode)
- {
- case kGPUImageFillModeStretch:
- {
- widthScaling = 1.0;
- heightScaling = 1.0;
- }; break;
- case kGPUImageFillModePreserveAspectRatio:
- {
- widthScaling = insetRect.size.width / currentViewSize.width;
- heightScaling = insetRect.size.height / currentViewSize.height;
- }; break;
- case kGPUImageFillModePreserveAspectRatioAndFill:
- {
- // CGFloat widthHolder = insetRect.size.width / currentViewSize.width;
- widthScaling = currentViewSize.height / insetRect.size.height;
- heightScaling = currentViewSize.width / insetRect.size.width;
- }; break;
- }
-
- imageVertices[0] = -widthScaling;
- imageVertices[1] = -heightScaling;
- imageVertices[2] = widthScaling;
- imageVertices[3] = -heightScaling;
- imageVertices[4] = -widthScaling;
- imageVertices[5] = heightScaling;
- imageVertices[6] = widthScaling;
- imageVertices[7] = heightScaling;
- });
-
- // static const GLfloat imageVertices[] = {
- // -1.0f, -1.0f,
- // 1.0f, -1.0f,
- // -1.0f, 1.0f,
- // 1.0f, 1.0f,
- // };
- }
- - (void)setBackgroundColorRed:(GLfloat)redComponent green:(GLfloat)greenComponent blue:(GLfloat)blueComponent alpha:(GLfloat)alphaComponent;
- {
- backgroundColorRed = redComponent;
- backgroundColorGreen = greenComponent;
- backgroundColorBlue = blueComponent;
- backgroundColorAlpha = alphaComponent;
- }
- + (const GLfloat *)textureCoordinatesForRotation:(GPUImageRotationMode)rotationMode;
- {
- // static const GLfloat noRotationTextureCoordinates[] = {
- // 0.0f, 0.0f,
- // 1.0f, 0.0f,
- // 0.0f, 1.0f,
- // 1.0f, 1.0f,
- // };
-
- static const GLfloat noRotationTextureCoordinates[] = {
- 0.0f, 1.0f,
- 1.0f, 1.0f,
- 0.0f, 0.0f,
- 1.0f, 0.0f,
- };
- static const GLfloat rotateRightTextureCoordinates[] = {
- 1.0f, 1.0f,
- 1.0f, 0.0f,
- 0.0f, 1.0f,
- 0.0f, 0.0f,
- };
- static const GLfloat rotateLeftTextureCoordinates[] = {
- 0.0f, 0.0f,
- 0.0f, 1.0f,
- 1.0f, 0.0f,
- 1.0f, 1.0f,
- };
-
- static const GLfloat verticalFlipTextureCoordinates[] = {
- 0.0f, 0.0f,
- 1.0f, 0.0f,
- 0.0f, 1.0f,
- 1.0f, 1.0f,
- };
-
- static const GLfloat horizontalFlipTextureCoordinates[] = {
- 1.0f, 1.0f,
- 0.0f, 1.0f,
- 1.0f, 0.0f,
- 0.0f, 0.0f,
- };
-
- static const GLfloat rotateRightVerticalFlipTextureCoordinates[] = {
- 1.0f, 0.0f,
- 1.0f, 1.0f,
- 0.0f, 0.0f,
- 0.0f, 1.0f,
- };
-
- static const GLfloat rotateRightHorizontalFlipTextureCoordinates[] = {
- 1.0f, 1.0f,
- 1.0f, 0.0f,
- 0.0f, 1.0f,
- 0.0f, 0.0f,
- };
- static const GLfloat rotate180TextureCoordinates[] = {
- 1.0f, 0.0f,
- 0.0f, 0.0f,
- 1.0f, 1.0f,
- 0.0f, 1.0f,
- };
-
- switch(rotationMode)
- {
- case kGPUImageNoRotation: return noRotationTextureCoordinates;
- case kGPUImageRotateLeft: return rotateLeftTextureCoordinates;
- case kGPUImageRotateRight: return rotateRightTextureCoordinates;
- case kGPUImageFlipVertical: return verticalFlipTextureCoordinates;
- case kGPUImageFlipHorizonal: return horizontalFlipTextureCoordinates;
- case kGPUImageRotateRightFlipVertical: return rotateRightVerticalFlipTextureCoordinates;
- case kGPUImageRotateRightFlipHorizontal: return rotateRightHorizontalFlipTextureCoordinates;
- case kGPUImageRotate180: return rotate180TextureCoordinates;
- }
- }
- #pragma mark -
- #pragma mark GPUInput protocol
- - (void)newFrameReadyAtTime:(CMTime)frameTime atIndex:(NSInteger)textureIndex;
- {
- runSynchronouslyOnVideoProcessingQueue(^{
- [GPUImageContext setActiveShaderProgram:displayProgram];
- [self setDisplayFramebuffer];
-
- glClearColor(backgroundColorRed, backgroundColorGreen, backgroundColorBlue, backgroundColorAlpha);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- glActiveTexture(GL_TEXTURE4);
- glBindTexture(GL_TEXTURE_2D, [inputFramebufferForDisplay texture]);
- glUniform1i(displayInputTextureUniform, 4);
-
- glVertexAttribPointer(displayPositionAttribute, 2, GL_FLOAT, 0, 0, imageVertices);
- glVertexAttribPointer(displayTextureCoordinateAttribute, 2, GL_FLOAT, 0, 0, [GPUImageView textureCoordinatesForRotation:inputRotation]);
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- [self presentFramebuffer];
- [inputFramebufferForDisplay unlock];
- inputFramebufferForDisplay = nil;
- });
- }
- - (NSInteger)nextAvailableTextureIndex;
- {
- return 0;
- }
- - (void)setInputFramebuffer:(GPUImageFramebuffer *)newInputFramebuffer atIndex:(NSInteger)textureIndex;
- {
- inputFramebufferForDisplay = newInputFramebuffer;
- [inputFramebufferForDisplay lock];
- }
- - (void)setInputRotation:(GPUImageRotationMode)newInputRotation atIndex:(NSInteger)textureIndex;
- {
- inputRotation = newInputRotation;
- }
- - (void)setInputSize:(CGSize)newSize atIndex:(NSInteger)textureIndex;
- {
- runSynchronouslyOnVideoProcessingQueue(^{
- CGSize rotatedSize = newSize;
-
- if (GPUImageRotationSwapsWidthAndHeight(inputRotation))
- {
- rotatedSize.width = newSize.height;
- rotatedSize.height = newSize.width;
- }
-
- if (!CGSizeEqualToSize(inputImageSize, rotatedSize))
- {
- inputImageSize = rotatedSize;
- [self recalculateViewGeometry];
- }
- });
- }
- - (CGSize)maximumOutputSize;
- {
- if ([self respondsToSelector:@selector(setContentScaleFactor:)])
- {
- CGSize pointSize = self.bounds.size;
- return CGSizeMake(self.contentScaleFactor * pointSize.width, self.contentScaleFactor * pointSize.height);
- }
- else
- {
- return self.bounds.size;
- }
- }
- - (void)endProcessing
- {
- }
- - (BOOL)shouldIgnoreUpdatesToThisTarget;
- {
- return NO;
- }
- - (BOOL)wantsMonochromeInput;
- {
- return NO;
- }
- - (void)setCurrentlyReceivingMonochromeInput:(BOOL)newValue;
- {
-
- }
- #pragma mark -
- #pragma mark Accessors
- - (CGSize)sizeInPixels;
- {
- if (CGSizeEqualToSize(_sizeInPixels, CGSizeZero))
- {
- return [self maximumOutputSize];
- }
- else
- {
- return _sizeInPixels;
- }
- }
- - (void)setFillMode:(GPUImageFillModeType)newValue;
- {
- _fillMode = newValue;
- [self recalculateViewGeometry];
- }
- @end
|