<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">Index: libvo/video_out.c
===================================================================
--- libvo/video_out.c	(revision 24714)
+++ libvo/video_out.c	(working copy)
@@ -98,6 +98,9 @@
 #ifdef HAVE_DXR2
 extern vo_functions_t video_out_dxr2;
 #endif
+#ifdef HAVE_PS3
+extern vo_functions_t video_out_ps3;
+#endif
 extern vo_functions_t video_out_dxr3;
 #ifdef HAVE_IVTV
 extern vo_functions_t video_out_ivtv;
@@ -203,6 +206,9 @@
 	&amp;video_out_fbdev,
 	&amp;video_out_fbdev2,
 #endif
+#ifdef HAVE_PS3
+	&amp;video_out_ps3,
+#endif
 #ifdef HAVE_SVGALIB
 	&amp;video_out_svga,
 #endif
Index: libvo/vo_ps3.c
===================================================================
--- libvo/vo_ps3.c	(revision 0)
+++ libvo/vo_ps3.c	(revision 0)
@@ -0,0 +1,785 @@
+/*
+ * vo_ps3.c - video out interface utilizing spu-medialib
+ *                   to offload scaling and yuv2rgb colorspace
+ *                   conversion to the PS3's SPEs:
+ *                   http://wiki.ps2dev.org/ps3:spu-medialib
+ *
+ *
+ * This is very experimental code which is not ready for
+ * public consumption.  Many todo:'s are remaining, and
+ * many more mistakes still need to be corrected.
+ *  
+ * Distributed AS IS.  Use at your own risk.  Author is not liable in any way
+ * for any use, misuse, nonuse, expectation, failed expectation, problem
+ * or anything else!
+ *
+ * Notes:
+ *    needs to do direct rendering, but you don't have
+ *    to specify -dr on the command line because vo will
+ *    enable it automatically if it can
+ *
+ *    needs to double buffer, but you don't have to specify that either (-double)
+ *
+ *    doesn't do windows - takes over framebuffer for now
+ *
+ *    h264 issues:
+ *       currently not working
+ *       video currently doesn't direct render unless u post process with -vf pp
+ *       broken on PS3 (regardless of vo) - too slow &amp; audio strange
+ *       try with -demuxer 35 -lavdopts fast:threads=2 for improvement, but still not usable
+ *       try with -vo null and still broken (see, it's not vo's fault :) )
+ *    
+ *    configure now autodetects ps3
+ *
+ *    works with:
+ *       'f'      for fullscreen scaling toggle
+ *       'space'  for pausing
+ *       '.'      for single frame stepping
+ * 
+ *    use -vo ps3:snapshot to save current buffers in a .yuv file on pause
+ *
+ * Bugs (known):
+ *    Non direct rendered video is broken - know why, but haven't gotten there yet
+ *    Lots more! :)
+ *
+ * Original version: Copyright 2007 by Bill Garrett (wgarrett@sc.rr.com)
+ *
+ * Changelog: 
+ *
+ */
+
+#include &lt;stdio.h&gt;
+#include &lt;stdlib.h&gt;
+#include &lt;string.h&gt;
+#include &lt;errno.h&gt;
+#include &lt;malloc.h&gt;
+#include &lt;libspe2.h&gt;
+
+#include "mplayer.h" //to get filename
+#include "config.h"
+#include "aspect.h"
+#include "mp_msg.h"
+#include "help_mp.h"
+#include "video_out.h"
+#include "video_out_internal.h"
+#include "subopt-helper.h"
+#include "fastmemcpy.h"
+
+#include &lt;spu-medialib/spu_control.h&gt;
+#include &lt;spu-medialib/yuv2argb_scaler.h&gt;
+#include &lt;ps3fb/libps3fb.h&gt;
+
+#define NUM_BUFFERS 2
+
+static vo_info_t info = {
+   "PS3 framebuffer w/ spe offload courtesy of spu_medialib (http://wiki.ps2dev.org/ps3:spu-medialib)",
+   "ps3",
+   "Bill Garrett &lt;wgarrett@sc.rr.com&gt;",
+   ""
+};
+
+LIBVO_EXTERN(ps3)
+
+static void yuvcsc_run();
+static void yuvcsc_check();
+static void fix_scale(void);
+static void snapshot();
+static void init_framebuffer();
+static void init_spu_medialib();
+static void setup_screen();
+static int toggle_fullscreen();
+static void cleanup_spu_medialib();
+static void clear();
+
+int maxW=1920, maxH=1080, max_buf_siz;
+
+int page=0, parking_lot_page=0, offset=0;
+
+uint8_t *inbuf[NUM_BUFFERS], *parking_lot[NUM_BUFFERS], *cur_buf;
+uint32_t srcW, srcH, src_buf_siz, src_stride[3], src_p_siz[3], src_fmt, src_bpp;
+uint32_t dstW, dstH, dst_buf_siz, dst_stride[3], dst_p_siz[3], dst_fmt, dst_bpp;
+uint8_t *src_plane[3];
+float src_aspect;
+char *src_title;
+
+void *fb_buf0, *fb_buf1;  //framebuffer ptrs
+int fbW, fbH;
+float fb_aspect;
+
+//sub option vars
+int debug=0, noscale=0, full=0, adj=0, snap=0;
+
+yuvscaler2argb_t *yuvcsc;                  //spu-medialib's NEW combined scaler &amp; colorspace converter
+unsigned int yuvcsc_msg;                   //spu-medialib messaging
+int yuvsW_req=16, yuvsH_req=4;            //yuvscaler w&amp;h division requirements
+int wait_yuvcsc=0, yuvcsc_not_ready=0;
+
+static int draw_frame_count = 0, draw_slice_count = 0, draw_image_count = 0, get_image_count = 0, flip_count = 0;
+
+
+/* preinit - pre-initialization section
+ * 
+ * Called before initializing video output driver for evaluating subopts.
+ * Currently, we don't utilize any subopts (e.g. -vo ps3:subopt
+ */
+static int preinit(const char *arg) {
+
+   opt_t subopts[] = {  //See subopt_helper.h
+      { "debug",     OPT_ARG_BOOL,  &amp;debug,              NULL,    0 },  //not impl - to repl DBG2 for JUST vo msgs
+      { "noscale",   OPT_ARG_BOOL,  &amp;noscale,            NULL,    0 },  //don't scale no matter what - dangerous if too big for fb
+      { "full",      OPT_ARG_BOOL,  &amp;full,               NULL,    0 },  //start in fullscreen, but 'f' toggles
+      { "adj",       OPT_ARG_BOOL,  &amp;adj,                NULL,    0 },  //scale to mplayer's suggested d_width &amp; d_height
+      { "snapshot",  OPT_ARG_BOOL,  &amp;snap,               NULL,    0 },  //take a raw yuv snapshot of two input buffers on pause
+      { NULL,        0,             NULL,                NULL,    0 }
+   };
+
+   if (subopt_parse(arg, subopts)) {
+      mp_msg(MSGT_VO, MSGL_WARN,
+         "Suboptions for -vo ps3:\n"
+         "  debug    - turn on debugging output NOT IMPL yet. use -v -v\n"
+         "  noscale  - don't scale video (dangerous if too big)\n"
+         "  full     - if scaling, scale to full screen\n"
+         "  adj      - honor &amp; scale to mplayer's suggested d_width x d_height\n"
+         "  snapshot - take a raw yuv snapshot of input buffers on pause (to inbuf0/1.yuv)\n"
+         "\n");
+   }
+
+   mp_msg(MSGT_VO, MSGL_INFO, "ps3 suboptions:\n"
+                              "           debug:%i\n"
+                              "           noscale:%i\n"
+                              "           full:%i\n"
+                              "           adj:%i\n"
+                              "           snapshot:%i\n",
+                              debug, noscale, full, adj, snap);
+
+   /* init PS3 FrameBuffer */
+   init_framebuffer();
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:preinit: Initialized framebuffer &amp; disabled console\n"
+                              "FB is %ix%i\n", fbW, fbH);
+
+   return 0;
+}
+
+
+/* query_format - determine which formats are supported by this vo
+*
+* formats specifies image format - see libmpcodec/img_format.h
+*/
+static int query_format(uint32_t format) {
+
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:query_format: Called for %s (0x%x)\n",
+   vo_format_name(format), format);
+   
+   switch (format) {
+   case IMGFMT_I420:    //Planar I420 0x30323449 
+   case IMGFMT_YV12:    //Planar YV12 0x32315659
+   case IMGFMT_IYUV:    //Planar IYUV 0x56555949
+      return VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_SWSCALE | VFCAP_ACCEPT_STRIDE;
+   default:
+      return VO_FALSE;  //not supporting anything else yet
+   }  
+}
+
+
+/* config - configure video output driver
+*
+* width,height are of source, d_width,d_height are suggested window size,
+* format specifies image format - see libmpcodec/img_format.h
+*/
+static int config(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t flags, char *title, uint32_t format) {
+
+   int i;
+
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:config: Times called:%i Setting up for src=%ix%i, suggested dst=%ix%i, format=%s (%x)\n"
+                              "                     vo_fs:%i, vo_doublebuffering:%i, vo_directrendering:%i, vo_screenwidth:%i, vo_screenheight:%i\n",
+                              vo_config_count, width, height, d_width, d_height, vo_format_name(format), format,
+                              vo_fs, vo_doublebuffering, vo_directrendering, vo_screenwidth, vo_screenheight);
+
+
+   if (vo_config_count &gt; 0) { //already config'd
+      //todo: probably should implement a destroy/restart here in case params changed
+      return 0;
+   }
+
+   srcW = dstW = width;     //original size - dst same unless scaled
+   srcH = dstH = height;
+   src_aspect = (float)srcW / (float)srcH;
+   src_fmt = format;
+   src_title = title;
+
+   //todo: Need to do this differently if vo is modified to support screen res changes
+   maxW=fbW; 
+   maxH=fbH;
+   max_buf_siz = maxW*maxH*2;
+
+   if(adj) {
+      dstW = d_width;    //suggested window size?
+      dstH = d_height;   //todo: read mplayer's code about this
+   }
+
+   vo_screenwidth=fbW;
+   vo_screenheight=fbH;
+   //vo_depthonscreen = todo:
+
+   vo_doublebuffering = VO_TRUE;    //is it ok to force these if not called with -double?
+   vo_directrendering = VO_TRUE;    //   and -dr?
+   //vo_fs = VO_TRUE;                 //   and -fs (forcing fullscreen)
+
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:config: Set vo_screen(width/heigh) to %ix%i, forced direct rendering, "
+                              "&amp; double buffering\n",
+                              vo_screenwidth, vo_screenheight);
+
+   switch (format) {
+      case IMGFMT_I420:                                     //Planar I420 0x30323449 
+      case IMGFMT_YV12:                                     //Planar YV12 0x32315659
+      case IMGFMT_IYUV:                                     //Planar IYUV 0x56555949
+         src_buf_siz = srcW*srcH + srcW*srcH/2;
+         dst_buf_siz = dstW*dstH + dstW*dstH/2;
+         
+         src_stride[0] = srcW;                              //buffer plane strides 0=y, 1=u, 2=v
+         src_stride[1] = src_stride[2] = src_stride[0]/2;
+         src_p_siz[0] = srcW * srcH;                        //buffer plane sizes 0=y, 1=u, 2=v
+         src_p_siz[1] = src_p_siz[2] = srcW/2 * srcH/2;
+         src_bpp = 12;
+         
+         dst_stride[0] = dstW;                              //buffer plane strides 0=y, 1=u, 2=v
+         dst_stride[1] = dst_stride[2] = dst_stride[0]/2;
+         dst_p_siz[0] = dstW * dstH;                        //buffer plane sizes 0=y, 1=u, 2=v
+         dst_p_siz[1] = dst_p_siz[2] = dstW/2 * dstH/2;
+         break;
+
+      default:
+         mp_msg(MSGT_VO, MSGL_FATAL, "vo_ps3:config: Unsupported format:%i\n", format);
+         return 1;
+   }
+  
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:config: src_buf_siz=%i, src_stride[]={%i,%i,%i}, src_p_siz[]={%i,%i,%i}\n"
+                              "                     dst_buf_siz=%i, dst_stride[]={%i,%i,%i}, dst_p_siz[]={%i,%i,%i}\n"
+                              "                     maxWxmaxH=%ix%i, max_buf_siz=%i, offset=%i\n",
+                              src_buf_siz, src_stride[0], src_stride[1], src_stride[2],
+                              src_p_siz[0], src_p_siz[1], src_p_siz[2],
+                              dst_buf_siz, dst_stride[0], dst_stride[1], dst_stride[2],
+                              dst_p_siz[0], dst_p_siz[1], dst_p_siz[2],
+                              maxW, maxH, max_buf_siz, offset);
+
+   
+   for(i=0; i&lt;NUM_BUFFERS; i++) { 
+      inbuf[i]=(uint8_t *)memalign(128, src_buf_siz*2);
+      
+      parking_lot[i]=(uint8_t *)memalign(128, src_buf_siz*2);      //place to park frames - probably quite wrong
+
+   }
+
+   clear();
+
+   setup_screen();
+
+   init_spu_medialib();
+
+   return 0;
+}
+
+static uint32_t get_image(mp_image_t * mpi) {
+   get_image_count++;
+
+   if ((mpi-&gt;flags &amp; MP_IMGFLAG_READABLE) &amp;&amp; (mpi-&gt;type == MP_IMGTYPE_IPB || mpi-&gt;type == MP_IMGTYPE_IP)) {
+      src_plane[0] = parking_lot[parking_lot_page];         //this is a perfect example of NOT KNOWING WHAT THE HELL I'M DOING! ;)
+      mpi-&gt;flags |= MP_IMGFLAG_ALLOCATED;                   //need to figure out how to handle them properly instead of shipping
+                                                            //them off to boarding school
+      parking_lot_page^=1;                                  //with direct rendering (-dr), this seems to work because
+                                                            //the frame gets drawn at the right time  by draw_image later,
+                                                            //but ofc the frame has to be copied back instead of direct rendered.
+                                                            
+                                                            //todo: without -dr, i'm not handling them right..
+
+      // todo: check parking_lot_page - probably shouldn't be flipping it or at least check if displaying right one
+
+   } else {
+      src_plane[0] = inbuf[page];
+      mpi-&gt;flags |= MP_IMGFLAG_DIRECT;
+   }
+
+   mpi-&gt;planes[0] = src_plane[0];
+   mpi-&gt;planes[1] = mpi-&gt;planes[0] + src_p_siz[0];
+   mpi-&gt;planes[2] = mpi-&gt;planes[1] + src_p_siz[1];
+
+   mpi-&gt;stride[0] = src_stride[0];
+   mpi-&gt;stride[1] = src_stride[1];
+   mpi-&gt;stride[2] = src_stride[2];
+
+   mpi-&gt;chroma_width = srcW/2;
+   mpi-&gt;chroma_height = srcH/2;
+
+   mpi-&gt;priv = src_plane[0];
+
+   if (mp_msg_test(MSGT_VO, MSGL_DBG2)) {
+      mp_msg(MSGT_VO, MSGL_DBG2, "vo_ps3:get_image: page=%i, inbuf[]={%p,%p}, parking_lot[]={%p,%p}\n"
+                                 "                        mpi: planes[]={%p,%p,%p}, strides[]={%i,%i,%i}, chroma=%ix%i, bpp=%i\n"
+                                 "                        imgfmt=0x%x, type=%u, flags=%u, priv=%p\n",
+                                 page, inbuf[0], inbuf[1], parking_lot[0], parking_lot[1],
+                                 mpi-&gt;planes[0], mpi-&gt;planes[1], mpi-&gt;planes[2], mpi-&gt;stride[0], mpi-&gt;stride[1], mpi-&gt;stride[2], 
+                                 mpi-&gt;chroma_width, mpi-&gt;chroma_height, mpi-&gt;bpp, mpi-&gt;imgfmt, mpi-&gt;type, mpi-&gt;flags, mpi-&gt;priv); 
+   }
+   return 0;
+}
+
+
+static uint32_t draw_image(mp_image_t *mpi) {
+
+   int i;
+   int mpi_p_siz[3];
+
+   draw_image_count++;
+
+   if (mpi-&gt;flags &amp; MP_IMGFLAG_DIRECT) { //already in buffer (direct rendered), just convert it
+      if (mp_msg_test(MSGT_VO, MSGL_DBG2))
+         mp_msg(MSGT_VO, MSGL_DBG2, "vo_ps3:draw_image: MP_IMGFLAG_DIRECT set =&gt; image is already in buffer,"
+                                    " so just convert it.\n"
+                                    "mpi-&gt;planes[]={%p,%p,%p}, mpi-&gt;stride[]={%i,%i,%i}. wxh=%ix%i\n",
+                                    mpi-&gt;planes[0], mpi-&gt;planes[1], mpi-&gt;planes[2], mpi-&gt;stride[0], mpi-&gt;stride[1],
+                                    mpi-&gt;stride[2], mpi-&gt;width, mpi-&gt;height);
+      yuvcsc_run(yuvcsc);
+      return 0;
+   }
+
+   //otherwise, copy it to the buffer first
+
+   //todo: not (mpi-&gt;flags &amp; MP_IMGFLAG_DIRECT) (no -dr flag for direct rendering),
+   // may need to handle MP_IMGFLAG_READABLE IPB (B) frames differently
+   // When direct rendering is enabled (-dr), I moved the B frames to a non-direct
+   // buffer and then when drawn with draw_image, they (seem) to work fine
+   // BUT, without direct rendering, don't know how to handle them :(
+   // Just drawing them as called makes a mess of the video.
+   if ((!vo_directrendering) &amp;&amp; (mpi-&gt;flags &amp; MP_IMGFLAG_READABLE) &amp;&amp;
+         (mpi-&gt;type == MP_IMGTYPE_IPB || mpi-&gt;type == MP_IMGTYPE_IP)) {
+      src_plane[0] = inbuf[page];   //don't know what to do yet - see note above
+   } else
+      src_plane[0] = inbuf[page];
+
+   src_plane[1] = src_plane[0] + src_p_siz[0];
+   src_plane[2] = src_plane[1] + src_p_siz[1];
+   
+   mpi_p_siz[0] = mpi-&gt;stride[0] * mpi-&gt;height;
+   mpi_p_siz[1] = mpi-&gt;stride[1] * mpi-&gt;chroma_height;
+   mpi_p_siz[2] = mpi-&gt;stride[2] * mpi-&gt;chroma_height;
+   
+   if (mp_msg_test(MSGT_VO, MSGL_DBG2)) {
+      mp_msg(MSGT_VO, MSGL_DBG2, "vo_ps3:draw_image: page=%i, mpi: strides[]={%i,%i,%i}, chroma=%ix%i, "
+                                 "bpp=%i, imgfmt=0x%x, type=%u, flags=%u, priv=%p, src_plane[0]=%p, mpi_p_siz[0]=%i,"
+                                 " mpi_p_siz[1]=%i\n",
+                                 page, mpi-&gt;stride[0], mpi-&gt;stride[1], mpi-&gt;stride[2], mpi-&gt;chroma_width,
+                                 mpi-&gt;chroma_height, mpi-&gt;bpp, mpi-&gt;imgfmt, mpi-&gt;type, mpi-&gt;flags, mpi-&gt;priv,
+                                 src_plane[0], mpi_p_siz[0], mpi_p_siz[1]); 
+      mp_msg(MSGT_VO, MSGL_DBG2, "vo_ps3:draw_image: mpi:pict_type:%i, stored:%ix%i, visible=%ix%i,%ix%i, "
+                                 "MP_IMGFLAG_PRESERVE:%i, MP_IMGFLAG_READABLE:%i, MP_IMGFLAG_DIRECT:%i, "
+                                 "MP_IMGFLAG_DRAW_CALLBACK:%i\n",
+                                 mpi-&gt;pict_type, mpi-&gt;width, mpi-&gt;height, mpi-&gt;x, mpi-&gt;y, mpi-&gt;w, mpi-&gt;h,
+                                 mpi-&gt;flags &amp; MP_IMGFLAG_PRESERVE, mpi-&gt;flags &amp; MP_IMGFLAG_READABLE,
+                                 mpi-&gt;flags &amp; MP_IMGFLAG_DIRECT, mpi-&gt;flags &amp; MP_IMGFLAG_DRAW_CALLBACK);
+   }
+
+   for(i=0; i&lt;3; i++) {  //planes y,u,v
+      if (mpi-&gt;stride[i] == src_stride[i]) //that's what we expect, just copy it
+         fast_memcpy(src_plane[i], mpi-&gt;planes[i], mpi_p_siz[i]);
+      else //mpi image is padded (why?) so convert strides (slower)
+         memcpy_pic(src_plane[i], mpi-&gt;planes[i], mpi-&gt;width, mpi-&gt;height, src_stride[i], mpi-&gt;stride[i]);
+   }
+   yuvcsc_run(yuvcsc);  //scale, convert, &amp; display
+
+   return 0;
+}
+
+
+static int draw_frame(uint8_t *src[]) {
+   draw_frame_count++;
+   
+   if(mp_msg_test(MSGT_VO, MSGL_DBG2))
+      mp_msg(MSGT_VO, MSGL_DBG2, "vo_ps3:draw_frame: src[0]=%p,src[1]=%p,src[2]=%p\n", src[0], src[1], src[2]);
+   
+   //int stride[] = {srcW * src_bpp, 0, 0};     //read somewhere in mplayer doc this should be the stride
+                                                //if you accept VFCAP_ACCEPT_STRIDE, but it's not what we
+                                                //are getting, so I guess it was wrong.
+   return draw_slice(src, src_stride, srcW, srcH, 0, 0);
+}
+
+
+static uint32_t start_slice(mp_image_t *mpi){
+
+   int mpi_p_siz[3];
+   
+   if (mp_msg_test(MSGT_VO, MSGL_DBG2)) { //all for testing. nothing really to do?
+      src_plane[0] = inbuf[page];
+      src_plane[1] = src_plane[0] + src_p_siz[0];
+      src_plane[2] = src_plane[1] + src_p_siz[1];
+   
+      mpi_p_siz[0] = mpi-&gt;stride[0] * mpi-&gt;height;
+      mpi_p_siz[1] = mpi-&gt;stride[1] * mpi-&gt;chroma_height;
+      mpi_p_siz[2] = mpi-&gt;stride[2] * mpi-&gt;chroma_height;
+
+      mp_msg(MSGT_VO, MSGL_DBG2, "vo_ps3:draw_image: page=%i, mpi: strides[]={%i,%i,%i}, chroma=%ix%i, bpp=%i, "
+                                 "imgfmt=0x%x, type=%i, priv=%p, src_plane[0]=%p, mpi_p_siz[0]=%i, mpi_p_siz[1]=%i\n",
+                                 page, mpi-&gt;stride[0], mpi-&gt;stride[1], mpi-&gt;stride[2], mpi-&gt;chroma_width,
+                                 mpi-&gt;chroma_height, mpi-&gt;bpp, mpi-&gt;imgfmt, mpi-&gt;type, mpi-&gt;priv, src_plane[0],
+                                 mpi_p_siz[0], mpi_p_siz[1]); 
+   }
+
+   return 0;
+}
+
+
+static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y) {
+
+   int i;
+   int slice_siz[3], offset[3];
+   
+   draw_slice_count++;
+
+   //note: the todo: below was for draw_image, but relevent here too?
+   //todo: if not (mpi-&gt;flags &amp; MP_IMGFLAG_DIRECT) (no -dr flag for direct rendering),
+   // may need to handle MP_IMGFLAG_PRESERVE frames differently?
+   
+   src_plane[0] = inbuf[page];
+   src_plane[1] = src_plane[0] + src_p_siz[0];
+   src_plane[2] = src_plane[1] + src_p_siz[1];
+   
+   // setup for YV12 - always for slice?  should add switch statement to check format
+   slice_siz[0] = stride[0] * h;                      //slice plane size is smaller than buffer plane size
+   slice_siz[1] = stride[1] * h/2;
+   slice_siz[2] = stride[2] * h/2;
+   
+   offset[0] = y * src_stride[0] + x;        //offset in dst buffer based on x,y
+   offset[1] = y/2 * src_stride[1] + x/2;
+   offset[2] = y/2 * src_stride[2] + x/2;    //should be same as u plane
+   
+   if (mp_msg_test(MSGT_VO, MSGL_DBG2))
+      mp_msg(MSGT_VO, MSGL_DBG2, "vo_ps3:draw_slice: page=%i, stride[]={%i,%i,%i}, w=%i, h=%i, x=%i, y=%i, "
+                                 "src_plane[0]=%p, offset[0]=%i, offset[1]=%i\n",
+                                 page, stride[0], stride[1], stride[2], w, h, x, y, src_plane[0], offset[0],
+                                 offset[1]); 
+   
+   for(i=0; i&lt;3; i++)  //planes y,u,v
+      if (stride[i] == src_stride[i])     //that's what we expect, just copy it
+         fast_memcpy(src_plane[i]+offset[i], src[i], slice_siz[i]);
+      else                                //mpi image is padded (stride&gt;normal) (why?) whatever, convert strides
+         memcpy_pic(src_plane[i]+offset[i], src[i], w, h, src_stride[i], stride[i]);
+   
+   return 0;
+}
+
+
+static void draw_osd(void) {
+}
+
+
+static void flip_page(void) {
+   flip_count++;
+
+   yuvcsc_check(yuvcsc);               //make sure spu_yuv2argb_scaler is done before displaying
+   ps3fb_swapVsync();
+   page=page^1;
+
+   if (mp_msg_test(MSGT_VO, MSGL_DBG2))
+      mp_msg(MSGT_VO, MSGL_DBG2, "vo_ps3:flip_page: Swapping fb.  Next write to inbuf[%i]=%p\n", page, inbuf[page]);
+}
+
+
+/* todo:  need to implement this! 
+ *
+ */
+static void check_events(void) {
+
+   //if (mp_msg_test(MSGT_VO, MSGL_DBG2))
+   //   mp_msg(MSGT_VO, MSGL_DBG2, "vo_ps3:check_events: called\n");
+}
+
+
+static int control(uint32_t request, void *data, ...) {
+
+   switch (request) {
+
+      case VOCTRL_QUERY_FORMAT:      /* 2 */
+         return query_format(*((uint32_t*)data));
+
+      case VOCTRL_RESET:             /* 3 */
+         mp_msg(MSGT_VO, MSGL_WARN, "vo_ps3:control: todo: handle RESET (%u)\n", request);
+	 return VO_NOTIMPL;
+
+      case VOCTRL_FULLSCREEN:        /* 5 */
+         return toggle_fullscreen();
+
+      case VOCTRL_SCREENSHOT:        /* 6 */ //copies current inbufs to inbuf0.yuv &amp; inbuf1.yuv
+         snapshot();                         //not really what's intended
+
+      case VOCTRL_PAUSE:             /* 7 */
+         if(snap)
+            snapshot();
+         return 0;
+
+      case VOCTRL_RESUME:            /* 8 */
+         return 0;
+
+      case VOCTRL_GET_IMAGE:         /* 9 */
+         return get_image(data);
+		     
+      case VOCTRL_DRAW_IMAGE:        /* 13 */
+         return draw_image(data);
+
+      case VOCTRL_UPDATE_SCREENINFO: /* 32 */
+         mp_msg(MSGT_VO, MSGL_WARN, "vo_ps3:control: todo: handle UPDATE_SCREENINFO (%u)\n", request);
+	 return VO_NOTIMPL;
+
+      case VOCTRL_START_SLICE:       /* 21 */
+         return start_slice(data);
+
+      default:
+         mp_msg(MSGT_VO, MSGL_WARN, "vo_ps3:control: Unhandled VOCTRL %u\n\n", request);
+         return VO_NOTIMPL;
+   }
+}
+
+
+static void uninit(void) {
+
+   int i;
+
+   cleanup_spu_medialib();
+   
+   /* Cleanup FrameBuffer and re-enable console */
+   ps3fb_cleanup();
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:uninit: Cleaned up FrameBuffer and re-enabled console.\n");
+
+   for (i=0; i&lt;NUM_BUFFERS; i++) {
+      free(inbuf[i]);
+      free(parking_lot[i]);
+   }
+
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:uninit: These SHOULD BE ZERO:\n"
+                              "        yuvcsc_not_ready:%i\n",
+                              yuvcsc_not_ready);
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:uninit: Statistics:\n"
+                              "        draw_frame calls:%i\n"
+                              "        draw_slice calls:%i\n"
+                              "        draw_image calls:%i\n"
+                              "        flip_page calls:%i\n"
+                              "        get_image calls:%i\n",
+                              draw_frame_count, draw_slice_count, draw_image_count, flip_count, get_image_count);
+   mp_msg(MSGT_VO, MSGL_INFO, "   Played src %s (%ix%i) at %ix%i %s\n",
+                              filename, srcW, srcH, dstW, dstH, (noscale ? "unscaled" : "scaled")); 
+}
+
+
+/* ps3 specific functions follow: */
+
+
+/* yuvcsc_run - time to put the image on the screen.  scale if needed, and then start yuv2rgb
+ *             todo:  this needs some work, but it's working.  see yuvs_check &amp; yuvc_check
+ *
+ */
+static void yuvcsc_run() {
+
+   yuvcsc_check();
+   wait_yuvcsc = 1;
+   if (mp_msg_test(MSGT_VO, MSGL_DBG2))
+      mp_msg(MSGT_VO, MSGL_DBG2, "vo_ps3:yuvcsc_run: sending RUN to spu_yuv2argb_scaler\n");
+   yuvscsc_send_message(yuvcsc, RUN);
+}
+
+
+/* yuvcsc_check - check spu_yuv2argb_scaler process to make sure we're ready to write
+ *               if not ready, wait.  Haven't seen it have to wait yet :)
+ *
+ */
+static void yuvcsc_check() {
+
+   if (wait_yuvcsc) {                               //make sure last copy finished - hopefully just haven't checked
+      if (mp_msg_test(MSGT_VO, MSGL_DBG2))
+         mp_msg(MSGT_VO, MSGL_DBG2, "vo_ps3:yuvs_check: asking for msg from yuvc\n");
+      yuvcsc_msg = yuvscsc_receive_message(yuvcsc);
+      while (yuvcsc_msg != RDY) {
+         yuvcsc_not_ready++;                         //todo: *shouldn't* get here - we don't want to waste time waiting
+         mp_msg(MSGT_VO, MSGL_WARN, "vo_ps3:yuvcsc_check: yuvcsc not ready to run! :(\n");
+         yuvcsc_msg = yuvscsc_receive_message(yuvcsc);
+      }
+      wait_yuvcsc = 0;
+   }
+}
+
+
+/* scale - adjust for full screen, yuvscaler requirements, etc.
+ *
+ */
+static void fix_scale(void) {
+
+   if(noscale) {
+      dstW = srcW;   //this is potentially the wrong way to display the image
+      dstH = srcH;   //if the aspects are different, but we're told NOT to scale
+      full = 0;      //and that takes precedence over full
+
+      //todo: NEED to quit if larger than screen res &amp; told not to scale 
+      //      cause that could over run the fb buffer and make a nice mess
+      return;
+   }
+
+   //we can scale
+
+   //determine the size - keep aspect &amp; consider scaler's need for w/16 &amp; h/2
+   //todo: put some thought into doing this right!!!
+
+   //The next line checks for a (hopefully) rare ocurrence where mplayer was forced to some strange
+   //resolution (-vf dsize=1904:1074) which is out of scale.  If forced to something way out of scale,
+   //should we just use it?
+   //if (dstW/dstH)
+
+   if((dstW &gt; fbW) || (dstH &gt; fbH) || full) {   //too big or full, so scale it as big as sreenres will allow
+
+      if (src_aspect &lt;= fb_aspect) {            //height is limiting factor
+         dstH = fbH;
+         dstW = dstH*src_aspect;
+      } else {                                  //width is limiting
+         dstW = fbW;
+         dstH = dstW/src_aspect;
+      }
+
+      //adjust for yuvscaler requirements
+      if (dstW != (dstW/yuvsW_req)*yuvsW_req) {
+         dstW = (dstW/yuvsW_req)*yuvsW_req;
+         dstH = (int)(dstW/src_aspect);
+      }
+      dstH = (dstH/yuvsH_req)*yuvsH_req;
+
+   }
+   //todo:  MAJOR BUG ABOVE! Normally, this should be fine, but if mplayer is called
+   //       with -vf dsize=someX:someY, and that someX or someY is way out of scale,
+   //       then the calc above might create a dstH that's way too big and overrun the
+   //       framebuffer.
+   //       The code above is assuming that the dstW &amp; dstH at this point are in the
+   //       proper aspect and not forced to something strange.
+
+
+   return;
+}
+
+
+static void snapshot() {
+
+   int i;
+   FILE * snapshot;
+   char *inbuf_file[]={"inbuf0.yuv", "inbuf1.yuv"};
+
+   for (i=0; i&lt;2; i++) {
+      snapshot = fopen(inbuf_file[i], "wb");
+      fwrite(inbuf[i], 1, src_buf_siz*2, snapshot);
+      fclose(snapshot);
+   }
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:snapshot: wrote current inbuf[] to inbuf0.yuv &amp; inbuf1.yuv\n");
+}
+
+
+
+static int toggle_fullscreen() {
+
+   //todo: check to see if normal size is already full.  If so, no point in destroy,create
+
+   full^=1;
+
+   if(!full) {
+      if(adj) {
+         dstW = vo_dwidth;    //suggested window size?
+         dstH = vo_dheight;   //todo: read mplayer's code about this
+      } else {
+         dstW = srcW;
+         dstH = srcH;
+      }
+   }  //otherwise fullscreen is taken care of next in setup_screen()
+
+   setup_screen();
+
+   //todo:  this is really rude.  don't need to destroy &amp; re-create.  use spu-medialib's update &amp; just clear fb
+   init_framebuffer();
+   cleanup_spu_medialib();
+   init_spu_medialib();
+
+   return 0;
+
+}
+
+
+static void setup_screen() {
+
+   //take care of scaling size and scaler requirements
+   fix_scale();
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:setup_screen: Using destination image size WxH:%ix%i\n",
+                              dstW, dstH);
+
+   //set aspect stuff
+   aspect_save_orig(srcW, srcH);
+   aspect_save_screenres(vo_screenwidth, vo_screenheight);
+   aspect_save_prescale(dstW, dstH);
+
+   vo_dx = (fbW-dstW)/2;
+   vo_dy = (fbH-dstH)/2;
+   offset = (fbW-dstW)/2 + fbW*(fbH-dstH)/2;
+
+   geometry(&amp;vo_dx, &amp;vo_dy, &amp;dstW, &amp;dstH, vo_screenwidth, vo_screenheight);
+   aspect(&amp;dstW, &amp;dstH, A_NOZOOM); //todo: read mplayer's code about this
+
+}
+
+
+static void init_framebuffer() {
+
+   fb_buf0 = ps3fb_init();
+   fb_buf1 = ps3fb_swap(); //get backbuffer
+   ps3fb_swap();           //but swap back
+
+   fbW=ps3fb_getXres();
+   fbH=ps3fb_getYres();
+   fb_aspect = (float)fbW / (float)fbH;
+
+}
+
+
+static void init_spu_medialib() {
+
+   //init spu-medialib's scaler &amp; colorspace converter on an spe
+   yuvcsc = yuvscsc_init_yuv2argb_scaler(srcW, srcH, dstW, dstH, offset, maxW,
+                              (ea_t *)inbuf[0],                               (ea_t *)inbuf[1],
+                              (ea_t *)(inbuf[0]+src_p_siz[0]),                (ea_t *)(inbuf[1]+src_p_siz[0]),
+                              (ea_t *)(inbuf[0]+src_p_siz[0]+src_p_siz[1]),   (ea_t *)(inbuf[1]+src_p_siz[0]+src_p_siz[1]),
+                              fb_buf0,                                        fb_buf1);
+
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:init_spu_medialib: Started spu-medialib's spu_yuv2argb_scaler runing\n");
+
+}
+
+
+
+static void cleanup_spu_medialib() {
+
+   yuvcsc_check();
+
+   yuvscsc_send_message(yuvcsc, STOP);
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:uninit: Told yuv2argb_scaler to stop\n");
+
+   yuvscsc_destroy(yuvcsc);
+   mp_msg(MSGT_VO, MSGL_INFO, "vo_ps3:uninit: Destroyed spu-medialib's scaler/converter\n");
+
+}
+
+
+
+static void clear() {
+
+   int i;
+
+   for(i=0; i&lt;NUM_BUFFERS; i++) { 
+      memset(inbuf[i], 0, src_buf_siz);
+      memset(parking_lot[i], 0, src_buf_siz);
+   }
+
+   //clear framebuffer
+   //memset(fb_buf0, 0, fbX*fbY*4*(res.num_frames));  //don't have num_frames!  need to read libps3fb 
+   //mean time, init clears it
+   init_framebuffer();
+
+}
Index: configure
===================================================================
--- configure	(revision 24714)
+++ configure	(working copy)
@@ -373,6 +373,7 @@
   --enable-x11             enable X11 video output [autodetect]
   --enable-xshape          enable XShape support [autodetect]
   --enable-fbdev           enable FBDev video output [autodetect]
+  --enable-ps3             enable FBDev video output SPU optimized for PS3 [autodetect]
   --enable-mlib            enable mediaLib video output (Solaris) [disable]
   --enable-3dfx            enable obsolete /dev/3dfx video output [disable]
   --enable-tdfxfb          enable tdfxfb video output [disable]
@@ -544,6 +545,7 @@
 _svga=auto
 _vesa=auto
 _fbdev=auto
+_ps3=auto
 _dvb=auto
 _dvbhead=auto
 _dxr2=auto
@@ -857,6 +859,8 @@
   --disable-vesa)	_vesa=no	;;
   --enable-fbdev)	_fbdev=yes	;;
   --disable-fbdev)	_fbdev=no	;;
+  --enable-ps3)        _ps3=yes        ;;
+  --disable-ps3)       _ps3=no         ;;
   --enable-dvb)		_dvb=yes	;;
   --disable-dvb)        _dvb=no		;;
   --enable-dvbhead)	_dvbhead=yes	;;
@@ -4443,6 +4447,28 @@
 echores "$_fbdev"
 
 
+echocheck "PS3"
+if test "$_ps3" = auto ; then
+  cat &gt; $TMPC &lt;&lt; EOF
+#include &lt;libspe2.h&gt;
+#include &lt;spu-medialib/spu_control.h&gt;
+#include &lt;spu-medialib/yuv2argb_scaler.h&gt;
+#include &lt;ps3fb/libps3fb.h&gt;
+int main(void) { return 0; }
+EOF
+  _ps3=no
+  cc_check -lspe2 -lps3fb -lspu-medialib &amp;&amp; _ps3=yes
+fi
+if test "$_ps3" = yes; then
+  _def_ps3='#define HAVE_PS3 1'
+  _ld_extra="$_ld_extra -lspe2 -lps3fb -lspu-medialib"
+  _vosrc="$_vosrc vo_ps3.c"
+  _vomodules="ps3 $_vomodules"
+else
+  _def_ps3='#undef HAVE_PS3'
+  _novomodules="ps3 $_novomodules"
+fi
+echores "$_ps3"
 
 echocheck "DVB"
 if test "$_dvb" = auto ; then
@@ -8449,6 +8475,7 @@
 $_def_mga
 $_def_xmga
 $_def_fbdev
+$_def_ps3
 $_def_dxr2
 $_def_dxr3
 $_def_ivtv
</pre></body></html>