From 6ca0d7b459d6e24242938698561da81ca7157ac4 Mon Sep 17 00:00:00 2001 From: KO Myung-Hun Date: Thu, 24 Nov 2011 19:22:22 +0900 Subject: [PATCH 09/10] Add KVA video output module for OS/2 --- configure.ac | 23 + modules/video_output/Modules.am | 8 + modules/video_output/kva.c | 1182 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 1213 insertions(+), 0 deletions(-) create mode 100644 modules/video_output/kva.c diff --git a/configure.ac b/configure.ac index 7fd4c1f..1fb28c1 100644 --- a/configure.ac +++ b/configure.ac @@ -3428,6 +3428,29 @@ dnl PKG_ENABLE_MODULES_VLC([CACA], [], [caca >= 0.99.beta14], [libcaca output],[auto]) dnl +dnl OS/2 KVA plugin +dnl +AC_ARG_ENABLE(kva, + [AS_HELP_STRING([--enable-kva], + [support the K Video Accelerator KVA (default enabled on OS/2)])],, [ + AS_IF([test "$SYS" = "os2"], [ + enable_kva="yes" + ]) +]) +have_kva="no" +KVA_LIBS="" +AS_IF([test "$enable_kva" != "no"], [ + AC_CHECK_HEADERS([kva.h], [ + have_kva="yes" + AC_CHECK_LIB(kva, main, [ + KVA_LIBS="-lkva" + ]) + ]) +]) +AC_SUBST(KVA_LIBS) +AM_CONDITIONAL([HAVE_KVA], [test "${have_kva}" = "yes"]) + +dnl dnl Audio plugins dnl diff --git a/modules/video_output/Modules.am b/modules/video_output/Modules.am index b10e98f..1c26b92 100644 --- a/modules/video_output/Modules.am +++ b/modules/video_output/Modules.am @@ -113,6 +113,14 @@ if HAVE_OS2 libvlc_LTLIBRARIES += libdrawable_plugin.la endif +libkva_plugin_la_SOURCES = kva.c +libkva_plugin_la_CFLAGS = $(AM_CFLAGS) +libkva_plugin_la_LIBADD = $(AM_LIBADD) $(KVA_LIBS) +libkva_plugin_la_DEPENDENCIES = +if HAVE_KVA +libvlc_LTLIBRARIES += libkva_plugin.la +endif + ### EGL ### libegl_plugin_la_SOURCES = egl.c libegl_plugin_la_CFLAGS = $(AM_CFLAGS) $(EGL_CFLAGS) diff --git a/modules/video_output/kva.c b/modules/video_output/kva.c new file mode 100644 index 0000000..7bce7f1 --- /dev/null +++ b/modules/video_output/kva.c @@ -0,0 +1,1182 @@ +/***************************************************************************** + * kva.c: KVA video output plugin for vlc + ***************************************************************************** + * Copyright (C) 2010, 2011 the VideoLAN team + * + * Authors: KO Myung-Hun + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close( vlc_object_t * ); + +#define KVA_FIXT23_TEXT N_( \ + "Enable a workaround for T23" ) +#define KVA_FIXT23_LONGTEXT N_( \ + "Enable this option if the diagonal stripes are displayed " \ + "when the window size is equal to or smaller than the movie size." ) +#define KVA_VIDEO_MODE_TEXT N_( \ + "Video mode" ) +#define KVA_VIDEO_MODE_LONGTEXT N_( \ + "Select a proper video mode to be used by KVA." ) + +static const char *const ppsz_kva_video_mode[] = { + "auto", "snap", "wo", "dive" }; +static const char *const ppsz_kva_video_mode_text[] = { + N_("Auto"), N_("SNAP"), N_("WarpOverlay!"), N_("DIVE") }; + +vlc_module_begin () + set_shortname( "KVA" ) + set_category( CAT_VIDEO ) + set_subcategory( SUBCAT_VIDEO_VOUT ) + add_string( "kva-video-mode", ppsz_kva_video_mode[0], KVA_VIDEO_MODE_TEXT, + KVA_VIDEO_MODE_LONGTEXT, false ) + change_string_list( ppsz_kva_video_mode, ppsz_kva_video_mode_text, 0 ) + add_bool( "kva-fixt23", false, KVA_FIXT23_TEXT, KVA_FIXT23_LONGTEXT, true ); + set_description( N_("K Video Acceleration video output") ) + set_capability( "vout display", 100 ) + add_shortcut( "kva" ) + set_callbacks( Open, Close ) +vlc_module_end () + +/***************************************************************************** + * vout_display_sys_t: video output method descriptor + ***************************************************************************** + * This structure is part of the video output thread descriptor. + * It describes the module specific properties of an output thread. + *****************************************************************************/ +struct vout_display_sys_t +{ + TID tid; + HEV ack_event; + int i_result; + HAB hab; + HMQ hmq; + HWND frame; + HWND client; + KVASETUP kvas; + KVACAPS kvac; + LONG i_screen_width; + LONG i_screen_height; + bool b_fixt23; + PFNWP p_old_frame; + RECTL client_rect; + vout_window_t *parent_window; + HWND parent; + RECTL parent_rect; + picture_pool_t *pool; + picture_resource_t resource; + unsigned button_pressed; + bool is_mouse_hidden; +}; + +struct picture_sys_t +{ + int i_chroma_shift; +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static picture_pool_t *Pool (vout_display_t *, unsigned); +static void Display(vout_display_t *, picture_t *, subpicture_t * ); +static int Control(vout_display_t *, int, va_list); +static void Manage (vout_display_t *); + +static int OpenDisplay ( vout_display_t *, video_format_t * ); +static void CloseDisplay( vout_display_t * ); + +static int KVALock( picture_t * ); +static void KVAUnlock( picture_t * ); + +static void MorphToPM ( void ); +static int ConvertKey ( USHORT ); +static MRESULT EXPENTRY MyFrameWndProc( HWND, ULONG, MPARAM, MPARAM ); +static MRESULT EXPENTRY WndProc ( HWND, ULONG, MPARAM, MPARAM ); + +#define WC_VLC_KVA "WC_VLC_KVA" + +#define COLOR_KEY 0x0F0F0F + +#define WM_VLC_MANAGE ( WM_USER + 1 ) +#define WM_VLC_FULLSCREEN_CHANGE ( WM_USER + 2 ) +#define WM_VLC_SIZE_CHANGE ( WM_USER + 3 ) + +static const char *psz_video_mode[ 3 ] = {"DIVE", "WarpOverlay!", "SNAP"}; + +static void PMThread( void *arg ) +{ + vout_display_t *vd = ( vout_display_t * )arg; + vout_display_sys_t * sys = vd->sys; + ULONG i_frame_flags; + QMSG qm; + char *psz_mode; + ULONG i_kva_mode; + + /* */ + video_format_t fmt = vd->fmt; + + /* */ + vout_display_info_t info = vd->info; + info.is_slow = false; + info.has_double_click = true; + info.has_hide_mouse = false; + info.has_pictures_invalid = false; + + MorphToPM(); + + sys->hab = WinInitialize( 0 ); + sys->hmq = WinCreateMsgQueue( sys->hab, 0); + + WinRegisterClass( sys->hab, + WC_VLC_KVA, + WndProc, + CS_SIZEREDRAW | CS_MOVENOTIFY, + sizeof( PVOID )); + + sys->b_fixt23 = var_CreateGetBool( vd, "kva-fixt23"); + + if( !sys->b_fixt23 ) + { + vout_window_cfg_t wnd_cfg; + + wnd_cfg.is_standalone = false; + wnd_cfg.type = VOUT_WINDOW_TYPE_HWND; + wnd_cfg.x = var_InheritInteger(vd, "video-x"); + wnd_cfg.y = var_InheritInteger(vd, "video-y"); + wnd_cfg.width = vd->cfg->display.width; + wnd_cfg.height = vd->cfg->display.height; + + /* If an external window was specified, we'll draw in it. */ + sys->parent_window = + vout_display_NewWindow( vd, &wnd_cfg ); + } + + if( sys->parent_window ) + { + sys->parent = ( HWND )sys->parent_window->handle.hwnd; + + /* Workaround : + * When an embedded window opened first, it is not positioned + * correctly. So reposition it here, again. + */ + WinSetWindowPos( WinQueryWindow( sys->parent, QW_PARENT ), + HWND_TOP, 0, 0, 0, 0, SWP_MOVE ); + + ULONG i_style = WinQueryWindowULong( sys->parent, QWL_STYLE ); + WinSetWindowULong( sys->parent, QWL_STYLE, + i_style | WS_CLIPCHILDREN ); + + i_frame_flags = FCF_TITLEBAR; + } + else + { + sys->parent = HWND_DESKTOP; + + i_frame_flags = FCF_SYSMENU | FCF_TITLEBAR | FCF_MINMAX | + FCF_SIZEBORDER | FCF_TASKLIST; + } + + sys->frame = + WinCreateStdWindow( sys->parent, /* parent window handle */ + WS_VISIBLE, /* frame window style */ + &i_frame_flags, /* window style */ + WC_VLC_KVA, /* class name */ + "", /* window title */ + 0L, /* default client style */ + NULLHANDLE, /* resource in exe file */ + 1, /* frame window id */ + &sys->client ); /* client window handle */ + + if( sys->frame == NULLHANDLE ) + { + msg_Err( vd, "cannot create a frame window"); + + goto exit_frame; + } + + WinSetWindowPtr( sys->client, 0, vd ); + + if( sys->b_fixt23 ) + { + WinSetWindowPtr( sys->frame, 0, vd ); + sys->p_old_frame = WinSubclassWindow( sys->frame, MyFrameWndProc ); + } + + psz_mode = var_CreateGetString( vd, "kva-video-mode" ); + + i_kva_mode = KVAM_AUTO; + if( strcmp( psz_mode, "snap" ) == 0 ) + i_kva_mode = KVAM_SNAP; + else if( strcmp( psz_mode, "wo" ) == 0 ) + i_kva_mode = KVAM_WO; + else if( strcmp( psz_mode, "dive" ) == 0 ) + i_kva_mode = KVAM_DIVE; + + free( psz_mode ); + + if( kvaInit( i_kva_mode, sys->client, COLOR_KEY )) + { + msg_Err( vd, "cannot initialize KVA"); + + goto exit_kva_init; + } + + kvaCaps( &sys->kvac ); + + msg_Dbg( vd, "selected video mode = %s", + psz_video_mode[ sys->kvac.ulMode - 1 ]); + + if( OpenDisplay( vd, &fmt ) ) + { + msg_Err( vd, "cannot open display"); + + goto exit_open_display; + } + + if( vd->cfg->is_fullscreen ) + { + if( sys->parent_window ) + vout_window_SetFullScreen(sys->parent_window, true); + else + WinPostMsg( sys->client, WM_VLC_FULLSCREEN_CHANGE, + MPFROMLONG( true ), 0 ); + } + + kvaDisableScreenSaver(); + + /* Setup vout_display now that everything is fine */ + vd->fmt = fmt; + vd->info = info; + + vd->pool = Pool; + vd->prepare = NULL; + vd->display = Display; + vd->control = Control; + vd->manage = Manage; + + /* Prevent SIG_FPE */ + _control87(MCW_EM, MCW_EM); + + sys->i_result = VLC_SUCCESS; + DosPostEventSem( sys->ack_event ); + + while( WinGetMsg( sys->hab, &qm, NULLHANDLE, 0, 0 )) + WinDispatchMsg( sys->hab, &qm ); + + kvaEnableScreenSaver(); + + CloseDisplay( vd ); + + /* fall through */ + +exit_open_display : + kvaDone(); + +exit_kva_init : + if( sys->b_fixt23 ) + WinSubclassWindow( sys->frame, sys->p_old_frame ); + + WinDestroyWindow( sys->frame ); + +exit_frame : + vout_display_DeleteWindow( vd, sys->parent_window ); + + if( sys->is_mouse_hidden ) + WinShowPointer( HWND_DESKTOP, TRUE ); + + WinDestroyMsgQueue( sys->hmq ); + WinTerminate( sys->hab ); + + sys->i_result = VLC_EGENERIC; + DosPostEventSem( sys->ack_event ); +} + +/** + * This function initializes KVA vout method. + */ +static int Open ( vlc_object_t *object ) +{ + vout_display_t *vd = (vout_display_t *)object; + vout_display_sys_t *sys; + + vd->sys = sys = calloc( 1, sizeof( *sys )); + if( !sys ) + return VLC_ENOMEM; + + DosCreateEventSem( NULL, &sys->ack_event, 0, FALSE ); + + sys->tid = _beginthread( PMThread, NULL, 1024 * 1024, vd ); + DosWaitEventSem( sys->ack_event, SEM_INDEFINITE_WAIT ); + + if( sys->i_result != VLC_SUCCESS ) + { + DosCloseEventSem( sys->ack_event ); + + free( sys ); + + return VLC_EGENERIC; + } + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Close: destroy KVA video thread output method + ***************************************************************************** + * Terminate an output method created by Open + *****************************************************************************/ +static void Close ( vlc_object_t *object ) +{ + vout_display_t * vd = (vout_display_t *)object; + vout_display_sys_t * sys = vd->sys; + + WinPostQueueMsg( sys->hmq, WM_QUIT, 0, 0 ); + + DosWaitThread( &sys->tid, DCWW_WAIT ); + + if( sys->pool ) + picture_pool_Delete( sys->pool ); + + DosCloseEventSem( sys->ack_event ); + + free( sys ); +} + +/** + * Return a pool of direct buffers + */ +static picture_pool_t *Pool(vout_display_t *vd, unsigned count) +{ + vout_display_sys_t *sys = vd->sys; + VLC_UNUSED(count); + + return sys->pool; +} + +/***************************************************************************** + * Display: displays previously rendered output + ***************************************************************************** + * This function sends the currently rendered image to the display. + *****************************************************************************/ +static void Display( vout_display_t *vd, picture_t *picture, + subpicture_t *subpicture ) +{ + VLC_UNUSED( vd ); + VLC_UNUSED( subpicture ); + + picture_Release( picture ); +} + +/***************************************************************************** + * Manage: handle Sys events + ***************************************************************************** + * This function should be called regularly by video output thread. It returns + * a non null value if an error occurred. + *****************************************************************************/ +static void Manage( vout_display_t *vd ) +{ + vout_display_sys_t * sys = vd->sys; + + /* Let a window procedure manage instead because if resizing a frame window + * here, WM_SIZE is not sent to its child window. + * Maybe, is this due to the different threads ? */ + WinPostMsg( sys->client, WM_VLC_MANAGE, 0, 0 ); +} + +/***************************************************************************** + * Control: control facility for the vout + *****************************************************************************/ +static int Control( vout_display_t *vd, int query, va_list args ) +{ + vout_display_sys_t *sys = vd->sys; + + switch (query) + { + case VOUT_DISPLAY_HIDE_MOUSE: + { + POINTL ptl; + + WinQueryPointerPos( HWND_DESKTOP, &ptl ); + if( WinWindowFromPoint( HWND_DESKTOP, &ptl, TRUE ) == sys->client ) + { + WinShowPointer( HWND_DESKTOP, FALSE ); + sys->is_mouse_hidden = true; + } + + return VLC_SUCCESS; + } + + case VOUT_DISPLAY_CHANGE_FULLSCREEN: + { + vout_display_cfg_t cfg = *va_arg(args, const vout_display_cfg_t *); + + if( sys->parent_window ) + vout_window_SetFullScreen(sys->parent_window, cfg.is_fullscreen); + else + WinPostMsg( sys->client, WM_VLC_FULLSCREEN_CHANGE, + MPFROMLONG( cfg.is_fullscreen ), 0 ); + + return VLC_SUCCESS; + } + + case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE: + { + const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *); + bool is_forced = va_arg(args, int); + + if( is_forced ) + { + if( sys->parent_window ) + { + vout_window_SetSize(sys->parent_window, + cfg->display.width, cfg->display.height); + + /* Workaround : + * If changing aspect ratio after resizing a main window, + * an embedded window is misplaced. So reposition it, here. + */ + WinSetWindowPos( WinQueryWindow( sys->parent, QW_PARENT ), + HWND_TOP, 0, 1, 0, 0, SWP_MOVE ); + WinSetWindowPos( WinQueryWindow( sys->parent, QW_PARENT ), + HWND_TOP, 0, 0, 0, 0, SWP_MOVE ); + } + else + WinPostMsg( sys->client, WM_VLC_SIZE_CHANGE, + MPFROMLONG( cfg->display.width ), + MPFROMLONG( cfg->display.height )); + } + + return VLC_SUCCESS; + } + + case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT: + case VOUT_DISPLAY_CHANGE_SOURCE_CROP: + { + const video_format_t *source = va_arg(args, const video_format_t *); + + if( query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT ) + { + sys->kvas.ulAspectWidth = ( int64_t )source->i_width * + source->i_sar_num / source->i_sar_den; + sys->kvas.ulAspectHeight = source->i_height; + } + else + { + sys->kvas.rclSrcRect.xLeft = source->i_x_offset; + sys->kvas.rclSrcRect.yTop = source->i_y_offset; + sys->kvas.rclSrcRect.xRight = source->i_x_offset + + source->i_visible_width; + sys->kvas.rclSrcRect.yBottom = source->i_y_offset + + source->i_visible_height; + } + + kvaSetup( &sys->kvas ); + + return VLC_SUCCESS; + } + + case VOUT_DISPLAY_RESET_PICTURES: + case VOUT_DISPLAY_CHANGE_WINDOW_STATE: + case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED: + case VOUT_DISPLAY_CHANGE_ZOOM: + case VOUT_DISPLAY_GET_OPENGL: + /* TODO */ + break; + } + + msg_Err(vd, "Unsupported query(=%d) in vout display KVA", query); + return VLC_EGENERIC; +} + +/* following functions are local */ + +/***************************************************************************** + * OpenDisplay: open and initialize KVA device + ***************************************************************************** + * Open and initialize display according to preferences specified in the vout + * thread fields. + *****************************************************************************/ +static int OpenDisplay( vout_display_t *vd, video_format_t *fmt ) +{ + vout_display_sys_t * sys = vd->sys; + const vlc_fourcc_t *fallback; + bool b_hw_accel = 0; + FOURCC i_kva_fourcc; + int i_chroma_shift; + char sz_title[ 256 ]; + RECTL rcl; + int w, h; + + msg_Dbg( vd, "render chroma = %4.4s", ( const char * )&fmt->i_chroma ); + + for( int pass = 0; pass < 2 && !b_hw_accel; pass++ ) + { + fallback = ( pass == 0 ) ? vlc_fourcc_GetYUVFallback( fmt->i_chroma ) : + vlc_fourcc_GetRGBFallback( fmt->i_chroma ); + + for( int i = 0; fallback[ i ]; i++ ) + { + switch( fallback[ i ]) + { + case VLC_CODEC_YV12: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YV12; + i_kva_fourcc = FOURCC_YV12; + i_chroma_shift = 1; + break; + + case VLC_CODEC_YUYV: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YUY2; + i_kva_fourcc = FOURCC_Y422; + i_chroma_shift = 0; + break; + + case VLC_CODEC_YV9: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YVU9; + i_kva_fourcc = FOURCC_YVU9; + i_chroma_shift = 2; + break; + + case VLC_CODEC_RGB24: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR24; + i_kva_fourcc = FOURCC_BGR3; + i_chroma_shift = 0; + break; + + case VLC_CODEC_RGB16: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR16; + i_kva_fourcc = FOURCC_R565; + i_chroma_shift = 0; + break; + + case VLC_CODEC_RGB15: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR15; + i_kva_fourcc = FOURCC_R555; + i_chroma_shift = 0; + break; + } + + if( b_hw_accel ) + { + fmt->i_chroma = fallback[ i ]; + break; + } + } + } + + if( !b_hw_accel ) + { + msg_Err( vd, "Ooops. There is no fourcc supported by KVA at all."); + + return VLC_EGENERIC; + } + + /* Set the RGB masks */ + fmt->i_rmask = sys->kvac.ulRMask; + fmt->i_gmask = sys->kvac.ulGMask; + fmt->i_bmask = sys->kvac.ulBMask; + + msg_Dbg( vd, "output chroma = %4.4s", ( const char * )&fmt->i_chroma ); + msg_Dbg( vd, "KVA chroma = %4.4s", ( const char * )&i_kva_fourcc ); + + w = vd->source.i_width; + h = vd->source.i_height; + + sys->kvas.ulLength = sizeof( KVASETUP ); + sys->kvas.szlSrcSize.cx = w; + sys->kvas.szlSrcSize.cy = h; + sys->kvas.rclSrcRect.xLeft = 0; + sys->kvas.rclSrcRect.yTop = 0; + sys->kvas.rclSrcRect.xRight = w; + sys->kvas.rclSrcRect.yBottom = h; + sys->kvas.ulRatio = KVAR_FORCEANY; + sys->kvas.ulAspectWidth = w; + sys->kvas.ulAspectHeight = h; + sys->kvas.fccSrcColor = i_kva_fourcc; + sys->kvas.fDither = TRUE; + + if( kvaSetup( &sys->kvas )) + { + msg_Err( vd, "cannot set up KVA"); + + return VLC_EGENERIC; + } + + /* Create the associated picture */ + picture_resource_t *rsc = &sys->resource; + rsc->p_sys = malloc( sizeof( *rsc->p_sys )); + if( !rsc->p_sys ) + return VLC_EGENERIC; + + rsc->p_sys->i_chroma_shift = i_chroma_shift; + + for( int i = 0; i < PICTURE_PLANE_MAX; i++ ) + { + rsc->p[ i ].p_pixels = NULL; + rsc->p[ i ].i_pitch = 0; + rsc->p[ i ].i_lines = 0; + } + + picture_t *picture = picture_NewFromResource( fmt, rsc ); + if( !picture ) + goto exit_picture; + + /* Wrap it into a picture pool */ + picture_pool_configuration_t pool_cfg; + memset( &pool_cfg, 0, sizeof( pool_cfg )); + pool_cfg.picture_count = 1; + pool_cfg.picture = &picture; + pool_cfg.lock = KVALock; + pool_cfg.unlock = KVAUnlock; + + sys->pool = picture_pool_NewExtended( &pool_cfg ); + if( !sys->pool ) + { + picture_Release( picture ); + + goto exit_picture; + } + + if (vd->cfg->display.title) + snprintf( sz_title, sizeof( sz_title ), "%s", vd->cfg->display.title ); + else + snprintf( sz_title, sizeof( sz_title ), + "%s (%4.4s to %4.4s - %s mode KVA output)", + VOUT_TITLE, + ( char * )&vd->fmt.i_chroma, + ( char * )&sys->kvas.fccSrcColor, + psz_video_mode[ sys->kvac.ulMode - 1 ]); + WinSetWindowText( sys->frame, sz_title ); + + sys->i_screen_width = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN ); + sys->i_screen_height = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN ); + + if( sys->parent_window ) + WinQueryWindowRect( sys->parent, &sys->client_rect ); + else + { + sys->client_rect.xLeft = ( sys->i_screen_width - w ) / 2; + sys->client_rect.yBottom = ( sys->i_screen_height - h ) / 2 ; + sys->client_rect.xRight = sys->client_rect.xLeft + w; + sys->client_rect.yTop = sys->client_rect.yBottom + h; + } + + rcl = sys->client_rect; + + WinCalcFrameRect( sys->frame, &rcl, FALSE); + + WinSetWindowPos( sys->frame, HWND_TOP, + rcl.xLeft, rcl.yBottom, + rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom, + SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW | + SWP_ACTIVATE ); + + return VLC_SUCCESS; + +exit_picture: + free( rsc->p_sys ); + + return VLC_EGENERIC; +} + +/***************************************************************************** + * CloseDisplay: close and reset KVA device + ***************************************************************************** + * This function returns all resources allocated by OpenDisplay and restore + * the original state of the device. + *****************************************************************************/ +static void CloseDisplay( vout_display_t *vd ) +{ + VLC_UNUSED( vd ); +} + +static int KVALock( picture_t *picture ) +{ + picture_sys_t *picsys = picture->p_sys; + PVOID kva_buffer; + ULONG kva_bpl; + + if( kvaLockBuffer( &kva_buffer, &kva_bpl )) + return VLC_EGENERIC; + + /* Packed or Y plane */ + picture->p->p_pixels = ( uint8_t * )kva_buffer; + picture->p->i_pitch = kva_bpl; + picture->p->i_lines = picture->format.i_height; + + /* Other planes */ + for( int n = 1; n < picture->i_planes; n++ ) + { + const plane_t *o = &picture->p[n-1]; + plane_t *p = &picture->p[n]; + + p->p_pixels = o->p_pixels + o->i_lines * o->i_pitch; + p->i_pitch = kva_bpl >> picsys->i_chroma_shift; + p->i_lines = picture->format.i_height >> picsys->i_chroma_shift; + } + + return VLC_SUCCESS; +} + +static void KVAUnlock( picture_t *picture ) +{ + VLC_UNUSED( picture ); + + kvaUnlockBuffer(); +} + +static void MorphToPM( void ) +{ + PPIB pib; + + DosGetInfoBlocks(NULL, &pib); + + /* Change flag from VIO to PM */ + if (pib->pib_ultype == 2) + pib->pib_ultype = 3; +} + +/***************************************************************************** + * Key events handling + *****************************************************************************/ +static const struct +{ + USHORT i_pmkey; + int i_vlckey; +} pmkeys_to_vlckeys[] = +{ + { VK_LEFT, KEY_LEFT }, + { VK_RIGHT, KEY_RIGHT }, + { VK_UP, KEY_UP }, + { VK_DOWN, KEY_DOWN }, + { VK_SPACE, ' ' }, + { VK_NEWLINE, KEY_ENTER }, + { VK_ENTER, KEY_ENTER }, + { VK_F1, KEY_F1 }, + { VK_F2, KEY_F2 }, + { VK_F3, KEY_F3 }, + { VK_F4, KEY_F4 }, + { VK_F5, KEY_F5 }, + { VK_F6, KEY_F6 }, + { VK_F7, KEY_F7 }, + { VK_F8, KEY_F8 }, + { VK_F9, KEY_F9 }, + { VK_F10, KEY_F10 }, + { VK_F11, KEY_F11 }, + { VK_F12, KEY_F12 }, + { VK_HOME, KEY_HOME }, + { VK_END, KEY_END }, + { VK_INSERT, KEY_INSERT }, + { VK_DELETE, KEY_DELETE }, +/* + Not supported + {, KEY_MENU }, +*/ + { VK_ESC, KEY_ESC }, + { VK_PAGEUP, KEY_PAGEUP }, + { VK_PAGEDOWN, KEY_PAGEDOWN }, + { VK_TAB, KEY_TAB }, + { VK_BACKSPACE, KEY_BACKSPACE }, +/* + Not supported + {, KEY_MOUSEWHEELUP }, + {, KEY_MOUSEWHEELDOWN }, + {, KEY_MOUSEWHEELLEFT }, + {, KEY_MOUSEWHEELRIGHT }, + + {, KEY_BROWSER_BACK }, + {, KEY_BROWSER_FORWARD }, + {, KEY_BROWSER_REFRESH }, + {, KEY_BROWSER_STOP }, + {, KEY_BROWSER_SEARCH }, + {, KEY_BROWSER_FAVORITES }, + {, KEY_BROWSER_HOME }, + {, KEY_VOLUME_MUTE }, + {, KEY_VOLUME_DOWN }, + {, KEY_VOLUME_UP }, + {, KEY_MEDIA_NEXT_TRACK }, + {, KEY_MEDIA_PREV_TRACK }, + {, KEY_MEDIA_STOP }, + {, KEY_MEDIA_PLAY_PAUSE }, +*/ + + { 0, 0 } +}; + +static int ConvertKey( USHORT i_pmkey ) +{ + int i; + for( i = 0; pmkeys_to_vlckeys[ i ].i_pmkey != 0; i++ ) + { + if( pmkeys_to_vlckeys[ i ].i_pmkey == i_pmkey ) + return pmkeys_to_vlckeys[ i ].i_vlckey; + } + return 0; +} + +static MRESULT EXPENTRY MyFrameWndProc( HWND hwnd, ULONG msg, MPARAM mp1, + MPARAM mp2 ) +{ + vout_display_t *vd = WinQueryWindowPtr( hwnd, 0 ); + vout_display_sys_t *sys = vd->sys; + + switch( msg ) + { + case WM_QUERYTRACKINFO : + { + PTRACKINFO pti = ( PTRACKINFO )mp2; + RECTL rcl; + + sys->p_old_frame( hwnd, msg, mp1, mp2 ); + + pti->rclBoundary.xLeft = 0; + pti->rclBoundary.yBottom = 0; + pti->rclBoundary.xRight = sys->i_screen_width; + pti->rclBoundary.yTop = sys->i_screen_height; + + WinCalcFrameRect( hwnd, &pti->rclBoundary, FALSE ); + + pti->ptlMaxTrackSize.x = pti->rclBoundary.xRight - + pti->rclBoundary.xLeft; + pti->ptlMaxTrackSize.y = pti->rclBoundary.yTop - + pti->rclBoundary.yBottom; + + rcl.xLeft = 0; + rcl.yBottom = 0; + rcl.xRight = sys->kvas.szlSrcSize.cx + 1; + rcl.yTop = sys->kvas.szlSrcSize.cy + 1; + + WinCalcFrameRect( hwnd, &rcl, FALSE ); + + pti->ptlMinTrackSize.x = rcl.xRight - rcl.xLeft; + pti->ptlMinTrackSize.y = rcl.yTop - rcl.yBottom; + + return MRFROMLONG( TRUE ); + } + + case WM_ADJUSTWINDOWPOS : + { + PSWP pswp = ( PSWP )mp1; + RECTL rcl; + + if( pswp->fl & SWP_SIZE ) + { + rcl.xLeft = pswp->x; + rcl.yBottom = pswp->y; + rcl.xRight = rcl.xLeft + pswp->cx; + rcl.yTop = rcl.yBottom + pswp->cy; + + WinCalcFrameRect( hwnd, &rcl, TRUE ); + + if( rcl.xRight - rcl.xLeft <= sys->kvas.szlSrcSize.cx ) + rcl.xRight = rcl.xLeft + ( sys->kvas.szlSrcSize.cx + 1 ); + + if( rcl.yTop - rcl.yBottom <= sys->kvas.szlSrcSize.cy ) + rcl.yTop = rcl.yBottom + ( sys->kvas.szlSrcSize.cy + 1 ); + + if( rcl.xRight - rcl.xLeft > sys->i_screen_width ) + { + rcl.xLeft = 0; + rcl.xRight = sys->i_screen_width; + } + + if( rcl.yTop - rcl.yBottom > sys->i_screen_height ) + { + rcl.yBottom = 0; + rcl.yTop = sys->i_screen_height; + } + + WinCalcFrameRect( hwnd, &rcl, FALSE ); + + if( pswp->x != rcl.xLeft || pswp->y != rcl.yBottom ) + pswp->fl |= SWP_MOVE; + + pswp->x = rcl.xLeft; + pswp->y = rcl.yBottom; + + pswp->cx = rcl.xRight - rcl.xLeft; + pswp->cy = rcl.yTop - rcl.yBottom; + } + + break; + } + } + + return sys->p_old_frame( hwnd, msg, mp1, mp2 ); +} + +static void MousePressed( vout_display_t *vd, HWND hwnd, unsigned button ) +{ + if( WinQueryFocus( HWND_DESKTOP ) != hwnd ) + WinSetFocus( HWND_DESKTOP, hwnd ); + + if( !vd->sys->button_pressed ) + WinSetCapture( HWND_DESKTOP, hwnd ); + + vd->sys->button_pressed |= 1 << button; + + vout_display_SendEventMousePressed( vd, button ); +} + +static void MouseReleased( vout_display_t *vd, unsigned button ) +{ + vd->sys->button_pressed &= ~(1 << button); + if( !vd->sys->button_pressed ) + WinSetCapture( HWND_DESKTOP, NULLHANDLE ); + + vout_display_SendEventMouseReleased( vd, button ); +} + +#define WM_MOUSELEAVE 0x41F + +static MRESULT EXPENTRY WndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 ) +{ + vout_display_t * vd = WinQueryWindowPtr( hwnd, 0 ); + MRESULT result = ( MRESULT )TRUE; + + if ( !vd ) + return WinDefWindowProc( hwnd, msg, mp1, mp2 ); + + vout_display_sys_t * sys = vd->sys; + RECTL rcl; + SWP swp; + + if ( sys->is_mouse_hidden && + ((msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) || + (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST) || + msg == WM_MOUSELEAVE)) + { + WinShowPointer(HWND_DESKTOP, TRUE); + sys->is_mouse_hidden = false; + } + + switch( msg ) + { + /* the user wants to close the window */ + case WM_CLOSE: + vout_display_SendEventClose(vd); + result = 0; + break; + + case WM_MOUSEMOVE : + { + SHORT i_mouse_x = SHORT1FROMMP( mp1 ); + SHORT i_mouse_y = SHORT2FROMMP( mp1 ); + RECTL movie_rect; + int i_movie_width, i_movie_height; + int i_src_width, i_src_height; + + /* Get a current movie area */ + kvaAdjustDstRect( &sys->kvas.rclSrcRect, &movie_rect ); + i_movie_width = movie_rect.xRight - movie_rect.xLeft; + i_movie_height = movie_rect.yTop - movie_rect.yBottom; + + i_src_width = sys->kvas.rclSrcRect.xRight - + sys->kvas.rclSrcRect.xLeft; + i_src_height = sys->kvas.rclSrcRect.yBottom - + sys->kvas.rclSrcRect.yTop; + + int x = ( i_mouse_x - movie_rect.xLeft ) * + i_src_width / i_movie_width + + sys->kvas.rclSrcRect.xLeft; + int y = ( i_mouse_y - movie_rect.yBottom ) * + i_src_height / i_movie_height; + + /* Invert Y coordinate and add y offset */ + y = ( i_src_height - y ) + sys->kvas.rclSrcRect.yTop;; + + vout_display_SendEventMouseMoved(vd, x, y); + + result = WinDefWindowProc( hwnd, msg, mp1,mp2 ); + break; + } + + case WM_BUTTON1DOWN : + MousePressed( vd, hwnd, MOUSE_BUTTON_LEFT ); + break; + + case WM_BUTTON2DOWN : + MousePressed( vd, hwnd, MOUSE_BUTTON_RIGHT ); + break; + + case WM_BUTTON3DOWN : + MousePressed( vd, hwnd, MOUSE_BUTTON_CENTER ); + break; + + case WM_BUTTON1UP : + MouseReleased( vd, MOUSE_BUTTON_LEFT ); + break; + + case WM_BUTTON2UP : + MouseReleased( vd, MOUSE_BUTTON_RIGHT ); + break; + + case WM_BUTTON3UP : + MouseReleased( vd, MOUSE_BUTTON_CENTER ); + break; + + case WM_BUTTON1DBLCLK : + vout_display_SendEventMouseDoubleClick(vd); + break; + + case WM_TRANSLATEACCEL : + /* We have no accelerator table at all */ + result = ( MRESULT )FALSE; + break; + + case WM_CHAR : + { + USHORT i_flags = SHORT1FROMMP( mp1 ); + USHORT i_ch = SHORT1FROMMP( mp2 ); + USHORT i_vk = SHORT2FROMMP( mp2 ); + int i_key = 0; + + /* If embedded window, let the parent process keys */ + if( sys->parent_window ) + { + WinPostMsg( sys->parent, msg, mp1, mp2 ); + break; + } + + if( !( i_flags & KC_KEYUP )) + { + if( i_flags & KC_VIRTUALKEY ) + /* convert the key if possible */ + i_key = ConvertKey( i_vk ); + else if(( i_flags & KC_CHAR ) && !HIBYTE( i_ch )) + i_key = tolower( i_ch ); + + if( i_key ) + { + if( i_flags & KC_SHIFT ) + i_key |= KEY_MODIFIER_SHIFT; + + if( i_flags & KC_CTRL ) + i_key |= KEY_MODIFIER_CTRL; + + if( i_flags & KC_ALT ) + i_key |= KEY_MODIFIER_ALT; + + vout_display_SendEventKey(vd, i_key); + } + } + break; + } + + /* Process Manage() call */ + case WM_VLC_MANAGE : + break; + + /* Fullscreen change */ + case WM_VLC_FULLSCREEN_CHANGE : + if( LONGFROMMP( mp1 )) + { + WinQueryWindowPos( sys->frame, &swp ); + sys->client_rect.xLeft = swp.x; + sys->client_rect.yBottom = swp.y; + sys->client_rect.xRight = sys->client_rect.xLeft + swp.cx; + sys->client_rect.yTop = sys->client_rect.yBottom + swp.cy; + WinCalcFrameRect( sys->frame, &sys->client_rect, TRUE ); + + rcl.xLeft = 0; + rcl.yBottom = 0; + rcl.xRight = sys->i_screen_width; + rcl.yTop = sys->i_screen_height; + } + else + rcl = sys->client_rect; + + WinCalcFrameRect( sys->frame, &rcl, FALSE ); + + WinSetWindowPos( sys->frame, HWND_TOP, + rcl.xLeft, rcl.yBottom, + rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom, + SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW | + SWP_ACTIVATE ); + break; + + /* Size change */ + case WM_VLC_SIZE_CHANGE : + rcl.xLeft = 0; + rcl.yBottom = 0; + rcl.xRight = LONGFROMMP( mp1 ); + rcl.yTop = LONGFROMMP( mp2 ); + WinCalcFrameRect( sys->frame, &rcl, FALSE ); + + WinSetWindowPos( sys->frame, NULLHANDLE, + 0, 0, + rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom, + SWP_SIZE ); + + WinQueryWindowPos( sys->frame, &swp ); + sys->client_rect.xLeft = swp.x; + sys->client_rect.yBottom = swp.y; + sys->client_rect.xRight = sys->client_rect.xLeft + swp.cx; + sys->client_rect.yTop = sys->client_rect.yBottom + swp.cy; + WinCalcFrameRect( sys->frame, &sys->client_rect, TRUE ); + break; + + default : + return WinDefWindowProc( hwnd, msg, mp1, mp2 ); + } + + /* If embedded window, we need to change our window size according to a + * parent window size */ + if( sys->parent_window ) + { + WinQueryWindowRect( sys->parent, &rcl ); + + if( rcl.xLeft != sys->parent_rect.xLeft || + rcl.yBottom != sys->parent_rect.yBottom || + rcl.xRight != sys->parent_rect.xRight || + rcl.yTop != sys->parent_rect.yTop) + { + sys->parent_rect = rcl; + + WinCalcFrameRect( sys->frame, &rcl, FALSE ); + + WinSetWindowPos( sys->frame, NULLHANDLE, + rcl.xLeft, rcl.yBottom, + rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom, + SWP_SIZE | SWP_MOVE ); + } + } + + return result; +} -- 1.7.3.2