Android 使用OpenGL ES 2.0将YUV420P转换为RGBA

Android 使用OpenGL ES 2.0将YUV420P转换为RGBA,android,opengl-es,opengl-es-2.0,yuv,Android,Opengl Es,Opengl Es 2.0,Yuv,我正在Android上使用OpenGL ES 2.0处理视频。图片数据被提取为YUV420P,我需要在我的OpenGL片段着色器的RGBA中处理它们 如何将YUV420P数据转换为RGBA?(鉴于视频,性能是关键) 更新:感谢Brad Larsson的回答,但看起来不太对劲 更新2:Duh,我仍然在使用我的RGBA片段着色器。当然,它看起来是错的。现在我有另一个问题。让我进一步挖掘 更新3:好吧,这里有点不对劲 我用这个做纹理。这是正确的吗 glTexImage2D(GL_TEXTURE_2D

我正在Android上使用OpenGL ES 2.0处理视频。图片数据被提取为YUV420P,我需要在我的OpenGL片段着色器的RGBA中处理它们

如何将YUV420P数据转换为RGBA?(鉴于视频,性能是关键)

更新:感谢Brad Larsson的回答,但看起来不太对劲

更新2:Duh,我仍然在使用我的RGBA片段着色器。当然,它看起来是错的。现在我有另一个问题。让我进一步挖掘

更新3:好吧,这里有点不对劲

我用这个做纹理。这是正确的吗

glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, luminanceBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width / 2, height / 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, chrominanceBuffer);

更新4:使用
GL\u LUMINANCE\u ALPHA
解决了交错问题,但图片仍然损坏,但。。。我刚刚了解到问题在于我的字节缓冲区,所以将这个标记为已回答。

苹果有几个iOS示例,其中他们在OpenGL ES 2.0着色器中将YUV420平面数据转换为RGBA。虽然不是专门针对Android的,但您应该仍然能够使用此GLSL着色器代码来实现您想要的功能

这是我在基于其示例的转换片段着色器中使用的内容:

 varying highp vec2 textureCoordinate;

 uniform sampler2D luminanceTexture;
 uniform sampler2D chrominanceTexture;

 void main()
 {
     mediump vec3 yuv;
     lowp vec3 rgb;

     yuv.x = texture2D(luminanceTexture, textureCoordinate).r;
     yuv.yz = texture2D(chrominanceTexture, textureCoordinate).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, -.39465, 2.03211,
      1.13983, -.58060,       0) * yuv;
      */

     // Using BT.709 which is the standard for HDTV
     rgb = mat3(      1,       1,       1,
                0, -.21482, 2.12798,
                1.28033, -.38059,       0) * yuv;

     gl_FragColor = vec4(rgb, 1);
 }
亮度纹理
是作为纹理的图像的Y平面,
色度纹理
是UV平面


我相信上面是为视频范围YUV调整的,所以您可能需要为全范围YUV调整这些值。对于iPhone 4S上的1080p视频帧,此着色器的运行时间仅为几分之一毫秒。

谢谢您的回答。我要试试这个。如何上传这两套制服?我假设我上传亮度缓冲区作为GL_亮度,但是较小的色度缓冲区应该使用什么?还有我要的亮度吗?我用现在的样子更新了我的问题。有些地方出了点问题。@BlueVoodoo-GL\u亮度应该适合亮度平面(A5 iOS设备有一个很好的GL\u RED\u EXT one组件格式,非常适合这种格式)。不过,色度纹理需要不止一个组件,因为其中有交错的UV组件。GL_LUMINANCE_ALPHA可能是实现这一点的方法(同样,A5 iOS设备的GL_RG_EXT也是一种很好的类型)。更多信息请参见此处的示例(iOS,但仍然适用):为什么选择apple 1和2组件扩展而不是标准版本?@brad你确定吗?luma/luma_alpha可以与A4/A5上的纹理缓存配合使用,并且不会在内部转换为RGBA。我观察到的苹果扩展之间的唯一区别是texel布局。。。我遗漏了什么吗?如果您使用
glu亮度
红色和绿色通道都包含相同的值。如果你想遵循Brad的答案,你应该设法使
GL\u RG
成为可能。我不确定
GL\u LUMINANCE\u ALPHA
有什么作用,但它可能包含红/绿/蓝(它们是相同的)和ALPHA的单独值。尝试了一些不同的组合,但无法使其工作,除非它是GL\u LUMINANCE。在上面的屏幕截图上,看起来上半部分具有原始视频帧下半部分的亮度级别。