Рендеринг YUV-видео в OpenGL ffmpeg с использованием CVPixelBufferRef и шейдеров - PullRequest
4 голосов
/ 05 марта 2012

Я использую для визуализации YUV-кадров ffmpeg с помощью метода iOS 5.0 "CVOpenGLESTextureCacheCreateTextureFromImage".

Я использую как пример с яблоком GLCameraRipple

Мой результат на экране iPhone такой: Экран iPhone

Iнужно знать, что я делаю неправильно.

Я поместил часть своего кода, чтобы найти ошибки.

ffmpeg configure frames:

ctx->p_sws_ctx = sws_getContext(ctx->p_video_ctx->width, 
                                ctx->p_video_ctx->height, 
                                ctx->p_video_ctx->pix_fmt, 
                                ctx->p_video_ctx->width, 
                                ctx->p_video_ctx->height,
                                PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);


// Framebuffer for RGB data
ctx->p_frame_buffer = malloc(avpicture_get_size(PIX_FMT_YUV420P,
                                                ctx->p_video_ctx->width, 
                                                ctx->p_video_ctx->height));

avpicture_fill((AVPicture*)ctx->p_picture_rgb, ctx->p_frame_buffer,PIX_FMT_YUV420P, 
               ctx->p_video_ctx->width, 
               ctx->p_video_ctx->height);

Мой метод рендеринга:

if (NULL == videoTextureCache) {
    NSLog(@"displayPixelBuffer error");
    return;
}    


CVPixelBufferRef pixelBuffer;    
   CVPixelBufferCreateWithBytes(kCFAllocatorDefault, mTexW, mTexH, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, buffer, mFrameW * 3, NULL, 0, NULL, &pixelBuffer);



CVReturn err;    
// Y-plane
glActiveTexture(GL_TEXTURE0);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, 
                                                   videoTextureCache,
                                                   pixelBuffer,
                                                   NULL,
                                                   GL_TEXTURE_2D,
                                                   GL_RED_EXT,
                                                   mTexW,
                                                   mTexH,
                                                   GL_RED_EXT,
                                                   GL_UNSIGNED_BYTE,
                                                   0,
                                                   &_lumaTexture);
if (err) 
{
    NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
}   

glBindTexture(CVOpenGLESTextureGetTarget(_lumaTexture), CVOpenGLESTextureGetName(_lumaTexture));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);     

// UV-plane
glActiveTexture(GL_TEXTURE1);
err = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, 
                                                   videoTextureCache,
                                                   pixelBuffer,
                                                   NULL,
                                                   GL_TEXTURE_2D,
                                                   GL_RG_EXT,
                                                   mTexW/2,
                                                   mTexH/2,
                                                   GL_RG_EXT,
                                                   GL_UNSIGNED_BYTE,
                                                   1,
                                                   &_chromaTexture);
if (err) 
{
    NSLog(@"Error at CVOpenGLESTextureCacheCreateTextureFromImage %d", err);
}

glBindTexture(CVOpenGLESTextureGetTarget(_chromaTexture), CVOpenGLESTextureGetName(_chromaTexture));
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);     

glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);

// Set the view port to the entire view
glViewport(0, 0, backingWidth, backingHeight);

static const GLfloat squareVertices[] = {
    1.0f, 1.0f,
    -1.0f, 1.0f,
    1.0f,  -1.0f,
    -1.0f,  -1.0f,
};

GLfloat textureVertices[] = {
    1, 1,
    1, 0,
    0, 1,
    0, 0,
};

// Draw the texture on the screen with OpenGL ES 2
[self renderWithSquareVertices:squareVertices textureVertices:textureVertices];


// Flush the CVOpenGLESTexture cache and release the texture
CVOpenGLESTextureCacheFlush(videoTextureCache, 0);    
CVPixelBufferRelease(pixelBuffer);     

 [moviePlayerDelegate bufferDone];

Метод RenderWithSquareVertices

    - (void)renderWithSquareVertices:(const GLfloat*)squareVertices textureVertices:(const GLfloat*)textureVertices
{


  // Use shader program.
    glUseProgram(shader.program);

// 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);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

// Present
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER];

}

Мой фрагментный шейдер:

uniform sampler2D SamplerY;
uniform sampler2D SamplerUV;


varying highp vec2 _texcoord;

void main()
{

mediump vec3 yuv;
lowp vec3 rgb;

yuv.x = texture2D(SamplerY, _texcoord).r;
yuv.yz = texture2D(SamplerUV, _texcoord).rg - vec2(0.5, 0.5);

// BT.601, which is the standard for SDTV is provided as a reference

/* rgb = mat3(    1,       1,     1,
 0, -.34413, 1.772,
 1.402, -.71414,     0) * yuv;*/


// Using BT.709 which is the standard for HDTV
rgb = mat3(      1,       1,      1,
           0, -.18732, 1.8556,
           1.57481, -.46813,      0) * yuv;

   gl_FragColor = vec4(rgb, 1);

}

Очень спасибо,

1 Ответ

1 голос
/ 04 сентября 2012

Я предполагаю, что проблема в том, что YUV420 (или I420) является трехплоскостным форматом изображения. I420 - это 8-битная плоскость Y, за которой следуют 8-битные 2x2 субсэмплированные плоскости U и V. Код из GLCameraRipple предполагает формат NV12: 8-битная плоскость Y, за которой следует чередующаяся плоскость U / V с подвыборкой 2x2. Учитывая это, я ожидаю, что вам понадобятся три текстуры. luma_tex, u_chroma_tex, v_chroma_tex.

Также обратите внимание, что GLCameraRipple также может ожидать «диапазон видео». Другими словами, значения для плоского формата: luma = [16,235] chroma = [16,240].

...