OpenGL ES 2.0的Andr​​oid上,YUV到RGB和FFmpeg的渲染 [英] openGL ES 2.0 on android , YUV to RGB and Rendering with ffMpeg

查看:697
本文介绍了OpenGL ES 2.0的Andr​​oid上,YUV到RGB和FFmpeg的渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的渲染死亡1〜2帧后,当后的视频显示。

致命错误11:布拉布拉...(究竟在发生与glDrawElements(Y部分))

我认为问题是'glPixelStorei或GL_RGB,GL_LUMINANCE但是..我不明白这一点。

我的呈现方式:

  1. 从网络获得

    德code数据,(SDK Getting-> NDK解码),入队。

  2. 出队的另一个线程(当然同步)准备好安装的OpenGL ES 2.0。(SDK)

  3. 在onDrawFrame,onSurfaceCreated,onSurfaceChanged方法被调用,它缩小到NDK。 (在NDK我的渲染源将连接下文。)

  4. 渲染。

如你所知,片段着色器使用的转换。 我的数据是YUV 420P(pix_fmt_YUV420p)(每像素12位)

下面是我的全部源代码。

我不是OpenGL ES的前任何所知,这是第一次。

请让我知道我是什么也提高了性能。

和我是什么用的glTexImage2D'参数'glTexSubImage2D','glRenderbufferStorage???? GL_LUMINANCE? GL_RGBA? GL_RGB? (GL_LUMINANCE现在使用)

 无效渲染:: set_draw_frame(JNIEnv的* jenv,jbyteArray YDATA,jbyteArray UDATA,jbyteArray VDATA)
{
    的for(int i = 0;我3;;我++){
        如果(yuv_data_ [I]!= NULL){
            免费(yuv_data_ [I]);
        }
    }

  INT YSIZE = -1;
  INT USIZE = -1;
  INT VSIZE = -1;

  如果(YDATA!= NULL){
        YSIZE =(INT)jenv-> GetArrayLength(YDATA);
    LOG_DEBUG(YSIZE数:%d,YSIZE);
        yuv_data_ [0] =(无符号字符*)malloc的(的sizeof(无符号字符)* YSIZE);
    memset的(yuv_data_ [0],0,YSIZE);
        jenv-> GetByteArrayRegion(YDATA,0,YSIZE,(jbyte *)yuv_data_ [0]);
    yuv_data_ [0] = reinter pret_cast<无符号字符*>(yuv_data_ [0]);
    } 其他 {
        YSIZE =(INT)jenv-> GetArrayLength(YDATA);
        yuv_data_ [0] =(无符号字符*)malloc的(的sizeof(无符号字符)* YSIZE);
    memset的(yuv_data_ [0],1,YSIZE);
  }

    如果(UDATA!= NULL){
        USIZE =(INT)jenv-> GetArrayLength(UDATA);
    LOG_DEBUG(USIZE数:%d,USIZE);
        yuv_data_ [1] =(无符号字符*)malloc的(的sizeof(无符号字符)* USIZE);
    memset的(yuv_data_ [1],0,USIZE);
        jenv-> GetByteArrayRegion(UDATA,0,USIZE,(jbyte *)yuv_data_ [1]);
    yuv_data_ [1] = reinter pret_cast<无符号字符*>(yuv_data_ [1]);
    } 其他 {
        USIZE = YSIZE / 4;
        yuv_data_ [1] =(无符号字符*)malloc的(的sizeof(无符号字符)* USIZE);
    memset的(yuv_data_ [1],1,USIZE);
  }

    如果(VDATA!= NULL){
        VSIZE =(INT)jenv-> GetArrayLength(VDATA);
    LOG_DEBUG(VSIZE数:%d,VSIZE);
        yuv_data_ [2] =(无符号字符*)malloc的(的sizeof(无符号字符)* VSIZE);
    memset的(yuv_data_ [2],0,VSIZE);
        jenv-> GetByteArrayRegion(VDATA,0,VSIZE,(jbyte *)yuv_data_ [2]);
    yuv_data_ [2] = reinter pret_cast<无符号字符*>(yuv_data_ [2]);
    } 其他 {
        VSIZE = YSIZE / 4;
        yuv_data_ [2] =(无符号字符*)malloc的(的sizeof(无符号字符)* VSIZE);
    memset的(yuv_data_ [2],1,VSIZE);
  }

    glClearColor(1.0F,1.0F,1.0F,1.0F);
    check_gl_error(glClearColor);
    glClear(GL_COLOR_BUFFER_BIT);
    check_gl_error(glClear);
}

无效渲染:: draw_frame()
{
  //创建绑定FBO
  glBindFramebuffer(GL_FRAMEBUFFER,frame_buffer_object_);
  check_gl_error(glBindFramebuffer);
    //添加程序的OpenGL环境
    glUseProgram(program_object_);
    check_gl_error(glUseProgram);

  的for(int i = 0;我3;;我++){
    LOG_DEBUG(成功);
      //绑定纹理
      glActiveTexture(GL_TEXTURE0 + I);
      check_gl_error(glActiveTexture);
      glBindTexture(GL_TEXTURE_2D,yuv_texture_id_ [I]);
      check_gl_error(glBindTexture);
      glUniform1i(yuv_texture_object_ [I],i)的;
      check_gl_error(glBindTexture);
    glTexSubImage2D(GL_TEXTURE_2D,0,0,0,stream_yuv_width_ [I],stream_yuv_height_ [I],GL_RGBA,GL_UNSIGNED_BYTE,yuv_data_ [I]);
      check_gl_error(glTexSubImage2D);
  }

  LOG_DEBUG(成功);
    //装载顶点信息
    glVertexAttribPointer(position_object_,2,GL_FLOAT,GL_FALSE,kStride,kVertexInformation);
    check_gl_error(glVertexAttribPointer);
    //载入纹理信息
    glVertexAttribPointer(texture_position_object_,2,GL_SHORT,GL_FALSE,kStride,kTextureCoordinateInformation);
    check_gl_error(glVertexAttribPointer);

LOG_DEBUG(9);
    glEnableVertexAttribArray(position_object_);
    check_gl_error(glEnableVertexAttribArray);
    glEnableVertexAttribArray(texture_position_object_);
    check_gl_error(glEnableVertexAttribArray);

  //返回窗口缓冲区
  glBindFramebuffer(GL_FRAMEBUFFER,0);
  check_gl_error(glBindFramebuffer);
  LOG_DEBUG(成功);
    //绘制正方形
    与glDrawElements(GL_TRIANGLE_STRIP,6,GL_UNSIGNED_SHORT,kIndicesInformation);
    check_gl_error(与glDrawElements);
}

无效渲染:: setup_render_to_texture()
{
    glGenFramebuffers(1,&安培; frame_buffer_object_);
    check_gl_error(glGenFramebuffers);
    glBindFramebuffer(GL_FRAMEBUFFER,frame_buffer_object_);
    check_gl_error(glBindFramebuffer);
    glGenRenderbuffers(1,&安培; render_buffer_object_);
    check_gl_error(glGenRenderbuffers);
    glBindRenderbuffer(GL_RENDERBUFFER,render_buffer_object_);
    check_gl_error(glBindRenderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER,GL_RGBA4,stream_yuv_width_ [0],stream_yuv_height_ [0]);
    check_gl_error(glRenderbufferStorage);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER,render_buffer_object_);
    check_gl_error(glFramebufferRenderbuffer);
  glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,yuv_texture_id_ [0],0);
    check_gl_error(glFramebufferTexture2D);
  glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,yuv_texture_id_ [1],0);
    check_gl_error(glFramebufferTexture2D);
  glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,yuv_texture_id_ [2],0);
    check_gl_error(glFramebufferTexture2D);

  glBindFramebuffer(GL_FRAMEBUFFER,0);
    check_gl_error(glBindFramebuffer);

    闪烁状态= glCheckFramebufferStatus(GL_FRAMEBUFFER);
    如果(状态!= GL_FRAMEBUFFER_COMPLETE){
        print_log(renderer.cpp,setup_graphics,FBO设置错。LOGERROR);
        LOG_ERROR(%D \ N状态);
        返回;
    }
}

无效渲染:: setup_yuv_texture()
{
    //使用紧凑的数据
    glPixelStorei(GL_UNPACK_ALIGNMENT,1);
    check_gl_error(glPixelStorei);

  的for(int i = 0;我3;;我++){
    如果(yuv_texture_id_ [I]){
      glDeleteTextures(1,&安培; yuv_texture_id_ [I]);
      check_gl_error(glDeleteTextures);
    }
      glActiveTexture(GL_TEXTURE0 + I);
      check_gl_error(glActiveTexture);
      //生成纹理对象
      glGenTextures(1,&安培; yuv_texture_id_ [I]);
      check_gl_error(glGenTextures);
      glBindTexture(GL_TEXTURE_2D,yuv_texture_id_ [I]);
      check_gl_error(glBindTexture);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
      check_gl_error(glTexParameteri);
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
      check_gl_error(glTexParameteri);
      glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
      check_gl_error(glTexParameterf);
      glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
      check_gl_error(glTexParameterf);
    过glEnable(GL_TEXTURE_2D);
    check_gl_error(过glEnable);
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,maximum_yuv_width_ [I],maximum_yuv_height_ [I],0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
      check_gl_error(glTexImage2D);
  }
}

无效渲染:: setup_graphics()
{
    print_gl_string(版本,GL_VERSION);
    print_gl_string(「卖方」,GL_VENDOR);
    print_gl_string(渲染,GL_RENDERER);
    print_gl_string(扩展,GL_EXTENSIONS);

    program_object_ = create_program(kVertexShader,kFragmentShader);
    如果(!program_object_){
        print_log(renderer.cpp,setup_graphics,无法创建计划。,LOGERROR);
        返回;
    }

    position_object_ = glGetAttribLocation(program_object_vPosition);
    check_gl_error(glGetAttribLocation);
    texture_position_object_ = glGetAttribLocation(program_object_vTexCoord);
    check_gl_error(glGetAttribLocation);

    yuv_texture_object_ [0] = glGetUniformLocation(program_object_yTexture);
    check_gl_error(glGetUniformLocation);
  yuv_texture_object_ [1] = glGetUniformLocation(program_object_uTexture);
    check_gl_error(glGetUniformLocation);
    yuv_texture_object_ [2] = glGetUniformLocation(program_object_vTexture);
    check_gl_error(glGetUniformLocation);

  setup_yuv_texture();
    setup_render_to_texture();

  glViewport(0,0,stream_yuv_width_ [0],stream_yuv_height_ [0]); // 736,480); // 1920,1080); // maximum_yuv_width_ [0],maximum_yuv_height_ [0]);
  check_gl_error(glViewport);
}

GLuint渲染:: create_program(为const char * vertex_source,为const char * fragment_source)
{
    GLuint vertexShader = load_shader(GL_VERTEX_SHADER,vertex_source);
    如果(!vertexShader){
        返回0;
    }

    GLuint pixelShader = load_shader(GL_FRAGMENT_SHADER,fragment_source);
    如果(!pixelShader){
        返回0;
    }

    GLuint程序= glCreateProgram();
    如果(节目){
        glAttachShader(程序,vertexShader);
        check_gl_error(glAttachShader);
        glAttachShader(程序,pixelShader);
        check_gl_error(glAttachShader);
        glLinkProgram(节目);
        / *获取一个状态* /
        闪烁linkStatus = GL_FALSE;
        glGetProgramiv(程序,GL_LINK_STATUS,&安培; linkStatus);
        如果(linkStatus!= GL_TRUE){
            闪烁bufLength = 0;
            glGetProgramiv(程序,GL_INFO_LOG_LENGTH,&安培; bufLength);
            如果(bufLength){
                字符* BUF =(字符*)malloc的(bufLength);
                如果(BUF){
                    glGetProgramInfoLog(程序,bufLength,NULL,BUF);
                    print_log(renderer.cpp,create_program,无法连接计划。,LOGERROR);
                    LOG_ERROR(%S \ N,BUF);
                    免费(BUF);
                }
            }
            glDeleteProgram(节目);
            计划= 0;
        }
    }
    返回程序;
}

GLuint渲染:: load_shader(GLenum shaderType,为const char *的PSource)
{
    GLuint着色器= glCreateShader(shaderType);
        如果(着色器){
            glShaderSource(着色,1,&安培;的PSource,NULL);
            glCompileShader(着色);
            / *获取一个状态* /
            编译闪烁= 0;
            glGetShaderiv(着色器,GL_COMPILE_STATUS,和放大器;编译);
            如果(!编译){
                闪烁infoLen = 0;
                glGetShaderiv(着色器,GL_INFO_LOG_LENGTH,和放大器; infoLen);
                如果(infoLen){
                    字符* BUF =(字符*)malloc的(infoLen);
                    如果(BUF){
                        glGetShaderInfoLog(着色器,infoLen,NULL,BUF);
                        print_log(renderer.cpp,load_shader,无法连接计划。,LOGERROR);
                                  LOG_ERROR(%D ::%S \ N,shaderType,BUF);
                        免费(BUF);
                    }
                    glDeleteShader(着色);
                    着色器= 0;
                }
            }
        }
    返回着色器;
}


无效渲染:: onDrawFrame(JNIEnv的* jenv,jbyteArray YDATA,jbyteArray UDATA,jbyteArray VDATA)
{
    set_draw_frame(jenv,YDATA,UDATA,VDATA);
    draw_frame();
    返回;
}

无效渲染::的setSize(INT stream_width,诠释stream_height){
  stream_yuv_width_ [0] = stream_width;
  stream_yuv_width_ [1] = stream_width / 2;
  stream_yuv_width_ [2] = stream_width / 2;
  stream_yuv_height_ [0] = stream_height;
  stream_yuv_height_ [1] = stream_height / 2;
  stream_yuv_height_ [2] = stream_height / 2;
}

无效渲染:: onSurfaceChanged(INT宽度,高度INT)
{
  mobile_yuv_width_ [0] =宽度;
  mobile_yuv_width_ [1] =宽度/ 2;
  mobile_yuv_width_ [2] =宽度/ 2;
  mobile_yuv_height_ [0] =高度;
  mobile_yuv_height_ [1] =高度/ 2;
  mobile_yuv_height_ [2] =高度/ 2;

  maximum_yuv_width_ [0] = 1920;
  maximum_yuv_width_ [1] =二分之一千九百二十零;
  maximum_yuv_width_ [2] =二分之一千九百二十零;
  maximum_yuv_height_ [0] = 1080;
  maximum_yuv_height_ [1] =二分之一千○八十零;
  maximum_yuv_height_ [2] =二分之一千〇八十零;

  //如果流大小不设置,默认大小D1
  //如果(stream_yuv_width_ [0] == 0){
    stream_yuv_width_ [0] = 736;
    stream_yuv_width_ [1] =二分之七百三十六;
    stream_yuv_width_ [2] =二分之七百三十六;
    stream_yuv_height_ [0] = 480;
    stream_yuv_height_ [1] =二分之四百八十零;
    stream_yuv_height_ [2] =二分之四百八十零;
  //}

    setup_graphics();
    返回;
}
 

下面是我的片段,顶点源和坐标:

 静态常量字符kVertexShader [] =
    属性vec4 vPosition; \ N
      属性VEC2 vTexCoord; \ N
      不同VEC2 v_vTexCoord; \ N
    无效的主要(){\ N
        GL_POSITION = vPosition; \ N
        v_vTexCoord = vTexCoord; \ N
    } \ N的;

静态常量字符kFragmentShader [] =
        precision mediump浮动; \ N
        不同VEC2 v_vTexCoord; \ N
        统一sampler2D yTexture; \ N
        统一sampler2D uTexture; \ N
        统一sampler2D vTexture; \ N
        无效的主要(){\ N
            浮Y =的Texture2D(yTexture,v_vTexCoord).R; \ N
            浮U =的Texture2D(uTexture,v_vTexCoord).R  -  0.5; \ N
            浮动V =的Texture2D(vTexture,v_vTexCoord).R  -  0.5; \ N
            浮动R = Y + 1.13983 * V; \ N
            浮G =Ÿ -  0.39465 * U  -  0.58060 * V; \ N
            浮动B = Y + 2.03211 * U; \ N
            gl_FragColor = vec4(R,G,B,1.0); \ñ
        } \ N的;

静态常量GLfloat kVertexInformation [] =
{
         -1.0F,1.0F,// TEXCOORD 0左上
         -1.0F,-1.0F,// TEXCOORD 1左下方
          1.0F,-1.0F,// TEXCOORD 2右下方
          1.0F,1.0F // TEXCOORD 3右上
};
静里的const GLshort kTextureCoordinateInformation [] =
{
          0,0,// TEXCOORD 0左上
          0,1,// TEXCOORD 1左下方
          1,1,// TEXCOORD 2右下
          1,0 // TEXCOORD 3右上
};
静态常量GLuint kStride = 0; // COORDS_PER_VERTEX * 4;
静里的const GLshort kIndicesInformation [] =
{
    0,1,2,
    0,2,3
};
 

解决方案

您不能调用glTexSubImage2D(),并期望它跟上视频的帧速率。这是一个非常常见的错误。 glTexSubImage2D()和glTexImage2D()是用于视频太慢。

您应该使用EGL图像扩展代替。有这样对于Android的例子在这里:

<一个href="http://software.intel.com/en-us/articles/using-opengl-es-to-accelerate-apps-with-legacy-2d-guis" rel="nofollow">http://software.intel.com/en-us/articles/using-opengl-es-to-accelerate-apps-with-legacy-2d-guis

My renderer dies 1~2 frames later when video shows after.

FATAL ERROR 11 : blabla...(Exactly occurs in glDrawElements (Y part))

I think problem is 'glPixelStorei' or 'GL_RGB', 'GL_LUMINANCE' but.. I don't get it.

My rendering way :

  1. Decode data that got from network, (SDK Getting-> NDK Decoding), Enqueueing.

  2. Dequeueing another threads (of course synchronized) get ready to setup OpenGL ES 2.0.(SDK)

  3. When onDrawFrame, onSurfaceCreated, onSurfaceChanged methods are called, it shrink down to NDK. (My Renderer source in NDK will attach below.)

  4. Rendering.

As you know, Fragment shader is using for conversion. My Data is YUV 420p (pix_fmt_YUV420p) (12bit per pixel)

Here is my entire source.

I haven't any knowledge about OpenGL ES before, this is first time.

Please let me know what am I do improving performance.

and What am I use parameters in 'glTexImage2D', 'glTexSubImage2D', 'glRenderbufferStorage'???? GL_LUMINANCE? GL_RGBA? GL_RGB? (GL_LUMINANCE is using now)

void Renderer::set_draw_frame(JNIEnv* jenv, jbyteArray yData, jbyteArray uData, jbyteArray vData)
{
    for (int i = 0; i < 3; i++) {
        if (yuv_data_[i] != NULL) {
            free(yuv_data_[i]);
        }
    }

  int YSIZE = -1;
  int USIZE = -1;
  int VSIZE = -1;

  if (yData != NULL) {
        YSIZE = (int)jenv->GetArrayLength(yData);
    LOG_DEBUG("YSIZE : %d", YSIZE);
        yuv_data_[0] = (unsigned char*)malloc(sizeof(unsigned char) * YSIZE);
    memset(yuv_data_[0], 0, YSIZE);
        jenv->GetByteArrayRegion(yData, 0, YSIZE, (jbyte*)yuv_data_[0]);
    yuv_data_[0] = reinterpret_cast<unsigned char*>(yuv_data_[0]);
    } else {
        YSIZE = (int)jenv->GetArrayLength(yData);
        yuv_data_[0] = (unsigned char*)malloc(sizeof(unsigned char) * YSIZE);
    memset(yuv_data_[0], 1, YSIZE);
  }

    if (uData != NULL) {
        USIZE = (int)jenv->GetArrayLength(uData);
    LOG_DEBUG("USIZE : %d", USIZE);
        yuv_data_[1] = (unsigned char*)malloc(sizeof(unsigned char) * USIZE);
    memset(yuv_data_[1], 0, USIZE);
        jenv->GetByteArrayRegion(uData, 0, USIZE, (jbyte*)yuv_data_[1]);
    yuv_data_[1] = reinterpret_cast<unsigned char*>(yuv_data_[1]);
    } else {
        USIZE = YSIZE/4;
        yuv_data_[1] = (unsigned char*)malloc(sizeof(unsigned char) * USIZE);
    memset(yuv_data_[1], 1, USIZE);
  }

    if (vData != NULL) {
        VSIZE = (int)jenv->GetArrayLength(vData);
    LOG_DEBUG("VSIZE : %d", VSIZE);
        yuv_data_[2] = (unsigned char*)malloc(sizeof(unsigned char) * VSIZE);
    memset(yuv_data_[2], 0, VSIZE);
        jenv->GetByteArrayRegion(vData, 0, VSIZE, (jbyte*)yuv_data_[2]);
    yuv_data_[2] = reinterpret_cast<unsigned char*>(yuv_data_[2]);
    } else {
        VSIZE = YSIZE/4;
        yuv_data_[2] = (unsigned char*)malloc(sizeof(unsigned char) * VSIZE);
    memset(yuv_data_[2], 1, VSIZE);
  }

    glClearColor(1.0F, 1.0F, 1.0F, 1.0F);
    check_gl_error("glClearColor");
    glClear(GL_COLOR_BUFFER_BIT);
    check_gl_error("glClear");
}

void Renderer::draw_frame()
{
  // Binding created FBO
  glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_object_);
  check_gl_error("glBindFramebuffer");
    // Add program to OpenGL environment
    glUseProgram(program_object_);
    check_gl_error("glUseProgram");

  for (int i = 0; i < 3; i++) {
    LOG_DEBUG("Success");
      //Bind texture
      glActiveTexture(GL_TEXTURE0 + i);
      check_gl_error("glActiveTexture");
      glBindTexture(GL_TEXTURE_2D, yuv_texture_id_[i]);
      check_gl_error("glBindTexture");
      glUniform1i(yuv_texture_object_[i], i);
      check_gl_error("glBindTexture");
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_yuv_width_[i], stream_yuv_height_[i], GL_RGBA, GL_UNSIGNED_BYTE, yuv_data_[i]);
      check_gl_error("glTexSubImage2D");
  }

  LOG_DEBUG("Success");
    // Load vertex information
    glVertexAttribPointer(position_object_, 2, GL_FLOAT, GL_FALSE, kStride, kVertexInformation);
    check_gl_error("glVertexAttribPointer");
    // Load texture information
    glVertexAttribPointer(texture_position_object_, 2, GL_SHORT, GL_FALSE, kStride, kTextureCoordinateInformation);
    check_gl_error("glVertexAttribPointer");

LOG_DEBUG("9");
    glEnableVertexAttribArray(position_object_);
    check_gl_error("glEnableVertexAttribArray");
    glEnableVertexAttribArray(texture_position_object_);
    check_gl_error("glEnableVertexAttribArray");

  // Back to window buffer
  glBindFramebuffer(GL_FRAMEBUFFER, 0);
  check_gl_error("glBindFramebuffer");
  LOG_DEBUG("Success");
    // Draw the Square
    glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, kIndicesInformation);
    check_gl_error("glDrawElements");
}

void Renderer::setup_render_to_texture()
{
    glGenFramebuffers(1, &frame_buffer_object_);
    check_gl_error("glGenFramebuffers");
    glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer_object_);
    check_gl_error("glBindFramebuffer");
    glGenRenderbuffers(1, &render_buffer_object_);
    check_gl_error("glGenRenderbuffers");
    glBindRenderbuffer(GL_RENDERBUFFER, render_buffer_object_);
    check_gl_error("glBindRenderbuffer");
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, stream_yuv_width_[0], stream_yuv_height_[0]);
    check_gl_error("glRenderbufferStorage");
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_buffer_object_);
    check_gl_error("glFramebufferRenderbuffer");
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yuv_texture_id_[0], 0);
    check_gl_error("glFramebufferTexture2D");  
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yuv_texture_id_[1], 0);
    check_gl_error("glFramebufferTexture2D");  
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yuv_texture_id_[2], 0);
    check_gl_error("glFramebufferTexture2D");  

  glBindFramebuffer(GL_FRAMEBUFFER, 0);
    check_gl_error("glBindFramebuffer");

    GLint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    if (status != GL_FRAMEBUFFER_COMPLETE) {
        print_log("renderer.cpp", "setup_graphics", "FBO setting fault.", LOGERROR);
        LOG_ERROR("%d\n", status);
        return;
    }
}

void Renderer::setup_yuv_texture() 
{
    // Use tightly packed data
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    check_gl_error("glPixelStorei");

  for (int i = 0; i < 3; i++) {
    if (yuv_texture_id_[i]) {
      glDeleteTextures(1, &yuv_texture_id_[i]);
      check_gl_error("glDeleteTextures");
    }
      glActiveTexture(GL_TEXTURE0+i);
      check_gl_error("glActiveTexture"); 
      // Generate texture object
      glGenTextures(1, &yuv_texture_id_[i]);
      check_gl_error("glGenTextures");
      glBindTexture(GL_TEXTURE_2D, yuv_texture_id_[i]);
      check_gl_error("glBindTexture");
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      check_gl_error("glTexParameteri");
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      check_gl_error("glTexParameteri");
      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
      check_gl_error("glTexParameterf");
      glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
      check_gl_error("glTexParameterf"); 
    glEnable(GL_TEXTURE_2D);
    check_gl_error("glEnable");
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, maximum_yuv_width_[i], maximum_yuv_height_[i], 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
      check_gl_error("glTexImage2D");
  }
}

void Renderer::setup_graphics()
{
    print_gl_string("Version", GL_VERSION);
    print_gl_string("Vendor", GL_VENDOR);
    print_gl_string("Renderer", GL_RENDERER);
    print_gl_string("Extensions", GL_EXTENSIONS);

    program_object_ = create_program(kVertexShader, kFragmentShader);
    if (!program_object_) {
        print_log("renderer.cpp", "setup_graphics", "Could not create program.", LOGERROR);
        return;
    }

    position_object_ = glGetAttribLocation(program_object_, "vPosition");
    check_gl_error("glGetAttribLocation");
    texture_position_object_ = glGetAttribLocation(program_object_, "vTexCoord");
    check_gl_error("glGetAttribLocation");

    yuv_texture_object_[0] = glGetUniformLocation(program_object_, "yTexture");
    check_gl_error("glGetUniformLocation");
  yuv_texture_object_[1] = glGetUniformLocation(program_object_, "uTexture");
    check_gl_error("glGetUniformLocation");
    yuv_texture_object_[2] = glGetUniformLocation(program_object_, "vTexture");
    check_gl_error("glGetUniformLocation");

  setup_yuv_texture();
    setup_render_to_texture();

  glViewport(0, 0, stream_yuv_width_[0], stream_yuv_height_[0]);//736, 480);//1920, 1080);//maximum_yuv_width_[0], maximum_yuv_height_[0]);
  check_gl_error("glViewport");
}

GLuint Renderer::create_program(const char* vertex_source, const char* fragment_source)
{
    GLuint vertexShader = load_shader(GL_VERTEX_SHADER, vertex_source);
    if (!vertexShader) {
        return 0;
    }

    GLuint pixelShader = load_shader(GL_FRAGMENT_SHADER, fragment_source);
    if (!pixelShader) {
        return 0;
    }

    GLuint program = glCreateProgram();
    if (program) {
        glAttachShader(program, vertexShader);
        check_gl_error("glAttachShader");
        glAttachShader(program, pixelShader);
        check_gl_error("glAttachShader");
        glLinkProgram(program);
        /* Get a Status */
        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);
                    print_log("renderer.cpp", "create_program", "Could not link program.", LOGERROR);
                    LOG_ERROR("%s\n", buf);
                    free(buf);
                }
            }
            glDeleteProgram(program);
            program = 0;
        }
    }
    return program;
}

GLuint Renderer::load_shader(GLenum shaderType, const char* pSource)
{
    GLuint shader = glCreateShader(shaderType);
        if (shader) {
            glShaderSource(shader, 1, &pSource, NULL);
            glCompileShader(shader);
            /* Get a Status */
            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) {
                        glGetShaderInfoLog(shader, infoLen, NULL, buf);
                        print_log("renderer.cpp", "load_shader", "Could not link program.", LOGERROR);
                                  LOG_ERROR("%d :: %s\n", shaderType, buf);
                        free(buf);
                    }
                    glDeleteShader(shader);
                    shader = 0;
                }
            }
        }
    return shader;
}


void Renderer::onDrawFrame(JNIEnv* jenv, jbyteArray yData, jbyteArray uData, jbyteArray vData)
{
    set_draw_frame(jenv, yData, uData, vData);
    draw_frame();
    return;
}

void Renderer::setSize(int stream_width, int stream_height) {
  stream_yuv_width_[0] = stream_width;
  stream_yuv_width_[1] = stream_width/2;
  stream_yuv_width_[2] = stream_width/2;
  stream_yuv_height_[0] = stream_height;
  stream_yuv_height_[1] = stream_height/2;
  stream_yuv_height_[2] = stream_height/2;
}

void Renderer::onSurfaceChanged(int width, int height)
{
  mobile_yuv_width_[0] = width;
  mobile_yuv_width_[1] = width/2;
  mobile_yuv_width_[2] = width/2; 
  mobile_yuv_height_[0] = height;
  mobile_yuv_height_[1] = height/2;
  mobile_yuv_height_[2] = height/2;

  maximum_yuv_width_[0] = 1920;
  maximum_yuv_width_[1] = 1920/2;
  maximum_yuv_width_[2] = 1920/2;
  maximum_yuv_height_[0] = 1080;
  maximum_yuv_height_[1] = 1080/2;
  maximum_yuv_height_[2] = 1080/2;

  // If stream size not setting, default size D1
  //if (stream_yuv_width_[0] == 0) {
    stream_yuv_width_[0] = 736;
    stream_yuv_width_[1] = 736/2;
    stream_yuv_width_[2] = 736/2;
    stream_yuv_height_[0] = 480;
    stream_yuv_height_[1] = 480/2;
    stream_yuv_height_[2] = 480/2;
  //}

    setup_graphics();
    return;
}

Here is my Fragment, Vertex source and coordinates :

static const char kVertexShader[] =
    "attribute vec4 vPosition;      \n"
      "attribute vec2 vTexCoord;        \n"
      "varying vec2 v_vTexCoord;        \n"
    "void main() {                        \n"
        "gl_Position = vPosition;       \n"
        "v_vTexCoord = vTexCoord;       \n"
    "}                                          \n";

static const char kFragmentShader[] =
        "precision mediump float;               \n"
        "varying vec2 v_vTexCoord;          \n"
        "uniform sampler2D yTexture;        \n"
        "uniform sampler2D uTexture;        \n"
        "uniform sampler2D vTexture;        \n"
        "void main() {                      \n"
            "float y=texture2D(yTexture, v_vTexCoord).r;\n"
            "float u=texture2D(uTexture, v_vTexCoord).r - 0.5;\n"
            "float v=texture2D(vTexture, v_vTexCoord).r - 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";

static const GLfloat kVertexInformation[] =
{
         -1.0f, 1.0f,           // TexCoord 0 top left
         -1.0f,-1.0f,           // TexCoord 1 bottom left
          1.0f,-1.0f,           // TexCoord 2 bottom right
          1.0f, 1.0f            // TexCoord 3 top right
};
static const GLshort kTextureCoordinateInformation[] =
{
          0, 0,         // TexCoord 0 top left
          0, 1,         // TexCoord 1 bottom left
          1, 1,         // TexCoord 2 bottom right
          1, 0          // TexCoord 3 top right
};
static const GLuint kStride = 0;//COORDS_PER_VERTEX * 4;
static const GLshort kIndicesInformation[] =
{
    0, 1, 2, 
    0, 2, 3
};

解决方案

You can't call glTexSubImage2D() and expect it to keep up with video frame rates. This is a very common mistake. glTexSubImage2D() and glTexImage2D() are too slow for video.

You should be using the EGL Image extensions instead. There is an example of this for Android here:

http://software.intel.com/en-us/articles/using-opengl-es-to-accelerate-apps-with-legacy-2d-guis

这篇关于OpenGL ES 2.0的Andr​​oid上,YUV到RGB和FFmpeg的渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆