[vlc-devel] [PATCH 10/11] Add KVA video output module for OS/2

Rémi Denis-Courmont remi at remlab.net
Sun Nov 20 14:21:56 CET 2011


Inline.

diff --git a/modules/video_output/kva.c b/modules/video_output/kva.c
new file mode 100644
index 0000000..3a8adca
--- /dev/null
+++ b/modules/video_output/kva.c
@@ -0,0 +1,1316 @@
+/*****************************************************************************
+ * kva.c: KVA video output plugin for vlc
+ *****************************************************************************
+ * Copyright (C) 2010, 2011 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 * );
+
+#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" )

Missing full point.

+#define KVA_VIDEO_MODE_TEXT N_( \
+    "Video mode" )
+#define KVA_VIDEO_MODE_LONGTEXT N_( \
+    "Select a proper video mode to be used by KVA" )

Same as above.

+
+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;

You should use picture_resource_t for this. If you need private data,
then there is picture_sys_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;

If you have a fixed number of pictures (1), you do not need this
indirection.

+    picture_pool_t *pool;
+    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 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);
+
+    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
+            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;
+    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:

This makes sense for VLC_CODEC_I420 and VLC_CODEC_J420, but none else.

+            b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YV12;
+            i_kva_fourcc = FOURCC_YV12;
+            fmt->i_chroma = VLC_CODEC_YV12;
+            break;
+    }
+
+    if( !b_hw_accel )

You should probably use vlc_fourcc_GetYUVFallback() (or
vlc_fourcc_GetRGBFallback()) instead of these two passes.

+    {
+        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;
+
+            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



-- 
Rémi Denis-Courmont
http://www.remlab.net/
http://fi.linkedin.com/in/remidenis



More information about the vlc-devel mailing list