]> git.sesse.net Git - vlc/blob - modules/video_output/kva.c
Fix Metacube header handling with multiple header blocks.
[vlc] / modules / video_output / kva.c
1 /*****************************************************************************
2  * kva.c: KVA video output plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2010, 2011, 2012 VLC authors and VideoLAN
5  *
6  * Authors: KO Myung-Hun <komh@chollian.net>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <vlc_common.h>
31 #include <vlc_plugin.h>
32 #include <vlc_vout_display.h>
33 #include <vlc_picture_pool.h>
34
35 #include <ctype.h>
36 #include <float.h>
37 #include <assert.h>
38
39 #include <fourcc.h>
40
41 #include <kva.h>
42
43 /*****************************************************************************
44  * Module descriptor
45  *****************************************************************************/
46 static int  Open ( vlc_object_t * );
47 static void Close( vlc_object_t * );
48
49 #define KVA_FIXT23_TEXT N_( \
50     "Enable a workaround for T23" )
51 #define KVA_FIXT23_LONGTEXT N_( \
52     "Enable this option if the diagonal stripes are displayed " \
53     "when the window size is equal to or smaller than the movie size." )
54 #define KVA_VIDEO_MODE_TEXT N_( \
55     "Video mode" )
56 #define KVA_VIDEO_MODE_LONGTEXT N_( \
57     "Select a proper video mode to be used by KVA." )
58
59 static const char *const ppsz_kva_video_mode[] = {
60     "auto", "snap", "wo", "vman", "dive" };
61 static const char *const ppsz_kva_video_mode_text[] = {
62     N_("Auto"), N_("SNAP"), N_("WarpOverlay!"), N_("VMAN"), N_("DIVE") };
63
64 vlc_module_begin ()
65     set_shortname( "KVA" )
66     set_category( CAT_VIDEO )
67     set_subcategory( SUBCAT_VIDEO_VOUT )
68     add_string( "kva-video-mode", ppsz_kva_video_mode[0], KVA_VIDEO_MODE_TEXT,
69                 KVA_VIDEO_MODE_LONGTEXT, false )
70         change_string_list( ppsz_kva_video_mode, ppsz_kva_video_mode_text )
71     add_bool( "kva-fixt23", false, KVA_FIXT23_TEXT, KVA_FIXT23_LONGTEXT, true )
72     set_description( N_("K Video Acceleration video output") )
73     set_capability( "vout display", 100 )
74     add_shortcut( "kva" )
75     set_callbacks( Open, Close )
76 vlc_module_end ()
77
78 /*****************************************************************************
79  * vout_display_sys_t: video output method descriptor
80  *****************************************************************************
81  * This structure is part of the video output thread descriptor.
82  * It describes the module specific properties of an output thread.
83  *****************************************************************************/
84 struct vout_display_sys_t
85 {
86     TID                tid;
87     HEV                ack_event;
88     int                i_result;
89     HAB                hab;
90     HMQ                hmq;
91     HWND               frame;
92     HWND               client;
93     KVASETUP           kvas;
94     KVACAPS            kvac;
95     LONG               i_screen_width;
96     LONG               i_screen_height;
97     bool               b_fixt23;
98     PFNWP              p_old_frame;
99     RECTL              client_rect;
100     vout_window_t     *parent_window;
101     HWND               parent;
102     RECTL              parent_rect;
103     picture_pool_t    *pool;
104     unsigned           button_pressed;
105     bool               is_mouse_hidden;
106     bool               is_on_top;
107 };
108
109 struct picture_sys_t
110 {
111     int i_chroma_shift;
112 };
113
114 /*****************************************************************************
115  * Local prototypes
116  *****************************************************************************/
117 static picture_pool_t *Pool   (vout_display_t *, unsigned);
118 static void            Display(vout_display_t *, picture_t *, subpicture_t * );
119 static int             Control(vout_display_t *, int, va_list);
120 static void            Manage (vout_display_t *);
121
122 static int  OpenDisplay ( vout_display_t *, video_format_t * );
123 static void CloseDisplay( vout_display_t * );
124
125 static int  KVALock( picture_t * );
126 static void KVAUnlock( picture_t * );
127
128 static void             MorphToPM     ( void );
129 static int              ConvertKey    ( USHORT );
130 static MRESULT EXPENTRY MyFrameWndProc( HWND, ULONG, MPARAM, MPARAM );
131 static MRESULT EXPENTRY WndProc       ( HWND, ULONG, MPARAM, MPARAM );
132
133 #define WC_VLC_KVA "WC_VLC_KVA"
134
135 #define COLOR_KEY 0x0F0F0F
136
137 #define WM_VLC_MANAGE               ( WM_USER + 1 )
138 #define WM_VLC_FULLSCREEN_CHANGE    ( WM_USER + 2 )
139 #define WM_VLC_SIZE_CHANGE          ( WM_USER + 3 )
140
141 static const char *psz_video_mode[ 4 ] = {"DIVE", "WarpOverlay!", "SNAP",
142                                           "VMAN"};
143
144 static void PMThread( void *arg )
145 {
146     vout_display_t *vd = ( vout_display_t * )arg;
147     vout_display_sys_t * sys = vd->sys;
148     ULONG i_frame_flags;
149     QMSG qm;
150     char *psz_mode;
151     ULONG i_kva_mode;
152
153     /* */
154     video_format_t fmt;
155     video_format_ApplyRotation(&fmt, &vd->fmt);
156
157     /* */
158     vout_display_info_t info = vd->info;
159     info.is_slow = false;
160     info.has_double_click = true;
161     info.has_hide_mouse = false;
162     info.has_pictures_invalid = false;
163
164     MorphToPM();
165
166     sys->hab = WinInitialize( 0 );
167     sys->hmq = WinCreateMsgQueue( sys->hab, 0);
168
169     WinRegisterClass( sys->hab,
170                       WC_VLC_KVA,
171                       WndProc,
172                       CS_SIZEREDRAW | CS_MOVENOTIFY,
173                       sizeof( PVOID ));
174
175     sys->b_fixt23 = var_CreateGetBool( vd, "kva-fixt23");
176
177     if( !sys->b_fixt23 )
178         /* If an external window was specified, we'll draw in it. */
179         sys->parent_window =
180             vout_display_NewWindow( vd, VOUT_WINDOW_TYPE_HWND );
181
182     if( sys->parent_window )
183     {
184         sys->parent = ( HWND )sys->parent_window->handle.hwnd;
185
186         ULONG i_style = WinQueryWindowULong( sys->parent, QWL_STYLE );
187         WinSetWindowULong( sys->parent, QWL_STYLE,
188                            i_style | WS_CLIPCHILDREN );
189
190         i_frame_flags = FCF_TITLEBAR;
191     }
192     else
193     {
194         sys->parent = HWND_DESKTOP;
195
196         i_frame_flags = FCF_SYSMENU    | FCF_TITLEBAR | FCF_MINMAX |
197                         FCF_SIZEBORDER | FCF_TASKLIST;
198     }
199
200     sys->frame =
201         WinCreateStdWindow( sys->parent,      /* parent window handle */
202                             WS_VISIBLE,       /* frame window style */
203                             &i_frame_flags,   /* window style */
204                             WC_VLC_KVA,       /* class name */
205                             "",               /* window title */
206                             0L,               /* default client style */
207                             NULLHANDLE,       /* resource in exe file */
208                             1,                /* frame window id */
209                             &sys->client );   /* client window handle */
210
211     if( sys->frame == NULLHANDLE )
212     {
213         msg_Err( vd, "cannot create a frame window");
214
215         goto exit_frame;
216     }
217
218     WinSetWindowPtr( sys->client, 0, vd );
219
220     if( !sys->parent_window )
221     {
222         WinSetWindowPtr( sys->frame, 0, vd );
223         sys->p_old_frame = WinSubclassWindow( sys->frame, MyFrameWndProc );
224     }
225
226     psz_mode = var_CreateGetString( vd, "kva-video-mode" );
227
228     i_kva_mode = KVAM_AUTO;
229     if( strcmp( psz_mode, "snap" ) == 0 )
230         i_kva_mode = KVAM_SNAP;
231     else if( strcmp( psz_mode, "wo" ) == 0 )
232         i_kva_mode = KVAM_WO;
233     else if( strcmp( psz_mode, "vman" ) == 0 )
234         i_kva_mode = KVAM_VMAN;
235     else if( strcmp( psz_mode, "dive" ) == 0 )
236         i_kva_mode = KVAM_DIVE;
237
238     free( psz_mode );
239
240     if( kvaInit( i_kva_mode, sys->client, COLOR_KEY ))
241     {
242         msg_Err( vd, "cannot initialize KVA");
243
244         goto exit_kva_init;
245     }
246
247     kvaCaps( &sys->kvac );
248
249     msg_Dbg( vd, "selected video mode = %s",
250              psz_video_mode[ sys->kvac.ulMode - 1 ]);
251
252     if( OpenDisplay( vd, &fmt ) )
253     {
254         msg_Err( vd, "cannot open display");
255
256         goto exit_open_display;
257     }
258
259     if( vd->cfg->is_fullscreen && !sys->parent_window )
260         WinPostMsg( sys->client, WM_VLC_FULLSCREEN_CHANGE,
261                     MPFROMLONG( true ), 0 );
262
263     kvaDisableScreenSaver();
264
265     /* Setup vout_display now that everything is fine */
266     vd->fmt     = fmt;
267     vd->info    = info;
268
269     vd->pool    = Pool;
270     vd->prepare = NULL;
271     vd->display = Display;
272     vd->control = Control;
273     vd->manage  = Manage;
274
275     /* Prevent SIG_FPE */
276     _control87(MCW_EM, MCW_EM);
277
278     sys->i_result = VLC_SUCCESS;
279     DosPostEventSem( sys->ack_event );
280
281     if( !sys->parent_window )
282         WinSetVisibleRegionNotify( sys->frame, TRUE );
283
284     while( WinGetMsg( sys->hab, &qm, NULLHANDLE, 0, 0 ))
285         WinDispatchMsg( sys->hab, &qm );
286
287     if( !sys->parent_window )
288         WinSetVisibleRegionNotify( sys->frame, FALSE );
289
290     kvaEnableScreenSaver();
291
292     CloseDisplay( vd );
293
294     /* fall through */
295
296 exit_open_display :
297     kvaDone();
298
299 exit_kva_init :
300     if( !sys->parent_window )
301         WinSubclassWindow( sys->frame, sys->p_old_frame );
302
303     WinDestroyWindow( sys->frame );
304
305 exit_frame :
306     vout_display_DeleteWindow( vd, sys->parent_window );
307
308     if( sys->is_mouse_hidden )
309         WinShowPointer( HWND_DESKTOP, TRUE );
310
311     WinDestroyMsgQueue( sys->hmq );
312     WinTerminate( sys->hab );
313
314     sys->i_result = VLC_EGENERIC;
315     DosPostEventSem( sys->ack_event );
316 }
317
318 /**
319  * This function initializes KVA vout method.
320  */
321 static int Open ( vlc_object_t *object )
322 {
323     vout_display_t *vd = (vout_display_t *)object;
324     vout_display_sys_t *sys;
325
326     vd->sys = sys = calloc( 1, sizeof( *sys ));
327     if( !sys )
328         return VLC_ENOMEM;
329
330     DosCreateEventSem( NULL, &sys->ack_event, 0, FALSE );
331
332     sys->tid = _beginthread( PMThread, NULL, 1024 * 1024, vd );
333     DosWaitEventSem( sys->ack_event, SEM_INDEFINITE_WAIT );
334
335     if( sys->i_result != VLC_SUCCESS )
336     {
337         DosCloseEventSem( sys->ack_event );
338
339         free( sys );
340
341         return VLC_EGENERIC;
342     }
343
344     return VLC_SUCCESS;
345 }
346
347 /*****************************************************************************
348  * Close: destroy KVA video thread output method
349  *****************************************************************************
350  * Terminate an output method created by Open
351  *****************************************************************************/
352 static void Close ( vlc_object_t *object )
353 {
354     vout_display_t * vd = (vout_display_t *)object;
355     vout_display_sys_t * sys = vd->sys;
356
357     WinPostQueueMsg( sys->hmq, WM_QUIT, 0, 0 );
358
359     DosWaitThread( &sys->tid, DCWW_WAIT );
360
361     if( sys->pool )
362         picture_pool_Release( sys->pool );
363
364     DosCloseEventSem( sys->ack_event );
365
366     free( sys );
367 }
368
369 /**
370  * Return a pool of direct buffers
371  */
372 static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
373 {
374     vout_display_sys_t *sys = vd->sys;
375     VLC_UNUSED(count);
376
377     return sys->pool;
378 }
379
380 /*****************************************************************************
381  * Display: displays previously rendered output
382  *****************************************************************************
383  * This function sends the currently rendered image to the display.
384  *****************************************************************************/
385 static void Display( vout_display_t *vd, picture_t *picture,
386                      subpicture_t *subpicture )
387 {
388     VLC_UNUSED( vd );
389     VLC_UNUSED( subpicture );
390
391     picture_Release( picture );
392 }
393
394 /*****************************************************************************
395  * Manage: handle Sys events
396  *****************************************************************************
397  * This function should be called regularly by video output thread. It returns
398  * a non null value if an error occurred.
399  *****************************************************************************/
400 static void Manage( vout_display_t *vd )
401 {
402     vout_display_sys_t * sys = vd->sys;
403
404     /* Let a window procedure manage instead because if resizing a frame window
405      * here, WM_SIZE is not sent to its child window.
406      * Maybe, is this due to the different threads ? */
407     WinPostMsg( sys->client, WM_VLC_MANAGE, 0, 0 );
408 }
409
410 /*****************************************************************************
411  * Control: control facility for the vout
412  *****************************************************************************/
413 static int Control( vout_display_t *vd, int query, va_list args )
414 {
415     vout_display_sys_t *sys = vd->sys;
416
417     switch (query)
418     {
419     case VOUT_DISPLAY_HIDE_MOUSE:
420     {
421         POINTL ptl;
422
423         WinQueryPointerPos( HWND_DESKTOP, &ptl );
424         if( !sys->is_mouse_hidden &&
425             WinWindowFromPoint( HWND_DESKTOP, &ptl, TRUE ) == sys->client )
426         {
427             WinShowPointer( HWND_DESKTOP, FALSE );
428             sys->is_mouse_hidden = true;
429         }
430
431         return VLC_SUCCESS;
432     }
433
434     case VOUT_DISPLAY_CHANGE_FULLSCREEN:
435     {
436         bool fs = va_arg(args, int);
437
438         WinPostMsg( sys->client, WM_VLC_FULLSCREEN_CHANGE, MPFROMLONG(fs), 0 );
439         return VLC_SUCCESS;
440     }
441
442     case VOUT_DISPLAY_CHANGE_WINDOW_STATE:
443     {
444         const unsigned state = va_arg( args, unsigned );
445         const bool is_on_top = (state & VOUT_WINDOW_STATE_ABOVE) != 0;
446
447         if( is_on_top )
448             WinSetWindowPos( sys->frame, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
449
450         sys->is_on_top = is_on_top;
451
452         return VLC_SUCCESS;
453     }
454
455     case VOUT_DISPLAY_CHANGE_DISPLAY_SIZE:
456     case VOUT_DISPLAY_CHANGE_ZOOM:
457     {
458         const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *);
459
460         WinPostMsg( sys->client, WM_VLC_SIZE_CHANGE,
461                     MPFROMLONG( cfg->display.width ),
462                     MPFROMLONG( cfg->display.height ));
463         return VLC_SUCCESS;
464     }
465
466     case VOUT_DISPLAY_CHANGE_SOURCE_ASPECT:
467     case VOUT_DISPLAY_CHANGE_SOURCE_CROP:
468     {
469         const video_format_t *src = va_arg(args, const video_format_t *);
470
471         if( query == VOUT_DISPLAY_CHANGE_SOURCE_ASPECT )
472         {
473             vout_display_place_t place;
474             vout_display_PlacePicture(&place, src, vd->cfg, false);
475
476             sys->kvas.ulAspectWidth  = place.width;
477             sys->kvas.ulAspectHeight = place.height;
478         }
479         else
480         {
481             video_format_t src_rot;
482             video_format_ApplyRotation(&src_rot, src);
483
484             sys->kvas.rclSrcRect.xLeft   = src_rot.i_x_offset;
485             sys->kvas.rclSrcRect.yTop    = src_rot.i_y_offset;
486             sys->kvas.rclSrcRect.xRight  = src_rot.i_x_offset +
487                                            src_rot.i_visible_width;
488             sys->kvas.rclSrcRect.yBottom = src_rot.i_y_offset +
489                                            src_rot.i_visible_height;
490         }
491
492         kvaSetup( &sys->kvas );
493
494         return VLC_SUCCESS;
495     }
496
497     case VOUT_DISPLAY_RESET_PICTURES:
498     case VOUT_DISPLAY_CHANGE_DISPLAY_FILLED:
499         /* TODO */
500         break;
501     }
502
503     msg_Err(vd, "Unsupported query(=%d) in vout display KVA", query);
504     return VLC_EGENERIC;
505 }
506
507 /* following functions are local */
508
509 /*****************************************************************************
510  * OpenDisplay: open and initialize KVA device
511  *****************************************************************************
512  * Open and initialize display according to preferences specified in the vout
513  * thread fields.
514  *****************************************************************************/
515 static int OpenDisplay( vout_display_t *vd, video_format_t *fmt )
516 {
517     vout_display_sys_t * sys = vd->sys;
518     const vlc_fourcc_t *fallback;
519     bool b_hw_accel = 0;
520     FOURCC i_kva_fourcc;
521     int i_chroma_shift;
522     char sz_title[ 256 ];
523     RECTL rcl;
524     int w, h;
525
526     msg_Dbg( vd, "render chroma = %4.4s", ( const char * )&fmt->i_chroma );
527
528     for( int pass = 0; pass < 2 && !b_hw_accel; pass++ )
529     {
530         fallback = ( pass == 0 ) ? vlc_fourcc_GetYUVFallback( fmt->i_chroma ) :
531                                    vlc_fourcc_GetRGBFallback( fmt->i_chroma );
532
533         for( int i = 0; fallback[ i ]; i++ )
534         {
535             switch( fallback[ i ])
536             {
537                 case VLC_CODEC_YV12:
538                     b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YV12;
539                     i_kva_fourcc = FOURCC_YV12;
540                     i_chroma_shift = 1;
541                     break;
542
543                 case VLC_CODEC_YUYV:
544                     b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YUY2;
545                     i_kva_fourcc = FOURCC_Y422;
546                     i_chroma_shift = 0;
547                     break;
548
549                 case VLC_CODEC_YV9:
550                     b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_YVU9;
551                     i_kva_fourcc = FOURCC_YVU9;
552                     i_chroma_shift = 2;
553                     break;
554
555                 case VLC_CODEC_RGB32:
556                     b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR32;
557                     i_kva_fourcc = FOURCC_BGR4;
558                     i_chroma_shift = 0;
559                     break;
560
561                 case VLC_CODEC_RGB24:
562                     b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR24;
563                     i_kva_fourcc = FOURCC_BGR3;
564                     i_chroma_shift = 0;
565                     break;
566
567                 case VLC_CODEC_RGB16:
568                     b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR16;
569                     i_kva_fourcc = FOURCC_R565;
570                     i_chroma_shift = 0;
571                     break;
572
573                 case VLC_CODEC_RGB15:
574                     b_hw_accel = sys->kvac.ulInputFormatFlags & KVAF_BGR15;
575                     i_kva_fourcc = FOURCC_R555;
576                     i_chroma_shift = 0;
577                     break;
578             }
579
580             if( b_hw_accel )
581             {
582                 fmt->i_chroma = fallback[ i ];
583                 break;
584             }
585         }
586     }
587
588     if( !b_hw_accel )
589     {
590         msg_Err( vd, "Ooops. There is no fourcc supported by KVA at all.");
591
592         return VLC_EGENERIC;
593     }
594
595     /* Set the RGB masks */
596     fmt->i_rmask = sys->kvac.ulRMask;
597     fmt->i_gmask = sys->kvac.ulGMask;
598     fmt->i_bmask = sys->kvac.ulBMask;
599
600     msg_Dbg( vd, "output chroma = %4.4s", ( const char * )&fmt->i_chroma );
601     msg_Dbg( vd, "KVA chroma = %4.4s", ( const char * )&i_kva_fourcc );
602
603     w = fmt->i_width;
604     h = fmt->i_height;
605
606     sys->kvas.ulLength           = sizeof( KVASETUP );
607     sys->kvas.szlSrcSize.cx      = w;
608     sys->kvas.szlSrcSize.cy      = h;
609     sys->kvas.rclSrcRect.xLeft   = fmt->i_x_offset;
610     sys->kvas.rclSrcRect.yTop    = fmt->i_y_offset;
611     sys->kvas.rclSrcRect.xRight  = fmt->i_x_offset + fmt->i_visible_width;
612     sys->kvas.rclSrcRect.yBottom = fmt->i_y_offset + fmt->i_visible_height;
613     sys->kvas.ulRatio            = KVAR_FORCEANY;
614     sys->kvas.ulAspectWidth      = w;
615     sys->kvas.ulAspectHeight     = h;
616     sys->kvas.fccSrcColor        = i_kva_fourcc;
617     sys->kvas.fDither            = TRUE;
618
619     if( kvaSetup( &sys->kvas ))
620     {
621         msg_Err( vd, "cannot set up KVA");
622
623         return VLC_EGENERIC;
624     }
625
626     /* Create the associated picture */
627     picture_sys_t *picsys = malloc( sizeof( *picsys ) );
628     if( picsys == NULL )
629         return VLC_ENOMEM;
630     picsys->i_chroma_shift = i_chroma_shift;
631
632     picture_resource_t resource = { .p_sys = picsys };
633     picture_t *picture = picture_NewFromResource( fmt, &resource );
634     if( !picture )
635     {
636         free( picsys );
637         return VLC_ENOMEM;
638     }
639
640     /* Wrap it into a picture pool */
641     picture_pool_configuration_t pool_cfg;
642     memset( &pool_cfg, 0, sizeof( pool_cfg ));
643     pool_cfg.picture_count = 1;
644     pool_cfg.picture       = &picture;
645     pool_cfg.lock          = KVALock;
646     pool_cfg.unlock        = KVAUnlock;
647
648     sys->pool = picture_pool_NewExtended( &pool_cfg );
649     if( !sys->pool )
650     {
651         picture_Release( picture );
652         return VLC_ENOMEM;
653     }
654
655     if (vd->cfg->display.title)
656         snprintf( sz_title, sizeof( sz_title ), "%s", vd->cfg->display.title );
657     else
658         snprintf( sz_title, sizeof( sz_title ),
659                   "%s (%4.4s to %4.4s - %s mode KVA output)",
660                   VOUT_TITLE,
661                   ( char * )&vd->fmt.i_chroma,
662                   ( char * )&sys->kvas.fccSrcColor,
663                   psz_video_mode[ sys->kvac.ulMode - 1 ]);
664     WinSetWindowText( sys->frame, sz_title );
665
666     sys->i_screen_width  = WinQuerySysValue( HWND_DESKTOP, SV_CXSCREEN );
667     sys->i_screen_height = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN );
668
669     if( sys->parent_window )
670         WinQueryWindowRect( sys->parent, &sys->client_rect );
671     else
672     {
673         sys->client_rect.xLeft   = ( sys->i_screen_width  - w ) / 2;
674         sys->client_rect.yBottom = ( sys->i_screen_height - h ) / 2 ;
675         sys->client_rect.xRight  = sys->client_rect.xLeft   + w;
676         sys->client_rect.yTop    = sys->client_rect.yBottom + h;
677     }
678
679     rcl = sys->client_rect;
680
681     WinCalcFrameRect( sys->frame, &rcl, FALSE);
682
683     WinSetWindowPos( sys->frame, HWND_TOP,
684                      rcl.xLeft, rcl.yBottom,
685                      rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
686                      SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW |
687                      SWP_ACTIVATE );
688
689     return VLC_SUCCESS;
690 }
691
692 /*****************************************************************************
693  * CloseDisplay: close and reset KVA device
694  *****************************************************************************
695  * This function returns all resources allocated by OpenDisplay and restore
696  * the original state of the device.
697  *****************************************************************************/
698 static void CloseDisplay( vout_display_t *vd )
699 {
700     VLC_UNUSED( vd );
701 }
702
703 static int KVALock( picture_t *picture )
704 {
705     picture_sys_t *picsys = picture->p_sys;
706     PVOID kva_buffer;
707     ULONG kva_bpl;
708
709     if( kvaLockBuffer( &kva_buffer, &kva_bpl ))
710         return VLC_EGENERIC;
711
712     /* Packed or Y plane */
713     picture->p->p_pixels = ( uint8_t * )kva_buffer;
714     picture->p->i_pitch  = kva_bpl;
715     picture->p->i_lines  = picture->format.i_height;
716
717     /* Other planes */
718     for( int n = 1; n < picture->i_planes; n++ )
719     {
720         const plane_t *o = &picture->p[n-1];
721         plane_t *p = &picture->p[n];
722
723         p->p_pixels = o->p_pixels + o->i_lines * o->i_pitch;
724         p->i_pitch  = kva_bpl >> picsys->i_chroma_shift;
725         p->i_lines  = picture->format.i_height >> picsys->i_chroma_shift;
726     }
727
728     return VLC_SUCCESS;
729 }
730
731 static void KVAUnlock( picture_t *picture )
732 {
733     VLC_UNUSED( picture );
734
735     kvaUnlockBuffer();
736 }
737
738 static void MorphToPM( void )
739 {
740     PPIB pib;
741
742     DosGetInfoBlocks(NULL, &pib);
743
744     /* Change flag from VIO to PM */
745     if (pib->pib_ultype == 2)
746         pib->pib_ultype = 3;
747 }
748
749 /*****************************************************************************
750  * Key events handling
751  *****************************************************************************/
752 static const struct
753 {
754     USHORT i_pmkey;
755     int    i_vlckey;
756 } pmkeys_to_vlckeys[] =
757 {
758     { VK_LEFT, KEY_LEFT },
759     { VK_RIGHT, KEY_RIGHT },
760     { VK_UP, KEY_UP },
761     { VK_DOWN, KEY_DOWN },
762     { VK_SPACE, ' ' },
763     { VK_NEWLINE, KEY_ENTER },
764     { VK_ENTER, KEY_ENTER },
765     { VK_F1, KEY_F1 },
766     { VK_F2, KEY_F2 },
767     { VK_F3, KEY_F3 },
768     { VK_F4, KEY_F4 },
769     { VK_F5, KEY_F5 },
770     { VK_F6, KEY_F6 },
771     { VK_F7, KEY_F7 },
772     { VK_F8, KEY_F8 },
773     { VK_F9, KEY_F9 },
774     { VK_F10, KEY_F10 },
775     { VK_F11, KEY_F11 },
776     { VK_F12, KEY_F12 },
777     { VK_HOME, KEY_HOME },
778     { VK_END, KEY_END },
779     { VK_INSERT, KEY_INSERT },
780     { VK_DELETE, KEY_DELETE },
781 /*
782     Not supported
783     {, KEY_MENU },
784 */
785     { VK_ESC, KEY_ESC },
786     { VK_PAGEUP, KEY_PAGEUP },
787     { VK_PAGEDOWN, KEY_PAGEDOWN },
788     { VK_TAB, KEY_TAB },
789     { VK_BACKSPACE, KEY_BACKSPACE },
790 /*
791     Not supported
792     {, KEY_MOUSEWHEELUP },
793     {, KEY_MOUSEWHEELDOWN },
794     {, KEY_MOUSEWHEELLEFT },
795     {, KEY_MOUSEWHEELRIGHT },
796
797     {, KEY_BROWSER_BACK },
798     {, KEY_BROWSER_FORWARD },
799     {, KEY_BROWSER_REFRESH },
800     {, KEY_BROWSER_STOP },
801     {, KEY_BROWSER_SEARCH },
802     {, KEY_BROWSER_FAVORITES },
803     {, KEY_BROWSER_HOME },
804     {, KEY_VOLUME_MUTE },
805     {, KEY_VOLUME_DOWN },
806     {, KEY_VOLUME_UP },
807     {, KEY_MEDIA_NEXT_TRACK },
808     {, KEY_MEDIA_PREV_TRACK },
809     {, KEY_MEDIA_STOP },
810     {, KEY_MEDIA_PLAY_PAUSE },
811 */
812
813     { 0, 0 }
814 };
815
816 static int ConvertKey( USHORT i_pmkey )
817 {
818     int i;
819     for( i = 0; pmkeys_to_vlckeys[ i ].i_pmkey != 0; i++ )
820     {
821         if( pmkeys_to_vlckeys[ i ].i_pmkey == i_pmkey )
822             return pmkeys_to_vlckeys[ i ].i_vlckey;
823     }
824     return 0;
825 }
826
827 static MRESULT EXPENTRY MyFrameWndProc( HWND hwnd, ULONG msg, MPARAM mp1,
828                                         MPARAM mp2 )
829 {
830     vout_display_t *vd = WinQueryWindowPtr( hwnd, 0 );
831     vout_display_sys_t *sys = vd->sys;
832
833     switch( msg )
834     {
835         case WM_QUERYTRACKINFO :
836         {
837             MRESULT mr;
838
839             mr = sys->p_old_frame( hwnd, msg, mp1, mp2 );
840             if( !sys->b_fixt23 )
841                 return mr;
842
843             PTRACKINFO pti = ( PTRACKINFO )mp2;
844             RECTL      rcl;
845
846             pti->rclBoundary.xLeft   = 0;
847             pti->rclBoundary.yBottom = 0;
848             pti->rclBoundary.xRight  = sys->i_screen_width;
849             pti->rclBoundary.yTop    = sys->i_screen_height;
850
851             WinCalcFrameRect( hwnd, &pti->rclBoundary, FALSE );
852
853             pti->ptlMaxTrackSize.x = pti->rclBoundary.xRight -
854                                      pti->rclBoundary.xLeft;
855             pti->ptlMaxTrackSize.y = pti->rclBoundary.yTop -
856                                      pti->rclBoundary.yBottom;
857
858             rcl.xLeft   = 0;
859             rcl.yBottom = 0;
860             rcl.xRight  = sys->kvas.szlSrcSize.cx + 1;
861             rcl.yTop    = sys->kvas.szlSrcSize.cy + 1;
862
863             WinCalcFrameRect( hwnd, &rcl, FALSE );
864
865             pti->ptlMinTrackSize.x = rcl.xRight - rcl.xLeft;
866             pti->ptlMinTrackSize.y = rcl.yTop - rcl.yBottom;
867
868             return MRFROMLONG( TRUE );
869         }
870
871         case WM_ADJUSTWINDOWPOS :
872         {
873             if( !sys->b_fixt23 )
874                 break;
875
876             PSWP  pswp = ( PSWP )mp1;
877
878             if( pswp->fl & SWP_SIZE )
879             {
880                 RECTL rcl;
881
882                 rcl.xLeft   = pswp->x;
883                 rcl.yBottom = pswp->y;
884                 rcl.xRight  = rcl.xLeft + pswp->cx;
885                 rcl.yTop    = rcl.yBottom + pswp->cy;
886
887                 WinCalcFrameRect( hwnd, &rcl, TRUE );
888
889                 if( rcl.xRight - rcl.xLeft <= sys->kvas.szlSrcSize.cx )
890                     rcl.xRight = rcl.xLeft + ( sys->kvas.szlSrcSize.cx + 1 );
891
892                 if( rcl.yTop - rcl.yBottom <= sys->kvas.szlSrcSize.cy )
893                     rcl.yTop = rcl.yBottom + ( sys->kvas.szlSrcSize.cy + 1 );
894
895                 if( rcl.xRight - rcl.xLeft > sys->i_screen_width )
896                 {
897                     rcl.xLeft  = 0;
898                     rcl.xRight = sys->i_screen_width;
899                 }
900
901                 if( rcl.yTop - rcl.yBottom > sys->i_screen_height )
902                 {
903                     rcl.yBottom = 0;
904                     rcl.yTop    = sys->i_screen_height;
905                 }
906
907                 WinCalcFrameRect( hwnd, &rcl, FALSE );
908
909                 if( pswp->x != rcl.xLeft || pswp->y != rcl.yBottom )
910                     pswp->fl |= SWP_MOVE;
911
912                 pswp->x = rcl.xLeft;
913                 pswp->y = rcl.yBottom;
914
915                 pswp->cx = rcl.xRight - rcl.xLeft;
916                 pswp->cy = rcl.yTop - rcl.yBottom;
917             }
918
919             break;
920         }
921
922         //case WM_VRNDISABLED :
923         case WM_VRNENABLED :
924             if( !vd->cfg->is_fullscreen && sys->is_on_top )
925                 WinSetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
926             break;
927     }
928
929     return sys->p_old_frame( hwnd, msg, mp1, mp2 );
930 }
931
932 static void MousePressed( vout_display_t *vd, HWND hwnd, unsigned button )
933 {
934     if( WinQueryFocus( HWND_DESKTOP ) != hwnd )
935         WinSetFocus( HWND_DESKTOP, hwnd );
936
937     if( !vd->sys->button_pressed )
938         WinSetCapture( HWND_DESKTOP, hwnd );
939
940     vd->sys->button_pressed |= 1 << button;
941
942     vout_display_SendEventMousePressed( vd, button );
943 }
944
945 static void MouseReleased( vout_display_t *vd, unsigned button )
946 {
947     vd->sys->button_pressed &= ~(1 << button);
948     if( !vd->sys->button_pressed )
949         WinSetCapture( HWND_DESKTOP, NULLHANDLE );
950
951     vout_display_SendEventMouseReleased( vd, button );
952 }
953
954 #define WM_MOUSELEAVE   0x41F
955
956 static MRESULT EXPENTRY WndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
957 {
958     vout_display_t * vd = WinQueryWindowPtr( hwnd, 0 );
959     MRESULT result = ( MRESULT )TRUE;
960
961     if ( !vd )
962         return WinDefWindowProc( hwnd, msg, mp1, mp2 );
963
964     vout_display_sys_t * sys = vd->sys;
965     RECTL rcl;
966     SWP   swp;
967
968     if ( sys->is_mouse_hidden &&
969          ((msg >= WM_MOUSEFIRST    && msg <= WM_MOUSELAST) ||
970           (msg >= WM_EXTMOUSEFIRST && msg <= WM_EXTMOUSELAST) ||
971            msg == WM_MOUSELEAVE))
972     {
973         WinShowPointer(HWND_DESKTOP, TRUE);
974         sys->is_mouse_hidden = false;
975     }
976
977     switch( msg )
978     {
979         /* the user wants to close the window */
980         case WM_CLOSE:
981             vout_display_SendEventClose(vd);
982             result = 0;
983             break;
984
985         case WM_MOUSEMOVE :
986         {
987             SHORT i_mouse_x = SHORT1FROMMP( mp1 );
988             SHORT i_mouse_y = SHORT2FROMMP( mp1 );
989             RECTL movie_rect;
990             int   i_movie_width, i_movie_height;
991             int   i_src_width, i_src_height;
992
993             /* Get a current movie area */
994             kvaAdjustDstRect( &sys->kvas.rclSrcRect, &movie_rect );
995             i_movie_width = movie_rect.xRight - movie_rect.xLeft;
996             i_movie_height = movie_rect.yTop - movie_rect.yBottom;
997
998             i_src_width =  sys->kvas.rclSrcRect.xRight -
999                            sys->kvas.rclSrcRect.xLeft;
1000             i_src_height = sys->kvas.rclSrcRect.yBottom -
1001                            sys->kvas.rclSrcRect.yTop;
1002
1003             int x = ( i_mouse_x - movie_rect.xLeft ) *
1004                     i_src_width / i_movie_width +
1005                     sys->kvas.rclSrcRect.xLeft;
1006             int y = ( i_mouse_y - movie_rect.yBottom ) *
1007                     i_src_height / i_movie_height;
1008
1009             /* Invert Y coordinate and add y offset */
1010             y = ( i_src_height - y ) + sys->kvas.rclSrcRect.yTop;;
1011
1012             vout_display_SendEventMouseMoved(vd, x, y);
1013
1014             result = WinDefWindowProc( hwnd, msg, mp1,mp2 );
1015             break;
1016         }
1017
1018         case WM_BUTTON1DOWN :
1019             MousePressed( vd, hwnd, MOUSE_BUTTON_LEFT );
1020             break;
1021
1022         case WM_BUTTON2DOWN :
1023             MousePressed( vd, hwnd, MOUSE_BUTTON_RIGHT );
1024             break;
1025
1026         case WM_BUTTON3DOWN :
1027             MousePressed( vd, hwnd, MOUSE_BUTTON_CENTER );
1028             break;
1029
1030         case WM_BUTTON1UP :
1031             MouseReleased( vd, MOUSE_BUTTON_LEFT );
1032             break;
1033
1034         case WM_BUTTON2UP :
1035             MouseReleased( vd, MOUSE_BUTTON_RIGHT );
1036             break;
1037
1038         case WM_BUTTON3UP :
1039             MouseReleased( vd, MOUSE_BUTTON_CENTER );
1040             break;
1041
1042         case WM_BUTTON1DBLCLK :
1043             vout_display_SendEventMouseDoubleClick(vd);
1044             break;
1045
1046         case WM_TRANSLATEACCEL :
1047             /* We have no accelerator table at all */
1048             result = ( MRESULT )FALSE;
1049             break;
1050
1051         case WM_CHAR :
1052         {
1053             USHORT i_flags = SHORT1FROMMP( mp1 );
1054             USHORT i_ch    = SHORT1FROMMP( mp2 );
1055             USHORT i_vk    = SHORT2FROMMP( mp2 );
1056             int    i_key   = 0;
1057
1058             /* If embedded window, let the parent process keys */
1059             if( sys->parent_window )
1060             {
1061                 WinPostMsg( sys->parent, msg, mp1, mp2 );
1062                 break;
1063             }
1064
1065             if( !( i_flags & KC_KEYUP ))
1066             {
1067                 if( i_flags & KC_VIRTUALKEY )
1068                     /* convert the key if possible */
1069                     i_key = ConvertKey( i_vk );
1070                 else if(( i_flags & KC_CHAR ) && !HIBYTE( i_ch ))
1071                     i_key = tolower( i_ch );
1072
1073                 if( i_key )
1074                 {
1075                     if( i_flags & KC_SHIFT )
1076                        i_key |= KEY_MODIFIER_SHIFT;
1077
1078                     if( i_flags & KC_CTRL )
1079                         i_key |= KEY_MODIFIER_CTRL;
1080
1081                     if( i_flags & KC_ALT )
1082                         i_key |= KEY_MODIFIER_ALT;
1083
1084                     vout_display_SendEventKey(vd, i_key);
1085                 }
1086             }
1087             break;
1088         }
1089
1090         /* Process Manage() call */
1091         case WM_VLC_MANAGE :
1092             break;
1093
1094         /* Fullscreen change */
1095         case WM_VLC_FULLSCREEN_CHANGE :
1096             if( LONGFROMMP( mp1 ))
1097             {
1098                 WinQueryWindowPos( sys->frame, &swp );
1099                 sys->client_rect.xLeft   = swp.x;
1100                 sys->client_rect.yBottom = swp.y;
1101                 sys->client_rect.xRight  = sys->client_rect.xLeft   + swp.cx;
1102                 sys->client_rect.yTop    = sys->client_rect.yBottom + swp.cy;
1103                 WinCalcFrameRect( sys->frame, &sys->client_rect, TRUE );
1104
1105                 rcl.xLeft   = 0;
1106                 rcl.yBottom = 0;
1107                 rcl.xRight  = sys->i_screen_width;
1108                 rcl.yTop    = sys->i_screen_height;
1109             }
1110             else
1111                 rcl = sys->client_rect;
1112
1113             WinCalcFrameRect( sys->frame, &rcl, FALSE );
1114
1115             WinSetWindowPos( sys->frame, HWND_TOP,
1116                              rcl.xLeft, rcl.yBottom,
1117                              rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
1118                              SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_SHOW |
1119                              SWP_ACTIVATE );
1120             break;
1121
1122         /* Size change */
1123         case WM_VLC_SIZE_CHANGE :
1124             rcl.xLeft   = 0;
1125             rcl.yBottom = 0;
1126             rcl.xRight  = LONGFROMMP( mp1 );
1127             rcl.yTop    = LONGFROMMP( mp2 );
1128             WinCalcFrameRect( sys->frame, &rcl, FALSE );
1129
1130             WinSetWindowPos( sys->frame, NULLHANDLE,
1131                              0, 0,
1132                              rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
1133                              SWP_SIZE );
1134
1135             WinQueryWindowPos( sys->frame, &swp );
1136             sys->client_rect.xLeft   = swp.x;
1137             sys->client_rect.yBottom = swp.y;
1138             sys->client_rect.xRight  = sys->client_rect.xLeft   + swp.cx;
1139             sys->client_rect.yTop    = sys->client_rect.yBottom + swp.cy;
1140             WinCalcFrameRect( sys->frame, &sys->client_rect, TRUE );
1141             break;
1142
1143         default :
1144             return WinDefWindowProc( hwnd, msg, mp1, mp2 );
1145     }
1146
1147     /* If embedded window, we need to change our window size according to a
1148      * parent window size */
1149     if( sys->parent_window )
1150     {
1151         WinQueryWindowRect( sys->parent, &rcl );
1152
1153         if( rcl.xLeft   != sys->parent_rect.xLeft   ||
1154             rcl.yBottom != sys->parent_rect.yBottom ||
1155             rcl.xRight  != sys->parent_rect.xRight  ||
1156             rcl.yTop    != sys->parent_rect.yTop)
1157         {
1158             sys->parent_rect = rcl;
1159
1160             WinCalcFrameRect( sys->frame, &rcl, FALSE );
1161
1162             WinSetWindowPos( sys->frame, NULLHANDLE,
1163                              rcl.xLeft, rcl.yBottom,
1164                              rcl.xRight - rcl.xLeft, rcl.yTop - rcl.yBottom,
1165                              SWP_SIZE | SWP_MOVE );
1166         }
1167     }
1168
1169     return result;
1170 }