[MPlayer-dev-eng] patch for quadbuffered stereo using "-vo gl2:stereo"

Stuart Levy slevy at ncsa.uiuc.edu
Wed Nov 28 19:35:22 CET 2007


Hello, and thank you all for creating mplayer!

I've been using an adapted version of Gabriel A. v. Winckler's patch
    http://www.itdp.de/mplayer-dev-eng/2005-06/msg00361.html
which provides for playing animations on a stereoscopic display.
It assumes that the left-half of each animation image goes to the
left eye, and the right-half to the right eye.
Advantages of this over the earlier patch is that
(a) it applies to current mplayer and (b) it uses the "gl2" driver and so allows
high resolution.   The original was built into the "gl" driver, where image
resolution was limited to the graphics card's max texture size.
"gl2" uses texture tiling and doesn't have that limitation.

I know this code isn't quite right -- in order to get the
window sized properly, you have to explicitly specify the "-x" and "-y"
options.  Otherwise (with default positioning or with -fs) it does something
screwy -- I'm not sure what, but the fact that the source movie is twice as
wide as normal confuses the default window sizing logic, and I don't understand
how to fix it.  Can anyone help?

Typical usage on a 1920x1080 stereo display could be:

    mplayer -vo gl2:stereo  -x 1920 -y 1080  file.mpeg

Of course the -vo argument starts with lowercase GL2, not g twelve.

Since MPEG requires images to be multiples of 16x16, I've been
making 3840x1072 MPEGs (using mjpegtools' mpeg2enc), where
each frame is the result of gluing two 1920x1072 images side by side.

   Stuart Levy, slevy at ncsa.uiuc.edu, March (and November), 2007
   NCSA, University of Illinois Urbana-Champaign

Index: libvo/vo_gl2.c
===================================================================
--- libvo/vo_gl2.c	(revision 25184)
+++ libvo/vo_gl2.c	(working copy)
@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <math.h>
 
 #include "config.h"
 #include "mp_msg.h"
@@ -46,6 +47,11 @@
 /* local data */
 static unsigned char *ImageData=NULL;
 
+// QuadBuffer Stereo
+static unsigned char quadbuffer_stereo = 0;
+
+
+
 #ifdef GL_WIN32
     static int gl_vinfo = 0;
     static HGLRC gl_context = 0;
@@ -358,23 +364,31 @@
 }
 
 
-static void drawTextureDisplay (void)
+static void drawTextureDisplay ( float tex0, float tex1 )
 {
   struct TexSquare *square = texgrid;
   int x, y;
+  int itx0, itx1;
+  GLfloat fxoff = tex0;
+  GLfloat fxscale = 1.0f / (tex1 - tex0);
 
+
   glColor3f(1.0,1.0,1.0);
 
+  itx0 = (int) (tex0 * texnumx);
+  itx1 = (int) ceilf(tex1 * texnumx);
+
   if (image_format == IMGFMT_YV12)
     glEnableYUVConversion(GL_TEXTURE_2D, use_yuv);
   for (y = 0; y < texnumy; y++) {
     int thish = texture_height;
     if (y == texnumy - 1 && image_height % texture_height)
       thish = image_height % texture_height;
-    for (x = 0; x < texnumx; x++) {
+    for (x = itx0; x < itx1; x++) {
       int thisw = texture_width;
       if (x == texnumx - 1 && image_width % texture_width)
         thisw = image_width % texture_width;
+      square = texgrid + y*texnumx + x;
       glBindTexture (GL_TEXTURE_2D, square->texobj);
       if (image_format == IMGFMT_YV12) {
         ActiveTexture(GL_TEXTURE1);
@@ -390,11 +404,10 @@
                     0, 0, thisw, thish, 0);
       }
 
-      glDrawTex(square->fx, square->fy, square->fw, square->fh,
+      glDrawTex((square->fx - fxoff) * fxscale, square->fy, square->fw * fxscale, square->fh,
                 0, 0, texture_width, texture_height,
                 texture_width, texture_height,
                 0, image_format == IMGFMT_YV12, 0);
-      square++;
     } /* for all texnumx */
   } /* for all texnumy */
   if (image_format == IMGFMT_YV12)
@@ -406,6 +419,8 @@
 static void resize(int *x,int *y){
   mp_msg(MSGT_VO,MSGL_V,"[gl2] Resize: %dx%d\n",*x,*y);
   if( vo_fs ) {
+    if ( quadbuffer_stereo )
+	glDrawBuffer(GL_BACK);
     glClear(GL_COLOR_BUFFER_BIT);
     aspect(x, y, A_ZOOM);
     panscan_calc();
@@ -432,18 +447,26 @@
 
 static void draw_alpha_32(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
    vo_draw_alpha_rgb32(w,h,src,srca,stride,ImageData+4*(y0*image_width+x0),4*image_width);
+   if (quadbuffer_stereo)
+      vo_draw_alpha_rgb32(w,h,src,srca,stride,ImageData+4*(y0*image_width+x0+image_width/2),4*image_width);
 }
 
 static void draw_alpha_24(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
    vo_draw_alpha_rgb24(w,h,src,srca,stride,ImageData+3*(y0*image_width+x0),3*image_width);
+   if (quadbuffer_stereo)
+      vo_draw_alpha_rgb24(w,h,src,srca,stride,ImageData+3*(y0*image_width+x0+image_width/2),3*image_width);
 }
 
 static void draw_alpha_16(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
    vo_draw_alpha_rgb16(w,h,src,srca,stride,ImageData+2*(y0*image_width+x0),2*image_width);
+   if (quadbuffer_stereo)
+      vo_draw_alpha_rgb16(w,h,src,srca,stride,ImageData+2*(y0*image_width+x0+image_width/2),2*image_width);
 }
 
 static void draw_alpha_15(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
    vo_draw_alpha_rgb15(w,h,src,srca,stride,ImageData+2*(y0*image_width+x0),2*image_width);
+   if (quadbuffer_stereo)
+      vo_draw_alpha_rgb15(w,h,src,srca,stride,ImageData+2*(y0*image_width+x0+image_width/2),2*image_width);
 }
 
 static void draw_alpha_null(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
@@ -483,6 +506,11 @@
     /* furthermore it must be RGBA (not color indexed) ... */
     res = glXGetConfig(dpy, vi_list + i, GLX_RGBA, &val);
     if (res || val == False) continue;
+    /* assure quadbuffered stereo if requested */
+    if (quadbuffer_stereo) {
+	res = glXGetConfig(dpy, vi_list + i, GLX_STEREO, &val);
+	if (res || val == False) continue;
+    }
     /* prefer less depth buffer size, */
     res = glXGetConfig(dpy, vi_list + i, GLX_DEPTH_SIZE, &val);
     if (res) continue;
@@ -530,7 +558,10 @@
   }
     vinfo = choose_glx_visual(mDisplay,mScreen,&vinfo_buf) < 0 ? NULL : &vinfo_buf;
     if (vinfo == NULL) {
-      mp_msg(MSGT_VO, MSGL_FATAL, "[gl2] no GLX support present\n");
+      if (quadbuffer_stereo)
+	  mp_msg(MSGT_VO, MSGL_FATAL, "[gl2] no Quadbuffered Stereo GLX support present\n");
+      else
+	  mp_msg(MSGT_VO, MSGL_FATAL, "[gl2] no GLX support present\n");
       return -1;
     }
 
@@ -592,9 +623,18 @@
   resize(&d_width, &d_height);
 
   glClearColor( 0.0f,0.0f,0.0f,0.0f );
-  glClear( GL_COLOR_BUFFER_BIT );
+  if ( quadbuffer_stereo ) {
+    glDrawBuffer(GL_BACK);
+    glClear( GL_COLOR_BUFFER_BIT );
+    glDrawBuffer(GL_BACK_LEFT);
+    drawTextureDisplay( 0.0f, 0.5f );
+    glDrawBuffer(GL_BACK_RIGHT);
+    drawTextureDisplay( 0.5f, 1.0f );
 
-  drawTextureDisplay ();
+  } else { 
+    glClear( GL_COLOR_BUFFER_BIT );
+    drawTextureDisplay ( 0.0f, 1.0f );
+  }
 
   return 0;
 }
@@ -611,6 +651,20 @@
   image_width = width;
   image_format = format;
 
+#if 0
+  if (quadbuffer_stereo) {
+    /* v. Winckler's patch had just d_width /= 2, but that doesn't seem right either.
+     * Mplayer experts please help!  Meanwhile, leave this section out.
+     * Then users must still give explicit -x and -y options as in
+     *   mplayer -vo gl2:stereo -x <SCREENWIDTH> -y <SCREENHEIGHT>  movie...
+     * At least *that* works.  But default window doesn't, nor does -fs,
+     * both apparently confused by double-wide aspect ratio of stereo anim files.
+     */
+    width /= 2;
+    d_width /= 2;
+  }
+#endif
+
   int_pause = 0;
 
 #ifdef HAVE_NEW_GUI
@@ -718,21 +772,31 @@
 static void draw_osd(void)
 {
   if (ImageData)
-    vo_draw_text(image_width,image_height,draw_alpha_fnc);
+    vo_draw_text( quadbuffer_stereo ? image_width/2 : image_width, image_height,draw_alpha_fnc);
 }
 
 static void
 flip_page(void)
 {
-  drawTextureDisplay();
+  if ( quadbuffer_stereo ) {
+    glDrawBuffer( GL_BACK_LEFT );
+    drawTextureDisplay( 0.0f, 0.5f );
+    glDrawBuffer( GL_BACK_RIGHT );
+    drawTextureDisplay( 0.5f, 1.0f );
+  } else {
+    drawTextureDisplay( 0.0f, 1.0f );
+  }
 
 //  glFlush();
   if (use_glFinish)
-  glFinish();
+    glFinish();
   swapGlBuffers();
 
   if (vo_fs) // Avoid flickering borders in fullscreen mode
+  {
+    if ( quadbuffer_stereo ) glDrawBuffer(GL_BACK);
     glClear (GL_COLOR_BUFFER_BIT);
+  }
 }
 
 static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y)
@@ -837,6 +901,7 @@
 static opt_t subopts[] = {
   {"yuv",          OPT_ARG_INT,  &use_yuv,      (opt_test_f)int_non_neg},
   {"glfinish",     OPT_ARG_BOOL, &use_glFinish, NULL},
+  {"stereo",       OPT_ARG_BOOL, &quadbuffer_stereo,    NULL},
   {NULL}
 };
 
@@ -859,6 +924,8 @@
             "    3: use fragment program with gamma correction.\n"
             "    4: use fragment program with gamma correction via lookup.\n"
             "    5: use ATI-specific method (for older cards).\n"
+	    "  stereo\n"
+	    "    use quadbuffered stereo: left-half image to left eye, etc.\n"
             "\n" );
     return -1;
   }



More information about the MPlayer-dev-eng mailing list