changeset 8013:bd100a3d486f

Here's a new vo plugin that uses DirectFB. It's meant for Matrox G400 cards and TV out. It's works like DVDMax in Windows. Instructions on how to make it work are at: http://www.sci.fi/~syrjala/directfb/readme.txt patch by Ville Syrj¸«£l¸«£ <syrjala@sci.fi>
author arpi
date Thu, 31 Oct 2002 23:54:26 +0000
parents a53966ed8afb
children 3d6904cee13e
files configure libvo/video_out.c libvo/vo_dfbmga.c
diffstat 3 files changed, 995 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/configure	Thu Oct 31 23:37:38 2002 +0000
+++ b/configure	Thu Oct 31 23:54:26 2002 +0000
@@ -2194,6 +2194,11 @@
   fi
   _vomodules="directfb $_vomodules"
   _ld_directfb='-ldirectfb'
+
+  if test "$_directfb_version" -ge 914; then
+    _vosrc="$_vosrc vo_dfbmga.c"
+    _vomodules="dfbmga $_vomodules"
+  fi
 else
   _def_directfb='#undef HAVE_DIRECTFB'
   _novomodules="directfb $_novomodules"
--- a/libvo/video_out.c	Thu Oct 31 23:37:38 2002 +0000
+++ b/libvo/video_out.c	Thu Oct 31 23:54:26 2002 +0000
@@ -90,7 +90,12 @@
 #ifdef HAVE_VESA
 extern vo_functions_t video_out_vesa;
 #endif
+#ifdef HAVE_DIRECTFB
 extern vo_functions_t video_out_directfb;
+#if DIRECTFBVERSION >= 914
+extern vo_functions_t video_out_dfbmga;
+#endif
+#endif
 #ifdef CONFIG_VIDIX
 extern vo_functions_t video_out_xvidix;
 #endif
@@ -177,7 +182,10 @@
 #endif
 #ifdef HAVE_DIRECTFB
 	&video_out_directfb,
-#endif	
+#if DIRECTFBVERSION >= 914
+        &video_out_dfbmga,
+#endif
+#endif
 #if defined(CONFIG_VIDIX) && defined(HAVE_X11) 
 	&video_out_xvidix,
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libvo/vo_dfbmga.c	Thu Oct 31 23:54:26 2002 +0000
@@ -0,0 +1,981 @@
+/*
+   MPlayer video driver for DirectFB / Matrox G400
+
+   Copyright (C) 2002 Ville Syrjala <syrjala@sci.fi>
+
+   Originally based on vo_directfb.c by
+   Jiri Svoboda <Jiri.Svoboda@seznam.cz>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2 of the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the
+   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+*/
+
+/* directfb includes */
+#include <directfb.h>
+
+/* other things */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/kd.h>
+#include <linux/fb.h>
+
+#include "config.h"
+#include "video_out.h"
+#include "video_out_internal.h"
+#include "fastmemcpy.h"
+#include "sub.h"
+#include "../postproc/rgb2rgb.h"
+
+#include "aspect.h"
+
+#ifndef min
+#define min(x,y) (((x)<(y))?(x):(y))
+#endif
+
+LIBVO_EXTERN(dfbmga)
+
+static vo_info_t vo_info = {
+     "DirectFB / Matrox G400",
+     "dfbmga",
+     "Ville Syrjala <syrjala@sci.fi>",
+     ""
+};
+
+extern int verbose;
+
+/******************************
+*	   directfb 	      *
+******************************/
+
+/*
+ * (Globals)
+ */
+static IDirectFB *dfb;
+
+static IDirectFBDisplayLayer *bes;
+static IDirectFBDisplayLayer *crtc2;
+static IDirectFBDisplayLayer *spic;
+
+static IDirectFBSurface *frame;
+static IDirectFBSurface *c2frame;
+static IDirectFBSurface *subframe;
+
+static DFBSurfacePixelFormat frame_format;
+static DFBSurfacePixelFormat subframe_format;
+
+static DFBRectangle drect;
+
+static IDirectFBInputDevice  *keyboard;
+static IDirectFBEventBuffer  *buffer;
+
+static unsigned int frame_pixel_size;
+static unsigned int subframe_pixel_size;
+
+static int inited = 0;
+
+static int stretch = 0;
+
+static int use_bes   = 0;
+static int use_crtc2 = 1;
+static int use_spic  = 1;
+
+/******************************
+*	    vo_directfb       *
+******************************/
+
+/* command line/config file options */
+#ifdef HAVE_FBDEV
+ extern char *fb_dev_name;
+#else
+ char *fb_dev_name;
+#endif
+
+static void ( *draw_alpha_p ) ( int w, int h, unsigned char *src,
+                                unsigned char *srca, int stride,
+                                unsigned char *dst, int dstride);
+
+static uint32_t in_width;
+static uint32_t in_height;
+static uint32_t screen_width;
+static uint32_t screen_height;
+
+static char *
+pixelformat_name( DFBSurfacePixelFormat format )
+{
+     switch(format) {
+     case DSPF_ARGB:
+          return "ARGB";
+     case DSPF_RGB32:
+          return "RGB32";
+     case DSPF_RGB24:
+	  return "RGB24";
+     case DSPF_RGB16:
+	  return "RGB16";
+     case DSPF_RGB15:
+	  return "RGB15";
+     case DSPF_YUY2:
+	  return "YUY2";
+     case DSPF_UYVY:
+	  return "UYVY";
+     case DSPF_YV12:
+	  return "YV12";
+     case DSPF_I420:
+	  return "I420";
+     case DSPF_LUT8:
+	  return "LUT8";
+     default:
+	  return "Unknown pixel format";
+     }
+}
+
+static DFBSurfacePixelFormat
+imgfmt_to_pixelformat( uint32_t format )
+{
+     switch (format) {
+     case IMGFMT_RGB32:
+     case IMGFMT_BGR32:
+	  return DSPF_ARGB;
+     case IMGFMT_RGB24:
+     case IMGFMT_BGR24:
+	  return DSPF_RGB24;
+     case IMGFMT_RGB16:
+     case IMGFMT_BGR16:
+	  return DSPF_RGB16;
+     case IMGFMT_RGB15:
+     case IMGFMT_BGR15:
+	  return DSPF_RGB15;
+     case IMGFMT_YUY2:
+	  return DSPF_YUY2;
+     case IMGFMT_UYVY:
+	  return DSPF_UYVY;
+     case IMGFMT_YV12:
+	  return DSPF_YV12;
+     case IMGFMT_I420:
+     case IMGFMT_IYUV:
+          return DSPF_I420;
+     default:
+	  return DSPF_UNKNOWN;
+     }
+}
+
+static uint32_t
+preinit( const char *arg )
+{
+     DFBSurfaceDescription dsc;
+
+     if (vo_subdevice) {
+          while (*vo_subdevice != '\0') {
+               if (!strncmp(vo_subdevice, "bes", 3)) {
+                    use_bes = 1;
+                    vo_subdevice += 3;
+               } else if (!strncmp(vo_subdevice, "nocrtc2", 7)) {
+                    use_crtc2 = 0;
+                    vo_subdevice += 7;
+               } else if (!strncmp(vo_subdevice, "nospic", 6)) {
+                    use_spic = 0;
+                    vo_subdevice += 6;
+               } else
+                    vo_subdevice++;
+          }
+     }
+     if (!use_bes && !use_crtc2) {
+	  fprintf( stderr, "vo_dfbmga: No output selected\n" );
+          return -1;
+     }
+
+     if (!inited) {
+          DirectFBInit( NULL, NULL );
+
+          if (!fb_dev_name && !(fb_dev_name = getenv( "FRAMEBUFFER" )))
+               fb_dev_name = "/dev/fb0";
+          DirectFBSetOption( "fbdev", fb_dev_name );
+          DirectFBSetOption( "no-cursor", "" );
+          DirectFBSetOption( "bg-color", "00000000" );
+
+          DirectFBCreate( &dfb );
+
+          inited = 1;
+     }
+
+     if (use_bes) {
+          dfb->GetDisplayLayer( dfb, 1, &bes );
+          bes->SetCooperativeLevel( bes, DLSCL_EXCLUSIVE );
+          bes->SetOpacity( bes, 0 );
+     }
+
+     if (use_crtc2) {
+          dfb->GetDisplayLayer( dfb, 2, &crtc2 );
+          crtc2->SetCooperativeLevel( crtc2, DLSCL_EXCLUSIVE );
+          crtc2->SetOpacity( crtc2, 0 );
+     }
+
+     dfb->GetInputDevice( dfb, DIDID_KEYBOARD, &keyboard );
+     keyboard->CreateEventBuffer( keyboard, &buffer );
+     buffer->Reset( buffer );
+
+     return 0;
+}
+
+static uint32_t
+config( uint32_t width, uint32_t height,
+        uint32_t d_width, uint32_t d_height,
+        uint32_t fullscreen,
+        char *title,
+	uint32_t format )
+{
+     DFBDisplayLayerConfig      dlc;
+     DFBDisplayLayerConfigFlags failed;
+     DFBSurfaceDescription      dsc;
+     DFBResult                  ret;
+
+     uint32_t out_width;
+     uint32_t out_height;
+
+     in_width  = width;
+     in_height = height;
+
+     aspect_save_orig(width, height);
+     aspect_save_prescale(d_width, d_height);
+
+     dlc.pixelformat   = imgfmt_to_pixelformat( format );
+
+     if (use_bes) {
+          /* Draw to BES surface */
+          dlc.flags       = DLCONF_WIDTH | DLCONF_HEIGHT | DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE;
+          dlc.width       = in_width;
+          dlc.height      = in_height;
+          dlc.buffermode  = DLBM_BACKVIDEO;
+
+          if (bes->TestConfiguration( bes, &dlc, &failed ) != DFB_OK)
+               return -1;
+          bes->SetConfiguration( bes, &dlc );
+          bes->GetSurface( bes, &frame );
+
+          aspect_save_screenres( 10000, 10000 );
+          aspect( &out_width, &out_height, A_ZOOM );
+          bes->SetScreenLocation( bes,
+                                  (1.0f - (float) out_width  / 10000.0f) / 2.0f,
+                                  (1.0f - (float) out_height / 10000.0f) / 2.0f,
+                                  (float) out_width  / 10000.0f,
+                                  (float) out_height / 10000.0f );
+     } else {
+          /* Draw to a temporary surface */
+          DFBSurfaceDescription dsc;
+
+          dsc.flags       = DSDESC_CAPS |
+                            DSDESC_WIDTH | DSDESC_HEIGHT |
+                            DSDESC_PIXELFORMAT;
+          dsc.caps        = DSCAPS_VIDEOONLY;
+          dsc.width       = in_width;
+          dsc.height      = in_height;
+          dsc.pixelformat = dlc.pixelformat;
+
+          dfb->CreateSurface( dfb, &dsc, &frame );
+     }
+
+     if (use_crtc2) {
+          dlc.flags      = DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE;
+          dlc.buffermode = DLBM_BACKVIDEO;
+
+          switch (dlc.pixelformat) {
+          case DSPF_I420:
+          case DSPF_YV12:
+               /* sub-picture supported */
+               break;
+
+          case DSPF_YUY2:
+          case DSPF_UYVY:
+               /* Blit to YUY2/UYVY not supported */
+               dlc.pixelformat = DSPF_ARGB;
+
+               /* fall through */
+          default:
+               /* sub-picture not supported */
+               use_spic = 0;
+          }
+
+          if (crtc2->TestConfiguration( crtc2, &dlc, &failed ) != DFB_OK)
+               return -1;
+          crtc2->SetConfiguration( crtc2, &dlc );
+          crtc2->GetSurface( crtc2, &c2frame );
+
+          c2frame->GetSize( c2frame, &screen_width, &screen_height );
+
+          /* Don't stretch only slightly smaller videos */
+          if ((in_width > (0.95 * screen_width)) &&
+              (in_width < screen_width))
+               out_width = in_width;
+          else
+               out_width = screen_width;
+          if ((in_height > (0.95 * screen_height)) &&
+              (in_height < screen_height))
+               out_height = in_height;
+          else
+               out_height = screen_height;
+
+          aspect_save_screenres( out_width, out_height );
+          aspect( &out_width, &out_height, (fullscreen & 0x01) ? A_ZOOM : A_NOZOOM );
+
+          if (in_width != out_width ||
+              in_height != out_height)
+               stretch = 1;
+          else
+               stretch = 0;
+
+          drect.x = (screen_width  - out_width)  / 2;
+          drect.y = (screen_height - out_height) / 2;
+          drect.w = out_width;
+          drect.h = out_height;
+
+          c2frame->Clear( c2frame, 0, 0, 0, 0 );
+          c2frame->Flip( c2frame, NULL, 0 );
+          c2frame->Clear( c2frame, 0, 0, 0, 0 );
+
+          printf( "vo_dfbmga: CRTC2 surface %dx%d %s\n", dlc.width, dlc.height, pixelformat_name( dlc.pixelformat ) );
+     } else
+          use_spic = 0;
+
+     frame->GetPixelFormat( frame, &frame_format );
+     frame_pixel_size = DFB_BYTES_PER_PIXEL( frame_format );
+     printf( "vo_dfbmga: Video surface %dx%d %s (%s)\n",
+             in_width, in_height,
+             pixelformat_name( frame_format ),
+             use_bes ? "BES" : "offscreen" );
+
+     if (use_spic) {
+          /* Draw OSD to sub-picture surface */
+          IDirectFBPalette *palette;
+          DFBColor          color;
+          int               i;
+
+          dfb->GetDisplayLayer( dfb, 3, &spic );
+          spic->SetCooperativeLevel( spic, DLSCL_EXCLUSIVE );
+          spic->SetOpacity( spic, 0 );
+
+          dlc.flags       = DLCONF_PIXELFORMAT | DLCONF_BUFFERMODE;
+          dlc.pixelformat = DSPF_LUT8;
+          dlc.buffermode  = DLBM_BACKVIDEO;
+          if (spic->TestConfiguration( spic, &dlc, &failed ) != DFB_OK)
+               return -1;
+          spic->SetConfiguration( spic, &dlc );
+
+          spic->GetSurface( spic, &subframe );
+
+          subframe->GetPalette( subframe, &palette );
+          color.a = 0;
+          for (i = 0; i < 16; i++) {
+               color.r = i * 17;
+               color.g = i * 17;
+               color.b = i * 17;
+               palette->SetEntries( palette, &color, 1, i );
+          }
+          palette->Release( palette );
+
+          subframe->Clear( subframe, 0, 0, 0, 0 );
+          subframe->Flip( subframe, NULL, 0 );
+          subframe->Clear( subframe, 0, 0, 0, 0 );
+     } else if (use_crtc2) {
+          /* Draw OSD to CRTC2 surface */
+          subframe = c2frame;
+     } else {
+          /* Draw OSD to BES surface */
+          subframe            = frame;
+          screen_width        = in_width;
+          screen_height       = in_height;
+     }
+
+     subframe->GetPixelFormat( subframe, &subframe_format );
+     subframe_pixel_size = DFB_BYTES_PER_PIXEL( subframe_format );
+     printf( "vo_dfbmga: Sub-picture surface %dx%d %s (%s)\n",
+             screen_width, screen_height,
+             pixelformat_name( subframe_format ),
+             use_crtc2 ? (use_spic ? "Sub-picture layer" : "CRTC2") : "BES" );
+
+     /* Display all needed layers */
+     if (use_bes)
+          bes->SetOpacity( bes, 0xFF );
+     if (use_crtc2)
+          crtc2->SetOpacity( crtc2, 0xFF );
+     if (use_spic)
+          spic->SetOpacity( spic, 0xFF );
+
+     return 0;
+}
+
+static uint32_t
+query_format( uint32_t format )
+{
+     switch (format) {
+          case IMGFMT_RGB32:
+          case IMGFMT_BGR32:
+          case IMGFMT_RGB24:
+          case IMGFMT_BGR24:
+          case IMGFMT_RGB16:
+          case IMGFMT_BGR16:
+          case IMGFMT_RGB15:
+          case IMGFMT_BGR15:
+          case IMGFMT_YUY2:
+          case IMGFMT_UYVY:
+          case IMGFMT_YV12:
+          case IMGFMT_I420:
+          case IMGFMT_IYUV:
+               return (VFCAP_HWSCALE_UP |
+                       VFCAP_HWSCALE_DOWN |
+                       VFCAP_CSP_SUPPORTED_BY_HW |
+                       VFCAP_CSP_SUPPORTED |
+                       VFCAP_OSD);
+     }
+
+     return 0;
+}
+
+static const vo_info_t *get_info( void )
+{
+	return &vo_info;
+}
+
+static void vo_draw_alpha_lut8( int w, int h,
+                                unsigned char* src,
+                                unsigned char *srca,
+                                int srcstride,
+                                unsigned char* dst,
+                                int dststride )
+{
+     int x;
+
+     while (h--) {
+          for (x = 0; x < w; x++) {
+               if (srca[x])
+                    dst[x] |= ((255 - srca[x]) & 0xF0) | (src[x] >> 4);
+          }
+          src  += srcstride;
+          srca += srcstride;
+          dst  += dststride;
+     }
+}
+
+static void
+draw_alpha( int x0, int y0,
+            int w, int h,
+            unsigned char *src,
+	    unsigned char *srca,
+            int stride )
+{
+     void *dst;
+     int pitch;
+
+     subframe->Lock( subframe, DSLF_WRITE, &dst, &pitch );
+
+     switch (subframe_format) {
+     case DSPF_LUT8:
+          vo_draw_alpha_lut8( w, h, src, srca, stride,
+                              ((uint8_t *) dst) + pitch * y0 + subframe_pixel_size * x0,
+                              pitch );
+          break;
+     case DSPF_RGB32:
+     case DSPF_ARGB:
+	  vo_draw_alpha_rgb32( w, h, src, srca, stride,
+			       (( uint8_t *) dst) + pitch * y0 + subframe_pixel_size * x0,
+                               pitch );
+	  break;
+     case DSPF_RGB24:
+	  vo_draw_alpha_rgb24( w, h, src, srca, stride,
+			       ((uint8_t *) dst) + pitch * y0 + subframe_pixel_size * x0,
+                               pitch );
+	  break;
+     case DSPF_RGB16:
+	  vo_draw_alpha_rgb16( w, h, src, srca, stride,
+			       ((uint8_t *) dst) + pitch * y0 + subframe_pixel_size * x0,
+                               pitch );
+	  break;
+     case DSPF_RGB15:
+	  vo_draw_alpha_rgb15( w, h, src, srca, stride,
+			       ((uint8_t *) dst) + pitch * y0 + subframe_pixel_size * x0,
+                               pitch );
+	  break;
+     case DSPF_YUY2:
+	  vo_draw_alpha_yuy2( w, h, src, srca, stride,
+			      ((uint8_t *) dst) + pitch * y0 + subframe_pixel_size * x0,
+                              pitch );
+	  break;
+     case DSPF_UYVY:
+	  vo_draw_alpha_yuy2( w, h, src, srca, stride,
+			      ((uint8_t *) dst) + pitch * y0 + subframe_pixel_size * x0 + 1,
+                              pitch );
+	  break;
+     case DSPF_I420:
+     case DSPF_YV12:
+	  vo_draw_alpha_yv12( w, h, src, srca, stride,
+			      ((uint8_t *) dst) + pitch * y0 + subframe_pixel_size * x0,
+                              pitch );
+	  break;
+     }
+
+     subframe->Unlock( subframe );
+}
+
+static uint32_t
+draw_frame( uint8_t * src[] )
+{
+     void *dst;
+     int pitch;
+
+     frame->Lock( frame, DSLF_WRITE, &dst, &pitch );
+
+     switch (frame_format) {
+     case DSPF_ARGB:
+     case DSPF_RGB32:
+     case DSPF_RGB24:
+     case DSPF_RGB16:
+     case DSPF_RGB15:
+     case DSPF_YUY2:
+     case DSPF_UYVY:
+          {
+               int i;
+               for (i = 0; i < in_height; i++) {
+                    memcpy( dst + i * pitch,
+                            src[0] + i * in_width * frame_pixel_size,
+                            in_width * frame_pixel_size );
+               }
+          }
+          break;
+     case DSPF_YV12:
+          {
+               int i;
+               for (i = 0; i < in_height; i++) {
+                    memcpy( dst + i * pitch,
+                            src[0] + i * in_width,
+                            in_width );
+               }
+               dst += pitch * in_height;
+               for (i = 0; i < in_height / 2; i++) {
+                    memcpy( dst + i * pitch / 2,
+                            src[2] + i * in_width / 2,
+                            in_width / 2 );
+               }
+               dst += pitch * in_height / 4;
+               for (i = 0; i < in_height / 2; i++) {
+                    memcpy( dst + i * pitch / 2,
+                            src[1] + i * in_width / 2,
+                            in_width / 2 );
+               }
+          }
+          break;
+     case DSPF_I420:
+          {
+               int i;
+               for (i = 0; i < in_height; i++) {
+                    memcpy( dst + i * pitch,
+                            src[0] + i * in_width,
+                            in_width );
+               }
+               dst += pitch * in_height;
+               for (i = 0; i < in_height / 2; i++) {
+                    memcpy( dst + i * pitch / 2,
+                            src[1] + i * in_width / 2,
+                            in_width / 2 );
+               }
+               dst += pitch * in_height / 4;
+               for (i = 0; i < in_height / 2; i++) {
+                    memcpy( dst + i * pitch / 2,
+                            src[2] + i * in_width / 2,
+                            in_width / 2 );
+               }
+          }
+          break;
+     }
+
+     frame->Unlock( frame );
+
+     return 0;
+}
+
+static uint32_t
+draw_slice( uint8_t * src[], int stride[], int w, int h, int x, int y )
+{
+     void *dst;
+     int pitch;
+
+     frame->Lock( frame, DSLF_WRITE, &dst, &pitch );
+
+     switch (frame_format) {
+     case DSPF_ARGB:
+     case DSPF_RGB32:
+     case DSPF_RGB24:
+     case DSPF_RGB16:
+     case DSPF_RGB15:
+     case DSPF_YUY2:
+     case DSPF_UYVY:
+          {
+               void *s;
+               int i;
+
+               dst += y * pitch + x * frame_pixel_size;
+               s = src[0];
+               for (i = 0; i < h; i++) {
+                    memcpy( dst, s, w );
+                    dst += pitch;
+                    s += stride[0];
+               }
+          }
+          break;
+     case DSPF_YV12:
+          {
+               void *d, *s;
+               int i;
+               d = dst + pitch * y + x;
+               s = src[0];
+               for (i = 0; i < h; i++) {
+                    memcpy( d, s, w );
+                    d += pitch;
+                    s += stride[0];
+               }
+               d = dst + pitch * in_height + pitch * y / 4 + x / 2;
+               s = src[2];
+               for (i = 0; i < h / 2; i++) {
+                    memcpy( d, s, w / 2 );
+                    d += pitch / 2;
+                    s += stride[2];
+               }
+               d = dst + pitch * in_height + pitch * in_height / 4 +
+                    pitch * y / 4 + x / 2;
+               s = src[1];
+               for (i = 0; i < h / 2; i++) {
+                    memcpy( d, s, w / 2 );
+                    d += pitch / 2;
+                    s += stride[1];
+               }
+          }
+	  break;
+     case DSPF_I420:
+          {
+               void *d, *s;
+               int i;
+               d = dst + pitch * y + x;
+               s = src[0];
+               for (i = 0; i < h; i++) {
+                    memcpy( d, s, w );
+                    d += pitch;
+                    s += stride[0];
+               }
+               d = dst + pitch * in_height + pitch * y / 4 + x / 2;
+               s = src[1];
+               for (i = 0; i < h / 2; i++) {
+                    memcpy( d, s, w / 2 );
+                    d += pitch / 2;
+                    s += stride[1];
+               }
+               d = dst + pitch * in_height + pitch * in_height / 4 +
+                    pitch * y / 4 + x / 2;
+               s = src[2];
+               for (i = 0; i < h / 2; i++) {
+                    memcpy( d, s, w / 2 );
+                    d += pitch / 2;
+                    s += stride[2];
+               }
+          }
+	  break;
+     }
+
+     frame->Unlock( frame );
+
+     return 0;
+}
+
+static void
+draw_osd( void )
+{
+     if (use_spic)
+          subframe->Clear( subframe, 0, 0, 0, 0 );
+     else if (!use_crtc2) {
+          /* Clear black bars around the picture */
+          c2frame->SetColor( c2frame, 0, 0, 0, 0 );
+          c2frame->FillRectangle( c2frame,
+                                  0, 0,
+                                  drect.x, drect.y + drect.h );
+          c2frame->FillRectangle( c2frame,
+                                  0, drect.y + drect.h,
+                                  drect.x + drect.w, drect.y );
+          c2frame->FillRectangle( c2frame,
+                                  drect.x, 0,
+                                  drect.x + drect.w, drect.y );
+          c2frame->FillRectangle( c2frame,
+                                  drect.x + drect.w, drect.y,
+                                  drect.x, drect.y + drect.h );
+     }
+
+     vo_draw_text( screen_width, screen_height, draw_alpha );
+
+     subframe->Flip( subframe, NULL, DSFLIP_WAITFORSYNC );
+}
+
+static void
+flip_page( void )
+{
+     /* Flip is done by draw_osd() when only BES is used */
+     if (!use_crtc2)
+          return;
+
+     if (use_bes)
+          /* Flip BES */
+          frame->Flip( frame, NULL, 0 );
+
+     /* Blit from BES/temp to CRTC2 */
+     c2frame->SetBlittingFlags( c2frame, DSBLIT_NOFX );
+     if (stretch)
+          c2frame->StretchBlit( c2frame, frame, NULL, &drect );
+     else
+          c2frame->Blit( c2frame, frame, NULL, drect.x, drect.y );
+
+     if (use_spic)
+          /* Flip CRTC2 */
+          c2frame->Flip( c2frame, NULL, DSFLIP_WAITFORSYNC );
+}
+
+static void
+uninit( void )
+{
+     buffer->Release( buffer );
+     keyboard->Release( keyboard );
+
+     frame->Release( frame );
+     if (use_bes) {
+          bes->SetOpacity( bes, 0 );
+          bes->Release( bes );
+     }
+     if (use_crtc2) {
+          c2frame->Release( c2frame );
+          crtc2->SetOpacity( crtc2, 0 );
+          crtc2->Release( crtc2 );
+     }
+     if (use_spic) {
+          subframe->Release( subframe );
+          spic->SetOpacity( spic, 0 );
+          spic->Release( spic );
+     }
+
+     /*
+      * Don't release. Segfault in preinit() if
+      * DirectFBCreate() called more than once.
+      *
+      * dfb->Release( dfb );
+      */
+}
+
+static int
+directfb_set_video_eq( const vidix_video_eq_t * info )
+{
+     DFBColorAdjustment ca;
+     float factor = (float) 0xffff / 2000.0;
+
+     ca.flags = DCAF_NONE;
+
+     if (info->cap & VEQ_CAP_BRIGHTNESS) {
+          ca.flags      |= DCAF_BRIGHTNESS;
+          ca.brightness  = info->brightness * factor + 0x8000;
+     }
+     if (info->cap & VEQ_CAP_CONTRAST) {
+          ca.flags    |= DCAF_CONTRAST;
+          ca.contrast  = info->contrast * factor + 0x8000;
+     }
+     if (info->cap & VEQ_CAP_HUE) {
+          ca.flags |= DCAF_HUE;
+          ca.hue    = info->hue * factor + 0x8000;
+     }
+     if (info->cap & VEQ_CAP_SATURATION) {
+          ca.flags      |= DCAF_SATURATION;
+          ca.saturation  = info->saturation * factor + 0x8000;
+     }
+
+     /* Prefer CRTC2 over BES */
+     if (use_crtc2)
+          crtc2->SetColorAdjustment( crtc2, &ca );
+     else if (use_bes)
+          bes->SetColorAdjustment( bes, &ca );
+
+     return 0;
+}
+
+static int
+directfb_get_video_eq( vidix_video_eq_t * info )
+{
+     DFBColorAdjustment ca;
+     float factor = 2000.0 / (float) 0xffff;
+
+     /* Prefer CRTC2 over BES */
+     if (use_crtc2)
+          crtc2->GetColorAdjustment( crtc2, &ca );
+     else if (use_bes)
+          bes->GetColorAdjustment( bes, &ca );
+     else
+          return 0;
+
+     if (ca.flags & DCAF_BRIGHTNESS) {
+          info->cap        |= VEQ_CAP_BRIGHTNESS;
+          info->brightness  = (ca.brightness - 0x8000) * factor;
+     }
+     if (ca.flags & DCAF_CONTRAST) {
+          info->cap      |= VEQ_CAP_CONTRAST;
+          info->contrast  = (ca.contrast - 0x8000) * factor;
+     }
+     if (ca.flags & DCAF_HUE) {
+          info->cap |= VEQ_CAP_HUE;
+          info->hue  = (ca.hue - 0x8000) * factor;
+     }
+     if (ca.flags & DCAF_SATURATION) {
+          info->cap        |= VEQ_CAP_SATURATION;
+          info->saturation  = (ca.saturation - 0x8000) * factor;
+     }
+
+     return 0;
+}
+
+static uint32_t
+control( uint32_t request, void *data, ... )
+{
+     switch (request) {
+     case VOCTRL_QUERY_FORMAT:
+	  return query_format( *((uint32_t *) data) );
+     case VOCTRL_SET_EQUALIZER:
+          {
+               va_list ap;
+               int value;
+               vidix_video_eq_t info;
+
+               va_start( ap, data );
+               value = va_arg( ap, int );
+               va_end( ap );
+
+               if (!strcasecmp( data, "brightness" )) {
+                    info.cap = VEQ_CAP_BRIGHTNESS;
+                    info.brightness = value * 10;
+               }
+               if (!strcasecmp( data, "contrast" )) {
+                    info.cap = VEQ_CAP_CONTRAST;
+                    info.contrast = value * 10;
+               }
+               if (!strcasecmp( data, "saturation" )) {
+                    info.cap = VEQ_CAP_SATURATION;
+                    info.saturation = value * 10;
+               }
+               if (!strcasecmp( data, "hue" )) {
+                    info.cap = VEQ_CAP_HUE;
+                    info.hue = value * 10;
+               }
+               if (directfb_set_video_eq( &info ))
+                    return VO_FALSE;
+
+               return VO_TRUE;
+          }
+     case VOCTRL_GET_EQUALIZER:
+          {
+               va_list ap;
+               int *value;
+               vidix_video_eq_t info;
+
+               if (directfb_get_video_eq( &info ))
+                    return VO_FALSE;
+
+               va_start( ap, data );
+               value = va_arg( ap, int* );
+               va_end( ap );
+
+               if (!strcasecmp( data, "brightness" ))
+                    if (info.cap & VEQ_CAP_BRIGHTNESS)
+                         *value = info.brightness / 10;
+               if (!strcasecmp( data, "contrast" ))
+                    if (info.cap & VEQ_CAP_CONTRAST)
+                         *value = info.contrast / 10;
+               if (!strcasecmp( data, "saturation" ))
+                    if (info.cap & VEQ_CAP_SATURATION)
+                         *value = info.saturation / 10;
+               if (!strcasecmp( data, "hue" ))
+                    if (info.cap & VEQ_CAP_HUE)
+                         *value = info.hue / 10;
+
+               return VO_TRUE;
+          }
+     }
+
+     return VO_NOTIMPL;
+}
+
+extern void mplayer_put_key( int code );
+
+#include "../linux/keycodes.h"
+
+static void
+check_events( void )
+{
+     static int opa = 255;
+     DFBInputEvent event;
+
+     if (buffer->GetEvent( buffer, DFB_EVENT( &event )) == DFB_OK) {
+          if (event.type == DIET_KEYPRESS) {
+               switch (event.key_symbol) {
+               case DIKS_ESCAPE:
+                    mplayer_put_key( 'q' );
+                    break;
+               case DIKS_PAGE_UP:
+                    mplayer_put_key( KEY_PAGE_UP );
+                    break;
+               case DIKS_PAGE_DOWN:
+                    mplayer_put_key( KEY_PAGE_DOWN );
+                    break;
+               case DIKS_CURSOR_UP:
+                    mplayer_put_key( KEY_UP );
+                    break;
+               case DIKS_CURSOR_DOWN:
+                    mplayer_put_key( KEY_DOWN );
+                    break;
+               case DIKS_CURSOR_LEFT:
+                    mplayer_put_key( KEY_LEFT );
+                    break;
+               case DIKS_CURSOR_RIGHT:
+                    mplayer_put_key( KEY_RIGHT );
+                    break;
+               case DIKS_INSERT:
+                    mplayer_put_key( KEY_INSERT );
+                    break;
+               case DIKS_DELETE:
+                    mplayer_put_key( KEY_DELETE );
+                    break;
+               case DIKS_HOME:
+                    mplayer_put_key( KEY_HOME );
+                    break;
+               case DIKS_END:
+                    mplayer_put_key( KEY_END );
+                    break;
+               default:
+                    mplayer_put_key( event.key_symbol );
+               }
+          }
+     }
+
+     /*
+      * empty buffer, because of repeating
+      * keyboard repeat is faster than key handling and this causes problems during seek
+      * temporary workabout. should be solved in the future
+      */
+     buffer->Reset( buffer );
+}