changeset 5507:d0d029fda134

video filter layer - written from scratch, but inspired a lot by Fredrik Kuivinen's patch
author arpi
date Sat, 06 Apr 2002 22:05:01 +0000
parents b8b6fcb5062a
children 53ce50ac2ce2
files cfg-common.h dec_video.h libmpcodecs/Makefile libmpcodecs/dec_video.c libmpcodecs/vd.c libmpcodecs/vf.c libmpcodecs/vf.h libmpcodecs/vf_crop.c libmpcodecs/vf_expand.c libmpcodecs/vf_vo.c mencoder.c mplayer.c
diffstat 12 files changed, 606 insertions(+), 123 deletions(-) [+]
line wrap: on
line diff
--- a/cfg-common.h	Sat Apr 06 22:00:50 2002 +0000
+++ b/cfg-common.h	Sat Apr 06 22:05:01 2002 +0000
@@ -96,6 +96,7 @@
 	{"tv", "MPlayer was compiled without TV Interface support\n", CONF_TYPE_PRINT, 0, 0, 0, NULL},
 #endif
 	{"vivo", vivoopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
+    {"vop", &vo_plugin_args, CONF_TYPE_STRING_LIST, 0, 0, 0, NULL},
 
 #else
 
@@ -179,4 +180,6 @@
         {NULL, NULL, 0, 0, 0, 0, NULL}
 };
 						
+extern char** vo_plugin_args;
+
 #endif
--- a/dec_video.h	Sat Apr 06 22:00:50 2002 +0000
+++ b/dec_video.h	Sat Apr 06 22:05:01 2002 +0000
@@ -6,11 +6,7 @@
 extern int init_video(sh_video_t *sh_video,char* codecname,int vfm,int status);
 extern void uninit_video(sh_video_t *sh_video);
 
-#ifdef USE_LIBVO2
-extern int decode_video(vo2_handle_t *video_out,sh_video_t *sh_video,unsigned char *start,int in_size,int drop_frame);
-#else
-extern int decode_video(vo_functions_t *video_out,sh_video_t *sh_video,unsigned char *start,int in_size,int drop_frame);
-#endif
+extern int decode_video(sh_video_t *sh_video,unsigned char *start,int in_size,int drop_frame);
 
 extern int get_video_quality_max(sh_video_t *sh_video);
 extern void set_video_quality(sh_video_t *sh_video,int quality);
--- a/libmpcodecs/Makefile	Sat Apr 06 22:00:50 2002 +0000
+++ b/libmpcodecs/Makefile	Sat Apr 06 22:05:01 2002 +0000
@@ -5,6 +5,7 @@
 
 AUDIO_SRCS=dec_audio.c ad.c ad_a52.c ad_acm.c ad_alaw.c ad_dk3adpcm.c ad_dshow.c ad_dvdpcm.c ad_ffmpeg.c ad_hwac3.c ad_imaadpcm.c ad_mp3.c ad_msadpcm.c ad_pcm.c ad_roqaudio.c ad_msgsm.c ad_faad.c ad_vorbis.c ad_libmad.c
 VIDEO_SRCS=dec_video.c vd.c vd_null.c vd_cinepak.c vd_qtrpza.c vd_ffmpeg.c vd_dshow.c vd_vfw.c vd_odivx.c vd_divx4.c vd_raw.c vd_xanim.c vd_msvidc.c vd_fli.c vd_qtrle.c vd_qtsmc.c vd_roqvideo.c vd_cyuv.c vd_nuv.c vd_libmpeg2.c vd_msrle.c vd_huffyuv.c vd_zlib.c vd_mpegpes.c
+VFILTER_SRCS=vf.c vf_vo.c vf_crop.c vf_expand.c
 
 ifeq ($(PNG),yes)
 VIDEO_SRCS += vd_mpng.c
@@ -14,7 +15,7 @@
 VIDEO_SRCS += vd_ijpg.c
 endif
 
-SRCS=$(AUDIO_SRCS) $(VIDEO_SRCS)
+SRCS=$(AUDIO_SRCS) $(VIDEO_SRCS) $(VFILTER_SRCS)
 OBJS=$(SRCS:.c=.o)
 
 CFLAGS  = -Wall $(OPTFLAGS) -I. -I.. -I../libmpdemux -I../loader $(EXTRA_INC)
--- a/libmpcodecs/dec_video.c	Sat Apr 06 22:00:50 2002 +0000
+++ b/libmpcodecs/dec_video.c	Sat Apr 06 22:05:01 2002 +0000
@@ -26,6 +26,7 @@
 
 #include "stheader.h"
 #include "vd.h"
+#include "vf.h"
 
 #include "dec_video.h"
 
@@ -152,15 +153,14 @@
 
 extern int vo_directrendering;
 
-int decode_video(vo_functions_t *video_out,sh_video_t *sh_video,unsigned char *start,int in_size,int drop_frame){
+int decode_video(sh_video_t *sh_video,unsigned char *start,int in_size,int drop_frame){
+vf_instance_t* vf=sh_video->vfilter;
 mp_image_t *mpi=NULL;
 int blit_frame=0;
 unsigned int t=GetTimer();
 unsigned int t2;
 double tt;
 
-sh_video->video_out=video_out;
-
 //if(!(sh_video->ds->flags&1) || sh_video->ds->pack_no<5)
 mpi=mpvdec->decode(sh_video, start, in_size, drop_frame);
 
@@ -185,13 +185,8 @@
 
 if(drop_frame) return 0;
 
-if(!(mpi->flags&(MP_IMGFLAG_DIRECT|MP_IMGFLAG_DRAW_CALLBACK))){
-    // blit frame:
-    if(mpi->flags&MP_IMGFLAG_PLANAR)
-        video_out->draw_slice(mpi->planes,mpi->stride,sh_video->disp_w,sh_video->disp_h,0,0);
-    else
-        video_out->draw_frame(mpi->planes);
-}
+//vo_draw_image(video_out,mpi);
+vf->put_image(vf,mpi);
 
     t2=GetTimer()-t2;
     tt=t2*0.000001f;
@@ -200,5 +195,3 @@
 
   return blit_frame;
 }
-
-
--- a/libmpcodecs/vd.c	Sat Apr 06 22:00:50 2002 +0000
+++ b/libmpcodecs/vd.c	Sat Apr 06 22:05:01 2002 +0000
@@ -20,6 +20,8 @@
 #include "stheader.h"
 
 #include "vd.h"
+#include "vf.h"
+
 //#include "vd_internal.h"
 
 extern vd_functions_t mpcodecs_vd_null;
@@ -96,7 +98,6 @@
 };
 
 #include "libvo/video_out.h"
-extern int vo_directrendering;
 
 // libvo opts:
 int fullscreen=0;
@@ -110,13 +111,6 @@
 int vo_flags=0;
 int vd_use_slices=1;
 
-static vo_tune_info_t vtune;
-
-static mp_image_t* static_images[2];
-static mp_image_t* temp_images[1];
-static mp_image_t* export_images[1];
-static int static_idx=0;
-
 extern vd_functions_t* mpvdec; // FIXME!
 
 int mpcodecs_config_vo(sh_video_t *sh, int w, int h, unsigned int preferred_outfmt){
@@ -124,7 +118,8 @@
     unsigned int out_fmt=0;
     int screen_size_x=0;//SCREEN_SIZE_X;
     int screen_size_y=0;//SCREEN_SIZE_Y;
-    vo_functions_t* video_out=sh->video_out;
+//    vo_functions_t* video_out=sh->video_out;
+    vf_instance_t* vf=sh->vfilter;
 
 #if 1
     if(!(sh->disp_w && sh->disp_h))
@@ -141,14 +136,14 @@
     mp_msg(MSGT_DECVIDEO,MSGL_INFO,"VDec: vo config request - %d x %d, %s  \n",
 	w,h,vo_format_name(preferred_outfmt));
 
-    if(!video_out) return 1; // temp hack
+    if(!vf) return 1; // temp hack
 
     // check if libvo and codec has common outfmt (no conversion):
     j=-1;
     for(i=0;i<CODECS_MAX_OUTFMT;i++){
 	out_fmt=sh->codec->outfmt[i];
 	if(out_fmt==(signed int)0xFFFFFFFF) continue;
-	vo_flags=video_out->control(VOCTRL_QUERY_FORMAT, &out_fmt);
+	vo_flags=vf->query_format(vf,out_fmt);
 	mp_msg(MSGT_CPLAYER,MSGL_DBG2,"vo_debug: query(%s) returned 0x%X (i=%d) \n",vo_format_name(out_fmt),vo_flags,i);
 	if((vo_flags&2) || (vo_flags && j<0)){
 	    // check (query) if codec really support this outfmt...
@@ -213,6 +208,7 @@
     }
   }
 
+#if 0
   if(video_out->get_info)
   { const vo_info_t *info = video_out->get_info();
     mp_msg(MSGT_CPLAYER,MSGL_INFO,"VO: [%s] %dx%d => %dx%d %s %s%s%s%s\n",info->short_name,
@@ -228,6 +224,7 @@
     if(info->comment && strlen(info->comment) > 0)
         mp_msg(MSGT_CPLAYER,MSGL_V,"VO: Comment: %s\n", info->comment);
   }
+#endif
 
     // Time to config libvo!
     mp_msg(MSGT_CPLAYER,MSGL_V,"video_out->init(%dx%d->%dx%d,flags=%d,'%s',0x%X)\n",
@@ -236,21 +233,25 @@
                       fullscreen|(vidmode<<1)|(softzoom<<2)|(flip<<3),
                       "MPlayer",out_fmt);
 
-    memset(&vtune,0,sizeof(vo_tune_info_t));
-    if(video_out->config(sh->disp_w,sh->disp_h,
+//    memset(&vtune,0,sizeof(vo_tune_info_t));
+    if(vf->config(vf,sh->disp_w,sh->disp_h,
                       screen_size_x,screen_size_y,
                       fullscreen|(vidmode<<1)|(softzoom<<2)|(flip<<3),
-                      "MPlayer",out_fmt,&vtune)){
+                      out_fmt)==0){
+//                      "MPlayer",out_fmt,&vtune)){
 	mp_msg(MSGT_CPLAYER,MSGL_FATAL,MSGTR_CannotInitVO);
 	return 0; // exit_player(MSGTR_Exit_error);
     }
 
+#if 0
 #define FREE_MPI(mpi) if(mpi){if(mpi->flags&MP_IMGFLAG_ALLOCATED) free(mpi->planes[0]); free(mpi); mpi=NULL;}
     FREE_MPI(static_images[0])
     FREE_MPI(static_images[1])
     FREE_MPI(temp_images[0])
     FREE_MPI(export_images[0])
 #undef FREE_MPI
+#endif
+
     return 1;
 }
 
@@ -259,89 +260,6 @@
 // returns NULL or allocated mp_image_t*
 // Note: buffer allocation may be moved to mpcodecs_config_vo() later...
 mp_image_t* mpcodecs_get_image(sh_video_t *sh, int mp_imgtype, int mp_imgflag, int w, int h){
-  mp_image_t* mpi=NULL;
-  int w2=w; //(mp_imgflag&MP_IMGFLAG_ACCEPT_STRIDE)?((w+15)&(~15)):w;
-  // Note: we should call libvo first to check if it supports direct rendering
-  // and if not, then fallback to software buffers:
-  switch(mp_imgtype){
-  case MP_IMGTYPE_EXPORT:
-//    mpi=new_mp_image(w,h);
-    if(!export_images[0]) export_images[0]=new_mp_image(w2,h);
-    mpi=export_images[0];
-    break;
-  case MP_IMGTYPE_STATIC:
-    if(!static_images[0]) static_images[0]=new_mp_image(w2,h);
-    mpi=static_images[0];
-    break;
-  case MP_IMGTYPE_TEMP:
-    if(!temp_images[0]) temp_images[0]=new_mp_image(w2,h);
-    mpi=temp_images[0];
-    break;
-  case MP_IMGTYPE_IPB:
-    if(!(mp_imgflag&MP_IMGFLAG_READABLE)){ // B frame:
-      if(!temp_images[0]) temp_images[0]=new_mp_image(w2,h);
-      mpi=temp_images[0];
-      break;
-    }
-  case MP_IMGTYPE_IP:
-    if(!static_images[static_idx]) static_images[static_idx]=new_mp_image(w2,h);
-    mpi=static_images[static_idx];
-    static_idx^=1;
-    break;
-  }
-  if(mpi){
-    mpi->type=mp_imgtype;
-    mpi->flags&=~(MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE|MP_IMGFLAG_DIRECT);
-    mpi->flags|=mp_imgflag&(MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE|MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_ACCEPT_WIDTH|MP_IMGFLAG_ALIGNED_STRIDE|MP_IMGFLAG_DRAW_CALLBACK);
-    if((mpi->width!=w2 || mpi->height!=h) && !(mpi->flags&MP_IMGFLAG_DIRECT)){
-	mpi->width=w2;
-	mpi->height=h;
-	if(mpi->flags&MP_IMGFLAG_ALLOCATED){
-	    // need to re-allocate buffer memory:
-	    free(mpi->planes[0]);
-	    mpi->flags&=~MP_IMGFLAG_ALLOCATED;
-	}
-    }
-    if(!mpi->bpp) mp_image_setfmt(mpi,sh->codec->outfmt[sh->outfmtidx]);
-    if(!(mpi->flags&MP_IMGFLAG_ALLOCATED) && mpi->type>MP_IMGTYPE_EXPORT){
-
-	// check libvo first!
-	vo_functions_t* vo=sh->video_out;
-	if(vo && vo_directrendering) vo->control(VOCTRL_GET_IMAGE,mpi);
-	
-        if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
-          // non-direct and not yet allocaed image. allocate it!
-	  mpi->planes[0]=memalign(64, mpi->bpp*mpi->width*mpi->height/8);
-	  if(mpi->flags&MP_IMGFLAG_PLANAR){
-	      // YV12/I420. feel free to add other planar formats here...
-	      if(!mpi->stride[0]) mpi->stride[0]=mpi->width;
-	      if(!mpi->stride[1]) mpi->stride[1]=mpi->stride[2]=mpi->width/2;
-	      if(mpi->flags&MP_IMGFLAG_SWAPPED){
-	          // I420/IYUV  (Y,U,V)
-	          mpi->planes[1]=mpi->planes[0]+mpi->width*mpi->height;
-	          mpi->planes[2]=mpi->planes[1]+(mpi->width>>1)*(mpi->height>>1);
-	      } else {
-	          // YV12,YVU9  (Y,V,U)
-	          mpi->planes[2]=mpi->planes[0]+mpi->width*mpi->height;
-	          mpi->planes[1]=mpi->planes[2]+(mpi->width>>1)*(mpi->height>>1);
-	      }
-	  } else {
-	      if(!mpi->stride[0]) mpi->stride[0]=mpi->width*mpi->bpp/8;
-	  }
-	  mpi->flags|=MP_IMGFLAG_ALLOCATED;
-        }
-	if(!(mpi->flags&MP_IMGFLAG_TYPE_DISPLAYED)){
-	    mp_msg(MSGT_DECVIDEO,MSGL_INFO,"*** %s mp_image_t, %dx%dx%dbpp %s %s, %d bytes\n",
-	          (mpi->flags&MP_IMGFLAG_DIRECT)?"Direct Rendering":"Allocating",
-	          mpi->width,mpi->height,mpi->bpp,
-		  (mpi->flags&MP_IMGFLAG_YUV)?"YUV":"RGB",
-		  (mpi->flags&MP_IMGFLAG_PLANAR)?"planar":"packed",
-	          mpi->bpp*mpi->width*mpi->height/8);
-	    mpi->flags|=MP_IMGFLAG_TYPE_DISPLAYED;
-	}
-	
-    }
-  }
-  return mpi;
+  return vf_get_image(sh->vfilter,sh->codec->outfmt[sh->outfmtidx],mp_imgtype,mp_imgflag,w,h);
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpcodecs/vf.c	Sat Apr 06 22:05:01 2002 +0000
@@ -0,0 +1,190 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../config.h"
+#include "../mp_msg.h"
+
+#include "../libvo/img_format.h"
+#include "../mp_image.h"
+#include "vf.h"
+
+extern vf_info_t vf_info_vo;
+extern vf_info_t vf_info_crop;
+extern vf_info_t vf_info_expand;
+
+char** vo_plugin_args=(char**) NULL;
+
+// list of available filters:
+static vf_info_t* filter_list[]={
+    &vf_info_crop,
+    &vf_info_expand,
+//    &vf_info_zoom,
+//    &vf_info_osd,
+    &vf_info_vo,
+    NULL
+};
+
+//============================================================================
+
+// mpi stuff:
+
+mp_image_t* vf_get_image(vf_instance_t* vf, unsigned int outfmt, int mp_imgtype, int mp_imgflag, int w, int h){
+  mp_image_t* mpi=NULL;
+  int w2=w; //(mp_imgflag&MP_IMGFLAG_ACCEPT_STRIDE)?((w+15)&(~15)):w;
+  // Note: we should call libvo first to check if it supports direct rendering
+  // and if not, then fallback to software buffers:
+  switch(mp_imgtype){
+  case MP_IMGTYPE_EXPORT:
+    if(!vf->imgctx.export_images[0]) vf->imgctx.export_images[0]=new_mp_image(w2,h);
+    mpi=vf->imgctx.export_images[0];
+    break;
+  case MP_IMGTYPE_STATIC:
+    if(!vf->imgctx.static_images[0]) vf->imgctx.static_images[0]=new_mp_image(w2,h);
+    mpi=vf->imgctx.static_images[0];
+    break;
+  case MP_IMGTYPE_TEMP:
+    if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=new_mp_image(w2,h);
+    mpi=vf->imgctx.temp_images[0];
+    break;
+  case MP_IMGTYPE_IPB:
+    if(!(mp_imgflag&MP_IMGFLAG_READABLE)){ // B frame:
+      if(!vf->imgctx.temp_images[0]) vf->imgctx.temp_images[0]=new_mp_image(w2,h);
+      mpi=vf->imgctx.temp_images[0];
+      break;
+    }
+  case MP_IMGTYPE_IP:
+    if(!vf->imgctx.static_images[vf->imgctx.static_idx]) vf->imgctx.static_images[vf->imgctx.static_idx]=new_mp_image(w2,h);
+    mpi=vf->imgctx.static_images[vf->imgctx.static_idx];
+    vf->imgctx.static_idx^=1;
+    break;
+  }
+  if(mpi){
+    mpi->type=mp_imgtype;
+    mpi->flags&=~(MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE|MP_IMGFLAG_DIRECT);
+    mpi->flags|=mp_imgflag&(MP_IMGFLAG_PRESERVE|MP_IMGFLAG_READABLE|MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_ACCEPT_WIDTH|MP_IMGFLAG_ALIGNED_STRIDE|MP_IMGFLAG_DRAW_CALLBACK);
+    if(!vf->draw_slice) mpi->flags&=~MP_IMGFLAG_DRAW_CALLBACK;
+    if((mpi->width!=w2 || mpi->height!=h) && !(mpi->flags&MP_IMGFLAG_DIRECT)){
+	mpi->width=w2;
+	mpi->height=h;
+	if(mpi->flags&MP_IMGFLAG_ALLOCATED){
+	    // need to re-allocate buffer memory:
+	    free(mpi->planes[0]);
+	    mpi->flags&=~MP_IMGFLAG_ALLOCATED;
+	}
+    }
+    if(!mpi->bpp) mp_image_setfmt(mpi,outfmt);
+    if(!(mpi->flags&MP_IMGFLAG_ALLOCATED) && mpi->type>MP_IMGTYPE_EXPORT){
+
+	// check libvo first!
+	if(vf->get_image) vf->get_image(vf,mpi);
+	
+        if(!(mpi->flags&MP_IMGFLAG_DIRECT)){
+          // non-direct and not yet allocaed image. allocate it!
+	  mpi->planes[0]=memalign(64, mpi->bpp*mpi->width*mpi->height/8);
+	  if(mpi->flags&MP_IMGFLAG_PLANAR){
+	      // YV12/I420. feel free to add other planar formats here...
+	      if(!mpi->stride[0]) mpi->stride[0]=mpi->width;
+	      if(!mpi->stride[1]) mpi->stride[1]=mpi->stride[2]=mpi->width/2;
+	      if(mpi->flags&MP_IMGFLAG_SWAPPED){
+	          // I420/IYUV  (Y,U,V)
+	          mpi->planes[1]=mpi->planes[0]+mpi->width*mpi->height;
+	          mpi->planes[2]=mpi->planes[1]+(mpi->width>>1)*(mpi->height>>1);
+	      } else {
+	          // YV12,YVU9  (Y,V,U)
+	          mpi->planes[2]=mpi->planes[0]+mpi->width*mpi->height;
+	          mpi->planes[1]=mpi->planes[2]+(mpi->width>>1)*(mpi->height>>1);
+	      }
+	  } else {
+	      if(!mpi->stride[0]) mpi->stride[0]=mpi->width*mpi->bpp/8;
+	  }
+	  mpi->flags|=MP_IMGFLAG_ALLOCATED;
+        }
+    }
+    if(!(mpi->flags&MP_IMGFLAG_TYPE_DISPLAYED)){
+	    mp_msg(MSGT_DECVIDEO,MSGL_INFO,"*** [%s] %s mp_image_t, %dx%dx%dbpp %s %s, %d bytes\n",
+		  vf->info->name,
+		  (mpi->type==MP_IMGTYPE_EXPORT)?"Exporting":
+	          ((mpi->flags&MP_IMGFLAG_DIRECT)?"Direct Rendering":"Allocating"),
+	          mpi->width,mpi->height,mpi->bpp,
+		  (mpi->flags&MP_IMGFLAG_YUV)?"YUV":"RGB",
+		  (mpi->flags&MP_IMGFLAG_PLANAR)?"planar":"packed",
+	          mpi->bpp*mpi->width*mpi->height/8);
+	    mpi->flags|=MP_IMGFLAG_TYPE_DISPLAYED;
+    }
+
+  }
+  return mpi;
+}
+
+//============================================================================
+
+vf_instance_t* vf_open_filter(vf_instance_t* next, char *name, char *args){
+    vf_instance_t* vf;
+    int i;
+    for(i=0;;i++){
+	if(!filter_list[i]){
+	    mp_msg(MSGT_VFILTER,MSGL_ERR,"Couldn't find video filter '%s'\n",name);
+	    return NULL; // no such filter!
+	}
+	if(!strcmp(filter_list[i]->name,name)) break;
+    }
+    vf=malloc(sizeof(vf_instance_t));
+    memset(vf,0,sizeof(vf_instance_t));
+    vf->info=filter_list[i];
+    vf->next=next;
+    vf->config=vf_next_config;
+    vf->control=vf_next_control;
+    vf->query_format=vf_next_query_format;
+    vf->put_image=vf_next_put_image;
+    vf->uninit=vf_next_uninit;
+    if(vf->info->open(vf,args)>0) return vf; // Success!
+    free(vf);
+    mp_msg(MSGT_VFILTER,MSGL_ERR,"Couldn't open video filter '%s'\n",name);
+    return NULL;
+}
+
+//============================================================================
+
+int vf_next_config(struct vf_instance_s* vf,
+        int width, int height, int d_width, int d_height,
+	unsigned int flags, unsigned int outfmt){
+    return vf->next->config(vf->next,width,height,d_width,d_height,flags,outfmt);
+}
+
+int vf_next_control(struct vf_instance_s* vf, int request, void* data){
+    return vf->next->control(vf->next,request,data);
+}
+
+int vf_next_query_format(struct vf_instance_s* vf, unsigned int fmt){
+    return vf->next->query_format(vf->next,fmt);
+}
+
+void vf_next_put_image(struct vf_instance_s* vf,mp_image_t *mpi){
+    return vf->next->put_image(vf->next,mpi);
+}
+
+void vf_next_uninit(struct vf_instance_s* vf){
+    return vf->next->uninit(vf->next);
+}
+
+//============================================================================
+
+vf_instance_t* append_filters(vf_instance_t* last){
+    vf_instance_t* vf;
+    if(!vo_plugin_args) return last;
+    while(*vo_plugin_args){
+	char* name=strdup(*vo_plugin_args);
+	char* args=strchr(name,'=');
+	if(args){args[0]=0;++args;}
+	mp_msg(MSGT_VFILTER,MSGL_INFO,"Opening video filter '%s' with args '%s'...\n",name,args);
+	vf=vf_open_filter(last,name,args);
+	if(vf) last=vf;
+	free(name);
+	++vo_plugin_args;
+    }
+    return last;
+}
+
+//============================================================================
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpcodecs/vf.h	Sat Apr 06 22:05:01 2002 +0000
@@ -0,0 +1,57 @@
+
+struct vf_instance_s;
+struct vf_priv_s;
+
+typedef struct vf_info_s {
+    const char *info;
+    const char *name;
+    const char *author;
+    const char *comment;
+    int (*open)(struct vf_instance_s* vf,char* args);
+} vf_info_t;
+
+typedef struct vf_image_context_s {
+    mp_image_t* static_images[2];
+    mp_image_t* temp_images[1];
+    mp_image_t* export_images[1];
+    int static_idx;
+} vf_image_context_t;
+
+typedef struct vf_instance_s {
+    vf_info_t* info;
+    // funcs:
+    int (*config)(struct vf_instance_s* vf,
+        int width, int height, int d_width, int d_height,
+	unsigned int flags, unsigned int outfmt);
+    int (*control)(struct vf_instance_s* vf,
+        int request, void* data);
+    int (*query_format)(struct vf_instance_s* vf,
+        unsigned int fmt);
+    void (*get_image)(struct vf_instance_s* vf,
+        mp_image_t *mpi);
+    void (*put_image)(struct vf_instance_s* vf,
+        mp_image_t *mpi);
+    void (*draw_slice)(struct vf_instance_s* vf,
+        unsigned char* src, int* stride, int w,int h, int x, int y);
+    void (*uninit)(struct vf_instance_s* vf);
+    // data:
+    vf_image_context_t imgctx;
+    struct vf_instance_s* next;
+    struct vf_priv_s* priv;
+} vf_instance_t;
+
+// functions:
+mp_image_t* vf_get_image(vf_instance_t* vf, unsigned int outfmt, int mp_imgtype, int mp_imgflag, int w, int h);
+vf_instance_t* vf_open_filter(vf_instance_t* next, char *name, char *args);
+
+// default wrappers:
+int vf_next_config(struct vf_instance_s* vf,
+        int width, int height, int d_width, int d_height,
+	unsigned int flags, unsigned int outfmt);
+int vf_next_control(struct vf_instance_s* vf, int request, void* data);
+int vf_next_query_format(struct vf_instance_s* vf, unsigned int fmt);
+void vf_next_put_image(struct vf_instance_s* vf,mp_image_t *mpi);
+void vf_next_uninit(struct vf_instance_s* vf);
+vf_instance_t* append_filters(vf_instance_t* last);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpcodecs/vf_crop.c	Sat Apr 06 22:05:01 2002 +0000
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../config.h"
+#include "../mp_msg.h"
+
+#include "../mp_image.h"
+#include "vf.h"
+
+struct vf_priv_s {
+    int crop_w,crop_h;
+    int crop_x,crop_y;
+};
+
+//===========================================================================//
+
+static int config(struct vf_instance_s* vf,
+        int width, int height, int d_width, int d_height,
+	unsigned int flags, unsigned int outfmt){
+    int ret;
+    printf("crop->config() called\n");
+    // calculate the missing parameters:
+    if(vf->priv->crop_w<=0 || vf->priv->crop_w>width) vf->priv->crop_w=width;
+    if(vf->priv->crop_h<=0 || vf->priv->crop_h>height) vf->priv->crop_h=height;
+    if(vf->priv->crop_x<0) vf->priv->crop_x=(width-vf->priv->crop_w)/2;
+    if(vf->priv->crop_y<0) vf->priv->crop_y=(height-vf->priv->crop_h)/2;
+    // check:
+    if(vf->priv->crop_w+vf->priv->crop_x>width) return 0; // bad width
+    if(vf->priv->crop_h+vf->priv->crop_y>height) return 0; // bad height
+    ret=vf_next_config(vf,vf->priv->crop_w,vf->priv->crop_h,d_width,d_height,flags,outfmt);
+    printf("crop->config() return %d\n",ret);
+    return ret;
+}
+
+static void put_image(struct vf_instance_s* vf, mp_image_t *mpi){
+    mp_image_t *dmpi=vf_get_image(vf->next,mpi->imgfmt,
+	MP_IMGTYPE_EXPORT, 0,
+	vf->priv->crop_w, vf->priv->crop_h);
+    if(mpi->flags&MP_IMGFLAG_PLANAR){
+	dmpi->planes[0]=mpi->planes[0]+
+	    vf->priv->crop_y*mpi->stride[0]+vf->priv->crop_x;
+	dmpi->planes[1]=mpi->planes[1]+
+	    (vf->priv->crop_y>>1)*mpi->stride[1]+(vf->priv->crop_x>>1);
+	dmpi->planes[2]=mpi->planes[2]+
+	    (vf->priv->crop_y>>1)*mpi->stride[2]+(vf->priv->crop_x>>1);
+	dmpi->stride[0]=mpi->stride[0];
+	dmpi->stride[1]=mpi->stride[1];
+	dmpi->stride[2]=mpi->stride[2];
+    } else {
+	dmpi->planes[0]=mpi->planes[0]+
+	    vf->priv->crop_y*mpi->stride[0]+
+	    vf->priv->crop_x*(mpi->bpp/8);
+	dmpi->stride[0]=mpi->stride[0];
+    }
+    vf_next_put_image(vf,dmpi);
+}
+
+//===========================================================================//
+
+static int open(vf_instance_t *vf, char* args){
+    vf->config=config;
+    vf->put_image=put_image;
+    vf->priv=malloc(sizeof(struct vf_priv_s));
+    // TODO: parse args ->
+    vf->priv->crop_x=
+    vf->priv->crop_y=
+    vf->priv->crop_w=
+    vf->priv->crop_h=-1;
+    if(args) sscanf(args, "%d:%d:%d:%d", 
+    &vf->priv->crop_w,
+    &vf->priv->crop_h,
+    &vf->priv->crop_x,
+    &vf->priv->crop_y);
+    printf("Crop: %d x %d, %d ; %d\n",
+    vf->priv->crop_w,
+    vf->priv->crop_h,
+    vf->priv->crop_x,
+    vf->priv->crop_y);
+    return 1;
+}
+
+vf_info_t vf_info_crop = {
+    "cropping",
+    "crop",
+    "A'rpi",
+    "",
+    open
+};
+
+//===========================================================================//
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpcodecs/vf_expand.c	Sat Apr 06 22:05:01 2002 +0000
@@ -0,0 +1,137 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../config.h"
+#include "../mp_msg.h"
+
+#include "../mp_image.h"
+#include "vf.h"
+
+#include "../libvo/fastmemcpy.h"
+
+struct vf_priv_s {
+    int exp_w,exp_h;
+    int exp_x,exp_y;
+    mp_image_t *dmpi;
+};
+
+//===========================================================================//
+
+static int config(struct vf_instance_s* vf,
+        int width, int height, int d_width, int d_height,
+	unsigned int flags, unsigned int outfmt){
+    int ret;
+    // calculate the missing parameters:
+    if(vf->priv->exp_w<width) vf->priv->exp_w=width;
+    if(vf->priv->exp_h<height) vf->priv->exp_h=height;
+    if(vf->priv->exp_x<0) vf->priv->exp_x=(vf->priv->exp_w-width)/2;
+    if(vf->priv->exp_y<0) vf->priv->exp_y=(vf->priv->exp_h-height)/2;
+    // check:
+//    if(vf->priv->exp_w+vf->priv->exp_x>width) return 0; // bad width
+//    if(vf->priv->exp_h+vf->priv->exp_y>height) return 0; // bad height
+    ret=vf_next_config(vf,vf->priv->exp_w,vf->priv->exp_h,d_width,d_height,flags,outfmt);
+    return ret;
+}
+
+// there are 4 cases:
+// codec --DR--> expand --DR--> vo
+// codec --DR--> expand -copy-> vo
+// codec -copy-> expand --DR--> vo
+// codec -copy-> expand -copy-> vo (worst case)
+
+static void get_image(struct vf_instance_s* vf, mp_image_t *mpi){
+    if(vf->priv->exp_w==mpi->width ||
+       (mpi->flags&(MP_IMGFLAG_ACCEPT_STRIDE|MP_IMGFLAG_ACCEPT_WIDTH)) ){
+	// try full DR !
+	vf->priv->dmpi=vf_get_image(vf->next,mpi->imgfmt,
+	    mpi->type, mpi->flags, vf->priv->exp_w, vf->priv->exp_h);
+	// set up mpi as a cropped-down image of dmpi:
+	if(mpi->flags&MP_IMGFLAG_PLANAR){
+	    mpi->planes[0]=vf->priv->dmpi->planes[0]+
+		vf->priv->exp_y*vf->priv->dmpi->stride[0]+vf->priv->exp_x;
+	    mpi->planes[1]=vf->priv->dmpi->planes[1]+
+		(vf->priv->exp_y>>1)*vf->priv->dmpi->stride[1]+(vf->priv->exp_x>>1);
+	    mpi->planes[2]=vf->priv->dmpi->planes[2]+
+		(vf->priv->exp_y>>1)*vf->priv->dmpi->stride[2]+(vf->priv->exp_x>>1);
+	    mpi->stride[0]=vf->priv->dmpi->stride[0];
+	    mpi->stride[1]=vf->priv->dmpi->stride[1];
+	    mpi->stride[2]=vf->priv->dmpi->stride[2];
+	} else {
+	    mpi->planes[0]=vf->priv->dmpi->planes[0]+
+		vf->priv->exp_y*vf->priv->dmpi->stride[0]+
+		vf->priv->exp_x*(vf->priv->dmpi->bpp/8);
+	    mpi->stride[0]=vf->priv->dmpi->stride[0];
+	}
+	mpi->flags|=MP_IMGFLAG_DIRECT;
+    }
+}
+
+static void put_image(struct vf_instance_s* vf, mp_image_t *mpi){
+    if(mpi->flags&MP_IMGFLAG_DIRECT){
+	vf_next_put_image(vf,vf->priv->dmpi);
+	return; // we've used DR, so we're ready...
+    }
+
+    // hope we'll get DR buffer:
+    vf->priv->dmpi=vf_get_image(vf->next,mpi->imgfmt,
+	MP_IMGTYPE_TEMP, MP_IMGFLAG_ACCEPT_STRIDE,
+	vf->priv->exp_w, vf->priv->exp_h);
+    
+    // copy mpi->dmpi...
+    if(mpi->flags&MP_IMGFLAG_PLANAR){
+	memcpy_pic(vf->priv->dmpi->planes[0]+
+	        vf->priv->exp_y*vf->priv->dmpi->stride[0]+vf->priv->exp_x,
+		mpi->planes[0], mpi->w, mpi->h,
+		vf->priv->dmpi->stride[0],mpi->stride[0]);
+	memcpy_pic(vf->priv->dmpi->planes[1]+
+		(vf->priv->exp_y>>1)*vf->priv->dmpi->stride[1]+(vf->priv->exp_x>>1),
+		mpi->planes[1], mpi->w>>1, mpi->h>>1,
+		vf->priv->dmpi->stride[1],mpi->stride[1]);
+	memcpy_pic(vf->priv->dmpi->planes[2]+
+		(vf->priv->exp_y>>1)*vf->priv->dmpi->stride[2]+(vf->priv->exp_x>>1),
+		mpi->planes[2], mpi->w>>1, mpi->h>>1,
+		vf->priv->dmpi->stride[2],mpi->stride[2]);
+    } else {
+	memcpy_pic(vf->priv->dmpi->planes[0]+
+	        vf->priv->exp_y*vf->priv->dmpi->stride[0]+vf->priv->exp_x*(vf->priv->dmpi->bpp/8),
+		mpi->planes[0], mpi->w*(vf->priv->dmpi->bpp/8), mpi->h,
+		vf->priv->dmpi->stride[0],mpi->stride[0]);
+    }
+    vf_next_put_image(vf,vf->priv->dmpi);
+}
+
+//===========================================================================//
+
+static int open(vf_instance_t *vf, char* args){
+    vf->config=config;
+    vf->get_image=get_image;
+    vf->put_image=put_image;
+    vf->priv=malloc(sizeof(struct vf_priv_s));
+    // TODO: parse args ->
+    vf->priv->exp_x=
+    vf->priv->exp_y=
+    vf->priv->exp_w=
+    vf->priv->exp_h=-1;
+    if(args) sscanf(args, "%d:%d:%d:%d", 
+    &vf->priv->exp_w,
+    &vf->priv->exp_h,
+    &vf->priv->exp_x,
+    &vf->priv->exp_y);
+    printf("Expand: %d x %d, %d ; %d\n",
+    vf->priv->exp_w,
+    vf->priv->exp_h,
+    vf->priv->exp_x,
+    vf->priv->exp_y);
+    return 1;
+}
+
+vf_info_t vf_info_expand = {
+    "expanding",
+    "expand",
+    "A'rpi",
+    "",
+    open
+};
+
+//===========================================================================//
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpcodecs/vf_vo.c	Sat Apr 06 22:05:01 2002 +0000
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../config.h"
+#include "../mp_msg.h"
+
+#include "../mp_image.h"
+#include "vf.h"
+
+#include "../libvo/video_out.h"
+
+//===========================================================================//
+
+#define video_out ((vo_functions_t*)(vf->priv))
+
+static int config(struct vf_instance_s* vf,
+        int width, int height, int d_width, int d_height,
+	unsigned int flags, unsigned int outfmt){
+    if(video_out->config(width,height,d_width,d_height,flags,"MPlayer",outfmt,NULL))
+	return 0;
+    return 1;
+}
+
+static int control(struct vf_instance_s* vf,
+        int request, void* data){
+    // return video_out->control(request,data);
+    return -3;
+}
+
+static int query_format(struct vf_instance_s* vf, unsigned int fmt){
+    return video_out->control(VOCTRL_QUERY_FORMAT,&fmt);
+}
+
+static void get_image(struct vf_instance_s* vf,
+        mp_image_t *mpi){
+    if(vo_directrendering) 
+	video_out->control(VOCTRL_GET_IMAGE,mpi);
+}
+
+static void put_image(struct vf_instance_s* vf,
+        mp_image_t *mpi){
+  // first check, maybe the vo/vf plugin implements draw_image using mpi:
+  if(video_out->control(VOCTRL_DRAW_IMAGE,mpi)==VO_TRUE) return; // done.
+  // nope, fallback to old draw_frame/draw_slice:
+  if(!(mpi->flags&(MP_IMGFLAG_DIRECT|MP_IMGFLAG_DRAW_CALLBACK))){
+    // blit frame:
+    if(mpi->flags&MP_IMGFLAG_PLANAR)
+        video_out->draw_slice(mpi->planes,mpi->stride,mpi->w,mpi->h,mpi->x,mpi->y);
+    else
+        video_out->draw_frame(mpi->planes);
+  }
+}
+
+static void draw_slice(struct vf_instance_s* vf,
+        unsigned char* src, int* stride, int w,int h, int x, int y){
+    video_out->draw_slice(src,stride,w,h,x,y);
+}
+
+static void uninit(struct vf_instance_s* vf){
+//    video_out->uninit();
+}
+
+//===========================================================================//
+
+static int open(vf_instance_t *vf, char* args){
+    vf->config=config;
+    vf->control=control;
+    vf->query_format=query_format;
+    vf->get_image=get_image;
+    vf->put_image=put_image;
+    vf->draw_slice=draw_slice;
+    vf->uninit=uninit;
+    vf->priv=(void*)args; // video_out
+    if(!video_out) return 0; // no vo ?
+//    if(video_out->preinit(args)) return 0; // preinit failed
+    return 1;
+}
+
+vf_info_t vf_info_vo = {
+    "libvo wrapper",
+    "vo",
+    "A'rpi",
+    "for internal use",
+    open
+};
+
+//===========================================================================//
--- a/mencoder.c	Sat Apr 06 22:00:50 2002 +0000
+++ b/mencoder.c	Sat Apr 06 22:05:01 2002 +0000
@@ -670,6 +670,8 @@
 sh_video->codec=NULL;
 if(out_video_codec>1){
 
+sh_video->vfilter=vf_open_filter(NULL,"vo",&video_out);
+sh_video->vfilter=append_filters(sh_video->vfilter);
 
 mp_msg(MSGT_CPLAYER,MSGL_INFO,"==========================================================================\n");
 
@@ -1566,7 +1568,7 @@
          raw_rgb_buffer2 = malloc(vo_w*vo_h*4);
      }
 	    
-     blit_frame=decode_video(&video_out,sh_video,start,in_size,0);
+     blit_frame=decode_video(sh_video,start,in_size,0);
      if(skip_flag>0) break;
      if(!blit_frame){
          // empty.
@@ -1608,7 +1610,7 @@
  }
  break;
 case VCODEC_RAW:
-    blit_frame=decode_video(&video_out,sh_video,start,in_size,0);
+    blit_frame=decode_video(sh_video,start,in_size,0);
     if(skip_flag>0) break;
     if(!blit_frame){
 	// empty.
@@ -1629,7 +1631,7 @@
 //		     long* keyframe, int quality);
     long flags=0;
     int ret;
-    blit_frame=decode_video(&video_out,sh_video,start,in_size,0);
+    blit_frame=decode_video(sh_video,start,in_size,0);
     if(skip_flag>0) break;
     if(!blit_frame){
 	// empty.
@@ -1648,7 +1650,7 @@
     printf("No support for Divx4 encore compiled in\n");
     mencoder_exit(1,NULL);
 #else
-    blit_frame=decode_video(&video_out,sh_video,start,in_size,0);
+    blit_frame=decode_video(sh_video,start,in_size,0);
     draw_sub();
     if(skip_flag>0) break;
     if(!blit_frame){
@@ -1692,7 +1694,7 @@
 #else
 	int out_size;
 
-	blit_frame=decode_video(&video_out,sh_video,start,in_size,0);
+	blit_frame=decode_video(sh_video,start,in_size,0);
 	if(skip_flag>0) break;
 	if(!blit_frame){
 	    // empty.
--- a/mplayer.c	Sat Apr 06 22:00:50 2002 +0000
+++ b/mplayer.c	Sat Apr 06 22:05:01 2002 +0000
@@ -1163,7 +1163,7 @@
 
 }
 //================== Init AUDIO (codec) ==========================
-current_module="init_audio_codec";
+current_module="find_audio_codec";
 
 if(sh_audio){
   // Go through the codec.conf and find the best codec...
@@ -1191,6 +1191,8 @@
   }
 }
 
+current_module="init_audio_codec";
+
 if(sh_audio){
   mp_msg(MSGT_CPLAYER,MSGL_V,"Initializing audio codec...\n");
   if(!init_audio(sh_audio)){
@@ -1215,6 +1217,11 @@
 sh_video->video_out=video_out;
 inited_flags|=INITED_VO;
 
+current_module="init_video_filters";
+
+sh_video->vfilter=vf_open_filter(NULL,"vo",video_out);
+sh_video->vfilter=append_filters(sh_video->vfilter);
+
 current_module="init_video_codec";
 
 mp_msg(MSGT_CPLAYER,MSGL_INFO,"==========================================================================\n");
@@ -1524,7 +1531,7 @@
 	// decode:
 	current_module="decode_video";
 //	printf("Decode! %p  %d  \n",start,in_size);
-	blit_frame=decode_video(video_out,sh_video,start,in_size,drop_frame);
+	blit_frame=decode_video(sh_video,start,in_size,drop_frame);
     }
     vdecode_time=video_time_usage-vdecode_time;
     //------------------------ frame decoded. --------------------