美文网首页
GPUImageView.m源码详解

GPUImageView.m源码详解

作者: 孙健会员 | 来源:发表于2016-09-06 01:28 被阅读752次
    #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;//r g b a
    
        CGSize boundsSizeAtFrameBufferEpoch;
    }
    
    @property (assign, nonatomic) NSUInteger aspectRatio;//比例
    
    - (void)commonInit;//init
    - (void)createDisplayFramebuffer;//创建帧缓存
    - (void)destroyDisplayFramebuffer;//销毁帧缓存
    - (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];
        if (!CGSizeEqualToSize(self.bounds.size, boundsSizeAtFrameBufferEpoch) &&
            !CGSizeEqualToSize(self.bounds.size, CGSizeZero)) {
            runSynchronouslyOnVideoProcessingQueue(^{
                [self destroyDisplayFramebuffer];
                [self createDisplayFramebuffer];
                [self recalculateViewGeometry];
            });
        }
    }
    
    - (void)dealloc
    {
        runSynchronouslyOnVideoProcessingQueue(^{
            [self destroyDisplayFramebuffer];
        });
    }
    - (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;
    
        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
    

    相关文章

      网友评论

          本文标题:GPUImageView.m源码详解

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