Hi,
We are developing a video player that renders to a GL_TEXTURE_EXTERNAL_OES texture. I seems that the colour of the video is slightly wrong on our Galaxy S8 test device. (in fact the colour of this video seems wrong in any built in or 3rd party video player apps on this device) On every other device in our possession the colour seems fine. My guess would be (after a LOT of fiddling with the colorspaces etc) that maybe the internal YUV -> RGB conversion could be guilty? If that's the case, could there be any workaround? (right now I'm trying to write our own conversion, but I'm afraid that wouldn't be ideal considering all the possible YUV output formats http://bigflake.com/mediacodec/ - see "Q5")
Here is the video:
Here is the first frame exported in photoshop:
And here is screenshot from the built in video player from the device:
If you look carefully, you can see, that colour of the grass is a little off.
Thanks,
Peter
Thanks, I should definitely try this out! Could you maybe give me some direction how to work with this target? I've already read the specification but I can't really find any other resources and I'm not really the Open GL expert here - as you probably can tell :)
This is my current fragment shader:
#extension GL_OES_EGL_image_external : requireuniform samplerExternalOES texture;varying highp vec2 varTexCoordinate;void main(){ gl_FragColor = texture2D(texture, varTexCoordinate);}
And this is how my texture is bound:
GLES20.glActiveTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);GLES20.glGenTextures(1, textures, 0);GLES20.glBindTexture(0, textures[0]);
#version 310 es #extension GL_EXT_yuv_target : require precision mediump float; uniform mediump __samplerExternal2DY2YEXT uVideo; vec3 yuv_to_rgb(vec3 yuv) { yuv -= vec3(16.0 / 255.0, 128.0 / 255.0, 128.0 / 255.0); return yuv.xxx * 1.164 + yuv.yyy * vec3(0.0, -0.391, 2.018) + yuv.zzz * vec3(1.596, -0.813, 0.0); } out vec3 FragColor; in vec2 vTex; void main() { FragColor = yuv_to_rgb(texture(uVideo, vTex).rgb); }
Something like this to do manual YUV conversion. Replace yuv_to_rgb as you see fit.
Thanks so much! You definitely are my hero of the day :)
*except that i had to change GL_EXT_yuv_target to GL_EXT_YUV_target in the 2nd line
Hi again,
It turns out that there are some other phones (namely Huawei M8 and P9 - that I know of) that have the same issue, but they don't have the GL_EXT_YUV_target extension. Do you have any idea maybe, how the manual conversion could be done in this case?
Yeah, I know this isn't exactly the right forum for these questions, but it seems you are far more experienced in this area then I am. Maybe you can save me some couple more days of research :)
If it doesn't have EXT_yuv_target, you'll probably have to construct a custom transform which inverts the RGB -> YUV transforms and transforms to YUV again with a different matrix.
If input is BT.604 and you need BT.709, I suppose you can build a matrix
m = bt709_transform * inverse(bt604_transform) on CPU,
and pass that down to the fragment shader as a uniform. That's the best option I can think of. Does the video have proper color space set in the H.264 (?) stream to begin with though?
It turns out that this kind ofcolor space information wasn't specified in the video (just said yuv420p), so I tried to convert it to BT.601* and BT.709 as well. Unfortunately both gave the same output as the original. (weird?)
About those conversions... Still not an expert over here :D After some googling I've found this: https://www.mathworks.com/matlabcentral/fileexchange/36417-yuv-files-reading-and-converting?focused=5229495&tab=function&requestedDomain=www.mathworks.com Are these the droirds.. ahem matrices I am looking for?
Ok so, I got the conversions working for both formats, now I just can't determine when to use which one. Is there any way to find out which conversion OpenGL is using internally with samplerExternalOES textures?