summaryrefslogtreecommitdiffstats
path: root/libvo
diff options
context:
space:
mode:
authorarpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-10-31 23:54:26 +0000
committerarpi <arpi@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-10-31 23:54:26 +0000
commit2d602b345bc2c5e216576a0be82e8416477c5f03 (patch)
tree785786e0957acfa16fdbb0946ffa22f5b469ca92 /libvo
parent304cac4da3048b961d9ed500ccac657a4d82db00 (diff)
downloadmpv-2d602b345bc2c5e216576a0be82e8416477c5f03.tar.bz2
mpv-2d602b345bc2c5e216576a0be82e8416477c5f03.tar.xz
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> git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@8014 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'libvo')
-rw-r--r--libvo/video_out.c10
-rw-r--r--libvo/vo_dfbmga.c981
2 files changed, 990 insertions, 1 deletions
diff --git a/libvo/video_out.c b/libvo/video_out.c
index ce0b3d9130..d426b4381d 100644
--- a/libvo/video_out.c
+++ b/libvo/video_out.c
@@ -90,7 +90,12 @@ extern vo_functions_t video_out_gif89a;
#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 @@ vo_functions_t* video_out_drivers[] =
#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
diff --git a/libvo/vo_dfbmga.c b/libvo/vo_dfbmga.c
new file mode 100644
index 0000000000..a1c3d2690b
--- /dev/null
+++ b/libvo/vo_dfbmga.c
@@ -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 );
+}