[MPlayer-dev-eng] [PATCH] view stereoscopic videos

Gordon Schmidt gordon.schmidt at s2000.tu-chemnitz.de
Sat Jan 23 15:34:27 CET 2010


Hi,

this is my first post in this list. I've created a filter to convert for
stereoscopic videos into other stereoscopic formats. Supported stereo
input contain images for the left eye and the right eye combined in one
video stream (e.g. side by side images as parallel and crosseye, and
some above/below variants). Output formats are also side by side and
above/below formats as well as some anaglyph modes (red/cyan,
green/magenta and yellow/blue) and mono video (only left or right eye
images). Supported image formats are IMGFMT_YV12 and IMGFMT_RGB24
(others may follow).

The Syntax looks like this: mplayer -vf stereo=<input_fmt>:<output_fmt>
video.avi
(e.g. stereo=slr:arc for displaying a parallel side by side video as
anaglyph red/cyan)

You can find some good samples of stereo videos for testing at
http://www.stereomaker.net/sample/index.html

Hopefully you'll like this feature.

Regards
Gordon


PS: This patch doesn't include changes on the documentation. I have no
clue how to do this and would be glad, if someone could give me a hand
with that.

-------------- next part --------------
Index: libmpcodecs/vf_stereo.c
===================================================================
--- libmpcodecs/vf_stereo.c	(revision 0)
+++ libmpcodecs/vf_stereo.c	(revision 0)
@@ -0,0 +1,961 @@
+/*
+ * Copyright (C) 2010 Gordon Schmidt <gordon.schmidt at s2000.tu-chemnitz.de>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MPlayer is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with MPlayer; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+//==includes==//
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+
+#include "img_format.h"
+#include "mp_image.h"
+#include "vf.h"
+
+#include "libvo/fastmemcpy.h"
+
+//==macros==//
+#define MIN(X,Y)                ((X) < (Y) ? (X) : (Y))
+#define MAX(X,Y)                ((X) < (Y) ? (Y) : (X))
+
+#define YUV2R(Y,V,U)            (MIN(255,MAX(0,((1192*((Y) - 16) + 1634*((V) - 128)                   ) >> 10))))
+#define YUV2G(Y,V,U)            (MIN(255,MAX(0,((1192*((Y) - 16) -  833*((V) - 128) -  400*((U) - 128)) >> 10))))
+#define YUV2B(Y,V,U)            (MIN(255,MAX(0,((1192*((Y) - 16)                    + 2066*((U) - 128)) >> 10))))
+
+#define RGB2Y(R,G,B)            (MIN(255,MAX(0,((( 263*(R) + 516*(G) + 100*(B)) >> 10) +  16))))
+#define RGB2V(R,G,B)            (MIN(255,MAX(0,((( 450*(R) - 377*(G) -  73*(B)) >> 10) + 128))))
+#define RGB2U(R,G,B)            (MIN(255,MAX(0,(((-152*(R) - 298*(G) + 450*(B)) >> 10) + 128))))
+
+#define RC_R(RL,RR,GL,GR,BL,BR) (RL)
+#define RC_G(RL,RR,GL,GR,BL,BR) (GR)
+#define RC_B(RL,RR,GL,GR,BL,BR) (BR)
+
+#define GM_R(RL,RR,GL,GR,BL,BR) (RR)
+#define GM_G(RL,RR,GL,GR,BL,BR) (GL)
+#define GM_B(RL,RR,GL,GR,BL,BR) (BR)
+
+#define YB_R(RL,RR,GL,GR,BL,BR) (RR)
+#define YB_G(RL,RR,GL,GR,BL,BR) (GR)
+#define YB_B(RL,RR,GL,GR,BL,BR) (BL)
+
+//slow version, that uses the RC transformation for RGB (should also work if these makros change)
+#define RC_Y(YL,YR,VL,VR,UL,UR) (RGB2Y(RC_R(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       RC_G(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       RC_B(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR))))
+#define RC_V(YL,YR,VL,VR,UL,UR) (RGB2V(RC_R(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       RC_G(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       RC_B(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR))))
+#define RC_U(YL,YR,VL,VR,UL,UR) (RGB2U(RC_R(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       RC_G(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       RC_B(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR))))
+
+//slow version, that uses the GM transformation for RGB (should also work if these makros change)
+#define GM_Y(YL,YR,VL,VR,UL,UR) (RGB2Y(GM_R(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       GM_G(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       GM_B(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR))))
+#define GM_V(YL,YR,VL,VR,UL,UR) (RGB2V(GM_R(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       GM_G(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       GM_B(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR))))
+#define GM_U(YL,YR,VL,VR,UL,UR) (RGB2U(GM_R(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       GM_G(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       GM_B(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR))))
+
+//slow version, that uses the YB transformation for RGB (should also work if these makros change)
+#define YB_Y(YL,YR,VL,VR,UL,UR) (RGB2Y(YB_R(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       YB_G(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       YB_B(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR))))
+#define YB_V(YL,YR,VL,VR,UL,UR) (RGB2V(YB_R(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       YB_G(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       YB_B(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR))))
+#define YB_U(YL,YR,VL,VR,UL,UR) (RGB2U(YB_R(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       YB_G(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR)), \
+                                       YB_B(YUV2R(YL,VL,UL),YUV2R(YR,VR,UR),YUV2G(YL,VL,UL),  \
+                                            YUV2G(YR,VR,UR),YUV2B(YL,VL,UL),YUV2B(YR,VR,UR))))
+
+#define M4(V1,V2,V3,V4)         (MIN(255,MAX(0,(((V1) + (V2) + (V3) + (V4)) >> 2))))
+
+//==types==//
+typedef enum stereo_code
+{
+  NOT_SET,                  //no value set - TODO: needs autodetection
+  SIDE_BY_SIDE_LR,          //side by side parallel (left eye left - right eye right)
+  SIDE_BY_SIDE_RL,          //side by side crosseye (right eye left - left eye right)
+  ABOVE_BELOW_LR,           //above-below (left eye above - right eye below)
+  ABOVE_BELOW_RL,           //above-below (right eye above - left eye below)
+  ABOVE_BELOW_2_LR,         //above-below (left eye above - right eye below) only half high resolution
+  ABOVE_BELOW_2_RL,         //above-below (right eye above - left eye below) only half high resolution
+  INTERLACED_LR,            //interlaced starting with left eye line (left eye on lines 0,2,..)
+  INTERLACED_RL,            //interlaced starting with right eye line (right eye on lines 0,2,..)
+  INTERLACED_2_LR,          //interlaced starting with left eye line (left eye on lines 0,2,..) only half high resolution
+  INTERLACED_2_RL,          //interlaced starting with right eye line (right eye on lines 0,2,..) only half high resolution
+  ANAGLYPH_RC,              //anaglyph red/cyan (red filter on left eye - cyan filter on right eye) 
+  ANAGLYPH_GM,              //anaglyph green/magenta (green filter on left eye - magenta filter on right eye)
+  ANAGLYPH_YB,              //anaglyph yellow/blue (yellow filter on left eye - blue filter on right eye)
+  MONO_L,                   //mono output for debugging - left eye only
+  MONO_R                    //mono output for debugging - right eye only
+} stereo_code;
+
+//==global variables==//
+struct vf_priv_s
+{
+  unsigned int w;
+  unsigned int h;
+  unsigned int out_w;
+  unsigned int out_h;
+  stereo_code in_fmt;
+  stereo_code out_fmt;
+  mp_image_t* img_src;
+  mp_image_t* img_dst;
+  unsigned char* img_l;
+  unsigned char* img_r;
+};
+
+extern int opt_screen_size_x;
+extern int opt_screen_size_y;
+
+//==functions==//
+static int config( struct vf_instance_s* vf, int width, int height, int d_width,
+                   int d_height, unsigned int flags, unsigned int outfmt )
+{
+  switch( vf->priv->in_fmt )
+  {
+    case SIDE_BY_SIDE_LR:
+    case SIDE_BY_SIDE_RL:
+    {
+      if( 0 != width % 2 )    //test for odd width
+      {
+        mp_msg( MSGT_VFILTER, MSGL_WARN, "[stereo] odd width of input\n" );
+        return 0;
+      }
+      vf->priv->w = ( width / 2 );
+      vf->priv->h = height;
+      break;
+    }
+    case ABOVE_BELOW_LR:
+    case ABOVE_BELOW_RL:
+//    case INTERLACED_LR:
+//    case INTERLACED_RL:
+    {
+      if( 0 != height % 2 )   //test for odd height
+      {
+        mp_msg( MSGT_VFILTER, MSGL_WARN, "[stereo] odd height of input\n" );
+        return 0;
+      }
+      vf->priv->w = width;
+      vf->priv->h = height / 2;
+      break;
+    }
+    case ABOVE_BELOW_2_LR:
+    case ABOVE_BELOW_2_RL:
+//    case INTERLACED_2_LR:
+//    case INTERLACED_2_RL:
+    {
+      if( 0 != height % 2 )   //test for odd height
+      {
+        mp_msg( MSGT_VFILTER, MSGL_WARN, "[stereo] odd height of input\n" );
+        return 0;
+      }
+      vf->priv->w = width;
+      vf->priv->h = height;
+      break;
+    }
+    case ANAGLYPH_RC:
+    case ANAGLYPH_GM:
+    case ANAGLYPH_YB:
+    case MONO_L:
+    case MONO_R:
+    default:
+    {
+      mp_msg( MSGT_VFILTER, MSGL_WARN, "[stereo] stereo format of input is not supported\n" );
+      return 0;
+      break;
+    }
+  }
+  switch( vf->priv->out_fmt )
+  {
+    case ANAGLYPH_RC:
+    case ANAGLYPH_GM:
+    case ANAGLYPH_YB:
+    case ABOVE_BELOW_2_LR:
+    case ABOVE_BELOW_2_RL:
+//    case INTERLACED_2_LR:
+//    case INTERLACED_2_RL:
+    case MONO_L:
+    case MONO_R:
+    {
+      vf->priv->out_w = vf->priv->w;
+      vf->priv->out_h = vf->priv->h;
+      break;
+    }
+    case SIDE_BY_SIDE_LR:
+    case SIDE_BY_SIDE_RL:
+    {
+      vf->priv->out_w = vf->priv->w * 2;
+      vf->priv->out_h = vf->priv->h;
+      break;
+    }
+    case ABOVE_BELOW_LR:
+    case ABOVE_BELOW_RL:
+//    case INTERLACED_LR:
+//    case INTERLACED_RL:
+    {
+      vf->priv->out_w = vf->priv->w;
+      vf->priv->out_h = vf->priv->h * 2;
+      break;
+    }
+    default:
+    {
+      mp_msg( MSGT_VFILTER, MSGL_WARN, "[stereo] stereo format of output is not supported\n" );
+      return 0;
+      break;
+    }
+  }
+  switch( outfmt )
+  {
+    case IMGFMT_YV12:
+    {
+      vf->priv->img_l = malloc( ( ( 3 * vf->priv->w * vf->priv->h ) >> 1 ) );
+      vf->priv->img_r = malloc( ( ( 3 * vf->priv->w * vf->priv->h ) >> 1 ) );
+      break;
+    }
+    case IMGFMT_RGB24:
+    {
+      vf->priv->img_l = malloc( 3 * vf->priv->w * vf->priv->h );
+      vf->priv->img_r = malloc( 3 * vf->priv->w * vf->priv->h );
+      break;
+    }
+    default:
+    {
+      mp_msg( MSGT_VFILTER, MSGL_WARN, "[stereo] unsupported input/output fmt\n" );
+      return 0;
+      break;
+    }
+  }
+  if( !opt_screen_size_x && !opt_screen_size_y )
+  {
+    d_width = d_width * vf->priv->out_w / width;
+    d_height = d_height * vf->priv->out_h / height;
+  }
+  mp_msg( MSGT_VFILTER, MSGL_INFO, "[stereo] DEBUG %d x %d -> %d x %d\n", width, height, vf->priv->out_w, vf->priv->out_h );
+  return vf_next_config( vf, vf->priv->out_w, vf->priv->out_h, d_width, d_height, flags, outfmt );
+}
+
+static int get_yv12( struct vf_instance_s* vf )
+{
+  switch( vf->priv->in_fmt )
+  {
+    case SIDE_BY_SIDE_LR:
+    {
+      int size = vf->priv->w * vf->priv->h;
+      memcpy_pic( vf->priv->img_l, vf->priv->img_src->planes[0], vf->priv->w, vf->priv->h, vf->priv->w, 2 * vf->priv->w );
+      memcpy_pic( vf->priv->img_r, vf->priv->img_src->planes[0] + vf->priv->w, vf->priv->w, vf->priv->h, vf->priv->w, 2 * vf->priv->w );
+
+      memcpy_pic( vf->priv->img_l + size, vf->priv->img_src->planes[1], vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w );
+      memcpy_pic( vf->priv->img_r + size, vf->priv->img_src->planes[1] + vf->priv->w / 2, vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w );
+
+      size = size + ( size >> 2 );
+      memcpy_pic( vf->priv->img_l + size, vf->priv->img_src->planes[2], vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w );
+      memcpy_pic( vf->priv->img_r + size, vf->priv->img_src->planes[2] + vf->priv->w / 2, vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w );
+      break;
+    }
+    case SIDE_BY_SIDE_RL:
+    {
+      int size = vf->priv->w * vf->priv->h;
+      memcpy_pic( vf->priv->img_l, vf->priv->img_src->planes[0] + vf->priv->w, vf->priv->w, vf->priv->h, vf->priv->w, 2 * vf->priv->w );
+      memcpy_pic( vf->priv->img_r, vf->priv->img_src->planes[0], vf->priv->w, vf->priv->h, vf->priv->w, 2 * vf->priv->w );
+
+      memcpy_pic( vf->priv->img_l + size, vf->priv->img_src->planes[1] + vf->priv->w / 2, vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w );
+      memcpy_pic( vf->priv->img_r + size, vf->priv->img_src->planes[1], vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w );
+
+      size = size + ( size >> 2 );
+      memcpy_pic( vf->priv->img_l + size, vf->priv->img_src->planes[2] + vf->priv->w / 2, vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w );
+      memcpy_pic( vf->priv->img_r + size, vf->priv->img_src->planes[2], vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w );
+      break;
+    }
+    case ABOVE_BELOW_LR:
+    {
+      int size = vf->priv->w * vf->priv->h;
+      int size2 = ( size >> 2 );
+      memcpy_pic( vf->priv->img_l, vf->priv->img_src->planes[0], vf->priv->w, vf->priv->h, vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_r, vf->priv->img_src->planes[0] + size, vf->priv->w, vf->priv->h, vf->priv->w, vf->priv->w );
+
+      memcpy_pic( vf->priv->img_l + size, vf->priv->img_src->planes[1], vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_r + size, vf->priv->img_src->planes[1] + size2, vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+
+      memcpy_pic( vf->priv->img_l + size + size2, vf->priv->img_src->planes[2], vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_r + size + size2, vf->priv->img_src->planes[2] + size2, vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      break;
+    }
+    case ABOVE_BELOW_RL:
+    {
+      int size = vf->priv->w * vf->priv->h;
+      int size2 = ( size >> 2 );
+      memcpy_pic( vf->priv->img_r, vf->priv->img_src->planes[0], vf->priv->w, vf->priv->h, vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_l, vf->priv->img_src->planes[0] + size, vf->priv->w, vf->priv->h, vf->priv->w, vf->priv->w );
+
+      memcpy_pic( vf->priv->img_r + size, vf->priv->img_src->planes[1], vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_l + size, vf->priv->img_src->planes[1] + size2, vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+
+      memcpy_pic( vf->priv->img_r + size + size2, vf->priv->img_src->planes[2], vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_l + size + size2, vf->priv->img_src->planes[2] + size2, vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      break;
+    }
+    case ABOVE_BELOW_2_LR:
+    {
+      int size = vf->priv->w * vf->priv->h;
+      int size2 = ( size >> 2 );
+      memcpy_pic( vf->priv->img_l, vf->priv->img_src->planes[0], vf->priv->w, vf->priv->h / 2, 2 * vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_l + vf->priv->w, vf->priv->img_src->planes[0], vf->priv->w, vf->priv->h / 2, 2 * vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_r, vf->priv->img_src->planes[0] + size / 2, vf->priv->w, vf->priv->h / 2, 2 * vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_r + vf->priv->w, vf->priv->img_src->planes[0] + size / 2, vf->priv->w, vf->priv->h / 2, 2 * vf->priv->w, vf->priv->w );
+
+      memcpy_pic( vf->priv->img_l + size, vf->priv->img_src->planes[1], vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_l + size + vf->priv->w / 2, vf->priv->img_src->planes[1], vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_r + size, vf->priv->img_src->planes[1] + size2 / 2, vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_r + size + vf->priv->w / 2, vf->priv->img_src->planes[1] + size2 / 2, vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+
+      memcpy_pic( vf->priv->img_l + size + size2, vf->priv->img_src->planes[2], vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_l + size + size2 + vf->priv->w / 2, vf->priv->img_src->planes[2], vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_r + size + size2, vf->priv->img_src->planes[2] + size2 / 2, vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_r + size + size2 + vf->priv->w / 2, vf->priv->img_src->planes[2] + size2 / 2, vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      break;
+    }
+    case ABOVE_BELOW_2_RL:
+    {
+      int size = vf->priv->w * vf->priv->h;
+      int size2 = ( size >> 2 );
+      memcpy_pic( vf->priv->img_r, vf->priv->img_src->planes[0], vf->priv->w, vf->priv->h / 2, 2 * vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_r + vf->priv->w, vf->priv->img_src->planes[0], vf->priv->w, vf->priv->h / 2, 2 * vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_l, vf->priv->img_src->planes[0] + size / 2, vf->priv->w, vf->priv->h / 2, 2 * vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_l + vf->priv->w, vf->priv->img_src->planes[0] + size / 2, vf->priv->w, vf->priv->h / 2, 2 * vf->priv->w, vf->priv->w );
+
+      memcpy_pic( vf->priv->img_r + size, vf->priv->img_src->planes[1], vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_r + size + vf->priv->w / 2, vf->priv->img_src->planes[1], vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_l + size, vf->priv->img_src->planes[1] + size2 / 2, vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_l + size + vf->priv->w / 2, vf->priv->img_src->planes[1] + size2 / 2, vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+
+      memcpy_pic( vf->priv->img_r + size + size2, vf->priv->img_src->planes[2], vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_r + size + size2 + vf->priv->w / 2, vf->priv->img_src->planes[2], vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_l + size + size2, vf->priv->img_src->planes[2] + size2 / 2, vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_l + size + size2 + vf->priv->w / 2, vf->priv->img_src->planes[2] + size2 / 2, vf->priv->w / 2, vf->priv->h / 4, vf->priv->w, vf->priv->w / 2 );
+      break;
+    }
+    //TODO: support for interlaced input
+    //TODO: support for anaglyph input
+    default:
+    {
+      mp_msg( MSGT_VFILTER, MSGL_WARN, "[stereo] stereo format of input is not supported\n" );
+      return 0;
+      break;
+    }
+  }
+  return 1;
+}
+
+static int set_yv12( struct vf_instance_s* vf )
+{
+  switch( vf->priv->out_fmt )
+  {
+    case SIDE_BY_SIDE_LR:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_l, vf->priv->w, vf->priv->h, 2 * vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1], vf->priv->img_l + ( vf->priv->w * vf->priv->h ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_dst->planes[2], vf->priv->img_l + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w, vf->priv->w / 2 );
+
+      memcpy_pic( vf->priv->img_dst->planes[0] + vf->priv->w, vf->priv->img_r, vf->priv->w, vf->priv->h, 2 * vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1] + vf->priv->w / 2, vf->priv->img_r + ( vf->priv->w * vf->priv->h ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_dst->planes[2] + vf->priv->w / 2, vf->priv->img_r + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w, vf->priv->w / 2 );
+      break;
+    }
+    case SIDE_BY_SIDE_RL:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0] + vf->priv->w, vf->priv->img_l, vf->priv->w, vf->priv->h, 2 * vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1] + vf->priv->w / 2, ( vf->priv->img_l + ( vf->priv->w * vf->priv->h ) ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_dst->planes[2] + vf->priv->w / 2, ( vf->priv->img_l + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ) ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w, vf->priv->w / 2 );
+
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_r, vf->priv->w, vf->priv->h, 2 * vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1], ( vf->priv->img_r + ( vf->priv->w * vf->priv->h ) ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_dst->planes[2], ( vf->priv->img_r + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ) ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w, vf->priv->w / 2 );
+      break;
+    }
+    case ABOVE_BELOW_LR:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_l, vf->priv->w, vf->priv->h, vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1], vf->priv->img_l + ( vf->priv->w * vf->priv->h ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_dst->planes[2], vf->priv->img_l + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+
+      memcpy_pic( vf->priv->img_dst->planes[0] + vf->priv->w * vf->priv->h, vf->priv->img_r, vf->priv->w, vf->priv->h, vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1] + ( ( vf->priv->w * vf->priv->h) >> 2 ), vf->priv->img_r + ( vf->priv->w * vf->priv->h ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_dst->planes[2] + ( ( vf->priv->w * vf->priv->h) >> 2 ), vf->priv->img_r + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      break;
+    }
+    case ABOVE_BELOW_RL:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_r, vf->priv->w, vf->priv->h, vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1], vf->priv->img_r + ( vf->priv->w * vf->priv->h ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_dst->planes[2], vf->priv->img_r + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+
+      memcpy_pic( vf->priv->img_dst->planes[0] + vf->priv->w * vf->priv->h, vf->priv->img_l, vf->priv->w, vf->priv->h, vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1] + ( ( vf->priv->w * vf->priv->h) >> 2 ), vf->priv->img_l + ( vf->priv->w * vf->priv->h ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_dst->planes[2] + ( ( vf->priv->w * vf->priv->h) >> 2 ), vf->priv->img_l + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      break;
+    }
+    case ABOVE_BELOW_2_LR:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_l, vf->priv->w, vf->priv->h / 2, vf->priv->w, 2 * vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1], vf->priv->img_l + ( vf->priv->w * vf->priv->h ), vf->priv->w / 2, vf->priv->h / 4, vf->priv->w / 2, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[2], vf->priv->img_l + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ), vf->priv->w / 2, vf->priv->h / 4, vf->priv->w / 2, vf->priv->w );
+
+      memcpy_pic( vf->priv->img_dst->planes[0] + ( ( vf->priv->w * vf->priv->h) >> 1 ), vf->priv->img_r, vf->priv->w, vf->priv->h / 2, vf->priv->w, 2 * vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1] + ( ( vf->priv->w * vf->priv->h) >> 3 ), vf->priv->img_r + ( vf->priv->w * vf->priv->h ), vf->priv->w / 2, vf->priv->h / 4, vf->priv->w / 2, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[2] + ( ( vf->priv->w * vf->priv->h) >> 3 ), vf->priv->img_r + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ), vf->priv->w / 2, vf->priv->h / 4, vf->priv->w / 2, vf->priv->w );
+      break;
+    }
+    case ABOVE_BELOW_2_RL:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_r, vf->priv->w, vf->priv->h / 2, vf->priv->w, 2 * vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1], vf->priv->img_r + ( vf->priv->w * vf->priv->h ), vf->priv->w / 2, vf->priv->h / 4, vf->priv->w / 2, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[2], vf->priv->img_r + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ), vf->priv->w / 2, vf->priv->h / 4, vf->priv->w / 2, vf->priv->w );
+
+      memcpy_pic( vf->priv->img_dst->planes[0] + ( ( vf->priv->w * vf->priv->h) >> 1 ), vf->priv->img_l, vf->priv->w, vf->priv->h / 2, vf->priv->w, 2 * vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1] + ( ( vf->priv->w * vf->priv->h) >> 3 ), vf->priv->img_l + ( vf->priv->w * vf->priv->h ), vf->priv->w / 2, vf->priv->h / 4, vf->priv->w / 2, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[2] + ( ( vf->priv->w * vf->priv->h) >> 3 ), vf->priv->img_l + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ), vf->priv->w / 2, vf->priv->h / 4, vf->priv->w / 2, vf->priv->w );
+      break;
+    }
+    case MONO_L:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_l, vf->priv->w, vf->priv->h, vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1], ( vf->priv->img_l + ( vf->priv->w * vf->priv->h ) ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_dst->planes[2], ( vf->priv->img_l + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ) ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      break;
+    }
+    case MONO_R:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_r, vf->priv->w, vf->priv->h, vf->priv->w, vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[1], ( vf->priv->img_r + ( vf->priv->w * vf->priv->h ) ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      memcpy_pic( vf->priv->img_dst->planes[2], ( vf->priv->img_r + 5 * ( ( vf->priv->w * vf->priv->h ) >> 2 ) ), vf->priv->w / 2, vf->priv->h / 2, vf->priv->w / 2, vf->priv->w / 2 );
+      break;
+    }
+    case ANAGLYPH_RC:
+    { //somehow u and v get mixed up - just switched it as a workaround
+      int x,y,i,j;
+      int size = vf->priv->w * vf->priv->h;
+      int size2 = size + ( size >> 2 );
+      unsigned char ml,mr;
+      for( y = 0; y < vf->priv->h; y++ )
+      {
+        for( x = 0; x < vf->priv->w; x++ )
+        {
+          i = vf->priv->w * y + x;
+          j = ( vf->priv->w >> 1 ) * ( y >> 1 ) + ( x >> 1 );
+          vf->priv->img_dst->planes[0][i] = RC_Y( vf->priv->img_l[i        ], vf->priv->img_r[i        ],
+                                                  vf->priv->img_l[size2 + j], vf->priv->img_r[size2 + j],
+                                                  vf->priv->img_l[size  + j], vf->priv->img_r[size  + j] );
+        }
+      }
+      for( y = 0; y < vf->priv->h; y+=2 )
+      {
+        for( x = 0; x < vf->priv->w; x+=2 )
+        {
+          i = vf->priv->w * y + x;
+          j = ( vf->priv->w >> 1 ) * ( y >> 1 ) + ( x >> 1 );
+          ml = M4( vf->priv->img_l[i], vf->priv->img_l[i + 1], vf->priv->img_l[i + vf->priv->w], vf->priv->img_l[i + vf->priv->w + 1] );
+          mr = M4( vf->priv->img_l[i], vf->priv->img_l[i + 1], vf->priv->img_l[i + vf->priv->w], vf->priv->img_l[i + vf->priv->w + 1] );
+          vf->priv->img_dst->planes[1][j] = RC_U( vf->priv->img_l[i        ], vf->priv->img_r[i        ],
+                                                  vf->priv->img_l[size2 + j], vf->priv->img_r[size2 + j],
+                                                  vf->priv->img_l[size  + j], vf->priv->img_r[size  + j] );
+          vf->priv->img_dst->planes[2][j] = RC_V( vf->priv->img_l[i        ], vf->priv->img_r[i        ],
+                                                  vf->priv->img_l[size2 + j], vf->priv->img_r[size2 + j],
+                                                  vf->priv->img_l[size  + j], vf->priv->img_r[size  + j] );
+        }
+      }
+      break;
+    }
+    case ANAGLYPH_GM:
+    { //somehow u and v get mixed up - just switched it as a workaround
+      int x,y,i,j;
+      int size = vf->priv->w * vf->priv->h;
+      int size2 = size + ( size >> 2 );
+      unsigned char ml,mr;
+      for( y = 0; y < vf->priv->h; y++ )
+      {
+        for( x = 0; x < vf->priv->w; x++ )
+        {
+          i = vf->priv->w * y + x;
+          j = ( vf->priv->w >> 1 ) * ( y >> 1 ) + ( x >> 1 );
+          vf->priv->img_dst->planes[0][i] = GM_Y( vf->priv->img_l[i        ], vf->priv->img_r[i        ],
+                                                  vf->priv->img_l[size2 + j], vf->priv->img_r[size2 + j],
+                                                  vf->priv->img_l[size  + j], vf->priv->img_r[size  + j] );
+        }
+      }
+      for( y = 0; y < vf->priv->h; y+=2 )
+      {
+        for( x = 0; x < vf->priv->w; x+=2 )
+        {
+          i = vf->priv->w * y + x;
+          j = ( vf->priv->w >> 1 ) * ( y >> 1 ) + ( x >> 1 );
+          ml = M4( vf->priv->img_l[i], vf->priv->img_l[i + 1], vf->priv->img_l[i + vf->priv->w], vf->priv->img_l[i + vf->priv->w + 1] );
+          mr = M4( vf->priv->img_l[i], vf->priv->img_l[i + 1], vf->priv->img_l[i + vf->priv->w], vf->priv->img_l[i + vf->priv->w + 1] );
+          vf->priv->img_dst->planes[1][j] = GM_U( vf->priv->img_l[i        ], vf->priv->img_r[i        ],
+                                                  vf->priv->img_l[size2 + j], vf->priv->img_r[size2 + j],
+                                                  vf->priv->img_l[size  + j], vf->priv->img_r[size  + j] );
+          vf->priv->img_dst->planes[2][j] = GM_V( vf->priv->img_l[i        ], vf->priv->img_r[i        ],
+                                                  vf->priv->img_l[size2 + j], vf->priv->img_r[size2 + j],
+                                                  vf->priv->img_l[size  + j], vf->priv->img_r[size  + j] );
+        }
+      }
+      break;
+    }
+    case ANAGLYPH_YB:
+    { //somehow u and v get mixed up - just switched it as a workaround
+      int x,y,i,j;
+      int size = vf->priv->w * vf->priv->h;
+      int size2 = size + ( size >> 2 );
+      unsigned char ml,mr;
+      for( y = 0; y < vf->priv->h; y++ )
+      {
+        for( x = 0; x < vf->priv->w; x++ )
+        {
+          i = vf->priv->w * y + x;
+          j = ( vf->priv->w >> 1 ) * ( y >> 1 ) + ( x >> 1 );
+          vf->priv->img_dst->planes[0][i] = YB_Y( vf->priv->img_l[i        ], vf->priv->img_r[i        ],
+                                                  vf->priv->img_l[size2 + j], vf->priv->img_r[size2 + j],
+                                                  vf->priv->img_l[size  + j], vf->priv->img_r[size  + j] );
+        }
+      }
+      for( y = 0; y < vf->priv->h; y+=2 )
+      {
+        for( x = 0; x < vf->priv->w; x+=2 )
+        {
+          i = vf->priv->w * y + x;
+          j = ( vf->priv->w >> 1 ) * ( y >> 1 ) + ( x >> 1 );
+          ml = M4( vf->priv->img_l[i], vf->priv->img_l[i + 1], vf->priv->img_l[i + vf->priv->w], vf->priv->img_l[i + vf->priv->w + 1] );
+          mr = M4( vf->priv->img_l[i], vf->priv->img_l[i + 1], vf->priv->img_l[i + vf->priv->w], vf->priv->img_l[i + vf->priv->w + 1] );
+          vf->priv->img_dst->planes[1][j] = YB_U( vf->priv->img_l[i        ], vf->priv->img_r[i        ],
+                                                  vf->priv->img_l[size2 + j], vf->priv->img_r[size2 + j],
+                                                  vf->priv->img_l[size  + j], vf->priv->img_r[size  + j] );
+          vf->priv->img_dst->planes[2][j] = YB_V( vf->priv->img_l[i        ], vf->priv->img_r[i        ],
+                                                  vf->priv->img_l[size2 + j], vf->priv->img_r[size2 + j],
+                                                  vf->priv->img_l[size  + j], vf->priv->img_r[size  + j] );
+        }
+      }
+      break;
+    }
+    //TODO: support for interlaced output
+    default:
+    {
+      mp_msg( MSGT_VFILTER, MSGL_WARN, "[stereo] stereo format of output is not supported\n" );
+      return 0;
+      break;
+    }
+  }
+  return 1;
+}
+
+static int get_rgb24( struct vf_instance_s* vf )
+{
+  switch( vf->priv->in_fmt )
+  {
+    case SIDE_BY_SIDE_LR:
+    {
+      memcpy_pic( vf->priv->img_l, vf->priv->img_src->planes[0], 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 6 * vf->priv->w );
+      memcpy_pic( vf->priv->img_r, ( vf->priv->img_src->planes[0] + 3 * vf->priv->w ), 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 6 * vf->priv->w );
+      break;
+    }
+    case SIDE_BY_SIDE_RL:
+    {
+      memcpy_pic( vf->priv->img_l, ( vf->priv->img_src->planes[0] + 3 * vf->priv->w ), 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 6 * vf->priv->w );
+      memcpy_pic( vf->priv->img_r, vf->priv->img_src->planes[0], 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 6 * vf->priv->w );
+      break;
+    }
+    case ABOVE_BELOW_LR:
+    {
+      memcpy_pic( vf->priv->img_l, vf->priv->img_src->planes[0], 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( vf->priv->img_r, ( vf->priv->img_src->planes[0] + 3 * vf->priv->w * vf->priv->h ), 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 3 * vf->priv->w );
+      break;
+    }
+    case ABOVE_BELOW_RL:
+    {
+      memcpy_pic( vf->priv->img_r, vf->priv->img_src->planes[0], 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( vf->priv->img_l, ( vf->priv->img_src->planes[0] + 3 * vf->priv->w * vf->priv->h ), 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 3 * vf->priv->w );
+      break;
+    }
+    case ABOVE_BELOW_2_LR:
+    {
+      memcpy_pic( vf->priv->img_l, vf->priv->img_src->planes[0], 3 * vf->priv->w, vf->priv->h / 2, 6 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( vf->priv->img_l + 3 * vf->priv->w, vf->priv->img_src->planes[0], 3 * vf->priv->w, vf->priv->h / 2, 6 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( vf->priv->img_r, ( vf->priv->img_src->planes[0] + 3 * vf->priv->w * vf->priv->h / 2 ), 3 * vf->priv->w, vf->priv->h / 2, 6 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( vf->priv->img_r + 3 * vf->priv->w, ( vf->priv->img_src->planes[0] + 3 * vf->priv->w * vf->priv->h / 2 ), 3 * vf->priv->w, vf->priv->h / 2, 6 * vf->priv->w, 3 * vf->priv->w );
+      break;
+    }
+    case ABOVE_BELOW_2_RL:
+    {
+      memcpy_pic( vf->priv->img_r, vf->priv->img_src->planes[0], 3 * vf->priv->w, vf->priv->h / 2, 6 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( vf->priv->img_r + 3 * vf->priv->w, vf->priv->img_src->planes[0], 3 * vf->priv->w, vf->priv->h / 2, 6 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( vf->priv->img_l, ( vf->priv->img_src->planes[0] + 3 * vf->priv->w * vf->priv->h / 2 ), 3 * vf->priv->w, vf->priv->h / 2, 6 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( vf->priv->img_l + 3 * vf->priv->w, ( vf->priv->img_src->planes[0] + 3 * vf->priv->w * vf->priv->h / 2 ), 3 * vf->priv->w, vf->priv->h / 2, 6 * vf->priv->w, 3 * vf->priv->w );
+      break;
+    }
+    //TODO: support for interlaced input
+    //TODO: support for anaglyph input
+    default:
+    {
+      mp_msg( MSGT_VFILTER, MSGL_WARN, "[stereo] stereo format of input is not supported\n" );
+      return 0;
+      break;
+    }
+  }
+  return 1;
+}
+
+static int set_rgb24( struct vf_instance_s* vf )
+{
+  switch( vf->priv->out_fmt )
+  {
+    case SIDE_BY_SIDE_LR:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_l, 3 * vf->priv->w, vf->priv->h, 6 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( ( vf->priv->img_dst->planes[0] + 3 * vf->priv->w ), vf->priv->img_r, 3 * vf->priv->w, vf->priv->h, 6 * vf->priv->w, 3 * vf->priv->w );
+      break;
+    }
+    case SIDE_BY_SIDE_RL:
+    {
+      memcpy_pic( ( vf->priv->img_dst->planes[0] + 3 * vf->priv->w ), vf->priv->img_l, 3 * vf->priv->w, vf->priv->h, 6 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_r, 3 * vf->priv->w, vf->priv->h, 6 * vf->priv->w, 3 * vf->priv->w );
+      break;
+    }
+    case ABOVE_BELOW_LR:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_l, 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[0] + 3 * vf->priv->w * vf->priv->h, vf->priv->img_r, 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 3 * vf->priv->w );
+      break;
+    }
+    case ABOVE_BELOW_RL:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_r, 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 3 * vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[0] + 3 * vf->priv->w * vf->priv->h, vf->priv->img_l, 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 3 * vf->priv->w );
+      break;
+    }
+    case ABOVE_BELOW_2_LR:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_l, 3 * vf->priv->w, vf->priv->h / 2, 3 * vf->priv->w, 6 * vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[0] + 3 * vf->priv->w * vf->priv->h / 2, vf->priv->img_r, 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 6 * vf->priv->w );
+      break;
+    }
+    case ABOVE_BELOW_2_RL:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_r, 3 * vf->priv->w, vf->priv->h / 2, 3 * vf->priv->w, 6 * vf->priv->w );
+      memcpy_pic( vf->priv->img_dst->planes[0] + 3 * vf->priv->w * vf->priv->h / 2, vf->priv->img_l, 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 6 * vf->priv->w );
+      break;
+    }
+    case MONO_L:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_l, 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 3 * vf->priv->w );
+      break;
+    }
+    case MONO_R:
+    {
+      memcpy_pic( vf->priv->img_dst->planes[0], vf->priv->img_r, 3 * vf->priv->w, vf->priv->h, 3 * vf->priv->w, 3 * vf->priv->w );
+      break;
+    }
+    case ANAGLYPH_RC:
+    {
+      int i;
+      int size = 3 * vf->priv->w * vf->priv->h;
+      for( i = 0; i < size; i += 3 )
+      { //merge
+        vf->priv->img_dst->planes[0][i]     = RC_R( vf->priv->img_l[i    ], vf->priv->img_r[i    ],
+                                                    vf->priv->img_l[i + 1], vf->priv->img_r[i + 1],
+                                                    vf->priv->img_l[i + 2], vf->priv->img_r[i + 2] );
+        vf->priv->img_dst->planes[0][i + 1] = RC_G( vf->priv->img_l[i    ], vf->priv->img_r[i    ],
+                                                    vf->priv->img_l[i + 1], vf->priv->img_r[i + 1],
+                                                    vf->priv->img_l[i + 2], vf->priv->img_r[i + 2] );
+        vf->priv->img_dst->planes[0][i + 2] = RC_B( vf->priv->img_l[i    ], vf->priv->img_r[i    ],
+                                                    vf->priv->img_l[i + 1], vf->priv->img_r[i + 1],
+                                                    vf->priv->img_l[i + 2], vf->priv->img_r[i + 2] );
+      }
+      break;
+    }
+    case ANAGLYPH_GM:
+    {
+      int i;
+      int size = 3 * vf->priv->w * vf->priv->h;
+      for( i = 0; i < size; i += 3 )
+      { //merge
+        vf->priv->img_dst->planes[0][i]     = GM_R( vf->priv->img_l[i    ], vf->priv->img_r[i    ],
+                                                    vf->priv->img_l[i + 1], vf->priv->img_r[i + 1],
+                                                    vf->priv->img_l[i + 2], vf->priv->img_r[i + 2] );
+        vf->priv->img_dst->planes[0][i + 1] = GM_G( vf->priv->img_l[i    ], vf->priv->img_r[i    ],
+                                                    vf->priv->img_l[i + 1], vf->priv->img_r[i + 1],
+                                                    vf->priv->img_l[i + 2], vf->priv->img_r[i + 2] );
+        vf->priv->img_dst->planes[0][i + 2] = GM_B( vf->priv->img_l[i    ], vf->priv->img_r[i    ],
+                                                    vf->priv->img_l[i + 1], vf->priv->img_r[i + 1],
+                                                    vf->priv->img_l[i + 2], vf->priv->img_r[i + 2] );
+      }
+      break;
+    }
+    case ANAGLYPH_YB:
+    {
+      int i;
+      int size = 3 * vf->priv->w * vf->priv->h;
+      for( i = 0; i < size; i += 3 )
+      { //merge
+        vf->priv->img_dst->planes[0][i]     = YB_R( vf->priv->img_l[i    ], vf->priv->img_r[i    ],
+                                                    vf->priv->img_l[i + 1], vf->priv->img_r[i + 1],
+                                                    vf->priv->img_l[i + 2], vf->priv->img_r[i + 2] );
+        vf->priv->img_dst->planes[0][i + 1] = YB_G( vf->priv->img_l[i    ], vf->priv->img_r[i    ],
+                                                    vf->priv->img_l[i + 1], vf->priv->img_r[i + 1],
+                                                    vf->priv->img_l[i + 2], vf->priv->img_r[i + 2] );
+        vf->priv->img_dst->planes[0][i + 2] = YB_B( vf->priv->img_l[i    ], vf->priv->img_r[i    ],
+                                                    vf->priv->img_l[i + 1], vf->priv->img_r[i + 1],
+                                                    vf->priv->img_l[i + 2], vf->priv->img_r[i + 2] );
+      }
+      break;
+    }
+    //TODO: support for interlaced output
+    default:
+    {
+      mp_msg( MSGT_VFILTER, MSGL_WARN, "[stereo] stereo format of output is not supported\n" );
+      return 0;
+      break;
+    }
+  }
+  return 1;
+}
+
+
+static int put_image( struct vf_instance_s* vf, mp_image_t* mpi, double pts )
+{
+  if( vf->priv->in_fmt == vf->priv->out_fmt )
+  { //nothing to do
+    vf->priv->img_dst = mpi; 
+  }
+  else
+  {
+    vf->priv->img_src = mpi;
+    switch( mpi->imgfmt )
+    {
+      case IMGFMT_YV12:
+      {
+        vf->priv->img_dst = vf_get_image( vf->next, IMGFMT_YV12, MP_IMGTYPE_TEMP, 0, vf->priv->out_w, vf->priv->out_h );
+        vf->priv->img_dst->h = vf->priv->out_h;
+        vf->priv->img_dst->width = vf->priv->out_w;
+        memset( vf->priv->img_dst->planes[0], 0, vf->priv->out_w * vf->priv->out_h );
+        memset( vf->priv->img_dst->planes[1], 128, ( ( vf->priv->out_w * vf->priv->out_h ) >> 2 ) );
+        memset( vf->priv->img_dst->planes[2], 128, ( ( vf->priv->out_w * vf->priv->out_h ) >> 2 ) );
+        if( 0 == get_yv12( vf ) )
+        {
+          return 0;
+        }
+        if( 0 == set_yv12( vf ) )
+        {
+          return 0;
+        }
+        break;
+      }
+      case IMGFMT_RGB24:
+      {
+        vf->priv->img_dst = vf_get_image( vf->next, IMGFMT_RGB24, MP_IMGTYPE_TEMP, 0, vf->priv->out_w, vf->priv->out_h );
+        vf->priv->img_dst->h = vf->priv->out_h;
+        vf->priv->img_dst->width = vf->priv->out_w;
+        if( 0 == get_rgb24( vf ) )
+        {
+          return 0;
+        }
+        if( 0 == set_rgb24( vf ) )
+        {
+          return 0;
+        }
+        break;
+      }
+      default:
+      {
+        mp_msg( MSGT_VFILTER, MSGL_WARN, "[stereo] unsupported input/output fmt\n" );
+        return 0;
+        break;
+      }
+    }
+  }
+  return vf_next_put_image( vf, vf->priv->img_dst, pts );
+}
+
+static int query_format( struct vf_instance_s* vf, unsigned int fmt )
+{
+  switch( fmt )
+  {
+    case IMGFMT_YV12:
+    case IMGFMT_RGB24:
+      return vf_next_query_format( vf, fmt );
+  }
+  return 0;
+}
+
+static stereo_code get_arg( char* arg )
+{
+  stereo_code return_value = NOT_SET;
+  if( arg )
+  {
+    if( 0 == strcmp( arg, "slr" ) )
+    {
+      return_value = SIDE_BY_SIDE_LR;
+    }
+    else if( 0 == strcmp( arg, "srl" ) )
+    {
+      return_value = SIDE_BY_SIDE_RL;
+    }
+    else if( 0 == strcmp( arg, "ablr" ) )
+    {
+      return_value = ABOVE_BELOW_LR;
+    }
+    else if( 0 == strcmp( arg, "abrl" ) )
+    {
+      return_value = ABOVE_BELOW_RL;
+    }
+    else if( 0 == strcmp( arg, "ab2lr" ) )
+    {
+      return_value = ABOVE_BELOW_2_LR;
+    }
+    else if( 0 == strcmp( arg, "ab2rl" ) )
+    {
+      return_value = ABOVE_BELOW_2_RL;
+    }
+/*interlaced in not support yet
+    else if( 0 == strcmp( arg, "ilr" ) )
+    {
+      return_value = INTERLACED_LR;
+    }
+    else if( 0 == strcmp( arg, "irl" ) )
+    {
+      return_value = INTERLACED_RL;
+    }
+    else if( 0 == strcmp( arg, "i2lr" ) )
+    {
+      return_value = INTERLACED_2_LR;
+    }
+    else if( 0 == strcmp( arg, "i2rl" ) )
+    {
+      return_value = INTERLACED_2_RL;
+    }
+    else if( 0 == strcmp( arg, "i2rl" ) )
+    {
+      return_value = INTERLACED_2_RL;
+    }
+*/
+    else if( 0 == strcmp( arg, "arc" ) )
+    {
+      return_value = ANAGLYPH_RC;
+    }
+    else if( 0 == strcmp( arg, "agm" ) )
+    {
+      return_value = ANAGLYPH_GM;
+    }
+    else if( 0 == strcmp( arg, "ayb" ) )
+    {
+      return_value = ANAGLYPH_YB;
+    }
+    else if( 0 == strcmp( arg, "ml" ) )
+    {
+      return_value = MONO_L;
+    }
+    else if( 0 == strcmp( arg, "mr" ) )
+    {
+      return_value = MONO_R;
+    }
+  }
+  return return_value;
+}
+
+static void uninit( struct vf_instance_s* vf )
+{
+  free( vf->priv->img_l );
+  free( vf->priv->img_r );
+  if( vf->priv )
+  {
+    free( vf->priv );
+  }
+}
+
+static int open( vf_instance_t* vf, char* args )
+{
+  //init priv
+  vf->priv = malloc( sizeof( struct vf_priv_s ) );
+  if( !vf->priv )
+  {
+    return 0;
+  }
+  vf->priv->in_fmt  = NOT_SET;
+  vf->priv->out_fmt = NOT_SET;
+
+  vf->config = config;
+  vf->put_image = put_image;
+	vf->query_format = query_format;
+  vf->uninit = uninit;
+  vf->default_reqs = VFCAP_ACCEPT_STRIDE;
+
+  if( args )
+  {
+    char* arg;
+    //input code
+    arg = strtok( args, ": \0\n" );
+    vf->priv->in_fmt = get_arg( arg );
+    //output code
+    arg = strtok( NULL, ": \0\n" );
+    vf->priv->out_fmt = get_arg( arg );
+  }
+  return 1;
+}
+
+//==info struct==//
+const vf_info_t vf_info_stereo = {
+  "stereoscopic 3d view",
+  "stereo",
+  "Gordon Schmidt",
+  "view stereoscopic videos",
+  open,
+  NULL
+};
Index: libmpcodecs/vf.c
===================================================================
--- libmpcodecs/vf.c	(revision 30392)
+++ libmpcodecs/vf.c	(working copy)
@@ -100,6 +100,7 @@
 extern const vf_info_t vf_info_blackframe;
 extern const vf_info_t vf_info_geq;
 extern const vf_info_t vf_info_ow;
+extern const vf_info_t vf_info_stereo;
 
 // list of available filters:
 static const vf_info_t* const filter_list[]={
@@ -193,6 +194,7 @@
     &vf_info_yadif,
     &vf_info_blackframe,
     &vf_info_ow,
+    &vf_info_stereo,
     NULL
 };
 
Index: Makefile
===================================================================
--- Makefile	(revision 30392)
+++ Makefile	(working copy)
@@ -453,6 +453,7 @@
               libmpcodecs/vf_smartblur.c \
               libmpcodecs/vf_softpulldown.c \
               libmpcodecs/vf_softskip.c \
+              libmpcodecs/vf_stereo.c \
               libmpcodecs/vf_swapuv.c \
               libmpcodecs/vf_telecine.c \
               libmpcodecs/vf_test.c \


More information about the MPlayer-dev-eng mailing list