[轉載]YUV格式紋理貼圖的例子

frameworks/native/opengl/tests/gl2_yuvtex/gl2_yuvtex.cpp 是Android提供的yuv格式紋理貼圖的例子。
 
前面先申請存放紋理數據的buffer
yuvTexBuffer = new GraphicBuffer(yuvTexWidth, yuvTexHeight, yuvTexFormat, yuvTexUsage);
其中 yuvTexFormat = HAL_PIXEL_FORMAT_YV12
 
class GraphicBuffer在 frameworks/native/include/ui/GraphicBuffer.h 中定義,其初始化函數通過initSize調用allocator.alloc申請空間。allocator是GraphicBufferAllocator的引用,這個class包含了alloc_device_t變量,是grallocHAL模塊中alloc設備使用的結構體,完成對圖形緩衝區的管理,實現從硬件內存到應用地址的映射。
 
後續會通過vendor driver提供的eglCreateImageKHR調用dpy->winsys->get_native_buffer,到winsysp_native_buffer_validate,get_buffer_egl_format,再到hal_format_to_egl_format,完成從HAL format到egl format的映射,例如 HAL_PIXEL_FORMAT_YV12 <-> EGL_COLOR_BUFFER_FORMAT_YV12_BT601_NARROW
配置在 arm/xxx/android/config/mali_config_interface_reference.cpp
 
在eglCreateImageKHR通過get_native_buffer到egl_color_buffer_wrap_external_planar生成EGLImageKHR後,調用glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image),從EGLImageKHR產生紋理。
 
這個過程利用了OpenGL的extension - GL_OES_EGL_image_external
這個extension定義了一個新的texture target - TEXTURE_EXTERNAL_OES;相應地在shader中增加了一個新的sampler類型 - samplerExternalOES,是a handle for accessing an external texture。
注意:這個extension已經過時,應該使用GL_OES_EGL_image_external_essl3
 
Vulkan則用VkSamplerYcbcrModelConversion定義了從source color model到shader color model的轉換。
typedef enum VkSamplerYcbcrModelConversion {
 VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY=0,    // input values unmodified
  VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY=1,  // no conversion but range expanded
  VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709=2,       // YCbCr to RGB as defined in BT.709
  VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601=3,      // YCbCr to RGB as defined in BT.601
  VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020=4,     // YCbCr to RGB as defined in BT.2020
} VkSamplerYcbcrModelConversion;
 
 
原程序的YUV值共有2^3=8種組合,所以輸出色塊共有8種顏色。爲了調試方便可以改動賦值以輸出純色,以紅色(255, 0, 0)爲例,
Y =  0.257 * R + 0.504 * G + 0.098 * B + 16  =  0.257 * 255 + 16  = 81
U = -0.148 * R - 0.291 * G + 0.439 * B + 128 = -0.148 * 255 + 128 = 90
V =  0.439 * R - 0.368 * G - 0.071 * B + 128 =  0.439 * 255 + 128 = 240
 
在修改yuvTexWidth = yuvTexHeight = 128的情況下,
yuvTexStrideY = 128
yuvTexOffsetV = 16384  yuvTexStrideV = 64
yuvTexOffsetU = 20480  yuvTexStrideU = 64
 
爲了檢查輸出,可以在renderFrame和eglSwapBuffers之間插入glReadPixels如下:
GLubyte *pixels = (GLubyte *) calloc(4, sizeof(GLubyte));
glReadPixels(w/2, h/2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
printf("RGBA values: %d %d %d %d\n", pixels[0], pixels[1], pixels[2], pixels[3]);
free(pixels);
 
另外ISP信號通常使用YUV420SP也就是NV21格式。
HAL_PIXEL_FORMAT_YCrCb_420_SP <-> EGL_COLOR_BUFFER_FORMAT_NV21_BT601_NARROW

 

 

 

 

 

 

http://blog.sina.com.cn/s/blog_5423c45a0102xk7h.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章