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

来源:互联网 发布:php服务器绑定域名 编辑:程序博客网 时间:2024/06/06 05:24

现在的图形化处理对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);

        returnNO;

    }

returnYES;

}


static GLuint compileShader(GLenum type,NSString *shaderString)

{

GLint status;

constGLchar *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

{

    returnrgbFragmentShaderString;

}


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

        returnNO;

    

    glActiveTexture(GL_TEXTURE0);

    glBindTexture(GL_TEXTURE_2D,_texture);

    glUniform1i(_uniformSampler, 0);

    

    returnYES;

}


- (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 [CAEAGLLayerclass];

}


- (void)layoutSubviews

{

    [superlayoutSubviews];

}


- (instancetype) initWithFrame:(CGRect)frame

{

    self = [superinitWithFrame:frame];

    if (self) {

        self.contentScaleFactor = 2.0;

        

        _renderer = [[KxMovieGLRenderer_RGBalloc] init];

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

        

        eaglLayer = (CAEAGLLayer*)self.layer;

        eaglLayer.opaque =YES;

        eaglLayer.drawableProperties = [NSDictionarydictionaryWithObjectsAndKeys:

                                        [NSNumbernumberWithBool:FALSE],kEAGLDrawablePropertyRetainedBacking,

                                        kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat,

                                        nil];

        

        _context = [[EAGLContextalloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

        

        if (!_context ||

            ![EAGLContextsetCurrentContext:_context]) {

            

            NSLog(@"failed to setup EAGLContext");            

            self =nil;

            returnnil;

        }

        

        glGenFramebuffers(1, &_framebuffer);

        glGenRenderbuffers(1, &_renderbuffer);

        glBindFramebuffer(GL_FRAMEBUFFER,_framebuffer);

        glBindRenderbuffer(GL_RENDERBUFFER,_renderbuffer);

        [_contextrenderbufferStorage:GL_RENDERBUFFERfromDrawable:(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;

            returnnil;

        }

        

        GLenum glError =glGetError();

        if (GL_NO_ERROR != glError) {

            

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

            self =nil;

            returnnil;

        }

                

        if (![selfloadShaders]) {

            

            self =nil;

            returnnil;

        }

        

        _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 = [[NSLockalloc] init];

        

        [selfclear];

    }

    

    returnself;

}



- (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 ([EAGLContextcurrentContext] == _context) {

        [EAGLContextsetCurrentContext: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 ([EAGLContextcurrentContext] == _context) {

[EAGLContextsetCurrentContext:nil];

}

    

_context =nil;

}


- (void)setContentMode:(UIViewContentMode)contentMode

{

    [synlocklock];

    [supersetContentMode:contentMode];

    [synlockunlock];

    

    if (_renderer.isValid) {

        [selfclear];

    }

}


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

    [_rendererresolveUniforms:_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 (![synlocktryLock])

        return;

        

    staticconst GLfloat texCoords[] = {

        0.0f, 1.0f,

        1.0f, 1.0f,

        0.0f, 0.0f,

        1.0f, 0.0f,

    };

    [EAGLContextsetCurrentContext:_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) {

        [_renderersetFrame:rgb :rgbSize :width :height];        


        if ([_rendererprepareRender]) {

            

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

    [_contextpresentRenderbuffer:GL_RENDERBUFFER];

    [synlockunlock];

}


- (void)clear

{

    [synlocklock];

    

    [EAGLContextsetCurrentContext:_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);

    [_contextpresentRenderbuffer:GL_RENDERBUFFER];

    

    [synlockunlock];

}


@end

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

原创粉丝点击