>From 2db3c18ba30bb24f7455bef34a65d1dd53373028 Mon Sep 17 00:00:00 2001 From: KO Myung-Hun Date: Sun, 20 Nov 2011 00:19:53 +0900 Subject: [PATCH 10/12] Add KVA video output module for OS/2 --- configure.ac | 23 + modules/video_output/Modules.am | 8 + modules/video_output/kva.c | 1353 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 1384 insertions(+), 0 deletions(-) create mode 100644 modules/video_output/kva.c diff --git a/configure.ac b/configure.ac index e67d978..2c408e0 100644 --- a/configure.ac +++ b/configure.ac @@ -3441,6 +3441,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..33a57df --- /dev/null +++ b/modules/video_output/kva.c @@ -0,0 +1,1353 @@ +/***************************************************************************** + * kva.c: KVA video output plugin for vlc + ***************************************************************************** + * Copyright (C) 2010 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 () + +typedef struct image_t +{ + int w, h; + int i_bpp; + int i_chroma_shift; + uint8_t *data[4]; /* y = 0, v = 1, u = 2 */ + int linesize[4]; + uint8_t *p; +} image_t; + +/***************************************************************************** + * 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; + image_t *p_image; + picture_pool_t *pool; + unsigned i_changes; + HMTX changes_mutex; + SIZEL szlSize; + unsigned button_pressed; + bool is_mouse_hidden; +}; + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ +static picture_pool_t *Pool (vout_display_t *, unsigned); +static void Display(vout_display_t *, picture_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 image_t *ImageCreate ( int , int , vlc_fourcc_t ); +static void ImageFree ( image_t * ); +static void ImageDisplay( image_t * ); +static void ImageCopy ( uint8_t *, uint8_t *, int, int, int, int ); + +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 KVA_FULLSCREEN_CHANGE 0x0001 +#define KVA_SIZE_CHANGE 0x0002 + +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 + { + DosRequestMutexSem( sys->changes_mutex, SEM_INDEFINITE_WAIT ); + sys->i_changes |= KVA_FULLSCREEN_CHANGE; + DosReleaseMutexSem( sys->changes_mutex ); + } + } + + 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 ); + + DosCreateMutexSem( NULL, &sys->changes_mutex, 0, FALSE ); + + sys->tid = _beginthread( PMThread, NULL, 1024 * 1024, vd ); + DosWaitEventSem( sys->ack_event, SEM_INDEFINITE_WAIT ); + + if( sys->i_result != VLC_SUCCESS ) + { + DosCloseMutexSem( sys->changes_mutex ); + + 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 ); + + DosCloseMutexSem( sys->changes_mutex ); + + 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); + + if (!sys->pool) + { + picture_resource_t rsc; + + memset(&rsc, 0, sizeof(rsc)); + + /* Packed or Y */ + rsc.Y_PIXELS = sys->p_image->data[0]; + rsc.p[Y_PLANE].i_lines = sys->p_image->h; + rsc.p[Y_PLANE].i_pitch = sys->p_image->linesize[0]; + + if( sys->p_image->i_chroma_shift ) + { + rsc.U_PIXELS = sys->p_image->data[1]; + rsc.p[U_PLANE].i_lines = sys->p_image->h >> sys->p_image->i_chroma_shift; + rsc.p[U_PLANE].i_pitch = sys->p_image->linesize[1]; + + rsc.V_PIXELS = sys->p_image->data[2]; + rsc.p[V_PLANE].i_lines = sys->p_image->h >> sys->p_image->i_chroma_shift; + rsc.p[V_PLANE].i_pitch = sys->p_image->linesize[2]; + } + + picture_t *picture = picture_NewFromResource(&vd->fmt, &rsc); + if (!picture) + return NULL; + + sys->pool = picture_pool_New(1, &picture); + } + + 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 *p_pic ) +{ + ImageDisplay( vd->sys->p_image ); + + picture_Release( p_pic ); +} + +/***************************************************************************** + * 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 + { + DosRequestMutexSem( sys->changes_mutex, SEM_INDEFINITE_WAIT ); + sys->i_changes |= KVA_FULLSCREEN_CHANGE; + DosReleaseMutexSem( sys->changes_mutex ); + } + + 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 + { + DosRequestMutexSem( sys->changes_mutex, SEM_INDEFINITE_WAIT ); + sys->szlSize.cx = cfg->display.width; + sys->szlSize.cy = cfg->display.height; + + sys->i_changes |= KVA_SIZE_CHANGE; + DosReleaseMutexSem( sys->changes_mutex ); + } + } + + 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; + bool b_hw_accel; + FOURCC i_kva_fourcc; + char sz_title[ 256 ]; + RECTL rcl; + int w, h; + + msg_Dbg( vd, "render chroma = %4.4s", ( const char * )&fmt->i_chroma ); + + switch( fmt->i_chroma ) + { + case VLC_CODEC_RGB15: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR15; + i_kva_fourcc = FOURCC_R555; + break; + + case VLC_CODEC_RGB16: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR16; + i_kva_fourcc = FOURCC_R565; + break; + + case VLC_CODEC_RGB24: + case VLC_CODEC_RGB32: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR24; + i_kva_fourcc = FOURCC_BGR3; + fmt->i_chroma = VLC_CODEC_RGB32; + break; + + case VLC_CODEC_YUYV: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YUY2; + i_kva_fourcc = FOURCC_Y422; + break; + + case VLC_CODEC_YV9: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YVU9; + i_kva_fourcc = FOURCC_YVU9; + break; + + case VLC_CODEC_YV12: + default: + b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YV12; + i_kva_fourcc = FOURCC_YV12; + fmt->i_chroma = VLC_CODEC_YV12; + break; + } + + if( !b_hw_accel ) + { + if( sys->kvac.ulInputFormatFlags & KVAF_YV12 ) + { + i_kva_fourcc = FOURCC_YV12; + fmt->i_chroma = VLC_CODEC_YV12; + } + else if( sys->kvac.ulInputFormatFlags & KVAF_YUY2 ) + { + i_kva_fourcc = FOURCC_Y422; + fmt->i_chroma = VLC_CODEC_YUYV; + } + else if( sys->kvac.ulInputFormatFlags & KVAF_YVU9 ) + { + i_kva_fourcc = FOURCC_YVU9; + fmt->i_chroma = VLC_CODEC_YV9; + } + else if( sys->kvac.ulInputFormatFlags & KVAF_BGR24 ) + { + i_kva_fourcc = FOURCC_BGR3; + fmt->i_chroma = VLC_CODEC_RGB24; + } + else if( sys->kvac.ulInputFormatFlags & KVAF_BGR16 ) + { + i_kva_fourcc = FOURCC_R565; + fmt->i_chroma = VLC_CODEC_RGB16; + } + else if( sys->kvac.ulInputFormatFlags & KVAF_BGR15 ) + { + i_kva_fourcc = FOURCC_R555; + fmt->i_chroma = VLC_CODEC_RGB15; + } + } + + /* 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; + } + + sys->p_image = ImageCreate( w, h, fmt->i_chroma ); + if( !sys->p_image ) + return VLC_EGENERIC; + + 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; +} + +/***************************************************************************** + * 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 ) +{ + ImageFree( vd->sys->p_image ); +} + +static image_t *ImageCreate( int w, int h, vlc_fourcc_t i_chroma ) +{ + int i_bpp; + int i_chroma_shift; + int size; + image_t *p_image; + + switch( i_chroma ) + { + case VLC_CODEC_RGB15: + i_bpp = 2; + i_chroma_shift = 0; + break; + + case VLC_CODEC_RGB16: + i_bpp = 2; + i_chroma_shift = 0; + break; + + case VLC_CODEC_RGB24: + i_bpp = 3; + i_chroma_shift = 0; + break; + + case VLC_CODEC_YUYV: + i_bpp = 2; + i_chroma_shift = 0; + break; + + case VLC_CODEC_YV9: + i_bpp = 1; + i_chroma_shift = 2; + break; + + case VLC_CODEC_YV12: + default: + i_bpp = 1; + i_chroma_shift = 1; + break; + } + + size = h * w * i_bpp; + if( i_chroma_shift ) + size += size >> ( i_chroma_shift << 1 ) << 1; + + p_image = calloc( 1, sizeof( image_t )); + if( !p_image ) + return NULL; + + p_image->p = malloc( size ); + if( !p_image->p ) + { + free( p_image ); + + return NULL; + } + + p_image->w = w; + p_image->h = h; + p_image->i_bpp = i_bpp; + p_image->i_chroma_shift = i_chroma_shift; + + p_image->data[ 0 ] = p_image->p; + p_image->linesize[ 0 ] = w * i_bpp; + + if( i_chroma_shift ) + { + p_image->data[ 1 ] = p_image->data[ 0 ] + h * p_image->linesize[ 0 ]; + p_image->linesize[ 1 ] = p_image->linesize[ 0 ] >> i_chroma_shift; + + p_image->data[ 2 ] = p_image->data[ 1 ] + ( h >> i_chroma_shift ) * p_image->linesize[ 1 ]; + p_image->linesize[ 2 ] = p_image->linesize[ 1 ]; + } + + return p_image; +} + +static void ImageFree( image_t *p_image ) +{ + free( p_image->p ); + free( p_image ); +} + +static void ImageDisplay( image_t *p_image ) +{ + PVOID p_kva_buffer; + ULONG i_kva_bpl; + + if (!kvaLockBuffer(&p_kva_buffer, &i_kva_bpl)) + { + uint8_t *dst[ 3 ] = { NULL }; + int dstStride[ 3 ] = { 0 }; + int i_bpl, i_height; + + /* Get packed or Y */ + dst[0] = p_kva_buffer; + dstStride[0] = i_kva_bpl; + + i_bpl = p_image->w * p_image->i_bpp; + i_height = p_image->h; + + /* Copy packed or Y */ + ImageCopy(dst[0], p_image->data[0], i_bpl, i_height, + dstStride[0], p_image->linesize[0]); + + /* YV12 or YVU9 ? */ + if( p_image->i_chroma_shift ) + { + /* Get V */ + dst[ 1 ] = dst[ 0 ] + p_image->h * dstStride[ 0 ]; + dstStride[ 1 ] = dstStride[ 0 ] >> p_image->i_chroma_shift; + + /* Get U */ + dst[ 2 ] = dst[ 1 ] + + ( p_image->h >> p_image->i_chroma_shift ) * dstStride[ 1 ]; + dstStride[ 2 ] = dstStride[ 1 ]; + + i_bpl >>= p_image->i_chroma_shift; + i_height >>= p_image->i_chroma_shift; + + /* Copy V */ + ImageCopy(dst[1], p_image->data[1], i_bpl, i_height, + dstStride[1], p_image->linesize[1]); + + /* Copy U */ + ImageCopy(dst[2], p_image->data[2], i_bpl, i_height, + dstStride[2], p_image->linesize[2]); + } + + kvaUnlockBuffer(); + } +} + +static void ImageCopy( uint8_t *p_dst, uint8_t *p_src, int i_bpl, int i_height, + int i_dst_stride, int i_src_stride ) +{ + if( i_dst_stride == i_src_stride ) + { + vlc_memcpy( p_dst, p_src, i_height * i_src_stride ); + } + else + { + for( ; i_height; i_height-- ) + { + vlc_memcpy( p_dst, p_src, i_bpl ); + p_dst += i_dst_stride; + p_src += i_src_stride; + } + } +} + +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; + + if( vd->cfg->is_fullscreen ) + break; + + 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; + + 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; + + pti->ptlMaxTrackSize.x = sys->i_screen_width; + pti->ptlMaxTrackSize.y = sys->i_screen_height; + + return MRFROMLONG( TRUE ); + } + + case WM_ADJUSTWINDOWPOS : + { + PSWP pswp = ( PSWP )mp1; + RECTL rcl; + + if( vd->cfg->is_fullscreen ) + break; + + 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 ); + + WinCalcFrameRect( hwnd, &rcl, FALSE ); + + 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; + } + + 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 ); + + if ( vd->sys->is_mouse_hidden && + ((msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) || + (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST) || + msg == WM_MOUSELEAVE)) + { + WinShowPointer(HWND_DESKTOP, TRUE); + vd->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( &vd->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 = vd->sys->kvas.rclSrcRect.xRight - + vd->sys->kvas.rclSrcRect.xLeft; + i_src_height = vd->sys->kvas.rclSrcRect.yBottom - + vd->sys->kvas.rclSrcRect.yTop; + + int x = ( i_mouse_x - movie_rect.xLeft ) * + i_src_width / i_movie_width + + vd->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 ) + vd->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( vd->sys->parent_window ) + { + WinPostMsg( vd->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; + + default : + return WinDefWindowProc( hwnd, msg, mp1, mp2 ); + } + + vout_display_sys_t * sys = vd->sys; + RECTL rcl; + + /* 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 ); + } + } + + DosRequestMutexSem( sys->changes_mutex, SEM_INDEFINITE_WAIT ); + + /* Fullscreen change */ + if( sys->i_changes & KVA_FULLSCREEN_CHANGE ) + { + if( vd->cfg->is_fullscreen ) + { + SWP swp; + + 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 ); + + sys->i_changes &= ~KVA_FULLSCREEN_CHANGE; + } + + /* Size change */ + if( sys->i_changes & KVA_SIZE_CHANGE ) + { + SWP swp; + + rcl.xLeft = 0; + rcl.yBottom = 0; + rcl.xRight = sys->szlSize.cx; + rcl.yTop = sys->szlSize.cy; + WinCalcFrameRect( sys->frame, &rcl, FALSE ); + + WinSetWindowPos( sys->frame, NULLHANDLE, + rcl.xLeft, rcl.yBottom, + rcl.xRight - rcl.xLeft, + rcl.yTop - rcl.yBottom, + SWP_MOVE | 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 ); + + sys->i_changes &= ~KVA_SIZE_CHANGE; + } + + DosReleaseMutexSem( sys->changes_mutex ); + + return result; +} -- 1.7.3.2