简体   繁体   中英

Android opengl es YUV to RGB conversion using shaders

I am working on a video player for android device, in which I am using ffmpeg for decoding and opengl es for rendering. I am stuck at one point where I am using opengl es shaders for YUV to RGB conversion. Application is able to display image but its not displaying correct colors. After conervting from YUV to RGB, image only displays green and pink colors. I did searched on google, but no solution found. Can any one please help me on this topic?

I am getting three different buffers (y, u, v) from ffmpeg and then I am passing these buffers to 3 textures as it is.

Here are shaders I am using.

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

Here is another person who had asked same question: Camera frame yuv to rgb conversion using GL shader language

Thank You.

UPDATE :

ClayMontgomery's shaders.

const char* VERTEX_SHADER = "\
attribute vec4 a_position;\
attribute vec2 a_texCoord;\
varying   vec2 gsvTexCoord;\
varying   vec2 gsvTexCoordLuma;\
varying   vec2 gsvTexCoordChroma;\
\
void main()\
{\
    gl_Position = a_position;\
    gsvTexCoord = a_texCoord;\
    gsvTexCoordLuma.s = a_texCoord.s / 2.0;\
    gsvTexCoordLuma.t = a_texCoord.t / 2.0;\
    gsvTexCoordChroma.s = a_texCoord.s / 4.0;\
    gsvTexCoordChroma.t = a_texCoord.t / 4.0;\
}";


const char* YUV_FRAGMENT_SHADER = "\
precision highp float;\
uniform sampler2D y_texture;\
uniform sampler2D u_texture;\
uniform sampler2D v_texture;\
varying   vec2 gsvTexCoord;\
varying vec2 gsvTexCoordLuma;\
varying vec2 gsvTexCoordChroma;\
\
void main()\
{\
    float y = texture2D(y_texture, gsvTexCoordLuma).r;\
    float u = texture2D(u_texture, gsvTexCoordChroma).r;\
    float v = texture2D(v_texture, gsvTexCoordChroma).r;\
    u = u - 0.5;\
    v = v - 0.5;\
    vec3 rgb;\
    rgb.r = y + (1.403 * v);\
    rgb.g = y - (0.344 * u) - (0.714 * v);\
    rgb.b = y + (1.770 * u);\
    gl_FragColor = vec4(rgb, 1.0);\
}";

Here is output:

在此输入图像描述

The pink and green colors indicate that your input luma and chroma values are not being normalized correctly before the CSC matrix calculations and some of your constants look wrong. Also, you should probably be scaling your texture coordinates for the chroma because it's typically sub-sampled with respect to the luma. There is a good guide to this here:

http://fourcc.org/fccyvrgb.php

Here is an implementation in GLSL that I coded and tested on the Freescale i.MX53. I recommend you try this code.

const char* pVertexShaderSource = "\
    uniform   mat4 gsuMatModelView;\
    uniform   mat4 gsuMatProj;\
    attribute vec4 gsaVertex;\
    attribute vec2 gsaTexCoord;\
    varying   vec2 gsvTexCoord;\
    varying   vec2 gsvTexCoordLuma;\
    varying   vec2 gsvTexCoordChroma;\
    \
    void main()\
    {\
        vec4 vPosition = gsuMatModelView * gsaVertex;\
        gl_Position = gsuMatProj * vPosition;\
        gsvTexCoord = gsaTexCoord;\
        gsvTexCoordLuma.s = gsaTexCoord.s / 2.0;\
        gsvTexCoordLuma.t = gsaTexCoord.t / 2.0;\
        gsvTexCoordChroma.s = gsaTexCoord.s / 4.0;\
        gsvTexCoordChroma.t = gsaTexCoord.t / 4.0;\
    }";


const char* pFragmentShaderSource = "\
    precision highp float;\
    uniform sampler2D gsuTexture0;\
    uniform sampler2D gsuTexture1;\
    uniform sampler2D gsuTexture2;\
    varying vec2 gsvTexCoordLuma;\
    varying vec2 gsvTexCoordChroma;\
    \
    void main()\
    {\
        float y = texture2D(gsuTexture0, gsvTexCoordLuma).r;\
        float u = texture2D(gsuTexture1, gsvTexCoordChroma).r;\
        float v = texture2D(gsuTexture2, gsvTexCoordChroma).r;\
        u = u - 0.5;\
        v = v - 0.5;\
        vec3 rgb;\
        rgb.r = y + (1.403 * v);\
        rgb.g = y - (0.344 * u) - (0.714 * v);\
        rgb.b = y + (1.770 * u);\
        gl_FragColor = vec4(rgb, 1.0);\
    }";

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM