Подтвердить что ты не робот

IOS - Как нарисовать изображение YUV с помощью openGL

В настоящее время я пытаюсь сделать изображение с помощью openGL (обновления изображений очень часто и, следовательно, необходимо перерисовать). Раньше я преобразовывал свое изображение из YUV в RGB, а затем использовал это новое изображение для рисования с помощью openGL. Все работало нормально, но процесс преобразования не был особенно быстрым.

Теперь я пытаюсь изменить код, чтобы в шейдерах openGL учитывалось преобразование. Осмотревшись, я нашел несколько фрагментов кода (особенно шейдеров и основную часть моей функции renderImage), которые помогли мне получить базовую линию, но я не могу заставить изображение правильно рисовать - все, что я когда-либо делал см. черное изображение.

Весьма вероятно, что мне не хватает чего-то чрезвычайно простого и важного. Мой опыт работы с openGL довольно ограничен. Если кто-нибудь может взглянуть и посмотреть, узнают ли они что-нибудь не так, пожалуйста, дайте мне знать.

Я должен указать, я пытаюсь поддерживать iOS 4.x, поэтому CVOpenGLESTextureCacheCreateTextureFromImage не должен использоваться (и я не очень уверен, как настроить его, даже если бы захотел).

Любая помощь будет оценена по достоинству. Код ниже -

Мой вершинный шейдер:

attribute vec4 position;
attribute vec4 inputTextureCoordinate;

varying vec2 textureCoordinate;

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

Фрагментный шейдер:

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

Функция 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];
    }
}

И, наконец, функция 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 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];
}
4b9b3361

Ответ 1

Вот несколько фрагментов кода из моего проекта "Movie Player для iOS".

1. фрагментарный шейдер

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. создавать текстуры из кадра YUV420p

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 вершины и текстурные координаты

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. кадр рендеринга

[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];

Ссылка на проект в github.