/* MPlayer video driver for DirectFB / Matrox G400 Copyright (C) 2002 Ville Syrjala Originally based on vo_directfb.c by Jiri Svoboda 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 /* other things */ #include #include #include #include #include #include #include #include #include #include #include #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 ", "" }; 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 ); }