2016-01-13 24 views
24

私は現在、ビデオストリームの接続とデコードにffmpegを使用してアンドロイドのrtspプレーヤーで作業しています。 OpenGL es 2.0を使用してYUVフレームをRGBフレームに変換して表示したいのですが、ブロックされています(初めてOpenGLを使用しています)。YUVからRGBへの変換と表示は、シェイダーを使用してandroid ndkから

私は自分の問題点を明確に説明しようとします。 NDKのアンドロイドから

私はこの方法を使用して(私は画像を表示するために使用するスレッドから)OpenGLのコンテキストを初期化します。

// 
EGLint attribs[] = { 
     EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 
     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 
     EGL_BLUE_SIZE, 8, 
     EGL_GREEN_SIZE, 8, 
     EGL_RED_SIZE, 8, 
     EGL_ALPHA_SIZE, 8, 
     EGL_NONE 
}; 
EGLint contextAttrs[] = { 
     EGL_CONTEXT_CLIENT_VERSION, 2, 
     EGL_NONE 
}; 

LOGI("Initializing context"); 

if((display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) 
{ 
    closeContext(); 
    return; 
} 

if(!eglInitialize(display, 0, 0)) 
{ 
    closeContext(); 
    return; 
} 

if(!eglChooseConfig(display, attribs, &config, 1, &numConfigs)) 
{ 
    closeContext(); 
    return; 
} 

if(!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) 
{ 
    closeContext(); 
    return; 
} 

ANativeWindow_setBuffersGeometry(window, 0, 0, format); 

if(!(surface = eglCreateWindowSurface(display, config, window, 0))) 
{ 
    closeContext(); 
    return; 
} 

if(!(context = eglCreateContext(display, config, 0, contextAttrs))) 
{ 
    closeContext(); 
    return; 
} 

if(!eglMakeCurrent(display, surface, surface, context)) 
{ 
    closeContext(); 
    return; 
} 

if(!eglQuerySurface(display, surface, EGL_WIDTH, &width) || !eglQuerySurface(display, surface, EGL_HEIGHT, &height)) 
{ 
    closeContext(); 
    return; 
} 

LOGI("EGLWIDTH : %d EGLHEIGHT : %d ", (int)width, (int)height); 

isInitEGLContext = 1; 

それから私のセットアップこの方法を使用してグラフィックス:

// 
//Load Vertex and Fragment Shader, attach shader and link program 
programId = createProgram(kVertexShader, kFragmentShader); 
LOGI("Program id : %d error : %d",(int) programId, glGetError()); 


if(!programId) 
{ 
    LOGI("Could not create program"); 
    return; 
} 
// get index of the generic vertex attribute bound to vPosition 
positionObject = (int) glGetAttribLocation(programId, "vPosition"); 

// get index of the generic vertex attribute bound to vTexCoord 
texturePosition = (int) glGetAttribLocation(programId, "vTexCoord"); 

// get the location of yTexture within the program (corresponding to program id) 
yuv_texture_object[0] = glGetUniformLocation(programId, "yTexture"); 

// get the location of uTexture within the program 
yuv_texture_object[1] = glGetUniformLocation(programId, "uTexture"); 

// get the location of vTexture within the program 
yuv_texture_object[2] = glGetUniformLocation(programId, "vTexture"); 

// Setup width of each planes (display size) 
stream_yuv_width[0] = 800; 
stream_yuv_width[1] = 400; 
stream_yuv_width[2] = 400; 

// Setup height of each planes (display size) 
stream_yuv_height[0] = 600; 
stream_yuv_height[1] = 300; 
stream_yuv_height[2] = 300; 

//set the view port 
glViewport(0,0,stream_yuv_width[0],stream_yuv_height[0]); 
LOGI("glViewPort() %d ", glGetError()); 

私は何かを得るまで表示サイズを(今のところは)ハードコーディングしています。

createProgramメソッドは、シェーダをロードし、プログラムを作成し、シェーダを正常にコンパイルしてリンクします。ここで

は私のシェーダです:

void setupYUVTexture() 
{ 
//Setup the pixel alignement 
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 
LOGI("glPixelStorei() : %d ", glGetError()); 
int i = 0; 

for(i = 0 ; i < 3 ; ++i) 
{ 
    //Check if the texture already setup 
    if(yuv_texture_id[i] != 0) 
    { 
     glDeleteTextures(1, &yuv_texture_id[i]); 
     yuv_texture_id[i] = 0; 
    } 
    // Active the i texture 
    glActiveTexture(GL_TEXTURE0 + i); 

    //Generate the texture name 
    glGenTextures(1, &yuv_texture_id[i]); 

    // Bind the texture 
    glBindTexture(GL_TEXTURE_2D, yuv_texture_id[i]); 

    // Setup the texture parameters 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 


    //Define the texture image 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, yuv_width[i], yuv_height[i], 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL); 
    LOGI("glTexImage2D() %d ", glGetError()); 
} 
} 

void renderToTexture() 
{ 
// Generate framebuffer object name 
    glGenFramebuffers(1, &frameBufferObject); 
    //Bind the framebuffer 
    glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject); 


    //Generate render buffer object name 
    glGenRenderbuffers(1, &renderBufferObject); 

    //Bind render buffer 
    glBindRenderbuffer(GL_RENDERBUFFER, renderBufferObject); 

    //Create and initialize render buffer for display RGBA with the same size of the viewport 
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 800, 600); 

    //Attach render buffer to frame buffer object 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderBufferObject); 

    //Attach y plane to frame buffer object 
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yuv_texture_id[0], 0); 

    //Attach u plane to frame buffer object 
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yuv_texture_id[1], 0); 

    //Attach v plane to frame buffer object 
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, yuv_texture_id[2], 0); 

    // Bind the framebuffer 
    glBindFramebuffer(GL_FRAMEBUFFER, 0); 

    //Check if the framebuffer is correctly setup 
    GLint status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 

    if(status != GL_FRAMEBUFFER_COMPLETE) 
    { 
     LOGI(" FBO setting fault : %d ", status); 
     return; 
    } 
} 

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

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 nx, ny; \n" 
"nx = v_vTexCoord.x; \n" 
"ny = v_vTexCoord.y; \n" 
"float y=texture2D(yTexture, v_vTexCoord).r;\n" 
"float u=texture2D(uTexture, vec2(nx/2.0, ny/2.0)).r;\n" 
"float v=texture2D(vTexture, vec2(nx/2.0, ny/2.0)).r;\n" 
"y = 1.1643 * (y - 0.0625);\n" 
"u = u - 0.5; \n" 
"v = v - 0.5; \n" 
"float r=y + 1.5958 * v;\n" 
"float g=y - 0.39173 * u - 0.81290 * v;\n" 
"float b=y + 2.017 * u;\n" 
"gl_FragColor = vec4(r, g, b, 1.0);\n" 
"}\n"; 

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 
}; 
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 
}; 
const GLuint kStride = 0;//COORDS_PER_VERTEX * 4; 
const GLshort kIndicesInformation[] = { 
    0, 1, 2, 
    0, 2, 3 
}; 

それから私セットアップYUVテクスチャと、この瞬間yuv_width [i]とyuv_heightで、テクスチャにレンダリング[i]の値を補正するように設定されています私はかつてのOpenGLテクスチャやその他の初期化

void drawFrame() 
{ 
LOGI("DrawFrame"); 
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject); 
printGLError("glBindFramebuffer"); 
glUseProgram(programId); 
printGLError("glUseProgram"); 
int i = 0; 
for(i = 0 ; i < 3 ; ++i) 
{ 
    glActiveTexture(GL_TEXTURE0 + i); 
    printGLError("glActiveTexture"); 

    glBindTexture(GL_TEXTURE_2D, yuv_texture_object[i]); 
    printGLError("glBindTexture"); 

    glUniform1i(yuv_texture_object[i], i); 
    printGLError("glUniform1i");    
    LOGI("Plan : %d Largeur : %d Hauteur : %d ", i, yuv_width[i], yuv_height[i]); 
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,yuv_width[i], yuv_height[i], GL_LUMINANCE, GL_UNSIGNED_BYTE, yuv_planes[i]); 
      printGLError("glTexSubImage2D"); 

    } 

    glVertexAttribPointer(positionObject, 2, GL_FLOAT, GL_FALSE, kStride, kVertexInformation); 
    printGLError("glVertexAttribPointer"); 

    glVertexAttribPointer(texturePosition, 2, GL_SHORT, GL_FALSE, kStride, kTextureCoordinateInformation); 
    printGLError("glVertexAttribPointer"); 

    glEnableVertexAttribArray(positionObject);  
    printGLError("glVertexAttribArray"); 

    glEnableVertexAttribArray(texturePosition); 
    printGLError("glVertexAttribArray"); 

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

    glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, kIndicesInformation); 
    printGLError("glDrawElements"); 

    eglSwapBuffers(display, surface); 
    printGLError("eglSwapBuffers"); 

} 

は私のドローフレーム方式、終了するには必要な属性は、フレームがデコードされたときにyバッファをyuv_planes[0]に、uバッファをyuv_planes[ 1]に、vバッファをyuv_planes[2]にそれぞれコピーします。

フレームが正しく、私がこの順に呼び出すffmpegの使用して復号化されたら:
からinitContext()
- setupGraphics()
- setupYUVTexture()
- renderToTexture()

が、私はdrawFrameを呼び出します。もちろん、すべてが初期化されるとき、私は各デコードされたフレームの後に直接drawFrameを呼び出します。

私は今出力しています。

Video display by opengl

画像のサイズは正しいですが、今私はここにブロックしています。なぜ画像表示が緑色であるのか分かりません! 任意のアイデア

+0

は3回の通話のそれぞれのglTexSubImage2Dレポートエラーをしていますか?あなたは[0、2]の代わりに[1、3]の範囲にある(++ i)を使用していることに注意してください。 yuv_width [3]は定義されていないので、最後の呼び出しが間違っているはずです(i = 3の場合)。また、glGetErrorがエラースタックの先頭の値を返してポップすることも知っておくべきです。つまり、スタックからすべてのエラーを取得するには一般にwhileループが必要です。あなたはそれをしないので、前の行で生成されたものの、次のglGetError呼び出しでエラーが報告されることがあります。 –

+0

シェーダを見ると、YUVとしてカラーコンポーネントを使用するのではなく、RGBとして変換してRGBに変換するように見えます。これは私にとっては大丈夫ですが、GL_LUMINANCEの代わりにGL_RGBを使用し、シェイダーのRGB値をYUVとして扱うべきです(すでにフラグメント化されているかどうかは分かりません)。助けて)。 –

+0

投稿を編集してコメントを追加し、Androidモニターの出力を追加しました。 最初に、glTexSubImage2Dは最初の呼び出し時と最後の呼び出し時にエラーを報告します。私のforループで使用しているインクリメントbefore文は正しいです。この例では、1から3ではなく0から2になります。いくつかのコンパイルでは、increment after文を使用すると一時属性が使用されますが、一時的な属性を使用しないため、この方法でループを記述することができます。少し速く)。私はあなたにそれが正しいことを示すために私のAndroidモニターの出力を得る前にログを持っていた。 –

答えて

1

これは多くのコードと間違っている可能性のあるものです。この種の問題をデバッグするには、私は一歩一歩進みます。

  1. 赤色(gl_FragColor = vec4(1.0, 0.5, 0.5, 1.0))を出力すると、設定が正しく動作していることを確認できます。
  2. すべてのテクスチャをグレースケールで出力しようとします。(gl_FragColor = vec4(y, y, y, 1.0)
  3. すべてが動作している場合は、おそらくあなたのyuv => rgb変換がどこかで間違っている可能性があります。
  4. それが機能しない場合、私はテクスチャマッピングの何かを疑うでしょう。 glTexSubImage2Dコールを再度確認してください。異なるストライドを渡すか、別の座標系を使用する必要があります。
関連する問題