changeset 34983:0034a2bf7b42

Support interleaving the two frame halves from a 3D video by an arbitrary 4x4 pattern. This should allow direct playback on some 3D TVs.
author reimar
date Sun, 12 Aug 2012 17:15:35 +0000
parents df138f843ebc
children c24d1a0c7665
files DOCS/man/en/mplayer.1 libvo/gl_common.c libvo/gl_common.h libvo/vo_gl.c libvo/vo_gl2.c
diffstat 5 files changed, 122 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/DOCS/man/en/mplayer.1	Sun Aug 12 13:24:54 2012 +0000
+++ b/DOCS/man/en/mplayer.1	Sun Aug 12 17:15:35 2012 +0000
@@ -4301,7 +4301,16 @@
 .IPs 3
 Convert side by side input to quadbuffered stereo.
 Only supported by very few OpenGL cards.
-.RE
+.IPs 4
+Mix left and right in a pixel pattern.
+Pattern is given by stipple option.
+.RE
+.IPs stipple=<bit pattern>
+Lowest 16 bit give the 4x4 pattern to use (default: 0x0f0f).
+Examples to try:
+0x0f0f, 0xf0f0: horizontal lines;
+0xaaaa, 0x5555: vertical lines;
+0xa5a5, 0x5a5a: checkerboard pattern
 .RE
 .sp 1
 .RS
--- a/libvo/gl_common.c	Sun Aug 12 13:24:54 2012 +0000
+++ b/libvo/gl_common.c	Sun Aug 12 17:15:35 2012 +0000
@@ -1394,7 +1394,7 @@
     "TEMP coord, coord2, cdelta, parmx, parmy, a, b, yuv;\n";
   int prog_remain;
   char *yuv_prog, *prog_pos;
-  int cur_texu = 3;
+  int cur_texu = 3 + params->has_alpha_tex;
   char lum_scale_texs[1];
   char chrom_scale_texs[1];
   char conv_texs[1];
@@ -1486,6 +1486,11 @@
     prog_remain -= strlen(prog_pos);
     prog_pos    += strlen(prog_pos);
   }
+  if (params->has_alpha_tex) {
+    snprintf(prog_pos, prog_remain, "TEX result.color.a, fragment.texcoord[3], texture[3], 2D;\n");
+    prog_remain -= strlen(prog_pos);
+    prog_pos    += strlen(prog_pos);
+  }
   snprintf(prog_pos, prog_remain, "MOV result.color.rgb, res;\nEND");
 
   mp_msg(MSGT_VO, MSGL_DBG2, "[gl] generated fragment program:\n%s\n", yuv_prog);
@@ -1634,6 +1639,24 @@
   }
 }
 
+void glSetupAlphaStippleTex(unsigned pattern) {
+  int i;
+  uint8_t stipple[16];
+  for (i = 0; i < 16; i++) {
+    stipple[i] = (pattern & 1) * 0xff;
+    pattern >>= 1;
+  }
+  mpglActiveTexture(GL_TEXTURE3);
+  glAdjustAlignment(2);
+  mpglPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+  mpglTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 4, 4, 0, GL_ALPHA, GL_UNSIGNED_BYTE, stipple);
+  mpglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+  mpglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+  mpglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+  mpglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+  mpglActiveTexture(GL_TEXTURE0);
+}
+
 void glEnable3DLeft(int type) {
   GLint buffer;
   if (type & GL_3D_SWAP)
@@ -1661,6 +1684,13 @@
       }
       mpglDrawBuffer(buffer);
       break;
+    case GL_3D_STIPPLE:
+      mpglActiveTexture(GL_TEXTURE3);
+      mpglEnable(GL_TEXTURE_2D);
+      mpglActiveTexture(GL_TEXTURE0);
+      mpglEnable(GL_BLEND);
+      mpglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+      break;
   }
 }
 
@@ -1691,6 +1721,13 @@
       }
       mpglDrawBuffer(buffer);
       break;
+    case GL_3D_STIPPLE:
+      mpglActiveTexture(GL_TEXTURE3);
+      mpglEnable(GL_TEXTURE_2D);
+      mpglActiveTexture(GL_TEXTURE0);
+      mpglEnable(GL_BLEND);
+      mpglBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
+      break;
   }
 }
 
@@ -1718,6 +1755,12 @@
       }
       mpglDrawBuffer(buffer);
       break;
+    case GL_3D_STIPPLE:
+      mpglActiveTexture(GL_TEXTURE3);
+      mpglDisable(GL_TEXTURE_2D);
+      mpglActiveTexture(GL_TEXTURE0);
+      mpglDisable(GL_BLEND);
+      break;
   }
 }
 
@@ -1737,13 +1780,16 @@
  * \param is_yv12 if != 0, also draw the textures from units 1 and 2,
  *                bits 8 - 15 and 16 - 23 specify the x and y scaling of those textures
  * \param flip flip the texture upside down
+ * \param use_stipple overlay texture 3 as 4x4 alpha stipple
  * \ingroup gltexture
  */
 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 is_yv12, int flip) {
+               int sx, int sy, int rect_tex, int is_yv12, int flip,
+               int use_stipple) {
   int chroma_x_shift = (is_yv12 >>  8) & 31;
   int chroma_y_shift = (is_yv12 >> 16) & 31;
+  GLfloat texcoords3[8] = {vo_dx / 4.0, vo_dy / 4.0, vo_dx / 4.0, (vo_dy + vo_dheight) / 4.0, (vo_dx + vo_dwidth) / 4.0, vo_dy / 4.0, (vo_dx + vo_dwidth) / 4.0, (vo_dy + vo_dheight) / 4.0};
   GLfloat xscale = 1 << chroma_x_shift;
   GLfloat yscale = 1 << chroma_y_shift;
   GLfloat tx2 = tx / xscale, ty2 = ty / yscale, tw2 = tw / xscale, th2 = th / yscale;
@@ -1764,6 +1810,11 @@
     mpglVertexPointer(2, GL_FLOAT, 0, vertices);
     mpglEnableClientState(GL_TEXTURE_COORD_ARRAY);
     mpglTexCoordPointer(2, GL_FLOAT, 0, texcoords);
+    if (use_stipple) {
+      mpglClientActiveTexture(GL_TEXTURE3);
+      mpglEnableClientState(GL_TEXTURE_COORD_ARRAY);
+      mpglTexCoordPointer(2, GL_FLOAT, 0, texcoords3);
+    }
     if (is_yv12) {
       mpglClientActiveTexture(GL_TEXTURE1);
       mpglEnableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -1774,6 +1825,10 @@
       mpglClientActiveTexture(GL_TEXTURE0);
     }
     mpglDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+    if (use_stipple) {
+      mpglClientActiveTexture(GL_TEXTURE3);
+      mpglDisableClientState(GL_TEXTURE_COORD_ARRAY);
+    }
     if (is_yv12) {
       mpglClientActiveTexture(GL_TEXTURE1);
       mpglDisableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -1791,24 +1846,32 @@
     mpglMultiTexCoord2f(GL_TEXTURE1, tx2, ty2);
     mpglMultiTexCoord2f(GL_TEXTURE2, tx2, ty2);
   }
+  if (use_stipple)
+    mpglMultiTexCoord2f(GL_TEXTURE3, texcoords3[0], texcoords3[1]);
   mpglVertex2f(x, y);
   mpglTexCoord2f(tx, ty + th);
   if (is_yv12) {
     mpglMultiTexCoord2f(GL_TEXTURE1, tx2, ty2 + th2);
     mpglMultiTexCoord2f(GL_TEXTURE2, tx2, ty2 + th2);
   }
+  if (use_stipple)
+    mpglMultiTexCoord2f(GL_TEXTURE3, texcoords3[2], texcoords3[3]);
   mpglVertex2f(x, y + h);
   mpglTexCoord2f(tx + tw, ty + th);
   if (is_yv12) {
     mpglMultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2 + th2);
     mpglMultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2 + th2);
   }
+  if (use_stipple)
+    mpglMultiTexCoord2f(GL_TEXTURE3, texcoords3[6], texcoords3[7]);
   mpglVertex2f(x + w, y + h);
   mpglTexCoord2f(tx + tw, ty);
   if (is_yv12) {
     mpglMultiTexCoord2f(GL_TEXTURE1, tx2 + tw2, ty2);
     mpglMultiTexCoord2f(GL_TEXTURE2, tx2 + tw2, ty2);
   }
+  if (use_stipple)
+    mpglMultiTexCoord2f(GL_TEXTURE3, texcoords3[4], texcoords3[5]);
   mpglVertex2f(x + w, y);
   mpglEnd();
 }
--- a/libvo/gl_common.h	Sun Aug 12 13:24:54 2012 +0000
+++ b/libvo/gl_common.h	Sun Aug 12 17:15:35 2012 +0000
@@ -320,7 +320,8 @@
                  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 is_yv12, int flip);
+               int sx, int sy, int rect_tex, int is_yv12, int flip,
+               int use_stipple);
 int loadGPUProgram(GLenum target, char *prog);
 
 /** \addtogroup glconversion
@@ -382,6 +383,18 @@
   }
   return 1;
 }
+
+static inline int glYUVSupportsAlphaTex(int conv)
+{
+  switch (conv)
+  {
+  case YUV_CONVERSION_COMBINERS:
+  case YUV_CONVERSION_COMBINERS_ATI:
+  case YUV_CONVERSION_TEXT_FRAGMENT:
+    return 0;
+  }
+  return 1;
+}
 /** \} */
 
 typedef struct {
@@ -394,6 +407,7 @@
   int chrom_texh;
   float filter_strength;
   float noise_strength;
+  int has_alpha_tex;
 } gl_conversion_params_t;
 
 int glAutodetectYUVConversion(void);
@@ -405,7 +419,9 @@
 #define GL_3D_RED_CYAN        1
 #define GL_3D_GREEN_MAGENTA   2
 #define GL_3D_QUADBUFFER      3
+#define GL_3D_STIPPLE         4
 
+void glSetupAlphaStippleTex(unsigned pattern);
 void glEnable3DLeft(int type);
 void glEnable3DRight(int type);
 void glDisable3D(int type);
--- a/libvo/vo_gl.c	Sun Aug 12 13:24:54 2012 +0000
+++ b/libvo/vo_gl.c	Sun Aug 12 17:15:35 2012 +0000
@@ -147,6 +147,7 @@
 static int custom_trect;
 static int mipmap_gen;
 static int stereo_mode;
+static int stipple;
 static enum MPGLType backend;
 
 static int int_pause;
@@ -250,7 +251,8 @@
   float bgamma = exp(log(8.0) * eq_bgamma / 100.0);
   gl_conversion_params_t params = {gl_target, yuvconvtype,
       {colorspace, levelconv, bri, cont, hue, sat, rgamma, ggamma, bgamma, 0},
-      texture_width, texture_height, 0, 0, filter_strength, noise_strength};
+      texture_width, texture_height, 0, 0, filter_strength, noise_strength,
+      stereo_mode == GL_3D_STIPPLE};
   mp_get_chroma_shift(image_format, &xs, &ys, &depth);
   params.chrom_texw = params.texw >> xs;
   params.chrom_texh = params.texh >> ys;
@@ -436,7 +438,7 @@
       texSize(i->w, i->h, &sx, &sy);
       mpglBindTexture(gl_target, *curtex++);
     }
-    glDrawTex(i->dst_x, i->dst_y, i->w, i->h, x, y, i->w, i->h, sx, sy, use_rectangle == 1, 0, 0);
+    glDrawTex(i->dst_x, i->dst_y, i->w, i->h, x, y, i->w, i->h, sx, sy, use_rectangle == 1, 0, 0, 0);
   }
   mpglEndList();
   mpglBindTexture(gl_target, 0);
@@ -515,8 +517,12 @@
   }
   if (use_osd == -1)
     use_osd = mpglBindTexture != NULL;
-  if (use_yuv == -1)
+  if (use_yuv == -1) {
     use_yuv = glAutodetectYUVConversion();
+    if (stereo_mode == GL_3D_STIPPLE &&
+        !glYUVSupportsAlphaTex(use_yuv))
+      use_yuv = 0;
+  }
   if (is_ati && (lscale == 1 || lscale == 2 || cscale == 1 || cscale == 2))
     mp_msg(MSGT_VO, MSGL_WARN, "[gl] Selected scaling mode may be broken on ATI cards.\n"
              "Tell _them_ to fix GL_REPEAT if you have issues.\n");
@@ -562,13 +568,8 @@
   if (mipmap_gen)
     mpglTexParameteri(gl_target, GL_GENERATE_MIPMAP, GL_TRUE);
 
-  if (is_yuv) {
+  if (is_yuv || stereo_mode == GL_3D_STIPPLE) {
     int i;
-    int xs, ys, depth;
-    int chroma_clear_val = 128;
-    scale_type = get_scale_type(1);
-    mp_get_chroma_shift(image_format, &xs, &ys, &depth);
-    chroma_clear_val >>= -depth & 7;
     mpglGenTextures(21, default_texs);
     default_texs[21] = 0;
     for (i = 0; i < 7; i++) {
@@ -577,6 +578,15 @@
       mpglBindTexture(GL_TEXTURE_RECTANGLE, default_texs[i + 7]);
       mpglBindTexture(GL_TEXTURE_3D, default_texs[i + 14]);
     }
+  }
+  if (stereo_mode == GL_3D_STIPPLE)
+    glSetupAlphaStippleTex(stipple);
+  if (is_yuv) {
+    int xs, ys, depth;
+    int chroma_clear_val = 128;
+    scale_type = get_scale_type(1);
+    mp_get_chroma_shift(image_format, &xs, &ys, &depth);
+    chroma_clear_val >>= -depth & 7;
     mpglActiveTexture(GL_TEXTURE1);
     glCreateClearTex(gl_target, gl_texfmt, gl_format, gl_type, scale_type,
                      texture_width >> xs, texture_height >> ys,
@@ -776,14 +786,14 @@
   mpglNewList(osdaDispList[osdtexCnt], GL_COMPILE);
   // render alpha
   mpglBindTexture(gl_target, osdatex[osdtexCnt]);
-  glDrawTex(x0, y0, w, h, 0, 0, w, h, sx, sy, use_rectangle == 1, 0, 0);
+  glDrawTex(x0, y0, w, h, 0, 0, w, h, sx, sy, use_rectangle == 1, 0, 0, 0);
   mpglEndList();
 #endif
   osdDispList[osdtexCnt] = mpglGenLists(1);
   mpglNewList(osdDispList[osdtexCnt], GL_COMPILE);
   // render OSD
   mpglBindTexture(gl_target, osdtex[osdtexCnt]);
-  glDrawTex(x0, y0, w, h, 0, 0, w, h, sx, sy, use_rectangle == 1, 0, 0);
+  glDrawTex(x0, y0, w, h, 0, 0, w, h, sx, sy, use_rectangle == 1, 0, 0, 0);
   mpglEndList();
 
   osdtexCnt++;
@@ -863,20 +873,20 @@
               0, 0, image_width >> 1, image_height,
               texture_width, texture_height,
               use_rectangle == 1, is_yuv,
-              mpi_flipped ^ vo_flipped);
+              mpi_flipped ^ vo_flipped, stereo_mode == GL_3D_STIPPLE);
     glEnable3DRight(stereo_mode);
     glDrawTex(0, 0, image_width, image_height,
               image_width >> 1, 0, image_width >> 1, image_height,
               texture_width, texture_height,
               use_rectangle == 1, is_yuv,
-              mpi_flipped ^ vo_flipped);
+              mpi_flipped ^ vo_flipped, stereo_mode == GL_3D_STIPPLE);
     glDisable3D(stereo_mode);
   } else {
     glDrawTex(0, 0, image_width, image_height,
               0, 0, image_width, image_height,
               texture_width, texture_height,
               use_rectangle == 1, is_yuv,
-              mpi_flipped ^ vo_flipped);
+              mpi_flipped ^ vo_flipped, 0);
   }
   if (is_yuv || custom_prog)
     glDisableYUVConversion(gl_target, yuvconvtype);
@@ -1206,6 +1216,7 @@
   {"mipmapgen",    OPT_ARG_BOOL, &mipmap_gen,   NULL},
   {"osdcolor",     OPT_ARG_INT,  &osd_color,    NULL},
   {"stereo",       OPT_ARG_INT,  &stereo_mode,  NULL},
+  {"stipple",      OPT_ARG_INT,  &stipple,      NULL},
   {"backend",      OPT_ARG_INT,  &backend,      valid_backend},
   {NULL}
 };
@@ -1240,6 +1251,7 @@
     mipmap_gen = 0;
     osd_color = 0xffffff;
     stereo_mode = 0;
+    stipple = 0x0f0f;
     if (subopt_parse(arg, subopts) != 0) {
       mp_msg(MSGT_VO, MSGL_FATAL,
               "\n-vo gl command line help:\n"
@@ -1320,6 +1332,9 @@
               "    1: side-by-side to red-cyan stereo\n"
               "    2: side-by-side to green-magenta stereo\n"
               "    3: side-by-side to quadbuffer stereo\n"
+              "    4: side-by-side to pixel pattern\n"
+              "  stipple=<0xBBBB>\n"
+              "    16 bits representing 4x4 pattern to use for stereo=4\n"
               "  backend=<n>\n"
               "   -1: auto-select\n"
               "    0: Win32/WGL\n"
--- a/libvo/vo_gl2.c	Sun Aug 12 13:24:54 2012 +0000
+++ b/libvo/vo_gl2.c	Sun Aug 12 17:15:35 2012 +0000
@@ -412,7 +412,7 @@
       glDrawTex(square->fx, square->fy, square->fw, square->fh,
                 0, 0, texture_width, texture_height,
                 texture_width, texture_height,
-                0, is_yuv, 0);
+                0, is_yuv, 0, 0);
       square++;
     } /* for all texnumx */
   } /* for all texnumy */