[MPlayer-dev-eng] [PATCH] yuv support for vo_gl

Reimar Döffinger Reimar.Doeffinger at stud.uni-karlsruhe.de
Fri Sep 9 12:11:14 CEST 2005


Hi,
On Fri, Sep 09, 2005 at 10:20:07AM +0200, Reimar D?ffinger wrote:
> On Fri, Sep 09, 2005 at 03:24:59AM +0400, Vladimir Mosgalin wrote:
> > There few anomalies within the image. First, it's brighter than it
> > should be. Since black pixels are really black, it's probably a matter
> > of gamma.
> > 
> > Second, the image has a slight greenish tint.
> 
> Yes, a bug in the fragment asm.
> 
> > Third, there is 1px wide green border in left and upper parts of the
> > picture.
> > Not solid green, but the color (a9,9b,90) changes to (68,c4,65)
> > (approx.) there.
> > It's unseen on black, but inspection shows that it is there, the color
> > is (0,13h,0).
> 
> I probably need to set the border colour for the textures, ssems for (some?) nVidia
> cards initializing the textures is enough...

Updated/fixed version. Report any bugs. Brightness/contrast behaves a
little weird at low values.

Greetings,
Reimar Döffinger
-------------- next part --------------
Index: libvo/gl_common.c
===================================================================
RCS file: /cvsroot/mplayer/main/libvo/gl_common.c,v
retrieving revision 1.17
diff -u -r1.17 gl_common.c
--- libvo/gl_common.c	25 Aug 2005 12:45:57 -0000	1.17
+++ libvo/gl_common.c	9 Sep 2005 10:06:56 -0000
@@ -18,6 +18,8 @@
 void (APIENTRY *ActiveTexture)(GLenum);
 void (APIENTRY *BindTexture)(GLenum, GLuint);
 void (APIENTRY *MultiTexCoord2f)(GLenum, GLfloat, GLfloat);
+void (APIENTRY *GenPrograms)(GLsizei, GLuint *);
+void (APIENTRY *DeletePrograms)(GLsizei, const GLuint *);
 void (APIENTRY *BindProgram)(GLenum, GLuint);
 void (APIENTRY *ProgramString)(GLenum, GLenum, GLsizei, const GLvoid *);
 void (APIENTRY *ProgramEnvParameter4f)(GLenum, GLuint, GLfloat, GLfloat,
@@ -246,6 +248,16 @@
   MultiTexCoord2f = getProcAddress("glMultiTexCoord2f");
   if (!MultiTexCoord2f)
     MultiTexCoord2f = getProcAddress("glMultiTexCoord2fARB");
+  GenPrograms = getProcAddress("glGenPrograms");
+  if (!GenPrograms)
+    GenPrograms = getProcAddress("glGenProgramsARB");
+  if (!GenPrograms)
+    GenPrograms = getProcAddress("glGenProgramsNV");
+  DeletePrograms = getProcAddress("glDeletePrograms");
+  if (!DeletePrograms)
+    DeletePrograms = getProcAddress("glDeleteProgramsARB");
+  if (!DeletePrograms)
+    DeletePrograms = getProcAddress("glDeleteProgramsNV");
   BindProgram = getProcAddress("glBindProgram");
   if (!BindProgram)
     BindProgram = getProcAddress("glBindProgramARB");
@@ -285,6 +297,7 @@
  */
 void glCreateClearTex(GLenum target, GLenum fmt, GLint filter,
                       int w, int h, char val) {
+  GLfloat border[4] = {val, val, val, val};
   GLenum clrfmt = (fmt == GL_ALPHA) ? GL_ALPHA : GL_LUMINANCE;
   char *init = (char *)malloc(w * h);
   memset(init, val, w * h);
@@ -296,6 +309,7 @@
   glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
   glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP);
   glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP);
+  glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, border);
   free(init);
 }
 
@@ -366,6 +380,117 @@
 }
 
 /**
+ * \brief Setup register combiners for YUV to RGB conversion.
+ */
+void glSetupYUVCombiners() {
+  GLfloat ucoef[] = { 0, -0.344, 1.770, 0 };
+  GLfloat vcoef[] = { 1.403, -0.714, 0, 0 };
+  GLint i;
+  glGetIntegerv(GL_MAX_GENERAL_COMBINERS_NV, &i);
+  if (i < 2)
+    mp_msg(MSGT_VO, MSGL_ERR,
+           "[gl] 2 general combiners needed for YUV combiner support (found %i)\n", i);
+  glGetIntegerv (GL_MAX_TEXTURE_UNITS, &i);
+  if (i < 3)
+    mp_msg(MSGT_VO, MSGL_ERR,
+           "[gl] 3 texture units needed for YUV combiner support (found %i)\n", i);
+  if (!CombinerInput || !CombinerOutput ||
+      !CombinerParameterfv || !CombinerParameteri) {
+    mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Combiner functions missing!\n", i);
+    return;
+  }
+  // coefficient (probably) must be in [0,1] range, so here comes the trick
+  // first put them in [-0.5, 0.5] range, then add 0.5
+  // can be undone with the HALF_BIAS and SCALE_BY_FOUR arguments
+  // for CombinerInput and CombinerOutput
+  for (i = 0; i < 4; i++) {
+    ucoef[i] = ucoef[i] * 0.25 + 0.5;
+    vcoef[i] = vcoef[i] * 0.25 + 0.5;
+  }
+  CombinerParameterfv(GL_CONSTANT_COLOR0_NV, ucoef);
+  CombinerParameterfv(GL_CONSTANT_COLOR1_NV, vcoef);
+
+  // UV first, like this green component can't overflow
+  CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV,
+                GL_TEXTURE1, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
+  CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
+                GL_CONSTANT_COLOR0_NV, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
+  CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV,
+                GL_TEXTURE2, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
+  CombinerInput(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV,
+                GL_CONSTANT_COLOR1_NV, GL_HALF_BIAS_NORMAL_NV, GL_RGB);
+  CombinerOutput(GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV,
+                 GL_SPARE0_NV, GL_SCALE_BY_FOUR_NV, GL_NONE, GL_FALSE,
+                 GL_FALSE, GL_FALSE);
+
+  // stage 2
+  CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_A_NV, GL_SPARE0_NV,
+                GL_SIGNED_IDENTITY_NV, GL_RGB);
+  CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_B_NV, GL_ZERO,
+                 GL_UNSIGNED_INVERT_NV, GL_RGB);
+  CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_C_NV,
+                GL_TEXTURE0, GL_SIGNED_IDENTITY_NV, GL_RGB);
+  CombinerInput(GL_COMBINER1_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO,
+                GL_UNSIGNED_INVERT_NV, GL_RGB);
+  CombinerOutput(GL_COMBINER1_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV,
+                 GL_SPARE0_NV, GL_NONE, GL_NONE, GL_FALSE,
+                 GL_FALSE, GL_FALSE);
+
+  // leave final combiner stage in default mode
+  CombinerParameteri(GL_NUM_GENERAL_COMBINERS_NV, 2);
+}
+
+static const char *yuv_prog_template =
+  "!!ARBfp1.0\n"
+  "TEMP res, u, v;\n"
+  "TEX res, fragment.texcoord[0], texture[0], 2D;\n"
+  "TEX u, fragment.texcoord[1], texture[1], 2D;\n"
+  "TEX v, fragment.texcoord[2], texture[2], 2D;\n"
+  "MAD res, res, {%.4f, %.4f, %.4f}, {%.4f, %.4f, %.4f};\n"
+  "MAD res, u, {%.4f, %.4f, %.4f}, res;\n"
+  "MAD result.color, v, {%.4f, %.4f, %.4f}, res;\n"
+  "END";
+
+void glSetupYUVFragprog(float bri, float cont, float uvcos, float uvsin) {
+  char yuv_prog[1000];
+  GLint i;
+  // this is the conversion matrix, with y, u, v factors
+  // for red, green, blue and the constant offsets
+  float ry, ru, rv, rc;
+  float gy, gu, gv, gc;
+  float by, bu, bv, bc;
+  glGetIntegerv (GL_MAX_TEXTURE_UNITS, &i);
+  if (i < 3)
+    mp_msg(MSGT_VO, MSGL_ERR,
+           "[gl] 3 texture units needed for YUV fragment support (found %i)\n", i);
+  if (!ProgramString) {
+    mp_msg(MSGT_VO, MSGL_FATAL, "[gl] ProgramString function missing!\n", i);
+    return;
+  }
+  ry = 1.164 * cont;
+  gy = 1.164 * cont;
+  by = 1.164 * cont;
+  ru = 0 * uvcos + 1.596 * uvsin;
+  rv = 0 * uvsin + 1.596 * uvcos;
+  gu = -0.391 * uvcos + -0.813 * uvsin;
+  gv = -0.391 * uvsin + -0.813 * uvcos;
+  bu = 2.018 * uvcos + 0 * uvsin;
+  bv = 2.018 * uvsin + 0 * uvcos;
+  rc = (-16 * ry + (-128) * ru + (-128) * rv) / 255.0 + bri;
+  gc = (-16 * gy + (-128) * gu + (-128) * gv) / 255.0 + bri;
+  bc = (-16 * by + (-128) * bu + (-128) * bv) / 255.0 + bri;
+  snprintf(yuv_prog, 1000, yuv_prog_template, ry, gy, by, rc, gc, bc,
+            ru, gu, bu, rv, gv, bv);
+  ProgramString(GL_FRAGMENT_PROGRAM, GL_PROGRAM_FORMAT_ASCII,
+                strlen(yuv_prog), yuv_prog);
+  glGetIntegerv(GL_PROGRAM_ERROR_POSITION, &i);
+  if (i != -1)
+    mp_msg(MSGT_VO, MSGL_ERR,
+      "[gl] Error compiling fragment program, make sure your card suports\n"
+      "GL_ARB_fragment_program (use glxinfo to check).");
+}
+
+/**
  * \brief draw a texture part at given 2D coordinates
  * \param x screen top coordinate
  * \param y screen left coordinate
@@ -381,18 +506,36 @@
  */
 void glDrawTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h,
                GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th,
-               int sx, int sy, int rect_tex) {
+               int sx, int sy, int rect_tex, int is_yv12) {
+  GLfloat tx2 = tx / 2, ty2 = ty / 2, tw2 = tw / 2, th2 = th / 2;
   if (!rect_tex) {
     tx /= sx; ty /= sy; tw /= sx; th /= sy;
+    tx2 = tx, ty2 = ty, tw2 = tw, th2 = th;
   }
   glBegin(GL_QUADS);
   glTexCoord2f(tx, ty);
+  if (is_yv12) {
+    MultiTexCoord2f(GL_TEXTURE1, tx2, ty2);
+    MultiTexCoord2f(GL_TEXTURE2, tx2, ty2);
+  }
   glVertex2f(x, y);
   glTexCoord2f(tx, ty + th);
+  if (is_yv12) {
+    MultiTexCoord2f(GL_TEXTURE1, tx2, ty2 + th2);
+    MultiTexCoord2f(GL_TEXTURE2, tx2, ty2 + th2);
+  }
   glVertex2f(x, y + h);
   glTexCoord2f(tx + tw, ty + th);
+  if (is_yv12) {
+    MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2 + th2);
+    MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2 + th2);
+  }
   glVertex2f(x + w, y + h);
   glTexCoord2f(tx + tw, ty);
+  if (is_yv12) {
+    MultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2);
+    MultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2);
+  }
   glVertex2f(x + w, y);
   glEnd();
 }
Index: libvo/gl_common.h
===================================================================
RCS file: /cvsroot/mplayer/main/libvo/gl_common.h,v
retrieving revision 1.14
diff -u -r1.14 gl_common.h
--- libvo/gl_common.h	25 Aug 2005 12:45:57 -0000	1.14
+++ libvo/gl_common.h	9 Sep 2005 10:06:57 -0000
@@ -17,6 +17,69 @@
 #include "x11_common.h"
 #endif
 
+// conditionally define all extension defines used
+// vendor specific extensions should be marked as such
+// (e.g. _NV), _ARB is not used to ease readability.
+#ifndef GL_MAX_GENERAL_COMBINERS_NV
+#define GL_MAX_GENERAL_COMBINERS_NV 0x854D
+#endif
+#ifndef GL_NUM_GENERAL_COMBINERS_NV
+#define GL_NUM_GENERAL_COMBINERS_NV 0x854E
+#endif
+#ifndef GL_CONSTANT_COLOR0_NV
+#define GL_CONSTANT_COLOR0_NV 0x852A
+#endif
+#ifndef GL_CONSTANT_COLOR1_NV
+#define GL_CONSTANT_COLOR1_NV 0x852B
+#endif
+#ifndef GL_COMBINER0_NV
+#define GL_COMBINER0_NV 0x8550
+#endif
+#ifndef GL_COMBINER1_NV
+#define GL_COMBINER1_NV 0x8551
+#endif
+#ifndef GL_VARIABLE_A_NV
+#define GL_VARIABLE_A_NV 0x8523
+#endif
+#ifndef GL_VARIABLE_B_NV
+#define GL_VARIABLE_B_NV 0x8524
+#endif
+#ifndef GL_VARIABLE_C_NV
+#define GL_VARIABLE_C_NV 0x8525
+#endif
+#ifndef GL_VARIABLE_D_NV
+#define GL_VARIABLE_D_NV 0x8526
+#endif
+#ifndef GL_UNSIGNED_INVERT_NV
+#define GL_UNSIGNED_INVERT_NV 0x8537
+#endif
+#ifndef GL_HALF_BIAS_NORMAL_NV
+#define GL_HALF_BIAS_NORMAL_NV 0x853A
+#endif
+#ifndef GL_SIGNED_IDENTITY_NV
+#define GL_SIGNED_IDENTITY_NV 0x853C
+#endif
+#ifndef GL_SCALE_BY_FOUR_NV
+#define GL_SCALE_BY_FOUR_NV 0x853F
+#endif
+#ifndef GL_DISCARD_NV
+#define GL_DISCARD_NV 0x8530
+#endif
+#ifndef GL_SPARE0_NV
+#define GL_SPARE0_NV 0x852E
+#endif
+#ifndef GL_MAX_TEXTURE_UNITS
+#define GL_MAX_TEXTURE_UNITS 0x84E2
+#endif
+#ifndef GL_TEXTURE0
+#define GL_TEXTURE0 0x84C0
+#endif
+#ifndef GL_TEXTURE1
+#define GL_TEXTURE1 0x84C1
+#endif
+#ifndef GL_TEXTURE2
+#define GL_TEXTURE2 0x84C2
+#endif
 #ifndef GL_TEXTURE_RECTANGLE
 #define GL_TEXTURE_RECTANGLE 0x84F5
 #endif
@@ -56,6 +119,15 @@
 #ifndef GL_UNSIGNED_SHORT_1_5_5_5_REV
 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366
 #endif
+#ifndef GL_FRAGMENT_PROGRAM
+#define GL_FRAGMENT_PROGRAM 0x8804
+#endif
+#ifndef GL_PROGRAM_FORMAT_ASCII
+#define GL_PROGRAM_FORMAT_ASCII 0x8875
+#endif
+#ifndef GL_PROGRAM_ERROR_POSITION
+#define GL_PROGRAM_ERROR_POSITION 0x864B
+#endif
 
 void glAdjustAlignment(int stride);
 
@@ -64,6 +136,8 @@
 int glFindFormat(uint32_t format, uint32_t *bpp, GLint *gl_texfmt,
                   GLenum *gl_format, GLenum *gl_type);
 int glFmt2bpp(GLenum format, GLenum type);
+void glSetupYUVCombiners();
+void glSetupYUVFragprog(float bri, float cont, float uvcos, float uvsin);
 void glCreateClearTex(GLenum target, GLenum fmt, GLint filter,
                       int w, int h, char val);
 void glUploadTex(GLenum target, GLenum format, GLenum type,
@@ -71,7 +145,7 @@
                  int x, int y, int w, int h, int slice);
 void glDrawTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h,
                GLfloat tx, GLfloat ty, GLfloat tw, GLfloat th,
-               int sx, int sy, int rect_tex);
+               int sx, int sy, int rect_tex, int is_yv12);
 
 //! could not set new window, will continue drawing into the old one.
 #define SET_WINDOW_FAILED -1
@@ -104,6 +178,8 @@
 extern void (APIENTRY *ActiveTexture)(GLenum);
 extern void (APIENTRY *BindTexture)(GLenum, GLuint);
 extern void (APIENTRY *MultiTexCoord2f)(GLenum, GLfloat, GLfloat);
+extern void (APIENTRY *GenPrograms)(GLsizei, GLuint *);
+extern void (APIENTRY *DeletePrograms)(GLsizei, const GLuint *);
 extern void (APIENTRY *BindProgram)(GLenum, GLuint);
 extern void (APIENTRY *ProgramString)(GLenum, GLenum, GLsizei, const GLvoid *);
 extern void (APIENTRY *ProgramEnvParameter4f)(GLenum, GLuint, GLfloat, GLfloat,
Index: libvo/vo_gl.c
===================================================================
RCS file: /cvsroot/mplayer/main/libvo/vo_gl.c,v
retrieving revision 1.93
diff -u -r1.93 vo_gl.c
--- libvo/vo_gl.c	5 Sep 2005 10:08:04 -0000	1.93
+++ libvo/vo_gl.c	9 Sep 2005 10:07:05 -0000
@@ -56,10 +56,12 @@
 static int osdtexCnt = 0;
 
 static int use_aspect;
+static int use_yuv;
 static int use_rectangle;
 static int err_shown;
 static uint32_t image_width;
 static uint32_t image_height;
+static uint32_t image_format;
 static int many_fmts;
 static int use_glFinish;
 static int swap_interval;
@@ -69,8 +71,18 @@
 static GLenum gl_type;
 static GLint gl_buffer;
 static int gl_buffersize;
+static GLint fragprog;
+static GLuint uvtexs[2];
 
 static int int_pause;
+static int eq_bri = 0;
+static int eq_cont = 0;
+static int eq_sat = 0;
+static int eq_hue = 0;
+static float gl_bri = 0.0;
+static float gl_cont = 1.0;
+static float gl_uvcos = 1.0;
+static float gl_uvsin = 0.0;
 
 static uint32_t texture_width;
 static uint32_t texture_height;
@@ -141,6 +153,29 @@
   mp_msg(MSGT_VO, MSGL_V, "[gl] Creating %dx%d texture...\n",
           texture_width, texture_height);
 
+  if (image_format == IMGFMT_YV12) {
+    fragprog = 0;
+    if (use_yuv == 1)
+      glSetupYUVCombiners();
+    else {
+      DeletePrograms(1, &fragprog);
+      GenPrograms(1, &fragprog);
+      BindProgram(GL_FRAGMENT_PROGRAM, fragprog);
+      glSetupYUVFragprog(gl_bri, gl_cont, gl_uvcos, gl_uvsin);
+    }
+    glDeleteTextures(2, uvtexs);
+    glGenTextures(2, uvtexs);
+    ActiveTexture(GL_TEXTURE1);
+    BindTexture(gl_target, uvtexs[0]);
+    glCreateClearTex(gl_target, gl_texfmt, GL_LINEAR,
+                     texture_width / 2, texture_height / 2, 128);
+    ActiveTexture(GL_TEXTURE2);
+    BindTexture(gl_target, uvtexs[1]);
+    glCreateClearTex(gl_target, gl_texfmt, GL_LINEAR,
+                     texture_width / 2, texture_height / 2, 128);
+    ActiveTexture(GL_TEXTURE0);
+    BindTexture(gl_target, 0);
+  }
   glCreateClearTex(gl_target, gl_texfmt, GL_LINEAR,
                    texture_width, texture_height, 0);
 
@@ -166,7 +201,13 @@
 	int tmp;
 	image_height = height;
 	image_width = width;
+	image_format = format;
 	glFindFormat(format, &tmp, &gl_texfmt, &gl_format, &gl_type);
+	if (format == IMGFMT_YV12) {
+	  gl_texfmt = GL_LUMINANCE8;
+	  gl_format = GL_LUMINANCE;
+	  gl_type = GL_UNSIGNED_BYTE;
+	}
 
 	int_pause = 0;
 
@@ -349,12 +390,12 @@
   // render alpha
   glBlendFunc(GL_ZERO, GL_SRC_ALPHA);
   BindTexture(gl_target, osdatex[osdtexCnt]);
-  glDrawTex(x0, y0, w, h, 0, 0, w, h, sx, sy, use_rectangle == 1);
+  glDrawTex(x0, y0, w, h, 0, 0, w, h, sx, sy, use_rectangle == 1, 0);
 #endif
   // render OSD
   glBlendFunc (GL_ONE, GL_ONE);
   BindTexture(gl_target, osdtex[osdtexCnt]);
-  glDrawTex(x0, y0, w, h, 0, 0, w, h, sx, sy, use_rectangle == 1);
+  glDrawTex(x0, y0, w, h, 0, 0, w, h, sx, sy, use_rectangle == 1, 0);
   glEndList();
 
   osdtexCnt++;
@@ -388,9 +429,32 @@
 //  glBindTexture(GL_TEXTURE_2D, texture_id);
 
   glColor3f(1,1,1);
+  if (image_format == IMGFMT_YV12) {
+    ActiveTexture(GL_TEXTURE1);
+    glEnable(gl_target);
+    ActiveTexture(GL_TEXTURE2);
+    glEnable(gl_target);
+    ActiveTexture(GL_TEXTURE0);
+    if (use_yuv == 1)
+      glEnable(GL_REGISTER_COMBINERS_NV);
+    else
+      glEnable(GL_FRAGMENT_PROGRAM);
+  }
   glDrawTex(0, 0, texture_width, texture_height,
             0, 0, texture_width, texture_height,
-            texture_width, texture_height, use_rectangle == 1);
+            texture_width, texture_height,
+            use_rectangle == 1, image_format == IMGFMT_YV12);
+  if (image_format == IMGFMT_YV12) {
+    if (use_yuv == 1)
+      glDisable(GL_REGISTER_COMBINERS_NV);
+    else
+      glDisable(GL_FRAGMENT_PROGRAM);
+    ActiveTexture(GL_TEXTURE2);
+    glDisable(gl_target);
+    ActiveTexture(GL_TEXTURE1);
+    glDisable(gl_target);
+    ActiveTexture(GL_TEXTURE0);
+  }
 
   if (osdtexCnt > 0) {
     // set special rendering parameters
@@ -426,6 +490,17 @@
 //static inline uint32_t draw_slice_x11(uint8_t *src[], uint32_t slice_num)
 static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y)
 {
+  glUploadTex(gl_target, gl_format, gl_type, src[0], stride[0],
+              x, y, w, h, slice_height);
+  if (image_format == IMGFMT_YV12) {
+    ActiveTexture(GL_TEXTURE1);
+    glUploadTex(gl_target, gl_format, gl_type, src[1], stride[1],
+                x / 2, y / 2, w / 2, h / 2, slice_height);
+    ActiveTexture(GL_TEXTURE2);
+    glUploadTex(gl_target, gl_format, gl_type, src[2], stride[2],
+                x / 2, y / 2, w / 2, h / 2, slice_height);
+    ActiveTexture(GL_TEXTURE0);
+  }
 	return 0;
 }
 
@@ -459,6 +534,15 @@
     err_shown = 1;
     return VO_FALSE;
   }
+  if (mpi->imgfmt == IMGFMT_YV12) {
+    // YV12
+    mpi->flags |= MP_IMGFLAG_COMMON_STRIDE | MP_IMGFLAG_COMMON_PLANE;
+    mpi->stride[0] = mpi->width;
+    mpi->planes[1] = mpi->planes[0] + mpi->stride[0] * mpi->height;
+    mpi->stride[1] = mpi->width >> 1;
+    mpi->planes[2] = mpi->planes[1] + mpi->stride[1] * (mpi->height >> 1);
+    mpi->stride[2] = mpi->width >> 1;
+  }
   mpi->flags |= MP_IMGFLAG_DIRECT;
   return VO_TRUE;
 }
@@ -476,6 +560,17 @@
   }
   glUploadTex(gl_target, gl_format, gl_type, data, mpi->stride[0],
               mpi->x, mpi->y, mpi->w, mpi->h, slice);
+  if (mpi->imgfmt == IMGFMT_YV12) {
+    data += mpi->planes[1] - mpi->planes[0];
+    ActiveTexture(GL_TEXTURE1);
+    glUploadTex(gl_target, gl_format, gl_type, data, mpi->stride[1],
+                mpi->x / 2, mpi->y / 2, mpi->w / 2, mpi->h / 2, slice);
+    data += mpi->planes[2] - mpi->planes[1];
+    ActiveTexture(GL_TEXTURE2);
+    glUploadTex(gl_target, gl_format, gl_type, data, mpi->stride[2],
+                mpi->x / 2, mpi->y / 2, mpi->w / 2, mpi->h / 2, slice);
+    ActiveTexture(GL_TEXTURE0);
+  }
   if (mpi->flags & MP_IMGFLAG_DIRECT)
     BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
   return VO_TRUE;
@@ -496,6 +591,8 @@
       caps |= VFCAP_OSD;
     if ((format == IMGFMT_RGB24) || (format == IMGFMT_RGBA))
         return caps;
+    if (use_yuv && format == IMGFMT_YV12)
+        return caps;
     if (many_fmts &&
          glFindFormat(format, NULL, NULL, NULL, NULL))
         return caps;
@@ -522,6 +619,7 @@
   {"aspect",       OPT_ARG_BOOL, &use_aspect,   NULL},
   {"slice-height", OPT_ARG_INT,  &slice_height, (opt_test_f)int_non_neg},
   {"rectangle",    OPT_ARG_INT,  &use_rectangle,(opt_test_f)int_non_neg},
+  {"yuv",          OPT_ARG_INT,  &use_yuv,      (opt_test_f)int_non_neg},
   {"glfinish",     OPT_ARG_BOOL, &use_glFinish, NULL},
   {"swapinterval", OPT_ARG_INT,  &swap_interval,NULL},
   {NULL}
@@ -534,6 +632,7 @@
     use_osd = 1;
     scaled_osd = 0;
     use_aspect = 1;
+    use_yuv = 0;
     use_rectangle = 0;
     use_glFinish = 0;
     swap_interval = 1;
@@ -561,6 +660,10 @@
               "    Interval in displayed frames between to buffer swaps.\n"
               "    1 is equivalent to enable VSYNC, 0 to disable VSYNC.\n"
               "    Requires GLX_SGI_swap_control support to work.\n"
+              "  yuv=<n>\n"
+              "    0: use software YUV to RGB conversion.\n"
+              "    1: use register combiners (nVidia only).\n"
+              "    2: use fragment program\n"
               "\n" );
       return -1;
     }
@@ -579,6 +682,16 @@
     return 0;
 }
 
+static void update_fragprog() {
+  double angle = eq_hue / 100.0 * 3.1415927;
+  gl_bri = eq_bri / 100.0;
+  gl_cont = (eq_cont + 100) / 100.0;
+  gl_uvcos = (eq_sat + 100) / 100.0 * cos(angle);
+  gl_uvsin = (eq_sat + 100) / 100.0 * sin(angle);
+  glSetupYUVFragprog(gl_bri, gl_cont, gl_uvcos, gl_uvsin);
+}
+
+
 static int control(uint32_t request, void *data, ...)
 {
   switch (request) {
@@ -614,6 +727,46 @@
     if (!use_aspect) return VO_NOTIMPL;
     resize (vo_dwidth, vo_dheight);
     return VO_TRUE;
+  case VOCTRL_GET_EQUALIZER:
+    {
+      va_list va;
+      int *value;
+      va_start(va, data);
+      value = va_arg(va, int *);
+      va_end(va);
+      if (strcasecmp(data, "brightness") == 0)
+        *value = eq_bri;
+      else if (strcasecmp(data, "contrast") == 0)
+        *value = eq_cont;
+      else if (strcasecmp(data, "saturation") == 0)
+        *value = eq_sat;
+      else if (strcasecmp(data, "hue") == 0)
+        *value = eq_hue;
+      if (image_format == IMGFMT_YV12 && use_yuv == 2)
+        return VO_TRUE;
+      break;
+    }
+  case VOCTRL_SET_EQUALIZER:
+    {
+      va_list va;
+      int value;
+      va_start(va, data);
+      value = va_arg(va, int);
+      va_end(va);
+      if (strcasecmp(data, "brightness") == 0)
+        eq_bri = value;
+      else if (strcasecmp(data, "contrast") == 0)
+        eq_cont = value;
+      else if (strcasecmp(data, "saturation") == 0)
+        eq_sat = value;
+      else if (strcasecmp(data, "hue") == 0)
+        eq_hue = value;
+      if (image_format == IMGFMT_YV12 && use_yuv == 2) {
+        update_fragprog();
+        return VO_TRUE;
+      }
+      break;
+    }
   }
   return VO_NOTIMPL;
 }
Index: libvo/vo_gl2.c
===================================================================
RCS file: /cvsroot/mplayer/main/libvo/vo_gl2.c,v
retrieving revision 1.75
diff -u -r1.75 vo_gl2.c
--- libvo/vo_gl2.c	25 Aug 2005 12:45:57 -0000	1.75
+++ libvo/vo_gl2.c	9 Sep 2005 10:07:07 -0000
@@ -484,7 +484,7 @@
 
       glDrawTex(square->fx, square->fy, square->fw, square->fh,
                 0, 0, texture_width, texture_height,
-                texture_width, texture_height, 0);
+                texture_width, texture_height, 0, 0);
       square++;
     } /* for all texnumx */
   } /* for all texnumy */


More information about the MPlayer-dev-eng mailing list