zoukankan      html  css  js  c++  java
  • GPUImage API文档之GPUImageFramebuffer类

      GPUImageFramebuffer类用于管理帧缓冲对象,负责帧缓冲对象的创建和销毁,读取帧缓冲内容

      属性

      @property(readonly) CGSize size

      说明:只读属性,在实现中,设置缓冲区的size

     

      @property(readonly) GPUTextureOptions textureOptions

      说明:纹理的选项

     

      @property(readonly) GLuint texture

      说明:管理纹理

     

      @property(readonly) BOOL missingFramebuffer

      说明:指示是否丢失帧缓冲对象

      

      方法

       - (id)initWithSize:(CGSize)framebufferSize

        说明:创建一个size为framebufferSize大小的帧缓冲对象

        参数:framebuffer的size。

        返回:创建成功的帧缓冲对象。

        实现

    - (id)initWithSize:(CGSize)framebufferSize;
    {
        GPUTextureOptions defaultTextureOptions;
        defaultTextureOptions.minFilter = GL_LINEAR;
        defaultTextureOptions.magFilter = GL_LINEAR;
        defaultTextureOptions.wrapS = GL_CLAMP_TO_EDGE;
        defaultTextureOptions.wrapT = GL_CLAMP_TO_EDGE;
        defaultTextureOptions.internalFormat = GL_RGBA;
        defaultTextureOptions.format = GL_BGRA;
        defaultTextureOptions.type = GL_UNSIGNED_BYTE;
    
        if (!(self = [self initWithSize:framebufferSize textureOptions:defaultTextureOptions onlyTexture:NO]))
        {
            return nil;
        }
    
        return self;
    }

     

         - (id)initWithSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)fboTextureOptions onlyTexture:(BOOL)onlyGenerateTexture

        说明:创建一个size为framebufferSize大小的帧缓冲对象

        参数:framebufferSize为framebuffer的size。fboTextureOptions是纹理的详细配置。onlyGenerateTexture说明是否只创建纹理而不创建陈帧缓冲对象。

        返回:创建成功的帧缓冲对象。

        实现

    - (id)initWithSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)fboTextureOptions onlyTexture:(BOOL)onlyGenerateTexture;
    {
        if (!(self = [super init]))
        {
            return nil;
        }
        
        _textureOptions = fboTextureOptions;
        _size = framebufferSize;
        framebufferReferenceCount = 0;
        referenceCountingDisabled = NO;
        _missingFramebuffer = onlyGenerateTexture;
    
        if (_missingFramebuffer)
        {
            runSynchronouslyOnVideoProcessingQueue(^{
                [GPUImageContext useImageProcessingContext];
                [self generateTexture];
                framebuffer = 0;
            });
        }
        else
        {
            [self generateFramebuffer];
        }
        return self;
    }

       - (id)initWithSize:(CGSize)framebufferSize overriddenTexture:(GLuint)inputTexture

        说明:创建一个size为framebufferSize大小的帧缓冲对象

        参数:inputTexture为输入的纹理,用于渲染图片。

        返回:创建成功的帧缓冲对象。

        实现

    - (id)initWithSize:(CGSize)framebufferSize overriddenTexture:(GLuint)inputTexture;
    {
        if (!(self = [super init]))
        {
            return nil;
        }
    
        GPUTextureOptions defaultTextureOptions;
        defaultTextureOptions.minFilter = GL_LINEAR;
        defaultTextureOptions.magFilter = GL_LINEAR;
        defaultTextureOptions.wrapS = GL_CLAMP_TO_EDGE;
        defaultTextureOptions.wrapT = GL_CLAMP_TO_EDGE;
        defaultTextureOptions.internalFormat = GL_RGBA;
        defaultTextureOptions.format = GL_BGRA;
        defaultTextureOptions.type = GL_UNSIGNED_BYTE;
    
        _textureOptions = defaultTextureOptions;
        _size = framebufferSize;
        framebufferReferenceCount = 0;
        referenceCountingDisabled = YES;
        
        _texture = inputTexture;
        
        return self;
    }

       - (void)activateFramebuffer

        说明:激活刚创建的framebuffer对象。只有调用它后,才会起作用。

        实现 

    - (void)activateFramebuffer;
    {
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        glViewport(0, 0, (int)_size.width, (int)_size.height);
    }

       - (void)lock

        说明:引用计数管理 +1

        实现

    - (void)lock;
    {
        if (referenceCountingDisabled)
        {
            return;
        }
        
        framebufferReferenceCount++;
    }

       - (void)unlock

        说明:引用计数管理 -1

        实现

    - (void)unlock;
    {
        if (referenceCountingDisabled)
        {
            return;
        }
    
        NSAssert(framebufferReferenceCount > 0, @"Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer?");
        framebufferReferenceCount--;
        if (framebufferReferenceCount < 1)
        {
            [[GPUImageContext sharedFramebufferCache] returnFramebufferToCache:self];
        }
    }

       - (void)clearAllLocks

        说明:引用计数管理 设置为0

        实现

    - (void)clearAllLocks;
    {
        framebufferReferenceCount = 0;
    }

       - (void)disableReferenceCounting

        说明:引用计数管理 禁用引用计数

        实现

    - (void)disableReferenceCounting;
    {
        referenceCountingDisabled = YES;
    }

       - (void)enableReferenceCounting

        说明:引用计数管理 启用引用计数

        实现

    - (void)enableReferenceCounting;
    {
        referenceCountingDisabled = NO;
    }

       - (CGImageRef)newCGImageFromFramebufferContents

        说明:输出帧缓冲内容。【说明待更新......】

        实现

    - (CGImageRef)newCGImageFromFramebufferContents;
    {
        // a CGImage can only be created from a 'normal' color texture
        NSAssert(self.textureOptions.internalFormat == GL_RGBA, @"For conversion to a CGImage the output texture format for this filter must be GL_RGBA.");
        NSAssert(self.textureOptions.type == GL_UNSIGNED_BYTE, @"For conversion to a CGImage the type of the output texture of this filter must be GL_UNSIGNED_BYTE.");
        
        __block CGImageRef cgImageFromBytes;
        
        runSynchronouslyOnVideoProcessingQueue(^{
            [GPUImageContext useImageProcessingContext];
            
            NSUInteger totalBytesForImage = (int)_size.width * (int)_size.height * 4;
            // It appears that the width of a texture must be padded out to be a multiple of 8 (32 bytes) if reading from it using a texture cache
            
            GLubyte *rawImagePixels;
            
            CGDataProviderRef dataProvider = NULL;
            if ([GPUImageContext supportsFastTextureUpload])
            {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
                NSUInteger paddedWidthOfImage = CVPixelBufferGetBytesPerRow(renderTarget) / 4.0;
                NSUInteger paddedBytesForImage = paddedWidthOfImage * (int)_size.height * 4;
                
                glFinish();
                CFRetain(renderTarget); // I need to retain the pixel buffer here and release in the data source callback to prevent its bytes from being prematurely deallocated during a photo write operation
                [self lockForReading];
                rawImagePixels = (GLubyte *)CVPixelBufferGetBaseAddress(renderTarget);
                dataProvider = CGDataProviderCreateWithData((__bridge_retained void*)self, rawImagePixels, paddedBytesForImage, dataProviderUnlockCallback);
                [[GPUImageContext sharedFramebufferCache] addFramebufferToActiveImageCaptureList:self]; // In case the framebuffer is swapped out on the filter, need to have a strong reference to it somewhere for it to hang on while the image is in existence
    #else
    #endif
            }
            else
            {
                [self activateFramebuffer];
                rawImagePixels = (GLubyte *)malloc(totalBytesForImage);
                glReadPixels(0, 0, (int)_size.width, (int)_size.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels);
                dataProvider = CGDataProviderCreateWithData(NULL, rawImagePixels, totalBytesForImage, dataProviderReleaseCallback);
                [self unlock]; // Don't need to keep this around anymore
            }
            
            CGColorSpaceRef defaultRGBColorSpace = CGColorSpaceCreateDeviceRGB();
            
            if ([GPUImageContext supportsFastTextureUpload])
            {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
                cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, CVPixelBufferGetBytesPerRow(renderTarget), defaultRGBColorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, dataProvider, NULL, NO, kCGRenderingIntentDefault);
    #else
    #endif
            }
            else
            {
                cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, 4 * (int)_size.width, defaultRGBColorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaLast, dataProvider, NULL, NO, kCGRenderingIntentDefault);
            }
            
            // Capture image with current device orientation
            CGDataProviderRelease(dataProvider);
            CGColorSpaceRelease(defaultRGBColorSpace);
            
        });
        
        return cgImageFromBytes;
    }

       - (void)restoreRenderTarget

        说明:还原渲染目标对象

        实现

    - (void)restoreRenderTarget;
    {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
        [self unlockAfterReading];
        CFRelease(renderTarget);
    #else
    #endif
    }

       - (void)lockForReading

        说明:锁定PixelBuffer

        实现:

    - (void)lockForReading
    {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
        if ([GPUImageContext supportsFastTextureUpload])
        {
            if (readLockCount == 0)
            {
                CVPixelBufferLockBaseAddress(renderTarget, 0);
            }
            readLockCount++;
        }
    #endif
    }

       - (void)unlockAfterReading

        说明:解锁PixelBuffer

    - (void)unlockAfterReading
    {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
        if ([GPUImageContext supportsFastTextureUpload])
        {
            NSAssert(readLockCount > 0, @"Unbalanced call to -[GPUImageFramebuffer unlockAfterReading]");
            readLockCount--;
            if (readLockCount == 0)
            {
                CVPixelBufferUnlockBaseAddress(renderTarget, 0);
            }
        }
    #endif
    }

       - (NSUInteger)bytesPerRow

        说明:获取pixel buffer的行字节数

        实现

    - (NSUInteger)bytesPerRow;
    {
        if ([GPUImageContext supportsFastTextureUpload])
        {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
            return CVPixelBufferGetBytesPerRow(renderTarget);
    #else
            return _size.width * 4; // TODO: do more with this on the non-texture-cache side
    #endif
        }
        else
        {
            return _size.width * 4;
        }
    }

       - (GLubyte *)byteBuffer

        说明:获取pixel buffer的基地址

        实现

    - (GLubyte *)byteBuffer;
    {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
        [self lockForReading];
        GLubyte * bufferBytes = CVPixelBufferGetBaseAddress(renderTarget);
        [self unlockAfterReading];
        return bufferBytes;
    #else
        return NULL; // TODO: do more with this on the non-texture-cache side
    #endif
    }

    完整代码

    #import <Foundation/Foundation.h>
    
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
    #import <OpenGLES/EAGL.h>
    #import <OpenGLES/ES2/gl.h>
    #import <OpenGLES/ES2/glext.h>
    #else
    #import <OpenGL/OpenGL.h>
    #import <OpenGL/gl.h>
    #endif
    
    #import <QuartzCore/QuartzCore.h>
    #import <CoreMedia/CoreMedia.h>
    
    
    typedef struct GPUTextureOptions {
        GLenum minFilter;
        GLenum magFilter;
        GLenum wrapS;
        GLenum wrapT;
        GLenum internalFormat;
        GLenum format;
        GLenum type;
    } GPUTextureOptions;
    
    @interface GPUImageFramebuffer : NSObject
    
    @property(readonly) CGSize size;
    @property(readonly) GPUTextureOptions textureOptions;
    @property(readonly) GLuint texture;
    @property(readonly) BOOL missingFramebuffer;
    
    // Initialization and teardown
    - (id)initWithSize:(CGSize)framebufferSize;
    - (id)initWithSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)fboTextureOptions onlyTexture:(BOOL)onlyGenerateTexture;
    - (id)initWithSize:(CGSize)framebufferSize overriddenTexture:(GLuint)inputTexture;
    
    // Usage
    - (void)activateFramebuffer;
    
    // Reference counting
    - (void)lock;
    - (void)unlock;
    - (void)clearAllLocks;
    - (void)disableReferenceCounting;
    - (void)enableReferenceCounting;
    
    // Image capture
    - (CGImageRef)newCGImageFromFramebufferContents;
    - (void)restoreRenderTarget;
    
    // Raw data bytes
    - (void)lockForReading;
    - (void)unlockAfterReading;
    - (NSUInteger)bytesPerRow;
    - (GLubyte *)byteBuffer;
    
    @end
    View Code

     

    #import "GPUImageFramebuffer.h"
    #import "GPUImageOutput.h"
    
    @interface GPUImageFramebuffer()
    {
        GLuint framebuffer;
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
        CVPixelBufferRef renderTarget;
        CVOpenGLESTextureRef renderTexture;
        NSUInteger readLockCount;
    #else
    #endif
        NSUInteger framebufferReferenceCount;
        BOOL referenceCountingDisabled;
    }
    
    - (void)generateFramebuffer;
    - (void)generateTexture;
    - (void)destroyFramebuffer;
    
    @end
    
    void dataProviderReleaseCallback (void *info, const void *data, size_t size);
    void dataProviderUnlockCallback (void *info, const void *data, size_t size);
    
    @implementation GPUImageFramebuffer
    
    @synthesize size = _size;
    @synthesize textureOptions = _textureOptions;
    @synthesize texture = _texture;
    @synthesize missingFramebuffer = _missingFramebuffer;
    
    #pragma mark -
    #pragma mark Initialization and teardown
    
    - (id)initWithSize:(CGSize)framebufferSize textureOptions:(GPUTextureOptions)fboTextureOptions onlyTexture:(BOOL)onlyGenerateTexture;
    {
        if (!(self = [super init]))
        {
            return nil;
        }
        
        _textureOptions = fboTextureOptions;
        _size = framebufferSize;
        framebufferReferenceCount = 0;
        referenceCountingDisabled = NO;
        _missingFramebuffer = onlyGenerateTexture;
    
        if (_missingFramebuffer)
        {
            runSynchronouslyOnVideoProcessingQueue(^{
                [GPUImageContext useImageProcessingContext];
                [self generateTexture];
                framebuffer = 0;
            });
        }
        else
        {
            [self generateFramebuffer];
        }
        return self;
    }
    
    - (id)initWithSize:(CGSize)framebufferSize overriddenTexture:(GLuint)inputTexture;
    {
        if (!(self = [super init]))
        {
            return nil;
        }
    
        GPUTextureOptions defaultTextureOptions;
        defaultTextureOptions.minFilter = GL_LINEAR;
        defaultTextureOptions.magFilter = GL_LINEAR;
        defaultTextureOptions.wrapS = GL_CLAMP_TO_EDGE;
        defaultTextureOptions.wrapT = GL_CLAMP_TO_EDGE;
        defaultTextureOptions.internalFormat = GL_RGBA;
        defaultTextureOptions.format = GL_BGRA;
        defaultTextureOptions.type = GL_UNSIGNED_BYTE;
    
        _textureOptions = defaultTextureOptions;
        _size = framebufferSize;
        framebufferReferenceCount = 0;
        referenceCountingDisabled = YES;
        
        _texture = inputTexture;
        
        return self;
    }
    
    - (id)initWithSize:(CGSize)framebufferSize;
    {
        GPUTextureOptions defaultTextureOptions;
        defaultTextureOptions.minFilter = GL_LINEAR;
        defaultTextureOptions.magFilter = GL_LINEAR;
        defaultTextureOptions.wrapS = GL_CLAMP_TO_EDGE;
        defaultTextureOptions.wrapT = GL_CLAMP_TO_EDGE;
        defaultTextureOptions.internalFormat = GL_RGBA;
        defaultTextureOptions.format = GL_BGRA;
        defaultTextureOptions.type = GL_UNSIGNED_BYTE;
    
        if (!(self = [self initWithSize:framebufferSize textureOptions:defaultTextureOptions onlyTexture:NO]))
        {
            return nil;
        }
    
        return self;
    }
    
    - (void)dealloc
    {
        [self destroyFramebuffer];
    }
    
    #pragma mark -
    #pragma mark Internal
    
    - (void)generateTexture;
    {
        glActiveTexture(GL_TEXTURE1);
        glGenTextures(1, &_texture);
        glBindTexture(GL_TEXTURE_2D, _texture);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _textureOptions.minFilter);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _textureOptions.magFilter);
        // This is necessary for non-power-of-two textures
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _textureOptions.wrapS);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _textureOptions.wrapT);
        
        // TODO: Handle mipmaps
    }
    
    - (void)generateFramebuffer;
    {
        runSynchronouslyOnVideoProcessingQueue(^{
            [GPUImageContext useImageProcessingContext];
        
            glGenFramebuffers(1, &framebuffer);
            glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
            
            // By default, all framebuffers on iOS 5.0+ devices are backed by texture caches, using one shared cache
            if ([GPUImageContext supportsFastTextureUpload])
            {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
                CVOpenGLESTextureCacheRef coreVideoTextureCache = [[GPUImageContext sharedImageProcessingContext] coreVideoTextureCache];
                // Code originally sourced from http://allmybrain.com/2011/12/08/rendering-to-a-texture-with-ios-5-texture-cache-api/
                
                CFDictionaryRef empty; // empty value for attr value.
                CFMutableDictionaryRef attrs;
                empty = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // our empty IOSurface properties dictionary
                attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
                CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);
                
                CVReturn err = CVPixelBufferCreate(kCFAllocatorDefault, (int)_size.width, (int)_size.height, kCVPixelFormatType_32BGRA, attrs, &renderTarget);
                if (err)
                {
                    NSLog(@"FBO size: %f, %f", _size.width, _size.height);
                    NSAssert(NO, @"Error at CVPixelBufferCreate %d", err);
                }
                
                err = CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault, coreVideoTextureCache, renderTarget,
                                                                    NULL, // texture attributes
                                                                    GL_TEXTURE_2D,
                                                                    _textureOptions.internalFormat, // opengl format
                                                                    (int)_size.width,
                                                                    (int)_size.height,
                                                                    _textureOptions.format, // native iOS format
                                                                    _textureOptions.type,
                                                                    0,
                                                                    &renderTexture);
                if (err)
                {
                    NSAssert(NO, @"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
                }
                
                CFRelease(attrs);
                CFRelease(empty);
                
                glBindTexture(CVOpenGLESTextureGetTarget(renderTexture), CVOpenGLESTextureGetName(renderTexture));
                _texture = CVOpenGLESTextureGetName(renderTexture);
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _textureOptions.wrapS);
                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _textureOptions.wrapT);
                
                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture), 0);
    #endif
            }
            else
            {
                [self generateTexture];
    
                glBindTexture(GL_TEXTURE_2D, _texture);
                
                glTexImage2D(GL_TEXTURE_2D, 0, _textureOptions.internalFormat, (int)_size.width, (int)_size.height, 0, _textureOptions.format, _textureOptions.type, 0);
                glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
            }
            
            #ifndef NS_BLOCK_ASSERTIONS
            GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
            NSAssert(status == GL_FRAMEBUFFER_COMPLETE, @"Incomplete filter FBO: %d", status);
            #endif
            
            glBindTexture(GL_TEXTURE_2D, 0);
        });
    }
    
    - (void)destroyFramebuffer;
    {
        runSynchronouslyOnVideoProcessingQueue(^{
            [GPUImageContext useImageProcessingContext];
            
            if (framebuffer)
            {
                glDeleteFramebuffers(1, &framebuffer);
                framebuffer = 0;
            }
    
            
            if ([GPUImageContext supportsFastTextureUpload] && (!_missingFramebuffer))
            {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
                if (renderTarget)
                {
                    CFRelease(renderTarget);
                    renderTarget = NULL;
                }
                
                if (renderTexture)
                {
                    CFRelease(renderTexture);
                    renderTexture = NULL;
                }
    #endif
            }
            else
            {
                glDeleteTextures(1, &_texture);
            }
    
        });
    }
    
    #pragma mark -
    #pragma mark Usage
    
    - (void)activateFramebuffer;
    {
        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
        glViewport(0, 0, (int)_size.width, (int)_size.height);
    }
    
    #pragma mark -
    #pragma mark Reference counting
    
    - (void)lock;
    {
        if (referenceCountingDisabled)
        {
            return;
        }
        
        framebufferReferenceCount++;
    }
    
    - (void)unlock;
    {
        if (referenceCountingDisabled)
        {
            return;
        }
    
        NSAssert(framebufferReferenceCount > 0, @"Tried to overrelease a framebuffer, did you forget to call -useNextFrameForImageCapture before using -imageFromCurrentFramebuffer?");
        framebufferReferenceCount--;
        if (framebufferReferenceCount < 1)
        {
            [[GPUImageContext sharedFramebufferCache] returnFramebufferToCache:self];
        }
    }
    
    - (void)clearAllLocks;
    {
        framebufferReferenceCount = 0;
    }
    
    - (void)disableReferenceCounting;
    {
        referenceCountingDisabled = YES;
    }
    
    - (void)enableReferenceCounting;
    {
        referenceCountingDisabled = NO;
    }
    
    #pragma mark -
    #pragma mark Image capture
    
    void dataProviderReleaseCallback (void *info, const void *data, size_t size)
    {
        free((void *)data);
    }
    
    void dataProviderUnlockCallback (void *info, const void *data, size_t size)
    {
        GPUImageFramebuffer *framebuffer = (__bridge_transfer GPUImageFramebuffer*)info;
        
        [framebuffer restoreRenderTarget];
        [framebuffer unlock];
        [[GPUImageContext sharedFramebufferCache] removeFramebufferFromActiveImageCaptureList:framebuffer];
    }
    
    - (CGImageRef)newCGImageFromFramebufferContents;
    {
        // a CGImage can only be created from a 'normal' color texture
        NSAssert(self.textureOptions.internalFormat == GL_RGBA, @"For conversion to a CGImage the output texture format for this filter must be GL_RGBA.");
        NSAssert(self.textureOptions.type == GL_UNSIGNED_BYTE, @"For conversion to a CGImage the type of the output texture of this filter must be GL_UNSIGNED_BYTE.");
        
        __block CGImageRef cgImageFromBytes;
        
        runSynchronouslyOnVideoProcessingQueue(^{
            [GPUImageContext useImageProcessingContext];
            
            NSUInteger totalBytesForImage = (int)_size.width * (int)_size.height * 4;
            // It appears that the width of a texture must be padded out to be a multiple of 8 (32 bytes) if reading from it using a texture cache
            
            GLubyte *rawImagePixels;
            
            CGDataProviderRef dataProvider = NULL;
            if ([GPUImageContext supportsFastTextureUpload])
            {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
                NSUInteger paddedWidthOfImage = CVPixelBufferGetBytesPerRow(renderTarget) / 4.0;
                NSUInteger paddedBytesForImage = paddedWidthOfImage * (int)_size.height * 4;
                
                glFinish();
                CFRetain(renderTarget); // I need to retain the pixel buffer here and release in the data source callback to prevent its bytes from being prematurely deallocated during a photo write operation
                [self lockForReading];
                rawImagePixels = (GLubyte *)CVPixelBufferGetBaseAddress(renderTarget);
                dataProvider = CGDataProviderCreateWithData((__bridge_retained void*)self, rawImagePixels, paddedBytesForImage, dataProviderUnlockCallback);
                [[GPUImageContext sharedFramebufferCache] addFramebufferToActiveImageCaptureList:self]; // In case the framebuffer is swapped out on the filter, need to have a strong reference to it somewhere for it to hang on while the image is in existence
    #else
    #endif
            }
            else
            {
                [self activateFramebuffer];
                rawImagePixels = (GLubyte *)malloc(totalBytesForImage);
                glReadPixels(0, 0, (int)_size.width, (int)_size.height, GL_RGBA, GL_UNSIGNED_BYTE, rawImagePixels);
                dataProvider = CGDataProviderCreateWithData(NULL, rawImagePixels, totalBytesForImage, dataProviderReleaseCallback);
                [self unlock]; // Don't need to keep this around anymore
            }
            
            CGColorSpaceRef defaultRGBColorSpace = CGColorSpaceCreateDeviceRGB();
            
            if ([GPUImageContext supportsFastTextureUpload])
            {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
                cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, CVPixelBufferGetBytesPerRow(renderTarget), defaultRGBColorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, dataProvider, NULL, NO, kCGRenderingIntentDefault);
    #else
    #endif
            }
            else
            {
                cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, 4 * (int)_size.width, defaultRGBColorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaLast, dataProvider, NULL, NO, kCGRenderingIntentDefault);
            }
            
            // Capture image with current device orientation
            CGDataProviderRelease(dataProvider);
            CGColorSpaceRelease(defaultRGBColorSpace);
            
        });
        
        return cgImageFromBytes;
    }
    
    - (void)restoreRenderTarget;
    {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
        [self unlockAfterReading];
        CFRelease(renderTarget);
    #else
    #endif
    }
    
    #pragma mark -
    #pragma mark Raw data bytes
    
    - (void)lockForReading
    {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
        if ([GPUImageContext supportsFastTextureUpload])
        {
            if (readLockCount == 0)
            {
                CVPixelBufferLockBaseAddress(renderTarget, 0);
            }
            readLockCount++;
        }
    #endif
    }
    
    - (void)unlockAfterReading
    {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
        if ([GPUImageContext supportsFastTextureUpload])
        {
            NSAssert(readLockCount > 0, @"Unbalanced call to -[GPUImageFramebuffer unlockAfterReading]");
            readLockCount--;
            if (readLockCount == 0)
            {
                CVPixelBufferUnlockBaseAddress(renderTarget, 0);
            }
        }
    #endif
    }
    
    - (NSUInteger)bytesPerRow;
    {
        if ([GPUImageContext supportsFastTextureUpload])
        {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
            return CVPixelBufferGetBytesPerRow(renderTarget);
    #else
            return _size.width * 4; // TODO: do more with this on the non-texture-cache side
    #endif
        }
        else
        {
            return _size.width * 4;
        }
    }
    
    - (GLubyte *)byteBuffer;
    {
    #if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
        [self lockForReading];
        GLubyte * bufferBytes = CVPixelBufferGetBaseAddress(renderTarget);
        [self unlockAfterReading];
        return bufferBytes;
    #else
        return NULL; // TODO: do more with this on the non-texture-cache side
    #endif
    }
    
    - (GLuint)texture;
    {
    //    NSLog(@"Accessing texture: %d from FB: %@", _texture, self);
        return _texture;
    }
    
    @end
    View Code

      

  • 相关阅读:
    无题
    一周损兵又折将
    防火墙安装配置(准备)
    徐州项目顺利验收
    悲惨的圣诞节
    [原]防火墙安装配置(日志)
    [转]有关加薪申请资料
    解决FireFox下XML对象转化成字符串
    ASP.NET Application and Page Life Cycle(asp.net生命周期)
    C# 利用反射动态创建对象[转]
  • 原文地址:https://www.cnblogs.com/salam/p/4963641.html
Copyright © 2011-2022 走看看