1
mirror of https://github.com/mpv-player/mpv synced 2024-11-18 21:16:10 +01:00

Add yuv to rgb conversion using a 3D lookup texture

git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@18656 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
reimar 2006-06-08 19:02:56 +00:00
parent dd5f3f5824
commit 497b2f561e
3 changed files with 84 additions and 0 deletions

View File

@ -3076,6 +3076,12 @@ GL_ARB_fragment_shader!).
At least three texture units are needed.
Provides saturation and hue control.
This method is fast but inexact.
.br
6: Use a 3D texture to do conversion via lookup.
Needs the GL_ARB_fragment_program extension and at least four texture units.
Provides brightness, contrast, saturation, hue and gamma control.
Gamma can also be set independently for red, green and blue.
Speed depends more on GPU memory bandwidth than other methods.
.RE
.IPs [l|c]scaler=<n>
Select the scaling function to use (seperately for luma and chroma).

View File

@ -723,6 +723,10 @@ static const char *yuv_lookup_prog_template =
"TEX result.color.b, res.baaa, texture[%c], 2D;"
"END";
static const char *yuv_lookup3d_prog_template =
"TEX result.color, yuv, texture[%c], 3D;"
"END";
static void create_scaler_textures(int scaler, int *texu, char *texs) {
switch (scaler) {
case YUV_SCALER_BILIN:
@ -737,10 +741,50 @@ static void create_scaler_textures(int scaler, int *texu, char *texs) {
}
}
static void gen_yuv2rgb_map(unsigned char *map, int size, float brightness,
float contrast, float uvcos, float uvsin,
float rgamma, float ggamma, float bgamma) {
int i, j, k;
float step = 1.0 / size;
float y, u, v, u_, v_;
float r, g, b;
v = -0.5;
for (i = -1; i <= size; i++) {
u = -0.5;
for (j = -1; j <= size; j++) {
y = -(16.0 / 255.0);
for (k = -1; k <= size; k++) {
u_ = uvcos * u + uvsin * v;
v_ = uvcos * v + uvsin * u;
r = 1.164 * y + 1.596 * v_;
g = 1.164 * y - 0.391 * u_ - 0.813 * v_;
b = 1.164 * y + 2.018 * u_ ;
r = pow(contrast * (r - 0.5) + 0.5 + brightness, 1.0 / rgamma);
g = pow(contrast * (g - 0.5) + 0.5 + brightness, 1.0 / ggamma);
b = pow(contrast * (b - 0.5) + 0.5 + brightness, 1.0 / bgamma);
if (r > 1) r = 1;
if (r < 0) r = 0;
if (g > 1) g = 1;
if (g < 0) g = 0;
if (b > 1) b = 1;
if (b < 0) b = 0;
*map++ = 255 * r;
*map++ = 255 * g;
*map++ = 255 * b;
y += (k == -1 || k == size - 1) ? step / 2 : step;
}
u += (j == -1 || j == size - 1) ? step / 2 : step;
}
v += (i == -1 || i == size - 1) ? step / 2 : step;
}
}
static void gen_gamma_map(unsigned char *map, int size, float gamma);
//! resolution of texture for gamma lookup table
#define LOOKUP_RES 512
//! resolution for 3D yuv->rgb conversion lookup table
#define LOOKUP_3DRES 32
static void create_conv_textures(int conv, int *texu, char *texs,
int brightness, int contrast, int uvcos, int uvsin,
int rgamma, int ggamma, int bgamma) {
@ -763,6 +807,32 @@ static void create_conv_textures(int conv, int *texu, char *texs,
ActiveTexture(GL_TEXTURE0);
texs[0] += '0';
break;
case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
{
int sz = LOOKUP_3DRES + 2; // texture size including borders
if (!TexImage3D) {
mp_msg(MSGT_VO, MSGL_ERR, "[gl] Missing 3D texture function!\n");
break;
}
texs[0] = (*texu)++;
ActiveTexture(GL_TEXTURE0 + texs[0]);
lookup_data = malloc(3 * sz * sz * sz);
gen_yuv2rgb_map(lookup_data, LOOKUP_3DRES, brightness, contrast,
uvcos, uvsin, rgamma, ggamma, bgamma);
glAdjustAlignment(sz);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
TexImage3D(GL_TEXTURE_3D, 0, 3, sz, sz, sz, 1,
GL_RGB, GL_UNSIGNED_BYTE, lookup_data);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_PRIORITY, 1.0);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
ActiveTexture(GL_TEXTURE0);
texs[0] += '0';
}
break;
default:
mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", conv);
}
@ -929,6 +999,9 @@ static void glSetupYUVFragprog(float brightness, float contrast,
ry, gy, by, ru, gu, bu, rv, gv, bv, rc, gc, bc,
conv_texs[0], conv_texs[0], conv_texs[0]);
break;
case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
snprintf(prog_pos, prog_remain, yuv_lookup3d_prog_template, conv_texs[0]);
break;
default:
mp_msg(MSGT_VO, MSGL_ERR, "[gl] unknown conversion type %i\n", YUV_CONVERSION(type));
break;
@ -983,6 +1056,7 @@ void glSetupYUVConversion(GLenum target, int type,
glSetupYUVCombinersATI(uvcos, uvsin);
break;
case YUV_CONVERSION_FRAGMENT_LOOKUP:
case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
case YUV_CONVERSION_FRAGMENT:
case YUV_CONVERSION_FRAGMENT_POW:
glSetupYUVFragprog(brightness, contrast, uvcos, uvsin,
@ -1020,6 +1094,7 @@ void glEnableYUVConversion(GLenum target, int type) {
ActiveTexture(GL_TEXTURE0);
glEnable(GL_FRAGMENT_SHADER_ATI);
break;
case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
case YUV_CONVERSION_FRAGMENT_LOOKUP:
case YUV_CONVERSION_FRAGMENT_POW:
case YUV_CONVERSION_FRAGMENT:
@ -1053,6 +1128,7 @@ void glDisableYUVConversion(GLenum target, int type) {
ActiveTexture(GL_TEXTURE0);
glDisable(GL_FRAGMENT_SHADER_ATI);
break;
case YUV_CONVERSION_FRAGMENT_LOOKUP3D:
case YUV_CONVERSION_FRAGMENT_LOOKUP:
case YUV_CONVERSION_FRAGMENT_POW:
case YUV_CONVERSION_FRAGMENT:

View File

@ -227,6 +227,8 @@ int loadGPUProgram(GLenum target, char *prog);
#define YUV_CONVERSION_FRAGMENT_LOOKUP 4
//! use ATI specific register combiners ("fragment program")
#define YUV_CONVERSION_COMBINERS_ATI 5
//! use a fragment program with 3D table lookup for YUV conversion
#define YUV_CONVERSION_FRAGMENT_LOOKUP3D 6
//! use normal bilinear scaling for textures
#define YUV_SCALER_BILIN 0
//! use higher quality bicubic scaling for textures