iOS -如何使用openGL绘制YUV图像。

时间:2021-12-14 05:50:29

Currently, I am trying to draw an image using openGL (the image updates very often, and thus must be redrawn). Previously, I was converting my image from YUV to RGB, and then using this new image to draw with openGL. All worked fine, but the conversion process was not particularly fast.

目前,我正在尝试使用openGL绘制一个图像(图像更新非常频繁,因此必须重新绘制)。之前,我把我的图像从YUV转换到RGB,然后使用这个新的图像来绘制openGL。一切都很好,但转换过程并不特别快。

I am now attempting to change the code so that the conversion is taken care of in the openGL shaders. After looking around, I've found a couple code snippets (particularly the shaders and the bulk of my renderImage function) that have helped me get a baseline, but I can't seem to actually get the image to draw properly - all I ever see is a black image.

我现在正在尝试更改代码,以便在openGL着色器中处理转换。在查看了之后,我发现了一些代码片段(尤其是着色器和我的renderImage函数的大部分),它们帮助我获得了一个基线,但是我似乎无法正确地画出图像——我所看到的只是一个黑色的图像。

It's quite likely that I'm missing something extremely simple and important - My experience with openGL is rather limited. If anyone can take a look and see if they recognize anything wrong, please let me know.

很可能我错过了一些极其简单和重要的事情——我对openGL的体验相当有限。如果有人能看一看,看他们是否认识错了,请告诉我。

I should point out, I'm trying to support iOS 4.x, so CVOpenGLESTextureCacheCreateTextureFromImage shouldn't be usable (and I'm not really positive how to setup to use it even if I wanted to).

我应该指出,我正在尝试支持ios4。x,所以cvopenglestexturecachecreatetextureatetecreatetecreatetexturecatetextuimage不应该是可用的(我也不太肯定如何设置它,即使我想使用它)。

Any help would be appreciated. Code below -

如有任何帮助,我们将不胜感激。下面的代码,

My Vertex shader:

我的顶点着色器:

attribute vec4 position;
attribute vec4 inputTextureCoordinate;

varying vec2 textureCoordinate;

void main()
{
    gl_Position = position;
    textureCoordinate = inputTextureCoordinate.xy;
}

Fragment Shader:

片段着色器:

#ifdef GL_ES
precision mediump float;
#endif

varying vec2 textureCoordinate;

uniform sampler2D videoFrame;
uniform sampler2D videoFrameUV;

const mat3 yuv2rgb = mat3(
                          1, 0, 1.2802,
                          1, -0.214821, -0.380589,
                          1, 2.127982, 0
                          );

void main() {
    vec3 yuv = vec3(
                    1.1643 * (texture2D(videoFrame, textureCoordinate).r - 0.0625),
                    texture2D(videoFrameUV, textureCoordinate).r - 0.5,
                    texture2D(videoFrameUV, textureCoordinate).a - 0.5
                    );
    vec3 rgb = yuv * yuv2rgb;

    gl_FragColor = vec4(rgb, 1.0);
}

The renderImage function:

renderImage函数:

-(void)renderImage:(ImageBuffer *)image
{
    if (image)
    {        
        int bufferHeight = image->GetHeight();
        int bufferWidth = image->GetWidth();

        if(!imageTexture){
            // Dealing with the Y portion of the YCbCr
            glActiveTexture(GL_TEXTURE0);
            glGenTextures(1, &imageTexture);
            //Bind Y texture
            glBindTexture(GL_TEXTURE_2D, imageTexture);
            glUniform1i(uniforms[UNIFORM_VIDEOFRAME], 0);
            // For fitting
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            // This is necessary for non-power-of-two textures
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

            glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, bufferWidth, bufferHeight, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image->GetPlanePointer(0));

            // Dealing with the CbCr potion of the YCbCr
            glActiveTexture(GL_TEXTURE1);
            glGenTextures(1, &imageTextureUV);
            //Bind CbCr texture
            glBindTexture(GL_TEXTURE_2D, imageTextureUV);
            glUniform1i(uniforms[UNIFORM_VIDEOFRAMEUV], 1);
            // For fitting
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            // This is necessary for non-power-of-two textures
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

            glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, bufferWidth/2, bufferHeight/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, image->GetPlanePointer(1));

        }

        [self drawFrame];
    }
}

And finally, the drawFrame function:

最后,drawFrame函数:

- (void)drawFrame
{
    [self setFramebuffer];

    // Replace the implementation of this method to do your own custom drawing.
    static const GLfloat squareVertices[] = {
        -1.0f, -1.0f,
        1.0f, -1.0f,
        -1.0f, 1.0f,
        1.0f, 1.0f
    };

    static const GLfloat textureVertices[] = {
//        1.0f, 1.0f,
//        1.0f, 0.0f,
//        0.0f,  1.0f,
//        0.0f,  0.0f,
        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f
//        0.0f, 0.8f,
//        1.0f, 0.8f,
//        0.0f, 0.2f,
//        1.0f, 0.2f
    };

    static float transY = 0.0f;


    if ([context API] == kEAGLRenderingAPIOpenGLES2) {
        // Use shader program.
        glUseProgram(program);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, imageTexture);

        // Update attribute values.
        glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
        glEnableVertexAttribArray(ATTRIB_VERTEX);
        glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GL_FLOAT, 0, 0, textureVertices);
        glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITON);

        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, imageTextureUV);

        // Update attribute values.
        glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, squareVertices);
        glEnableVertexAttribArray(ATTRIB_VERTEX);
        glVertexAttribPointer(ATTRIB_TEXTUREPOSITON, 2, GL_FLOAT, 0, 0, textureVertices);
        glEnableVertexAttribArray(ATTRIB_TEXTUREPOSITON);

        // Validate program before drawing. This is a good check, but only really necessary in a debug build.
        // DEBUG macro must be defined in your debug configurations if that's not already the case.
#if defined(DEBUG)
        if (![self validateProgram:program]) {
            NSLog(@"Failed to validate program: %d", program);
            return;
        }
#endif
    } else {
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0.0f, (GLfloat)(sinf(transY)/2.0f), 0.0f);
        transY += 0.075f;

        glVertexPointer(2, GL_FLOAT, 0, squareVertices);
        glEnableClientState(GL_VERTEX_ARRAY);
    } 

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    [self presentFramebuffer];
}

1 个解决方案

#1


21  

Here is some snippets of code from my project 'movie player for iOS'.

这里是一些我的项目“电影播放器”的代码片段。

1. fragment shader

varying highp vec2 v_texcoord;  
uniform sampler2D s_texture_y;  
uniform sampler2D s_texture_u;  
uniform sampler2D s_texture_v;   
void main() {  
    highp float y = texture2D(s_texture_y, v_texcoord).r;  
    highp float u = texture2D(s_texture_u, v_texcoord).r - 0.5;  
    highp float v = texture2D(s_texture_v, v_texcoord).r - 0.5;  
    highp float r = y +             1.402 * v;  
    highp float g = y - 0.344 * u - 0.714 * v;  
    highp float b = y + 1.772 * u;  
    gl_FragColor = vec4(r,g,b,1.0);  
}

2. create textures from YUV420p frame

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);  
glGenTextures(3, _textures);  
const UInt8 *pixels[3] = { yuvFrame.luma.bytes, yuvFrame.chromaB.bytes, yuvFrame.chromaR.bytes };  
const NSUInteger widths[3]  = { frameWidth, frameWidth / 2, frameWidth / 2 };  
const NSUInteger heights[3] = { frameHeight, frameHeight / 2, frameHeight / 2 };  
for (int i = 0; i < 3; ++i) {  
    glBindTexture(GL_TEXTURE_2D, _textures[i]);  
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widths[i],heights[i],0,GL_LUMINANCE,GL_UNSIGNED_BYTE,pixels[i]);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  
}

3. init vertices and texture coords

static const GLfloat texCoords[] = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f };  
static const GLfloat vertices[]= {-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f };

4. render frame

[EAGLContext setCurrentContext:_context];  
glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);  
glViewport(0, 0, _backingWidth, _backingHeight);  
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);  
glClear(GL_COLOR_BUFFER_BIT);  
glUseProgram(_program);  
for (int i = 0; i < 3; ++i) {  
    glActiveTexture(GL_TEXTURE0 + i);  
    glBindTexture(GL_TEXTURE_2D, _textures[i]);  
    glUniform1i(_uniformSamplers[i], i);  
}  
glVertexAttribPointer(ATTRIBUTE_VERTEX, 2, GL_FLOAT, 0, 0, vertices);  
glEnableVertexAttribArray(ATTRIBUTE_VERTEX);  
glVertexAttribPointer(ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, 0, 0, texCoords);  
glEnableVertexAttribArray(ATTRIBUTE_TEXCOORD);  
glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);  
[_context presentRenderbuffer:GL_RENDERBUFFER];

The link to project on github.

链接到github上的项目。

#1


21  

Here is some snippets of code from my project 'movie player for iOS'.

这里是一些我的项目“电影播放器”的代码片段。

1. fragment shader

varying highp vec2 v_texcoord;  
uniform sampler2D s_texture_y;  
uniform sampler2D s_texture_u;  
uniform sampler2D s_texture_v;   
void main() {  
    highp float y = texture2D(s_texture_y, v_texcoord).r;  
    highp float u = texture2D(s_texture_u, v_texcoord).r - 0.5;  
    highp float v = texture2D(s_texture_v, v_texcoord).r - 0.5;  
    highp float r = y +             1.402 * v;  
    highp float g = y - 0.344 * u - 0.714 * v;  
    highp float b = y + 1.772 * u;  
    gl_FragColor = vec4(r,g,b,1.0);  
}

2. create textures from YUV420p frame

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);  
glGenTextures(3, _textures);  
const UInt8 *pixels[3] = { yuvFrame.luma.bytes, yuvFrame.chromaB.bytes, yuvFrame.chromaR.bytes };  
const NSUInteger widths[3]  = { frameWidth, frameWidth / 2, frameWidth / 2 };  
const NSUInteger heights[3] = { frameHeight, frameHeight / 2, frameHeight / 2 };  
for (int i = 0; i < 3; ++i) {  
    glBindTexture(GL_TEXTURE_2D, _textures[i]);  
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, widths[i],heights[i],0,GL_LUMINANCE,GL_UNSIGNED_BYTE,pixels[i]);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  
}

3. init vertices and texture coords

static const GLfloat texCoords[] = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f };  
static const GLfloat vertices[]= {-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f };

4. render frame

[EAGLContext setCurrentContext:_context];  
glBindFramebuffer(GL_FRAMEBUFFER, _framebuffer);  
glViewport(0, 0, _backingWidth, _backingHeight);  
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);  
glClear(GL_COLOR_BUFFER_BIT);  
glUseProgram(_program);  
for (int i = 0; i < 3; ++i) {  
    glActiveTexture(GL_TEXTURE0 + i);  
    glBindTexture(GL_TEXTURE_2D, _textures[i]);  
    glUniform1i(_uniformSamplers[i], i);  
}  
glVertexAttribPointer(ATTRIBUTE_VERTEX, 2, GL_FLOAT, 0, 0, vertices);  
glEnableVertexAttribArray(ATTRIBUTE_VERTEX);  
glVertexAttribPointer(ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, 0, 0, texCoords);  
glEnableVertexAttribArray(ATTRIBUTE_TEXCOORD);  
glBindRenderbuffer(GL_RENDERBUFFER, _renderbuffer);  
[_context presentRenderbuffer:GL_RENDERBUFFER];

The link to project on github.

链接到github上的项目。