OpenGL/OpenGL ES入门:渲染YUV数据实践

纹理:GPU中的一块数据结构,YUV数据先经过采样,转成rgb显示。

着色器代码,先通过compile编译成GPU能识别的机器语言,再交由GPU进行显示。

shader着色器,texture纹理,Utility通用工具,context,surface,

vertex shader顶点着色器,fragment shader片元着色器,

实践

1.yuv的字节数

现有宽为w高为h的一个视频,现在定义了一个data[] bytes变量并存储了这个视频的一帧数据。

  • bytes数组中,先连续存储每个像素的灰度信息,y通道占w*h个字节;
  • 然后顺序存储颜色数据,u和v分别占一个字节,每个颜色数据共占2个字节,所以uv通道占(w/2)(h/2)2=w*h/2个字。

2.纹理

2.1 纹理的组成

  • y通道的数据生成一个opengl纹理;
  • uv通道的数据生成一个opengl纹理;
  • 两个纹理作为渲染时的输入,在渲染过程中由GPU组装还原出来视频画面

yv12是三个纹理是y一个,u一个,v一个;nv12是y一个,uv一个。

2.2 纹理格式

 GL_LUMINANCE 和 GL_LUMINANCE_ALPHA 格式的纹理。

  • GL_LUMINANCE 纹理用来加载 NV21 Y Plane 的数据;
  • GL_LUMINANCE_ALPHA 纹理用来加载 UV Plane 的数据。
基本内部格式 所提取的颜色
GL_ALPHA (0,0,0,A)
GL_LUMINANCE (L,L,L,1)--->亮度
GL_LUMINANCE_ALPHA (L,L,L,A)--->透明度
GL_INTENSITY (I,I,I,I)
GL_RGB (R,G,B,1)
GL_RGBA (R,G,B,A)

3. YUV渲染步骤

  • 第一步:初始化上下文
  • 第二步:初始化着色器程序(编译链接着色器程序,生成2个纹理-->确定纹理坐标及对应的顶点坐标-->加载纹理坐标和顶点坐标数据到着色器程序);
  • 第三步:初始化buffer;
  • 第四步:初始化纹理(分别加载NV21的两个Plane数据到2个纹理);
  • 第五步:绘制。

4.代码案例

在OpenGL中,片元着色器最后输出的都是rgba的数据,所以使用OpenGL来渲染YUV数据的关键还是将YUV数据传递给着色器,并在着色器中将YUV转化为RGB。

OpenGL ES 系列教程_hongge372的博客-CSDN博客_opengles教程

第一步:初始化上下文

void initContextGL(const char* hWindow)
{
    // double dpr = emscripten_get_device_pixel_ratio();
    // emscripten_set_element_css_size(hWindow, nWmdWidth / dpr, nWndHeight / dpr);
    // emscripten_set_canvas_element_size(hWindow, nWmdWidth, nWndHeight);
    // printf("create size success\n");
    EmscriptenWebGLContextAttributes attrs;
    emscripten_webgl_init_context_attributes(&attrs);
    attrs.alpha = 0;
#if MAX_WEBGL_VERSION >= 2
    attrs.majorVersion = 2;
#endif
    EMSCRIPTEN_WEBGL_CONTEXT_HANDLE glContext = emscripten_webgl_create_context(hWindow, &attrs);
    assert(glContext);
    EMSCRIPTEN_RESULT res=emscripten_webgl_make_context_current(glContext);
    assert(res == EMSCRIPTEN_RESULT_SUCCESS);
    assert(emscripten_webgl_get_current_context() == glContext);
    printf("create context success 1730\n");
}

第二步:初始化着色器程序

/*顶点着色器代码*/
static const char g_pGLVS[] =              ///<普通纹理渲染顶点着色器
{
    "precision mediump float;"
    "attribute vec4 position; "
    "attribute vec4 texCoord; "
    "varying vec4 pp; "

    "void main() "
    "{ "
    "    gl_Position = position; "
    "    pp = texCoord; "
    "} "
};

/*像素着色器代码*/
const char* g_pGLFS =              ///<YV12片段着色器
{
    "precision mediump float;"
    "varying 
  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
OpenGL ES中将YUV数据转换为RGB格式需要进行以下步骤: 1. 创建一个纹理对象,用于存储转换后的RGB数据。 2. 将YUV数据绑定到一个纹理单元上。 3. 创建一个着色器程序,用于将YUV数据转换为RGB格式。 4. 将纹理对象绑定到FBO(Frame Buffer Object),并将着色器程序与FBO绑定。 5. 渲染FBO以将YUV数据转换为RGB格式。 下面是一个简单的代码示例: 1. 创建纹理对象 ``` GLuint textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 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); ``` 2. 绑定YUV数据到纹理单元 ``` glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, yData); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width / 2, height / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, uvData); ``` 3. 创建着色器程序 ``` const char* vertexShader = "attribute vec4 position;\n" "attribute vec2 texCoord;\n" "varying vec2 v_texCoord;\n" "void main()\n" "{\n" " gl_Position = position;\n" " v_texCoord = texCoord;\n" "}\n"; const char* fragmentShader = "precision highp float;\n" "varying vec2 v_texCoord;\n" "uniform sampler2D yTexture;\n" "uniform sampler2D uvTexture;\n" "void main()\n" "{\n" " float y = texture2D(yTexture, v_texCoord).r;\n" " float u = texture2D(uvTexture, v_texCoord).r - 0.5;\n" " float v = texture2D(uvTexture, v_texCoord).a - 0.5;\n" " float r = y + 1.13983 * v;\n" " float g = y - 0.39465 * u - 0.58060 * v;\n" " float b = y + 2.03211 * u;\n" " gl_FragColor = vec4(r, g, b, 1.0);\n" "}\n"; GLuint programID = glCreateProgram(); GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShaderID, 1, &vertexShader, NULL); glCompileShader(vertexShaderID); glAttachShader(programID, vertexShaderID); GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShaderID, 1, &fragmentShader, NULL); glCompileShader(fragmentShaderID); glAttachShader(programID, fragmentShaderID); glLinkProgram(programID); glUseProgram(programID); ``` 4. 绑定纹理对象到FBO,并将着色器程序与FBO绑定 ``` GLuint fboID; glGenFramebuffers(1, &fboID); glBindFramebuffer(GL_FRAMEBUFFER, fboID); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0); glViewport(0, 0, width, height); glUseProgram(programID); glUniform1i(glGetUniformLocation(programID, "yTexture"), 0); glUniform1i(glGetUniformLocation(programID, "uvTexture"), 1); ``` 5. 渲染FBO ``` GLfloat vertices[] = { -1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f }; GLubyte indices[] = {0, 1, 2, 3}; glVertexAttribPointer(glGetAttribLocation(programID, "position"), 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), vertices); glVertexAttribPointer(glGetAttribLocation(programID, "texCoord"), 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), vertices + 2); glEnableVertexAttribArray(glGetAttribLocation(programID, "position")); glEnableVertexAttribArray(glGetAttribLocation(programID, "texCoord")); glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices); glDisableVertexAttribArray(glGetAttribLocation(programID, "position")); glDisableVertexAttribArray(glGetAttribLocation(programID, "texCoord")); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值