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