changeset 18655:6aa0b26d584b

Add yuv to rgb conversion using a 3D lookup texture
author reimar
date Thu, 08 Jun 2006 19:02:56 +0000
parents 9fb5e9cdcae8
children e30061e7e1f8
files DOCS/man/en/mplayer.1 libvo/gl_common.c libvo/gl_common.h
diffstat 3 files changed, 84 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/DOCS/man/en/mplayer.1	Thu Jun 08 18:56:33 2006 +0000
+++ b/DOCS/man/en/mplayer.1	Thu Jun 08 19:02:56 2006 +0000
@@ -3076,6 +3076,12 @@
 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).
--- a/libvo/gl_common.c	Thu Jun 08 18:56:33 2006 +0000
+++ b/libvo/gl_common.c	Thu Jun 08 19:02:56 2006 +0000
@@ -723,6 +723,10 @@
   "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 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 @@
       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 @@
                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 @@
       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 @@
       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 @@
       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:
--- a/libvo/gl_common.h	Thu Jun 08 18:56:33 2006 +0000
+++ b/libvo/gl_common.h	Thu Jun 08 19:02:56 2006 +0000
@@ -227,6 +227,8 @@
 #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