[vlc-devel] [PATCH 26/41] Add KVA video output module for OS/2
KO Myung-Hun
komh at chollian.net
Mon Oct 10 13:44:05 CEST 2011
---
configure.ac | 14 +
include/vlc_vout_window.h | 4 +-
lib/media_player.c | 6 +-
modules/gui/qt4/components/simple_preferences.cpp | 7 +
modules/gui/qt4/qt4.cpp | 8 +-
modules/gui/qt4/ui/sprefs_video.ui | 37 +
modules/video_output/Modules.am | 2 +
modules/video_output/kva.c | 1444 +++++++++++++++++++++
src/libvlc.c | 2 +-
src/video_output/window.c | 2 +-
10 files changed, 1515 insertions(+), 11 deletions(-)
create mode 100644 modules/video_output/kva.c
diff --git a/configure.ac b/configure.ac
index d4b6245..079011d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3433,6 +3433,20 @@ dnl
PKG_ENABLE_MODULES_VLC([CACA], [], [caca >= 0.99.beta14], [libcaca output],[auto])
dnl
+dnl OS/2 KVA plugin
+dnl
+AC_ARG_ENABLE(kva,
+ [ --enable-kva OS/2 KVA support (default enabled on OS/2)])
+if test "${enable_kva}" != "no" &&
+ (test "${SYS}" = "os2" || test "${enable_kva}" = "yes")
+then
+ AC_CHECK_HEADERS(kva.h,
+ [ VLC_ADD_PLUGIN([kva])
+ VLC_ADD_LDFLAGS([kva],[-lkva])
+ ], [ AC_MSG_ERROR([cannot find KVA headers]) ])
+fi
+
+dnl
dnl Audio plugins
dnl
diff --git a/include/vlc_vout_window.h b/include/vlc_vout_window.h
index b722d4b..aac70e0 100644
--- a/include/vlc_vout_window.h
+++ b/include/vlc_vout_window.h
@@ -46,7 +46,7 @@ enum {
VOUT_WINDOW_TYPE_NSOBJECT,
};
-#if defined (WIN32)
+#if defined (WIN32) || defined (__OS2__)
# define VOUT_WINDOW_TYPE_NATIVE VOUT_WINDOW_TYPE_HWND
#elif defined (__unix__)
# define VOUT_WINDOW_TYPE_NATIVE VOUT_WINDOW_TYPE_XID
@@ -113,7 +113,7 @@ struct vout_window_t {
vout_window_sys_t *sys;
};
-/**
+/**
* Creates a new window.
*
* @param module plugin name (usually "$window")
diff --git a/lib/media_player.c b/lib/media_player.c
index 0fbd2e3..14d5bce 100644
--- a/lib/media_player.c
+++ b/lib/media_player.c
@@ -413,7 +413,7 @@ libvlc_media_player_new( libvlc_instance_t *instance )
var_Create (mp, "vmem-height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
var_Create (mp, "vmem-pitch", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
var_Create (mp, "drawable-xid", VLC_VAR_INTEGER);
-#ifdef WIN32
+#if defined (WIN32) || defined (__OS2__)
var_Create (mp, "drawable-hwnd", VLC_VAR_INTEGER);
#endif
#ifdef __APPLE__
@@ -935,7 +935,7 @@ void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
void *drawable )
{
assert (p_mi != NULL);
-#ifdef WIN32
+#if defined (WIN32) || defined (__OS2__)
var_SetString (p_mi, "window",
(drawable != NULL) ? "embed-hwnd,any" : "");
var_SetInteger (p_mi, "drawable-hwnd", (uintptr_t)drawable);
@@ -950,7 +950,7 @@ void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
{
assert (p_mi != NULL);
-#ifdef WIN32
+#if defined (WIN32) || defined (__OS2__)
return (void *)(uintptr_t)var_GetInteger (p_mi, "drawable-hwnd");
#else
return NULL;
diff --git a/modules/gui/qt4/components/simple_preferences.cpp b/modules/gui/qt4/components/simple_preferences.cpp
index e48c4e6..b910321 100644
--- a/modules/gui/qt4/components/simple_preferences.cpp
+++ b/modules/gui/qt4/components/simple_preferences.cpp
@@ -233,6 +233,13 @@ SPrefsPanel::SPrefsPanel( intf_thread_t *_p_intf, QWidget *_parent,
ui.hwYUVBox->setVisible( false );
#endif
+#ifdef __OS2__
+ CONFIG_BOOL( "kva-fixt23", kvaFixT23 );
+ CONFIG_GENERIC( "kva-video-mode", StringList, ui.kvaVideoModeLabel,
+ kvaVideoMode );
+#else
+ ui.kvaBox->setVisible( false );
+#endif
CONFIG_GENERIC( "deinterlace", IntegerList, ui.deinterLabel, deinterlaceBox );
CONFIG_GENERIC( "deinterlace-mode", StringList, ui.deinterModeLabel, deinterlaceModeBox );
diff --git a/modules/gui/qt4/qt4.cpp b/modules/gui/qt4/qt4.cpp
index c8a32b7..945afdb 100644
--- a/modules/gui/qt4/qt4.cpp
+++ b/modules/gui/qt4/qt4.cpp
@@ -283,11 +283,11 @@ vlc_module_begin ()
set_callbacks( OpenDialogs, Close )
-#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_WS_MAC)
+#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_PM)
add_submodule ()
#if defined(Q_WS_X11)
set_capability( "vout window xid", 0 )
-#elif defined(Q_WS_WIN)
+#elif defined(Q_WS_WIN) || defined(Q_WS_PM)
set_capability( "vout window hwnd", 0 )
#elif defined(Q_WS_MAC)
set_capability( "vout window nsobject", 0 )
@@ -616,8 +616,8 @@ static int WindowOpen( vout_window_t *p_wnd, const vout_window_cfg_t *cfg )
return VLC_EGENERIC;
p_wnd->display.x11 = NULL;
-#elif defined (Q_WS_WIN)
- p_wnd->handle.hwnd = p_mi->getVideo( &i_x, &i_y, &i_width, &i_height );
+#elif defined (Q_WS_WIN) || defined(Q_WS_PM)
+ p_wnd->handle.hwnd = (void *)p_mi->getVideo( &i_x, &i_y, &i_width, &i_height );
if( !p_wnd->handle.hwnd )
return VLC_EGENERIC;
diff --git a/modules/gui/qt4/ui/sprefs_video.ui b/modules/gui/qt4/ui/sprefs_video.ui
index 764b94f..c231a56 100644
--- a/modules/gui/qt4/ui/sprefs_video.ui
+++ b/modules/gui/qt4/ui/sprefs_video.ui
@@ -134,6 +134,41 @@
</widget>
</item>
<item>
+ <widget class="QGroupBox" name="kvaBox" >
+ <property name="title" >
+ <string>KVA</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="1" column="1" colspan="2" >
+ <widget class="QComboBox" name="kvaVideoMode" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="kvaVideoModeLabel" >
+ <property name="text" >
+ <string>Video mode</string>
+ </property>
+ <property name="buddy" >
+ <cstring>kvaVideoMode</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" colspan="2" >
+ <widget class="QCheckBox" name="kvaFixT23" >
+ <property name="text" >
+ <string>Enable a workaround for T23</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Video</string>
@@ -301,6 +336,8 @@
<tabstop>outputModule</tabstop>
<tabstop>wallpaperMode</tabstop>
<tabstop>dXdisplayDevice</tabstop>
+ <tabstop>kvaFixT23</tabstop>
+ <tabstop>kvaVideoMode</tabstop>
<tabstop>deinterlaceBox</tabstop>
<tabstop>deinterlaceModeBox</tabstop>
<tabstop>arLine</tabstop>
diff --git a/modules/video_output/Modules.am b/modules/video_output/Modules.am
index 8170558..393a6b5 100644
--- a/modules/video_output/Modules.am
+++ b/modules/video_output/Modules.am
@@ -14,6 +14,8 @@ SOURCES_yuv = yuv.c
SOURCES_vout_macosx = macosx.m opengl.h opengl.c
SOURCES_vout_ios = ios.m opengl.h opengl.c
SOURCES_android_surface = androidsurface.c
+SOURCES_kva = kva.c
+
### OpenGL ###
# TODO: merge all three source files (?)
diff --git a/modules/video_output/kva.c b/modules/video_output/kva.c
new file mode 100644
index 0000000..5b6baad
--- /dev/null
+++ b/modules/video_output/kva.c
@@ -0,0 +1,1444 @@
+/*****************************************************************************
+ * kva.c: KVA video output plugin for vlc
+ *****************************************************************************
+ * Copyright (C) 2010 the VideoLAN team
+ *
+ * Authors: KO Myung-Hun <komh at chollian.net>
+ *
+ * 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 <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_vout_display.h>
+#include <vlc_picture_pool.h>
+
+#include <ctype.h>
+#include <float.h>
+#include <assert.h>
+
+#include <fourcc.h>
+
+#include <kva.h>
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+static int EmOpen ( vlc_object_t * );
+static void EmClose( 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 )
+
+ add_submodule()
+ set_shortname( N_("Drawable"))
+ set_description( N_("Embedded window video"))
+ set_category( CAT_VIDEO )
+ set_subcategory( SUBCAT_VIDEO_VOUT )
+ set_capability("vout window hwnd", 70 )
+ set_callbacks( EmOpen, EmClose )
+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;
+ 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
+ vd->sys->i_changes |= KVA_FULLSCREEN_CHANGE;
+ }
+
+ 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 )
+ {
+ 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 );
+
+ 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
+ sys->i_changes |= KVA_FULLSCREEN_CHANGE;
+
+ 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
+ {
+ sys->szlSize.cx = cfg->display.width;
+ sys->szlSize.cy = cfg->display.height;
+
+ sys->i_changes |= KVA_SIZE_CHANGE;
+ }
+ }
+
+ 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 );
+ }
+ }
+
+ /* 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;
+ }
+
+ return result;
+}
+
+static int EmControl (vout_window_t *, int, va_list);
+
+static vlc_mutex_t serializer = VLC_STATIC_MUTEX;
+
+/**
+ * Find the drawable set by libvlc application.
+ */
+static int EmOpen (vlc_object_t *obj)
+{
+ vout_window_t *wnd = (vout_window_t *)obj;
+ void **used, *val;
+ size_t n = 0;
+
+ if (var_Create (obj->p_libvlc, "hwnd-in-use", VLC_VAR_ADDRESS)
+ || var_Create (obj, "drawable-hwnd", VLC_VAR_DOINHERIT | VLC_VAR_ADDRESS))
+ return VLC_ENOMEM;
+
+ val = var_GetAddress (obj, "drawable-hwnd");
+ var_Destroy (obj, "drawable-hwnd");
+
+ /* Keep a list of busy drawables, so we don't overlap videos if there are
+ * more than one video track in the stream. */
+ vlc_mutex_lock (&serializer);
+ used = var_GetAddress (obj->p_libvlc, "hwnd-in-use");
+ if (used != NULL)
+ {
+ while (used[n] != NULL)
+ {
+ if (used[n] == val)
+ goto skip;
+ n++;
+ }
+ }
+
+ used = realloc (used, sizeof (*used) * (n + 2));
+ if (used != NULL)
+ {
+ used[n] = val;
+ used[n + 1] = NULL;
+ var_SetAddress (obj->p_libvlc, "hwnd-in-use", used);
+ }
+ else
+ {
+skip:
+ msg_Warn (wnd, "HWND %p is busy", val);
+ val = NULL;
+ }
+ vlc_mutex_unlock (&serializer);
+
+ if (val == NULL)
+ return VLC_EGENERIC;
+
+ wnd->handle.hwnd = val;
+ wnd->control = EmControl;
+ wnd->sys = val;
+ return VLC_SUCCESS;
+}
+
+/**
+ * Release the drawable.
+ */
+static void EmClose (vlc_object_t *obj)
+{
+ vout_window_t *wnd = (vout_window_t *)obj;
+ void **used, *val = wnd->sys;
+ size_t n = 0;
+
+ /* Remove this drawable from the list of busy ones */
+ vlc_mutex_lock (&serializer);
+ used = var_GetAddress (obj->p_libvlc, "hwnd-in-use");
+ assert (used);
+ while (used[n] != val)
+ {
+ assert (used[n]);
+ n++;
+ }
+ do
+ used[n] = used[n + 1];
+ while (used[++n] != NULL);
+
+ if (n == 0)
+ var_SetAddress (obj->p_libvlc, "hwnd-in-use", NULL);
+ vlc_mutex_unlock (&serializer);
+
+ if (n == 0)
+ free (used);
+ /* Variables are reference-counted... */
+ var_Destroy (obj->p_libvlc, "hwnd-in-use");
+}
+
+static int EmControl (vout_window_t *wnd, int query, va_list ap)
+{
+ VLC_UNUSED( ap );
+
+ switch (query)
+ {
+ case VOUT_WINDOW_SET_SIZE: /* not allowed */
+ case VOUT_WINDOW_SET_STATE: /* not allowed either, would be ugly */
+ return VLC_EGENERIC;
+ default:
+ msg_Warn (wnd, "unsupported control query %d", query);
+ return VLC_EGENERIC;
+ }
+}
diff --git a/src/libvlc.c b/src/libvlc.c
index 44d7c6f..021f9f0 100644
--- a/src/libvlc.c
+++ b/src/libvlc.c
@@ -705,7 +705,7 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
var_Create( p_libvlc, "drawable-clip-right", VLC_VAR_INTEGER );
var_Create( p_libvlc, "drawable-nsobject", VLC_VAR_ADDRESS );
#endif
-#ifdef WIN32
+#if defined (WIN32) || defined (__OS2__)
var_Create( p_libvlc, "drawable-hwnd", VLC_VAR_INTEGER );
#endif
diff --git a/src/video_output/window.c b/src/video_output/window.c
index b98a3e9..7bf388c 100644
--- a/src/video_output/window.c
+++ b/src/video_output/window.c
@@ -64,7 +64,7 @@ vout_window_t *vout_window_New(vlc_object_t *obj,
const char *type;
switch (cfg->type) {
-#ifdef WIN32
+#if defined(WIN32) || defined(__OS2__)
case VOUT_WINDOW_TYPE_HWND:
type = "vout window hwnd";
window->handle.hwnd = NULL;
--
1.7.3.2
More information about the vlc-devel
mailing list