IOS FFmpeg H.264解码

2020-09-04  本文已影响0人  copy_farmer

1.**本地集成FFmpeg **

(引用) iOS集成FFmpeg及视频格式转码

2.pod集成(省事,但是有些参数不能修改)

  pod 'FFmpeg'

3.定义YUV结构体 DecodeH264Data_YUV.h

#ifndef _DECODEH264DATA_YUV_
#define _DECODEH264DATA_YUV_

#pragma pack(push, 1)

typedef struct H264FrameDef
{
    unsigned int    length;
    unsigned char*  dataBuffer;
    
}H264Frame;

typedef struct  H264YUVDef
{
    unsigned int    width;
    unsigned int    height;
    H264Frame       luma;
    H264Frame       chromaB;
    H264Frame       chromaR;
    
}H264YUV_Frame;


#pragma pack(pop)

#endif

4.解码器H264Decoder.h

#import <Foundation/Foundation.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#import "DecodeH264Data_YUV.h"


@protocol H264DecoderDelegate <NSObject>

@optional
- (void)updateDecodedH264FrameData: (H264YUV_Frame*)yuvFrame;
@end

@interface H264Decoder : NSObject
{
    int pictureWidth;
    AVCodec*    pCodec;
    AVCodecContext* pCodecCtx;
    AVFrame*    pVideoFrame;
}

@property (nonatomic, strong) NSData *sps;
@property (nonatomic, strong) NSData *pps;
@property (nonatomic, weak) id<H264DecoderDelegate> delegate;
@property (nonatomic, assign) BOOL hasIFrame;

+ (H264Decoder *)sharedInstance;
- (id)init;
- (void)decodeSpsPps:(NSData *)sps pps:(NSData *)pps;
- (int)decodeH264IFrames:(NSData *)h264Data;
- (int)decodeH264Frames:(NSData *)data;

@end


#import "H264Decoder.h"

typedef enum
{
    NALUTypeSliceNoneIDR = 1,
    NALUTypeSliceIDR = 5,
    NALUTypeSPS = 7,
    NALUTypePPS = 8
} NALUType;

@interface H264Decoder ()
{
    BOOL _needFilter;
}

@end

@implementation H264Decoder

+ (H264Decoder *)sharedInstance {
    static dispatch_once_t once;
    static id instance;
    dispatch_once(&once, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

- (id) init
{
    if(self=[super init])
    {
        _needFilter = NO;
        pCodec      =NULL;
        pCodecCtx   =NULL;
        pVideoFrame =NULL;
        
        pictureWidth = 0;
        
        av_register_all();
     
        pCodec=avcodec_find_decoder(AV_CODEC_ID_H264);
        if(!pCodec)
        {
            printf("Codec not find\n");
        }
        pCodecCtx=avcodec_alloc_context3(pCodec);
        if(!pCodecCtx)
        {
            printf("allocate codec context error\n");
        }
        
        pCodecCtx->flags2 |= CODEC_FLAG2_FAST;
        pCodecCtx->thread_count = 2;
        pCodecCtx->thread_type = FF_THREAD_FRAME;
        pCodecCtx->flags|=CODEC_FLAG_LOW_DELAY;
        
        avcodec_open2(pCodecCtx, pCodec, NULL);
        
        pVideoFrame=av_frame_alloc();
        
    }
    
    return self;
}


-(void)decodeSpsPps:(NSData *)sps pps:(NSData *)pps
{
    self.sps = sps;
    self.pps = pps;
    
    [self decodeSpsPpsData:sps];
    [self decodeSpsPpsData:pps];
}

- (int)getNALUType:(NSData *)NALU
{
    uint8_t * bytes = (uint8_t *) NALU.bytes;
    return bytes[4] & 0x1F;
}

- (int)decodeH264IFrames:(NSData *)h264Data
{
    _needFilter = YES;
    if([h264Data length] < 5)
    {
        return 0;
    }
    int type = [self getNALUType: h264Data];
    if(type == NALUTypeSliceIDR)
    {
        //NSLog(@"decodeH264IFrames");
        return [self decodeH264Frames:h264Data];
    }
    else
    {
        return 0;
    }
    
}


- (int)decodeH264Frames:(NSData *)h264Data
{
    if(_needFilter)
    {
        int type = [self getNALUType: h264Data];
        if(type == NALUTypeSliceIDR)
        {
            _needFilter = NO;
        }
        else
        {
            return 0;
        }
    }
    
    int got_picture = [self decodeH264Data:h264Data];
    

    if((pictureWidth !=0 ) && (pictureWidth!=pCodecCtx->width))
    {
        pictureWidth = pCodecCtx->width;
        return -1;
    }
    //YUV 420 Y U V  -> RGB
    if(got_picture)
    {

        unsigned int lumaLength= (pCodecCtx->height)*(MIN(pVideoFrame->linesize[0], pCodecCtx->width));
        unsigned int chromBLength=((pCodecCtx->height)/2)*(MIN(pVideoFrame->linesize[1], (pCodecCtx->width)/2));
        unsigned int chromRLength=((pCodecCtx->height)/2)*(MIN(pVideoFrame->linesize[2], (pCodecCtx->width)/2));
        
        H264YUV_Frame    yuvFrame;
        memset(&yuvFrame, 0, sizeof(H264YUV_Frame));
        
        yuvFrame.luma.length = lumaLength;
        yuvFrame.chromaB.length = chromBLength;
        yuvFrame.chromaR.length =chromRLength;
        
        yuvFrame.luma.dataBuffer=(unsigned char*)malloc(lumaLength);
        yuvFrame.chromaB.dataBuffer=(unsigned char*)malloc(chromBLength);
        yuvFrame.chromaR.dataBuffer=(unsigned char*)malloc(chromRLength);
        
        copyDecodedFrame(pVideoFrame->data[0],yuvFrame.luma.dataBuffer,pVideoFrame->linesize[0],
                         pCodecCtx->width,pCodecCtx->height);
        copyDecodedFrame(pVideoFrame->data[1], yuvFrame.chromaB.dataBuffer,pVideoFrame->linesize[1],
                         pCodecCtx->width / 2,pCodecCtx->height / 2);
        copyDecodedFrame(pVideoFrame->data[2], yuvFrame.chromaR.dataBuffer,pVideoFrame->linesize[2],
                         pCodecCtx->width / 2,pCodecCtx->height / 2);
        
        yuvFrame.width=pCodecCtx->width;
        yuvFrame.height=pCodecCtx->height;
        __weak __typeof__(self) weakSelf = self;
        dispatch_sync(dispatch_get_main_queue(), ^{
            
            [weakSelf updateYUVFrameOnMainThread:(H264YUV_Frame*)&yuvFrame];
        });
        
        free(yuvFrame.luma.dataBuffer);
        free(yuvFrame.chromaB.dataBuffer);
        free(yuvFrame.chromaR.dataBuffer);
        
    }

    return 0;
}

void copyDecodedFrame(unsigned char *src, unsigned char *dist,int linesize, int width, int height)
{
    width = MIN(linesize, width);
    for (NSUInteger i = 0; i < height; ++i)
    {
        memcpy(dist, src, width);
        dist += width;
        src += linesize;
    }
}

- (void)updateYUVFrameOnMainThread:(H264YUV_Frame*)yuvFrame
{
    if(yuvFrame!=NULL)
    {
        if([self.delegate respondsToSelector:@selector(updateDecodedH264FrameData:)])
        {
            [self.delegate updateDecodedH264FrameData:yuvFrame];
        }
    }
}

-(int)decodeSpsPpsData:(NSData *)data
{
    @synchronized (self) {
        uint8_t *ch;
        ch = malloc([data length] + 4);
        ch[0]=0;
        ch[1]=0;
        ch[2]=0;
        ch[3]=1;
        
        memcpy(ch + 4, [data bytes], [data length]);
        
        AVPacket packet;
        av_init_packet(&packet);
        
        packet.data = ch;
        packet.size = (int)[data length] + 4;
        
        int got_picture = 0;
        avcodec_decode_video2(pCodecCtx, pVideoFrame, &got_picture, &packet);
        av_packet_unref(&packet);
        free(ch);
        return got_picture;
    }

}
-(int)decodeH264Data:(NSData *)data
{
    @synchronized (self) {
        uint8_t *ch = (uint8_t *)data.bytes;
        ch[0]=0;
        ch[1]=0;
        ch[2]=0;
        ch[3]=1;
        
        AVPacket packet;
        av_init_packet(&packet);
        
        packet.data = ch;
        packet.size = (int)[data length];
        
        int got_picture = 0;
        avcodec_decode_video2(pCodecCtx, pVideoFrame, &got_picture, &packet);
        av_packet_unref(&packet);
        return got_picture;
    }
    
}

5.YUV播放(OpenGLES)

#import <UIKit/UIKit.h>
#import "DecodeH264Data_YUV.h"


@interface OpenGLGLRenderer_YUV : NSObject
{
    
    GLint _uniformSamplers[3];
    GLuint _textures[3];
}

- (BOOL) isValid;
- (NSString *)fragmentShader;
- (void) resolveUniforms: (GLuint) program;
- (void) setFrame: (H264YUV_Frame *) frame;
- (BOOL) prepareRender;

@end



@interface OpenGLFrameView : UIView
{
    EAGLContext     *_context;
    GLuint          _framebuffer;
    GLuint          _renderbuffer;
    GLint           _backingWidth;
    GLint           _backingHeight;
    GLuint          _program;
    GLint           _uniformMatrix;
    GLfloat         _vertices[8];
    
    CGPoint      begainPoint;
    

    
    OpenGLGLRenderer_YUV* _renderer;
}


- (id)initWithFrame:(CGRect)frame;
- (void)render:(H264YUV_Frame *)frame;
- (UIImage*)snapshotPicture;
@end
#define PT_DELAY 1.5

#import "OpenGLFrameView.h"
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
#import "ZOStatusTool.h"


#pragma mark - shaders

#define STRINGIZE(x) #x
#define STRINGIZE2(x) STRINGIZE(x)
#define SHADER_STRING(text) @ STRINGIZE2(text)

NSString *const vertexShaderString = SHADER_STRING
(
    attribute vec4 position;
    attribute vec2 texcoord;
    uniform mat4 modelViewProjectionMatrix;
    varying vec2 v_texcoord;
 
    void main()
    {
        gl_Position = modelViewProjectionMatrix * position;
        v_texcoord = texcoord.xy;
    }
 
 );

NSString *const rgbFragmentShaderString = SHADER_STRING
(
    varying highp vec2 v_texcoord;
    uniform sampler2D s_texture;
 
    void main()
    {
        gl_FragColor = texture2D(s_texture, v_texcoord);
    }
 
 );

NSString *const yuvFragmentShaderString = SHADER_STRING
(
    varying highp vec2 v_texcoord;
    uniform sampler2D s_texture_y;
    uniform sampler2D s_texture_u;
    uniform sampler2D s_texture_v;
 
    void main()
    {
        highp float y = texture2D(s_texture_y, v_texcoord).r;
        highp float u = texture2D(s_texture_u, v_texcoord).r - 0.5;
        highp float v = texture2D(s_texture_v, v_texcoord).r - 0.5;
     
        highp float r = y + 1.402 * v;
        highp float g = y - 0.344 * u - 0.714 * v;
        highp float b = y + 1.772 * u;
     
        gl_FragColor = vec4(r,g,b,1.0);
    }
 
 );

static BOOL validateProgram(GLuint prog)
{
    GLint status;
    
    glValidateProgram(prog);
    
    
    glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
    if (status == GL_FALSE) {
        printf("Validate program failed %d\n", prog);
        return NO;
    }
    
    return YES;
}

static GLuint compileShader(GLenum type, NSString *shaderString)
{
    GLint status;
    const GLchar *sources = (GLchar *)shaderString.UTF8String;
    
    GLuint shader = glCreateShader(type);
    if (shader == 0 || shader == GL_INVALID_ENUM)
    {
        printf("Create shader failed%d\n", type);
        return 0;
    }
    
    glShaderSource(shader, 1, &sources, NULL);
    glCompileShader(shader);
    

    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
    if (status == GL_FALSE)
    {
        glDeleteShader(shader);
        printf("Compile shader failed\n");
        return 0;
    }
    
    return shader;
}

static void mat4f_LoadOrtho(float left, float right, float bottom, float top, float near, float far, float* mout)
{
    float r_l = right - left;
    float t_b = top - bottom;
    float f_n = far - near;
    float tx = - (right + left) / (right - left);
    float ty = - (top + bottom) / (top - bottom);
    float tz = - (far + near) / (far - near);
    
    mout[0] = 2.0f / r_l;
    mout[1] = 0.0f;
    mout[2] = 0.0f;
    mout[3] = 0.0f;
    
    mout[4] = 0.0f;
    mout[5] = 2.0f / t_b;
    mout[6] = 0.0f;
    mout[7] = 0.0f;
    
    mout[8] = 0.0f;
    mout[9] = 0.0f;
    mout[10] = -2.0f / f_n;
    mout[11] = 0.0f;
    
    mout[12] = tx;
    mout[13] = ty;
    mout[14] = tz;
    mout[15] = 1.0f;
}


#pragma mark - frame renderers



@implementation OpenGLGLRenderer_YUV

- (BOOL) isValid
{
    return (_textures[0] != 0);
}

- (NSString *) fragmentShader
{
    return yuvFragmentShaderString;
}

- (void) resolveUniforms: (GLuint) program
{
    _uniformSamplers[0] = glGetUniformLocation(program, "s_texture_y");
    _uniformSamplers[1] = glGetUniformLocation(program, "s_texture_u");
    _uniformSamplers[2] = glGetUniformLocation(program, "s_texture_v");
}

- (void) setFrame: (H264YUV_Frame *)frame
{
    H264YUV_Frame *yuvFrame = (H264YUV_Frame *)frame;
    
    
    assert(yuvFrame->luma.length == yuvFrame->width * yuvFrame->height);
    assert(yuvFrame->chromaB.length == (yuvFrame->width * yuvFrame->height) / 4);
    assert(yuvFrame->chromaR.length == (yuvFrame->width * yuvFrame->height) / 4);
    
    
    const NSUInteger frameWidth = yuvFrame->width;
    const NSUInteger frameHeight = yuvFrame->height;
    
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    
    if (0 == _textures[0])
    {
        glGenTextures(3, _textures);
    }
    
    const UInt8 *pixels[3] = {(UInt8 *)yuvFrame->luma.dataBuffer, (UInt8 *)yuvFrame->chromaB.dataBuffer, (UInt8 *)yuvFrame->chromaR.dataBuffer};
    
    const NSUInteger widths[3]  = { frameWidth, frameWidth / 2, frameWidth / 2 };
    const NSUInteger heights[3] = { frameHeight, frameHeight / 2, frameHeight / 2 };
    
    for (int i = 0; i < 3; ++i)
    {
        
        glBindTexture(GL_TEXTURE_2D, _textures[i]);
        
        glTexImage2D(GL_TEXTURE_2D,
                     0,
                     GL_LUMINANCE,
                     (int)widths[i],
                     (int)heights[i],
                     0,
                     GL_LUMINANCE,
                     GL_UNSIGNED_BYTE,
                     pixels[i]);
        
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    }
}

- (BOOL) prepareRender
{
    if (_textures[0] == 0)
        return NO;
    
    for (int i = 0; i < 3; ++i) {
        glActiveTexture(GL_TEXTURE0 + i);
        glBindTexture(GL_TEXTURE_2D, _textures[i]);
        glUniform1i(_uniformSamplers[i], i);
    }
    
    return YES;
}

- (void)dealloc
{
    //printf("----------------Release openGL ES Rennder--------------------->>>>>>\n");
    if (_textures[0])
    {
        glDeleteTextures(3, _textures);
    }
}


@end

#pragma mark - gl view

enum {
    ATTRIBUTE_VERTEX,
    ATTRIBUTE_TEXCOORD,
};

@implementation OpenGLFrameView

+ (Class) layerClass
{
    return [CAEAGLLayer class];
}

- (id) initWithFrame:(CGRect)frame
{

    if (self= [super initWithFrame:frame])
    {
        
        _renderer = [[OpenGLGLRenderer_YUV alloc] init];
        
        self.contentScaleFactor = [[UIScreen mainScreen] scale];
        CAEAGLLayer *eaglLayer = (CAEAGLLayer*) self.layer;
        eaglLayer.opaque = YES;
        eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
                                        [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking,
                                        kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
                                        nil];
        
        _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
        
        if (!_context ||
            ![EAGLContext setCurrentContext:_context])
        {
            
            printf("Setup EAGLContext failed \n");
            self = nil;
            return nil;
        }
        
        glGenFramebuffers(1, &_framebuffer);
        glGenRenderbuffers(1, &_renderbuffer);
        glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);
        glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);
        [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderbuffer);
        
        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        if (status != GL_FRAMEBUFFER_COMPLETE)
        {
            
            printf(" Make complete framebuffer object failed %x\n", status);
            self = nil;
            return nil;
        }
        
        GLenum glError = glGetError();
        if (GL_NO_ERROR != glError)
        {
            
            printf("failed to setup GL %x\n", glError);
            self = nil;
            return nil;
        }
        
        if (![self loadShaders])
        {
            
            self = nil;
            return nil;
        }
        
        _vertices[0] = -1.0f;
        _vertices[1] = -1.0f;
        _vertices[2] =  1.0f;
        _vertices[3] = -1.0f;
        _vertices[4] = -1.0f;
        _vertices[5] =  1.0f;
        _vertices[6] =  1.0f;
        _vertices[7] =  1.0f;
        
        //printf("setup OpenGL ES success\n");
    }

    return self;
}

- (void)dealloc
{
    //printf("----------------Release openGL ES --------------------->>>>>>\n");
    if(_renderer!=nil)
    {
        _renderer= nil;
    }
    if (_framebuffer) {
        glDeleteFramebuffers(1, &_framebuffer);
        _framebuffer = 0;
    }
    
    if (_renderbuffer) {
        glDeleteRenderbuffers(1, &_renderbuffer);
        _renderbuffer = 0;
    }
    
    if (_program) {
        glDeleteProgram(_program);
        _program = 0;
    }
    
    if ([EAGLContext currentContext] == _context) {
        [EAGLContext setCurrentContext:nil];
        _context = nil;
    }
    
}


- (void)layoutSubviews
{
    glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);
    [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer];
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
    
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE)
    {
        
       //printf("Make complete framebuffer object failed %x\n", status);
        
    }
    else
    {
        
       //printf("Setup GL framebuffer success %d:%d\n", _backingWidth, _backingHeight);
    }
    
    [self updateVertices];
    [self render: nil];
}

- (void)setContentMode:(UIViewContentMode)contentMode
{
    [super setContentMode:contentMode];
    [self updateVertices];
    if (_renderer.isValid){
        [self render:nil];
    }
}

- (BOOL)loadShaders
{
    BOOL result = NO;
    GLuint vertShader = 0, fragShader = 0;
    
    _program = glCreateProgram();
    
    vertShader = compileShader(GL_VERTEX_SHADER, vertexShaderString);
    if (!vertShader)
        goto exit;
    
    fragShader = compileShader(GL_FRAGMENT_SHADER,  _renderer.fragmentShader);
    if (!fragShader)
        goto exit;
    
    glAttachShader(_program, vertShader);
    glAttachShader(_program, fragShader);
    glBindAttribLocation(_program, ATTRIBUTE_VERTEX, "position");
    glBindAttribLocation(_program, ATTRIBUTE_TEXCOORD, "texcoord");
    
    glLinkProgram(_program);
    
    GLint status;
    glGetProgramiv(_program, GL_LINK_STATUS, &status);
    if (status == GL_FALSE) {
        printf("Link program failed %d\n", _program);
        goto exit;
    }
    
    result = validateProgram(_program);
    
    _uniformMatrix = glGetUniformLocation(_program, "modelViewProjectionMatrix");
    [_renderer resolveUniforms:_program];
    
exit:
    
    if (vertShader){
        glDeleteShader(vertShader);
    }
    if (fragShader){
        glDeleteShader(fragShader);
    }
    
    if (result) {
        
        //printf("Setup GL programm ok\n");
        
    } else {
        
        glDeleteProgram(_program);
        _program = 0;
    }
    
    return result;
}


- (void)updateVertices
{
    const BOOL fit      = (self.contentMode == UIViewContentModeScaleAspectFit);
    const float width   = 640;
    const float height  = 360;
    const float dH      = (float)_backingHeight / height;
    const float dW      = (float)_backingWidth    / width;
    const float dd      = fit ? MIN(dH, dW) : MAX(dH, dW);
    const float h       = (height * dd / (float)_backingHeight);
    const float w       = (width  * dd / (float)_backingWidth );
    
    _vertices[0] = - w;
    _vertices[1] = - h;
    _vertices[2] =   w;
    _vertices[3] = - h;
    _vertices[4] = - w;
    _vertices[5] =   h;
    _vertices[6] =   w;
    _vertices[7] =   h;
}

- (void)render: (H264YUV_Frame *)frame
{
    
    static const GLfloat texCoords[] =
    {
        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,
    };
    
    [EAGLContext setCurrentContext:_context];
    
    glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);
    glViewport(0, 0, _backingWidth, _backingHeight);
    
    //glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    
    //glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
    
    
    //glClear(GL_COLOR_BUFFER_BIT);
    
    glUseProgram(_program);
    
    if (frame)
    {
        [_renderer setFrame:frame];
    }
    
    if ([_renderer prepareRender])
    {
        
        GLfloat modelviewProj[16];
        mat4f_LoadOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, modelviewProj);
        glUniformMatrix4fv(_uniformMatrix, 1, GL_FALSE, modelviewProj);
        
        glVertexAttribPointer(ATTRIBUTE_VERTEX, 2, GL_FLOAT, 0, 0, _vertices);
        glEnableVertexAttribArray(ATTRIBUTE_VERTEX);
        glVertexAttribPointer(ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, 0, 0, texCoords);
        glEnableVertexAttribArray(ATTRIBUTE_TEXCOORD);
        
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        
        if ([[ZOStatusTool shareStatusTool] singleShot]) {
            glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
        }
    }
    
    glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);
    [_context presentRenderbuffer:GL_RENDERBUFFER];
}




- (UIImage*)snapshotPicture
{

    glBindRenderbuffer(GL_RENDERBUFFER, _framebuffer);
    
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &_backingWidth);
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &_backingHeight);
    
    NSInteger x = 0, y = 0, width = _backingWidth, height = _backingHeight;
    
    NSInteger dataLength = width * height * 4;
    GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));
    
    
    glPixelStorei(GL_PACK_ALIGNMENT, 4);
    glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
    
    CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    
    CGImageRef iref = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrderDefault,ref, NULL, NO, kCGRenderingIntentDefault);
    
    
    NSInteger widthInPoints, heightInPoints;
    
    if (NULL != UIGraphicsBeginImageContextWithOptions)
    {
        
        CGFloat scale = 1;
        widthInPoints = width / scale;
        heightInPoints = height / scale;
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(widthInPoints, heightInPoints), NO, scale);
    }
    else
    {
        
        widthInPoints = width;
        heightInPoints = height;
        UIGraphicsBeginImageContext(CGSizeMake(widthInPoints, heightInPoints));
        
    }
    CGContextRef cgcontext = UIGraphicsGetCurrentContext();
    
    CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
    CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref);
    
    UIImage *retImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();
    
    free(data);
    CFRelease(ref);
    CFRelease(colorspace);
    CGImageRelease(iref);

    return retImage;
    
}
@end
上一篇下一篇

猜你喜欢

热点阅读