音视频学习四: Opengl ES Shader讲解

  • Shader

           音视频学习四: Opengl ES Shader讲解_第1张图片

生成测试yuv数据和pcm数据命令:

ffmpeg -i test.mp4 -f si6le test.pcm
ffmpeg -i 720.mp4 -pix_fmt yuv20p -s 424x240 out.yuv

具体显示yuv数据 --- 着色器语言 GLSL (运行在显卡上,不消耗cpu)

-GLSL的基本语法与C语言基本相同

-它完美支持向量和矩阵操作

-GLSL提供了大量的内置函数来提供丰富的扩展功能

-它是通过限定符操作来管理输入输出类型的

①顶点着色器:顶点着色器被使用在传统的基于顶点的操作,例如位移矩阵、计算光照方程、产生贴图坐标。顶点着色器被应用指定,应用于客户的顶点转化是针对每个顶点执行一次,用于确定顶点位置

作用:顶点坐标输出成材质坐标

                              音视频学习四: Opengl ES Shader讲解_第2张图片

②片元着色器:在片元着色器阶段只有唯一的varying 输出变量-即内建变量:gl_FragColo

是针对每个片元(可以理解为每个像素)执行一次,用于确定每个片元(像素)的颜色

作用:输出像素格式

 

                                                   音视频学习四: Opengl ES Shader讲解_第3张图片

  • 顶点信息
float *vertexData = new float[12]{
    1.0f, -1.0f, 0.0f,
    -1.0f, -1.0f, 0.0f,
    1.0f, 1.0f, 0.0f,
    -1.0f, 1.0f, 0.0f};

 

              音视频学习四: Opengl ES Shader讲解_第4张图片

// 顶点着色器 glsl代码
static const char *vertexShader = GET_STR(
        attribute
        vec4 aPosition; //顶点坐标
        attribute
        vec2 aTexCoord; //材质顶点坐标
        varying
        vec2 vTexCoord;   //输出的材质坐标
        void main() {
            vTexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
            gl_Position = aPosition;
        }
);
  • 材质坐标
float *textureVertexData = new float[8]{
 1.0f, 0.0f,//右下
 0.0f, 0.0f,//左下
 1.0f, 1.0f,//右上
 0.0f, 1.0f//左上
};

               音视频学习四: Opengl ES Shader讲解_第5张图片

//yuv420p 片元着色器,软解码和部分x86硬解码
static const char *fragYUV_420P= GET_STR(
        precision
        mediump float;    //精度
        varying
        vec2 vTexCoord;     //顶点着色器传递的坐标
        uniform
        sampler2D yTexture; //输入的材质(不透明灰度,单像素)
        uniform
        sampler2D uTexture;
        uniform
        sampler2D vTexture;
        void main() {
            vec3 yuv;
            vec3 rgb;
            yuv.r = texture2D(yTexture, vTexCoord).r;
            yuv.g = texture2D(uTexture, vTexCoord).r - 0.5;
            yuv.b = texture2D(vTexture, vTexCoord).r - 0.5;
            rgb = mat3(1.0, 1.0, 1.0,
                       0.0, -0.39465, 2.03211,
                       1.13983, -0.58060, 0.0) * yuv;
            //输出像素颜色
            gl_FragColor = vec4(rgb, 1.0);
        }
);
//NV12 片元着色器 glsl代码
static const char *fragNV12 = GET_STR(
        precision
        mediump float;    //精度
        varying
        vec2 vTexCoord;     //顶点着色器传递的坐标
        uniform
        sampler2D yTexture; //输入的材质(不透明灰度,单像素)
        uniform
        sampler2D uvTexture;
        void main() {
            vec3 yuv;
            vec3 rgb;
            yuv.r = texture2D(yTexture, vTexCoord).r;
            yuv.g = texture2D(uvTexture, vTexCoord).r - 0.5;
            yuv.b = texture2D(uvTexture, vTexCoord).a - 0.5;
            rgb = mat3(1.0, 1.0, 1.0,
                       0.0, -0.39465, 2.03211,
                       1.13983, -0.58060, 0.0) * yuv;
            //输出像素颜色
            gl_FragColor = vec4(rgb, 1.0);
        }
);
  • yuv转rgb
// 方法一:使用转换公式
R = Y + 1.402 (Cr-128)
G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
B = Y + 1.772 (Cb-128)
// 方法二: 使用转换矩阵
(1.0, 1.0,  1.0,
0.0, -0.39465, 2.03211,
1.13983, -0.58060, 0.0)
  • shader初始化代码演示
bool XShader::Init(XShaderType type) {
    XLOGE("Enter XShader::Init()!");
    Close();
    //shader 初始化
    //顶点坐标初始化
    vsh = InitShader(vertexShader, GL_VERTEX_SHADER);
    if (vsh == 0) {
        mux.unlock();
        XLOGE("InitShader GL_VERTEX_SHADER failed!");
        return false;
    }
    XLOGE("@@@@@@@@@@@@@@@@ type: %d", type);
    //片元初始化
    switch (type) {
        case XSHADER_yuv420P: //片元yuv420 shader初始化
            fsh = InitShader(fragYUV_420P, GL_FRAGMENT_SHADER);
            break;
        case XSHADER_NV12:  // NV12
            fsh = InitShader(fragNV12, GL_FRAGMENT_SHADER);
            break;
        case XSHADER_NV21:
            fsh = InitShader(fragNV21, GL_FRAGMENT_SHADER);
            break;
        default:
            mux.unlock();
            XLOGE("XShaderType format is error!");
            break;
    }

    if (fsh == 0) {
        mux.unlock();
        XLOGE("InitShader GL_FRAGMENT_SHADER failed!");
        return false;
    }

    //创建渲染程序
    program = glCreateProgram();
    if (program == 0) {
        mux.unlock();
        XLOGE("===========>>glCreateProgram failed! ");
        return false;
    }
    //渲染程序中加入着色器代码
    glAttachShader(program, vsh);
    glAttachShader(program, fsh);
    //连接程序
    glLinkProgram(program);
    GLint status;
    glGetProgramiv(program, GL_LINK_STATUS, &status);
    if (status != GL_TRUE) {
        mux.unlock();
        XLOGE("=========>> glLinkProgram failed!");
        return false;
    }

    //激活渲染程序
    glUseProgram(program);
    /////////////////////////////////////////////////////
    //加入三维顶点数据 两个三角形组成正方形
    static float ver[] = {
            1.0f, -1.f, 0.0f,
            -1.0f, -1.0f, 0.0f,
            1.0f, 1.0f, 0.0f,
            -1.0f, 1.0f, 0.0f
    };

    GLuint apos = glGetAttribLocation(program, "aPosition");
    glEnableVertexAttribArray(apos);
    //传递值
    glVertexAttribPointer(apos, 3, GL_FLOAT, GL_FALSE, 12, ver);

    //加入材质坐标
    static float txts[] = {
            1.0f, 0.0f,
            0.0f, 0.0f,
            1.0f, 1.0f,
            0.0f, 1.0f
    };

    GLuint atex = glGetAttribLocation(program, "aTexCoord");
    glEnableVertexAttribArray(atex);
    glVertexAttribPointer(atex, 2, GL_FLOAT, GL_FALSE, 8, txts);

    //材质纹理初始化
    //设置纹理层
    glUniform1i(glGetUniformLocation(program, "yTexture"), 0); //纹理层第一层
    switch (type) {
        case XSHADER_yuv420P:
            glUniform1i(glGetUniformLocation(program, "uTexture"), 1); //纹理层第二层
            glUniform1i(glGetUniformLocation(program, "vTexture"), 2); //纹理层第三层
            break;
        case XSHADER_NV12:
        case XSHADER_NV21:
            glUniform1i(glGetUniformLocation(program, "uvTexture"), 1); //纹理层第二层
            break;
    }
    mux.unlock();
    XLOGE("InitShader success!");
    return true;
}

 

//shader 初始化
static GLuint InitShader(const char *code, GLint type) {
    GLuint sh = glCreateShader(type);
    if (sh == 0) {
        XLOGE("====>> InitShader failed! %d", type);
        return 0;
    }
    //加载shader
    glShaderSource(sh,
                   1, //shader 数量
                   &code,//shader代码
            //代码长度
                   0);
    //编译shader
    glCompileShader(sh);

    //获取编译情况
    GLint status;
    glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
    if (status == 0) {
        XLOGE("glGetShaderiv failed!");
        return 0;
    }
    XLOGE("glGetShaderiv succee!");
    return sh;
}
  • 开始绘制 代码演示

    virtual void Draw(unsigned char *data[], int width, int height) {
//        XLOGE("XTexture Draw!");
//        XLOGE("width %d  height %d", width, height);
        mux.lock();
        shader.GetTexture(0, width, height, data[0]);      //y
        if (XSHADER_yuv420P == textureType) {
            shader.GetTexture(1, width / 2, height / 2, data[1]);  //u
            shader.GetTexture(2, width / 2, height / 2, data[2]);  //v
        } else {
            shader.GetTexture(1, width / 2, height / 2, data[1], true); //uv
        }
        shader.Draw();
        if (xegl) {
            xegl->Draw();
        }
        mux.unlock();
    }

 

void XShader::GetTexture(unsigned int index, int width, int height, unsigned char *buf, bool isa) {
//    XLOGE("XShader  width %d  height %d", width, height);
    //默认灰度图GL_LUMINANCE,透明通道GL_LUMINANCE_ALPHA
    unsigned int format = isa ? GL_LUMINANCE_ALPHA : GL_LUMINANCE;
    mux.lock();
    if (texts[index] == 0) {
        glGenTextures(1, &texts[index]);//创建纹理
        //设置纹理属性
        glBindTexture(GL_TEXTURE_2D, texts[index]);
        //缩小过滤器
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        //放大过滤器
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        //设置纹理格式和大小
        glTexImage2D(GL_TEXTURE_2D,
                     0,//细节基本 0默认
                     format,//gpu内部格式,灰度图
                     width, height,//尺寸是2的次方
                     0,//边框
                     format,//数据的像素格式 亮度,灰度图 要与上面一致
                     GL_UNSIGNED_BYTE,//像素的数据类型
                     NULL//纹理的数据
        );
    }
    glActiveTexture(GL_TEXTURE0 + index);//激活第index层纹理
    glBindTexture(GL_TEXTURE_2D, texts[index]);//绑定到创建的opengl纹理
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, GL_UNSIGNED_BYTE,
                    buf);//替换纹理内容
    mux.unlock();
}

void XShader::Draw() {
//    XLOGE("XShader Draw!");dra
    mux.lock();
    if (program == 0) {
        mux.unlock();
        XLOGE("Program is NUll when call Draw of Xshader!");
        return;
    }
    //三维绘制
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    mux.unlock();
}

 

 

 

 

 

 

你可能感兴趣的:(android,音视频)