分享一个利用OpenGl处理图像的H264与H265播放器

现在的图形化处理对OpenGL的运用越来越多,除了系统的播放控件可以进行视频的播放以外,还可以使用openGL来进行视频的播放,以下是一个简易的H264与H265的播发器分享给大家

-------------------------------------------------------------------------------------------------------

#import <UIKit/UIKit.h>


@interface vsGLView : UIView


- (instancetype) initWithFrame:(CGRect)frame;


// 更新图像(rgb24)

-(void)updateImage:(void*)rgb :(UInt32)rgbSize :(UInt32)width :(UInt32)height;


//清除残余图像

- (void) clear;



@end


----------------------------------------------------------

#import "vsGLView.h"

#import <QuartzCore/QuartzCore.h>

#import <OpenGLES/EAGLDrawable.h>

#import <OpenGLES/EAGL.h>

#import <OpenGLES/ES2/gl.h>

#import <OpenGLES/ES2/glext.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);

    

#ifdef DEBUG

    GLint logLength;

    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);

    if (logLength > 0)

    {

        GLchar *log = (GLchar *)malloc(logLength);

        glGetProgramInfoLog(prog, logLength, &logLength, log);

        NSLog(@"Program validate log:\n%s", log);

        free(log);

    }

#endif

    

    glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);

    if (status == GL_FALSE) {

NSLog(@"Failed to validate program %d", 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) {

        NSLog(@"Failed to create shader %d", type);

        return 0;

    }

    

    glShaderSource(shader, 1, &sources, NULL);

    glCompileShader(shader);

#ifdef DEBUG

GLint logLength;

    glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);

    if (logLength > 0)

    {

        GLchar *log = (GLchar *)malloc(logLength);

        glGetShaderInfoLog(shader, logLength, &logLength, log);

        NSLog(@"Shader compile log:\n%s", log);

        free(log);

    }

#endif

    

    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);

    if (status == GL_FALSE) {

        glDeleteShader(shader);

NSLog(@"Failed to compile shader:\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


@protocol KxMovieGLRenderer

- (BOOL) isValid;

- (NSString *) fragmentShader;

- (void) resolveUniforms: (GLuint) program;

- (void) setFrame: (void*)rgb :(UInt32)rgbSize :(UInt32)width :(UInt32)height;

- (BOOL) prepareRender;

@end


@interface KxMovieGLRenderer_RGB : NSObject<KxMovieGLRenderer> {

    

    GLint _uniformSampler;

    GLuint _texture;

}

@end


@implementation KxMovieGLRenderer_RGB


- (BOOL) isValid

{

    return (_texture != 0);

}


- (NSString *) fragmentShader

{

    return rgbFragmentShaderString;

}


- (void) resolveUniforms: (GLuint) program

{

    _uniformSampler = glGetUniformLocation(program, "s_texture");

}


- (void) setFrame: (void*)rgb :(UInt32)rgbSize :(UInt32)width :(UInt32)height;

{

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    

    if (0 == _texture)

        glGenTextures(1, &_texture);

    

    glBindTexture(GL_TEXTURE_2D, _texture);    

    glTexImage2D(GL_TEXTURE_2D,

                 0,

                 GL_RGBA,

                 width,

                 height,

                 0,

                 GL_RGBA,

                 GL_UNSIGNED_BYTE,

                 rgb);

    

    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 (_texture == 0)

        return NO;

    

    glActiveTexture(GL_TEXTURE0);

    glBindTexture(GL_TEXTURE_2D, _texture);

    glUniform1i(_uniformSampler, 0);

    

    return YES;

}


- (void) dealloc

{

    if (_texture) {

        glDeleteTextures(1, &_texture);

        _texture = 0;

    }

}


@end



//


#pragma mark - gl view


enum {

ATTRIBUTE_VERTEX,

   ATTRIBUTE_TEXCOORD,

};


@implementation vsGLView {    

    CAEAGLLayer     *eaglLayer;

    EAGLContext     *_context;

    GLuint          _framebuffer;

    GLuint          _renderbuffer;

    GLint           _frameWidth;

    GLint           _frameHeight;

    GLint           _backingWidth;

    GLint           _backingHeight;

    GLuint          _program;

    GLint           _uniformMatrix;

    GLfloat         _vertices[8];

    NSLock          *synlock;

    

    id<KxMovieGLRenderer> _renderer;

}


+ (Class) layerClass

{

return [CAEAGLLayer class];

}


- (void)layoutSubviews

{

    [super layoutSubviews];

}


- (instancetype) initWithFrame:(CGRect)frame

{

    self = [super initWithFrame:frame];

    if (self) {

        self.contentScaleFactor = 2.0;

        

        _renderer = [[KxMovieGLRenderer_RGB alloc] init];

//        NSLog(@"OK use RGB GL renderer");

        

        eaglLayer = (CAEAGLLayer*) self.layer;

        eaglLayer.opaque = YES;

        eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:

                                        [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking,

                                        kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,

                                        nil];

        

        _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

        

        if (!_context ||

            ![EAGLContext setCurrentContext:_context]) {

            

            NSLog(@"failed to setup EAGLContext");            

            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) {

            

            NSLog(@"failed to make complete framebuffer object %x", status);

            self = nil;

            return nil;

        }

        

        GLenum glError = glGetError();

        if (GL_NO_ERROR != glError) {

            

            NSLog(@"failed to setup GL %x", glError);

            self = nil;

            return nil;

        }

                

        if (![self loadShaders]) {

            

            self = nil;

            return nil;

        }

        

        _vertices[0] = -1.0f;  // x0

        _vertices[1] = -1.0f;  // y0

        _vertices[2] =  1.0f;  // ..

        _vertices[3] = -1.0f;

        _vertices[4] = -1.0f;

        _vertices[5] =  1.0f;

        _vertices[6] =  1.0f;  // x3

        _vertices[7] =  1.0f;  // y3

        

//        NSLog(@"OK setup GL");

        

        synlock = [[NSLock alloc] init];

        

        [self clear];

    }

    

    return self;

}



- (void)disMiss

{

    _renderer = nil;

    synlock = 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)dealloc

{

    _renderer = nil;

    synlock   = 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)setContentMode:(UIViewContentMode)contentMode

{

    [synlock lock];

    [super setContentMode:contentMode];

    [synlock unlock];

    

    if (_renderer.isValid) {

        [self clear];

    }

}


- (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) {

NSLog(@"Failed to link program %d", _program);

        goto exit;

    }

    

    result = validateProgram(_program);

        

    _uniformMatrix = glGetUniformLocation(_program, "modelViewProjectionMatrix");

    [_renderer resolveUniforms:_program];

exit:

    

    if (vertShader)

        glDeleteShader(vertShader);

    if (fragShader)

        glDeleteShader(fragShader);

    

    if (result) {

        

//        NSLog(@"OK setup GL programm");

        

    } else {

        

        glDeleteProgram(_program);

        _program = 0;

    }

    

    return result;

}


// 更新图像(rgb24)

-(void)updateImage:(void*)rgb :(UInt32)rgbSize :(UInt32)width :(UInt32)height

{

    if (![synlock tryLock])

        return;

        

    static const GLfloat texCoords[] = {

        0.0f, 1.0f,

        1.0f, 1.0f,

        0.0f, 0.0f,

        1.0f, 0.0f,

    };

    [EAGLContext setCurrentContext:_context];

    

    glUseProgram(_program);


    glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);

    glViewport(0, 0, _backingWidth, _backingHeight);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    

    if (rgb) {

        [_renderer setFrame:rgb :rgbSize :width :height];        


        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);

            

        #if 0

            if (!validateProgram(_program))

            {

                NSLog(@"Failed to validate program");

                [synlock unlock];

                return;

            }

        #endif

            

            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);        

        }

    }

    glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);

    [_context presentRenderbuffer:GL_RENDERBUFFER];

    [synlock unlock];

}


- (void)clear

{

    [synlock lock];

    

    [EAGLContext setCurrentContext:_context];

    glUseProgram(_program);


    glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);

    glViewport(0, 0, _backingWidth, _backingHeight);

    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);

    [_context presentRenderbuffer:GL_RENDERBUFFER];

    

    [synlock unlock];

}


@end

--------------------------------------------------------------------------------------------------------------------------
熟悉GLKViewController使用的同学都知道,controller类自带一个udapte函数,因此该播放器需要手动调用udate方法,读取视频的buffer,进行图像的更新
更多OpenGl的知识可以参考OpenGl开发指南

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值