OpenGL渲染(YUV数据格式)

//GLRender.h
#ifndef __GLRENDER_H_
#define __GLRENDER_H_

#include "YUVData.h"
#include "SNMutex.h"

#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
#import <QuartzCore/CAMediaTiming.h>
#import <QuartzCore/CATransform3D.h>
#import <Foundation/NSObject.h>

typedef  GLint EGLint;

class GLRender
{
    typedef enum 
    {
        VERTICAL = 0,
        HORIZONTAL
    }ORIENT_T;

public:
	GLRender();
	~GLRender();

public:
	int nativeGLRender(PYUVData &yuvdata);
	void nativeGLRender(char *pFrame);
	int digitalRegionZoom(int bootom_x , int bootom_y, int top_x, int top_y);
	int close();
	bool setGLSurface(const int p_nWidth, const int p_nHeight, CAEAGLLayer *layer);

private:
	void render(const void *data);
	void render(PYUVData &yuvdata);
	void configGL();
	GLuint loadShader(GLenum shaderType, const char* pSource); 
	GLuint createProgram(const char* pVertexSource, const char* pFragmentSource);
	bool setupGraphics(EGLint w, EGLint h) ;
	void setTexture(GLuint texture);
    
    void setupBuffers();
    void createBuffers();
    void releaseBuffers();

private:
	SNMutex  m_SNMutex;
	int mWidth, mGLSurfaceWidth;
	int mHeight, mGLSurfaceHeight;
	bool surface_ok;
	ORIENT_T mOrient;
	GLfloat *mSquareVertices;
    
private:
	EAGLContext *mContext;
	GLuint  mViewRenderbuffer;
	GLuint  mViewFramebuffer;
	CAEAGLLayer  *mSurface;
	GLuint  mGlProgram; 

	GLuint m_texturePlanarY;
	GLuint m_texturePlanarU;
	GLuint m_texturePlanarV;

	GLint  mPositionLoc;
	GLint  mTexCoordLoc;

	GLint  mSamplerY;
	GLint  mSamplerU;
	GLint  mSamplerV;
    
    int mCurrentLayerWidth;
    int mCurrentLayerHeight;
};

#endif


//GLRender.cpp
#include "GLRender.h"

#define   LOGI  printf("GLRender: "); printf
#define   LOGE  printf("GLRender: "); printf
#define   eglGetError glGetError

#import "ScreenParam.h"
#import <OpenGLES/EAGLDrawable.h>
#import <QuartzCore/QuartzCore.h>

typedef   GLint  EGLint;
#define   EGL_SUCCESS GL_NO_ERROR

const int VERTEX_STRIDE = 6 * sizeof(GLfloat);

const GLfloat squareVertices[] = {
    1.0f, -1.0f, 0.0f, 1.0f,    // Position 0
    1.0f, 1.0f,                 // TexCoord 0
    1.0f, 1.f, 0.0f, 1.0f,      // Position 1
    1.0f,  0.0f,                // TexCoord 1
    -1.0f, -1.0f, 0.0f, 1.0f,   // Position 2
    0.0f,  1.0f,                // TexCoord 2
    -1.0f,  1.f, 0.0f, 1.0f,    // Position 3
    0.0f,  0.0f,                // TexCoord 3
};

//Vertext shader language
static const char gVertexShader[] =
"attribute vec4 a_Position;\n"
"attribute vec2 a_texCoord;\n"
"varying vec2 v_texCoord;\n"
"void main() {\n"
"  gl_Position = a_Position;\n"
"  v_texCoord = a_texCoord;\n"
"}\n";

//Fragment shader language
static const char gFragmentShader[] =
"varying lowp vec2 v_texCoord;\n"     
"uniform sampler2D SamplerY;\n"  
"uniform sampler2D SamplerU;\n"  
"uniform sampler2D SamplerV;\n"  
"void main(void)\n"  
"{\n"  
"mediump vec3 yuv;\n"  
"lowp vec3 rgb;\n"  
"yuv.x = texture2D(SamplerY, v_texCoord).r;\n"  
"yuv.y = texture2D(SamplerU, v_texCoord).r - 0.5;\n"  
"yuv.z = texture2D(SamplerV, v_texCoord).r - 0.5;\n"  
"rgb = mat3( 1,   1,   1,\n"  
"0,       -0.39465,  2.03211,\n"  
"1.13983,   -0.58060,  0) * yuv;\n"  
"gl_FragColor = vec4(rgb, 1);\n"  
"}\n";  

GLRender::GLRender()
:surface_ok(false)
,mContext(NULL)
,mOrient(VERTICAL)
,mViewRenderbuffer(NULL)
,mViewFramebuffer(NULL)
{
    mSquareVertices = (GLfloat *)malloc(sizeof(squareVertices));
    memcpy(mSquareVertices,squareVertices,sizeof(squareVertices));
}

GLRender::~GLRender()
{
    this->releaseBuffers();
    free(mSquareVertices);
}

int GLRender::close()
{
    LOCK_SNMUTEX(m_SNMutex);
    if (surface_ok)
    {
        if (mContext)
        {
            glClearColor(0, 0, 0, 0);
            glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
            [mContext  presentRenderbuffer:GL_RENDERBUFFER];
            
            [EAGLContext setCurrentContext:mContext];
            this->releaseBuffers();
            [EAGLContext setCurrentContext:nil];

            if (mContext){
                mContext = nil;
            }
        }
        mSurface = NULL;
        surface_ok = false ;
    }
    return 0;
}

GLuint GLRender::loadShader(GLenum shaderType, const char* pSource) {
    GLuint shader = glCreateShader(shaderType);
    if (shader) {
        glShaderSource(shader, 1, &pSource, NULL);
        glCompileShader(shader);
        GLint compiled = 0;
            
        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
        if (!compiled) {
            GLint infoLen = 0;
            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
            
            if (infoLen) {
                char* buf = (char*) malloc(infoLen);
                if (buf != NULL) {
                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
                    LOGE("Could not compile shader %d:\n%s\n", shaderType, buf);
                    free(buf);
                }   
                glDeleteShader(shader);
                shader = 0;
            }   
        }   

    }   
    return shader;
}


GLuint GLRender::createProgram(const char* pVertexSource, const char* pFragmentSource)
{
    GLuint program = glCreateProgram();
    if (program) {
        GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
        if (!vertexShader) {
            return 0;
        }else{
            glAttachShader(program, vertexShader);
        }
        
        GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
        if (!pixelShader) {
            return 0;
        }else{
            glAttachShader(program, pixelShader);
        }
        
        glLinkProgram(program);
        GLint linkStatus = GL_FALSE;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
        
        if (linkStatus != GL_TRUE) {
            GLint bufLength = 0;
            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
            if (bufLength) {
                char* buf = (char*) malloc(bufLength);
                if (buf) {
                    glGetProgramInfoLog(program, bufLength, NULL, buf);
                    LOGE("Could not link program:\n%s\n", buf);
                    free(buf);
                }   
            }   
            glDeleteProgram(program);
            program = 0;
        }   
    }   
    return program;
}

void GLRender::setupBuffers()
{
    glDisable(GL_DEPTH_TEST);
    
    mPositionLoc = glGetAttribLocation(mGlProgram, "a_Position");
    glEnableVertexAttribArray(mPositionLoc);
    glVertexAttribPointer(mPositionLoc, 4, GL_FLOAT,GL_FALSE, VERTEX_STRIDE, mSquareVertices);
    
    mTexCoordLoc = glGetAttribLocation(mGlProgram, "a_texCoord");
    glEnableVertexAttribArray(mTexCoordLoc);
    glVertexAttribPointer(mTexCoordLoc, 2, GL_FLOAT, GL_FALSE, VERTEX_STRIDE, &mSquareVertices[4]);
    
    this->createBuffers();
}

void GLRender::createBuffers()
{
    [EAGLContext setCurrentContext:mContext];
    
    //Create render buffer
    glGenRenderbuffers(1, &mViewRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, mViewRenderbuffer);
    
    //Create frame buffer
    glGenFramebuffers(1, &mViewFramebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, mViewFramebuffer);
    
    //Create viewport
    [mContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:mSurface];
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &mGLSurfaceWidth);
    glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &mGLSurfaceHeight);
    glViewport(0.0, 0.0, mGLSurfaceWidth, mGLSurfaceHeight);
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, mViewRenderbuffer);
    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE){
        NSLog(@"Failure with framebuffer generation");
    }
}

void GLRender::releaseBuffers()
{
    if (mViewFramebuffer){
        glDeleteFramebuffers(1, &mViewFramebuffer);
        mViewFramebuffer = 0;
    }
    
    if (mViewFramebuffer){
        glDeleteRenderbuffers(1, &mViewRenderbuffer);
        mViewRenderbuffer = 0;
    }
}

bool GLRender::setupGraphics(EGLint w, EGLint h)
{
    mGlProgram = createProgram(gVertexShader, gFragmentShader);
    if (!mGlProgram) {
        LOGE("Could not create program.");
        return false;
    }

    // Get sampler location
    mSamplerY = glGetUniformLocation(mGlProgram, "SamplerY");
    mSamplerU = glGetUniformLocation(mGlProgram, "SamplerU");
    mSamplerV = glGetUniformLocation(mGlProgram, "SamplerV");

    glUseProgram(mGlProgram);  
    glGenTextures(1, &m_texturePlanarY);
    glGenTextures(1, &m_texturePlanarU);
    glGenTextures(1, &m_texturePlanarV);

    glActiveTexture(GL_TEXTURE0);
    setTexture(m_texturePlanarY);
    glUniform1i(mSamplerY, 0);

    glActiveTexture(GL_TEXTURE1);
    setTexture(m_texturePlanarU);
    glUniform1i(mSamplerU, 1);

    glActiveTexture(GL_TEXTURE2);
    setTexture(m_texturePlanarV);
    glUniform1i(mSamplerV, 2);

    surface_ok = true;
    return true;
}

void GLRender::nativeGLRender(char *pFrame)
{
    LOCK_SNMUTEX(m_SNMutex);
    this->configGL();
    
    if (surface_ok)
    {
        glViewport(0, 0, mGLSurfaceWidth, mGLSurfaceHeight);

        mPositionLoc  = glGetAttribLocation(mGlProgram, "a_Position");
        mTexCoordLoc     = glGetAttribLocation(mGlProgram, "a_texCoord");

        glEnableVertexAttribArray(mPositionLoc);
        glVertexAttribPointer(mPositionLoc, 4, GL_FLOAT,GL_FALSE, VERTEX_STRIDE, mSquareVertices);
            
        // Load the texture coordinate
        glEnableVertexAttribArray(mTexCoordLoc);
        glVertexAttribPointer(mTexCoordLoc, 2, GL_FLOAT, GL_FALSE, VERTEX_STRIDE, &mSquareVertices[4]);

        glDisable(GL_BLEND);
        glActiveTexture(GL_TEXTURE0);
        setTexture(m_texturePlanarY);
        glUniform1i(mSamplerY, 0);
        
        glActiveTexture(GL_TEXTURE1);
        setTexture(m_texturePlanarU);
        glUniform1i(mSamplerU, 1);
        
        glActiveTexture(GL_TEXTURE2);
        setTexture(m_texturePlanarV);
        glUniform1i(mSamplerV, 2);
        
        render(pFrame);
    }
}
int GLRender::nativeGLRender(PYUVData &yuvdata)
{
    LOCK_SNMUTEX(m_SNMutex);
    if(mCurrentLayerHeight != mSurface.bounds.size.height && mCurrentLayerWidth != mSurface.bounds.size.width){
        mCurrentLayerWidth = mSurface.bounds.size.width;
        mCurrentLayerHeight = mSurface.bounds.size.height;

        if((mCurrentLayerWidth > [ScreenParam screenWidth] - 5 && mCurrentLayerWidth < [ScreenParam screenWidth] + 5)){
               surface_ok = false ;
        }
    }
    this->configGL();

    if (surface_ok){
        
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &mGLSurfaceWidth);
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &mGLSurfaceHeight);
        glBindRenderbuffer(GL_RENDERBUFFER, mViewRenderbuffer);
        
        mPositionLoc = glGetAttribLocation(mGlProgram, "a_Position");
        mTexCoordLoc = glGetAttribLocation(mGlProgram, "a_texCoord");
        
        glVertexAttribPointer(mPositionLoc, 4, GL_FLOAT,GL_FALSE, VERTEX_STRIDE, mSquareVertices);
        glEnableVertexAttribArray(mPositionLoc);
        
        glVertexAttribPointer(mTexCoordLoc, 2, GL_FLOAT, GL_FALSE, VERTEX_STRIDE, &mSquareVertices[4]);
        glEnableVertexAttribArray(mTexCoordLoc);
        
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &mGLSurfaceWidth);
        glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &mGLSurfaceHeight);
        
        glViewport(0, 0, mGLSurfaceWidth, mGLSurfaceHeight);
        render(yuvdata);
    }else{
        LOGE("NativeGLRender error.");
        return -1;
    }
    
    return 0;
}

void GLRender::setTexture(GLuint texture)
{
    glBindTexture ( GL_TEXTURE_2D, texture);
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
}  

void GLRender::render(PYUVData &yuvdata)
{
    const uint8_t *src_y = (uint8_t *)yuvdata->data[0];
    const uint8_t *src_u = (uint8_t *)yuvdata->data[1];
    const uint8_t *src_v = (uint8_t *)yuvdata->data[2];

    glBindRenderbuffer(GL_RENDERBUFFER, mViewRenderbuffer);
    [mContext  presentRenderbuffer:GL_RENDERBUFFER];
    
    glBindTexture ( GL_TEXTURE_2D, m_texturePlanarY);
    glTexImage2D ( GL_TEXTURE_2D, 0, GL_LUMINANCE, mWidth,   mHeight,   0, GL_LUMINANCE, GL_UNSIGNED_BYTE, src_y);
    
    glBindTexture( GL_TEXTURE_2D, m_texturePlanarU );
    glTexImage2D ( GL_TEXTURE_2D, 0, GL_LUMINANCE, mWidth/2, mHeight/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, src_u);
    
    glBindTexture ( GL_TEXTURE_2D,m_texturePlanarV );
    glTexImage2D ( GL_TEXTURE_2D, 0, GL_LUMINANCE, mWidth/2, mHeight/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, src_v);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

void GLRender::render( const void *data)
{
    const uint8_t *src_y = (const uint8_t *)data;
    const uint8_t *src_u = (const uint8_t *)data + mWidth * mHeight;
    const uint8_t *src_v = src_u + (mWidth / 2 * mHeight / 2);

    glBindTexture ( GL_TEXTURE_2D, m_texturePlanarY);
    glTexImage2D ( GL_TEXTURE_2D, 0, GL_LUMINANCE, mWidth,   mHeight,   0, GL_LUMINANCE, GL_UNSIGNED_BYTE, src_y);
    
    glBindTexture( GL_TEXTURE_2D, m_texturePlanarU );
    glTexImage2D ( GL_TEXTURE_2D, 0, GL_LUMINANCE, mWidth/2, mHeight/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, src_u);
    
    glBindTexture ( GL_TEXTURE_2D,m_texturePlanarV );
    glTexImage2D ( GL_TEXTURE_2D, 0, GL_LUMINANCE, mWidth/2, mHeight/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, src_v);
} 

void GLRender::configGL()
{
    if ((mSurface != NULL) && (!surface_ok)){
        if (mContext){
            mContext = nil;
        }
        
        memcpy(mSquareVertices,squareVertices,sizeof(squareVertices));
        if(!mContext){
            mContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
            
            if (!mContext || ![EAGLContext setCurrentContext:mContext]) {
                return;
            }
        }
        
        this->releaseBuffers();
        this->setupBuffers();
        setupGraphics(mGLSurfaceWidth,mGLSurfaceHeight);
    }
}

int GLRender::digitalRegionZoom(int bootom_x , int bootom_y,  int top_x,  int top_y)
{
    #define GET_SCALE(x)	(x/100.00)
    #define CHECK_VALID(x)  (x<0||x>100)
   
    int stride = 6;
    if (CHECK_VALID(bootom_x) || CHECK_VALID(bootom_y) || CHECK_VALID(top_x) || CHECK_VALID(top_y)){
        return -1;
    }

    GLfloat zoom_textures[4][2]={
        static_cast<GLfloat>GET_SCALE(bootom_x),static_cast<GLfloat>(GET_SCALE(bootom_y)),
        static_cast<GLfloat>GET_SCALE( top_x  ),static_cast<GLfloat>GET_SCALE(bootom_y),
        static_cast<GLfloat>GET_SCALE( bootom_x  ), static_cast<GLfloat>GET_SCALE(top_y),
        static_cast<GLfloat>GET_SCALE(top_x), static_cast<GLfloat>GET_SCALE(top_y)
    };

    LOCK_SNMUTEX(m_SNMutex);
    for(int i = 0; i < 4; i++){
    	mSquareVertices[i*stride+4]=  zoom_textures[i][0];
    	mSquareVertices[i*stride+4+1] = zoom_textures[i][1];
    }
    return 0;
}

bool GLRender::setGLSurface(const int p_nWidth, const int p_nHeight, CAEAGLLayer  *layer)
{
    mWidth = p_nWidth;
    mHeight = p_nHeight;
    mSurface = layer;
    
    mCurrentLayerWidth = layer.bounds.size.width;
    mCurrentLayerHeight = layer.bounds.size.height;
    return true;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值