directx.c 81.2 KB
Newer Older
1
/*****************************************************************************
gbazin's avatar
   
gbazin committed
2
 * vout.c: Windows DirectX video output display method
3
 *****************************************************************************
4
 * Copyright (C) 2001-2004 the VideoLAN team
5
 * $Id$
6
 *
gbazin's avatar
gbazin committed
7
 * Authors: Gildas Bazin <gbazin@videolan.org>
gbazin's avatar
   
gbazin committed
8
 *
9
10
11
12
 * 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.
gbazin's avatar
   
gbazin committed
13
 *
14
15
16
17
18
19
20
 * 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
dionoea's avatar
dionoea committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
23
24
 *****************************************************************************/

/*****************************************************************************
gbazin's avatar
   
gbazin committed
25
26
27
28
29
30
31
32
33
34
 * Preamble:
 *
 * This plugin will use YUV overlay if supported, using overlay will result in
 * the best video quality (hardware interpolation when rescaling the picture)
 * and the fastest display as it requires less processing.
 *
 * If YUV overlay is not supported this plugin will use RGB offscreen video
 * surfaces that will be blitted onto the primary surface (display) to
 * effectively display the pictures. This fallback method also enables us to
 * display video in window mode.
35
 *
36
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
37
#include <errno.h>                                                 /* ENOMEM */
38

39
40
41
42
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

43
#include <vlc/vlc.h>
44
#include <vlc_plugin.h>
zorglub's avatar
zorglub committed
45
#include <vlc_interface.h>
zorglub's avatar
zorglub committed
46
#include <vlc_playlist.h>
zorglub's avatar
zorglub committed
47
#include <vlc_vout.h>
gbazin's avatar
   
gbazin committed
48

gbazin's avatar
   
gbazin committed
49
#include <windows.h>
gbazin's avatar
   
gbazin committed
50
#include <ddraw.h>
51
#include <commctrl.h>
gbazin's avatar
   
gbazin committed
52

53
54
55
#ifndef UNDER_CE
#   include <multimon.h>
#endif
56
57
#undef GetSystemMetrics

gbazin's avatar
   
gbazin committed
58
59
60
61
#ifndef MONITOR_DEFAULTTONEAREST
#   define MONITOR_DEFAULTTONEAREST 2
#endif

gbazin's avatar
   
gbazin committed
62
63
#include "vout.h"

64
65
66
67
68
69
70
71
72
73
74
75
76
/*****************************************************************************
 * picture_sys_t: direct buffer method descriptor
 *****************************************************************************
 * This structure is part of the picture descriptor, it describes the
 * DirectX specific properties of a direct buffer.
 *****************************************************************************/
struct picture_sys_t
{
    LPDIRECTDRAWSURFACE2 p_surface;
    LPDIRECTDRAWSURFACE2 p_front_surface;
    DDSURFACEDESC        ddsd;
};

gbazin's avatar
   
gbazin committed
77
78
79
80
81
82
/*****************************************************************************
 * DirectDraw GUIDs.
 * Defining them here allows us to get rid of the dxguid library during
 * the linking stage.
 *****************************************************************************/
#include <initguid.h>
damienf's avatar
damienf committed
83
84
#undef GUID_EXT
#define GUID_EXT
gbazin's avatar
   
gbazin committed
85
86
DEFINE_GUID( IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 );
DEFINE_GUID( IID_IDirectDrawSurface2, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27 );
87
88

/*****************************************************************************
gbazin's avatar
   
gbazin committed
89
 * Local prototypes.
90
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
91
92
static int  OpenVideo  ( vlc_object_t * );
static void CloseVideo ( vlc_object_t * );
93

gbazin's avatar
   
gbazin committed
94
95
96
97
static int  Init      ( vout_thread_t * );
static void End       ( vout_thread_t * );
static int  Manage    ( vout_thread_t * );
static void Display   ( vout_thread_t *, picture_t * );
98
static void FirstDisplay( vout_thread_t *, picture_t * );
99
static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
gbazin's avatar
   
gbazin committed
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

static int  NewPictureVec  ( vout_thread_t *, picture_t *, int );
static void FreePictureVec ( vout_thread_t *, picture_t *, int );
static int  UpdatePictureStruct( vout_thread_t *, picture_t *, int );

static int  DirectXInitDDraw      ( vout_thread_t *p_vout );
static void DirectXCloseDDraw     ( vout_thread_t *p_vout );
static int  DirectXCreateDisplay  ( vout_thread_t *p_vout );
static void DirectXCloseDisplay   ( vout_thread_t *p_vout );
static int  DirectXCreateSurface  ( vout_thread_t *p_vout,
                                    LPDIRECTDRAWSURFACE2 *, int, int, int );
static void DirectXCloseSurface   ( vout_thread_t *p_vout,
                                    LPDIRECTDRAWSURFACE2 );
static int  DirectXCreateClipper  ( vout_thread_t *p_vout );
static void DirectXGetDDrawCaps   ( vout_thread_t *p_vout );
gbazin's avatar
   
gbazin committed
115
116
static int  DirectXLockSurface    ( vout_thread_t *p_vout, picture_t *p_pic );
static int  DirectXUnlockSurface  ( vout_thread_t *p_vout, picture_t *p_pic );
117

118
static DWORD DirectXFindColorkey( vout_thread_t *p_vout, uint32_t *i_color );
119

120
void SwitchWallpaperMode( vout_thread_t *, bool );
121

gbazin's avatar
   
gbazin committed
122
/* Object variables callbacks */
gbazin's avatar
   
gbazin committed
123
124
static int FindDevicesCallback( vlc_object_t *, char const *,
                                vlc_value_t, vlc_value_t, void * );
125
126
static int WallpaperCallback( vlc_object_t *, char const *,
                              vlc_value_t, vlc_value_t, void * );
gbazin's avatar
   
gbazin committed
127

128
129
130
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Christophe Massiot's avatar
Christophe Massiot committed
131
#define HW_YUV_TEXT N_("Use hardware YUV->RGB conversions")
132
133
134
#define HW_YUV_LONGTEXT N_( \
    "Try to use hardware acceleration for YUV->RGB conversions. " \
    "This option doesn't have any effect when using overlays." )
zorglub's avatar
zorglub committed
135

Christophe Massiot's avatar
Christophe Massiot committed
136
#define SYSMEM_TEXT N_("Use video buffers in system memory")
137
138
139
140
141
#define SYSMEM_LONGTEXT N_( \
    "Create video buffers in system memory instead of video memory. This " \
    "isn't recommended as usually using video memory allows to benefit from " \
    "more hardware acceleration (like rescaling or YUV->RGB conversions). " \
    "This option doesn't have any effect when using overlays." )
zorglub's avatar
zorglub committed
142

Christophe Massiot's avatar
Christophe Massiot committed
143
#define TRIPLEBUF_TEXT N_("Use triple buffering for overlays")
gbazin's avatar
   
gbazin committed
144
#define TRIPLEBUF_LONGTEXT N_( \
145
    "Try to use triple buffering when using YUV overlays. That results in " \
gbazin's avatar
   
gbazin committed
146
    "much better video quality (no flickering)." )
zorglub's avatar
zorglub committed
147

gbazin's avatar
   
gbazin committed
148
#define DEVICE_TEXT N_("Name of desired display device")
149
150
151
152
#define DEVICE_LONGTEXT N_("In a multiple monitor configuration, you can " \
    "specify the Windows device name of the display that you want the video " \
    "window to open on. For example, \"\\\\.\\DISPLAY1\" or " \
    "\"\\\\.\\DISPLAY2\"." )
gbazin's avatar
   
gbazin committed
153

154
155
156
157
158
159
#define WALLPAPER_TEXT N_("Enable wallpaper mode ")
#define WALLPAPER_LONGTEXT N_( \
    "The wallpaper mode allows you to display the video as the desktop " \
    "background. Note that this feature only works in overlay mode and " \
    "the desktop must not already have a wallpaper." )

gbazin's avatar
   
gbazin committed
160
161
static char *ppsz_dev[] = { "" };
static char *ppsz_dev_text[] = { N_("Default") };
162
163

vlc_module_begin();
164
    set_shortname( "DirectX" );
zorglub's avatar
zorglub committed
165
166
    set_category( CAT_VIDEO );
    set_subcategory( SUBCAT_VIDEO_VOUT );
gbazin's avatar
   
gbazin committed
167
    add_bool( "directx-hw-yuv", 1, NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT,
168
              true );
gbazin's avatar
   
gbazin committed
169
    add_bool( "directx-use-sysmem", 0, NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT,
170
              true );
gbazin's avatar
   
gbazin committed
171
    add_bool( "directx-3buffering", 1, NULL, TRIPLEBUF_TEXT,
172
              TRIPLEBUF_LONGTEXT, true );
gbazin's avatar
   
gbazin committed
173
174

    add_string( "directx-device", "", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
175
                true );
gbazin's avatar
   
gbazin committed
176
        change_string_list( ppsz_dev, ppsz_dev_text, FindDevicesCallback );
gbazin's avatar
   
gbazin committed
177
        change_action_add( FindDevicesCallback, N_("Refresh list") );
gbazin's avatar
   
gbazin committed
178

179
    add_bool( "directx-wallpaper", 0, NULL, WALLPAPER_TEXT, WALLPAPER_LONGTEXT,
180
              true );
181

182
    set_description( N_("DirectX video output") );
gbazin's avatar
   
gbazin committed
183
    set_capability( "video output", 100 );
184
    add_shortcut( "directx" );
gbazin's avatar
   
gbazin committed
185
    set_callbacks( OpenVideo, CloseVideo );
186
187
188

    /* FIXME: Hack to avoid unregistering our window class */
    linked_with_a_crap_library_which_uses_atexit( );
189
190
191
192
193
194
195
196
197
198
vlc_module_end();

#if 0 /* FIXME */
    /* check if we registered a window class because we need to
     * unregister it */
    WNDCLASS wndclass;
    if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
        UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
#endif

gbazin's avatar
   
gbazin committed
199
200
201
202
203
204
205
206
/*****************************************************************************
 * OpenVideo: allocate DirectX video thread output method
 *****************************************************************************
 * This function allocates and initialize the DirectX vout method.
 *****************************************************************************/
static int OpenVideo( vlc_object_t *p_this )
{
    vout_thread_t * p_vout = (vout_thread_t *)p_this;
gbazin's avatar
gbazin committed
207
    vlc_value_t val;
208
    HMODULE huser32;
gbazin's avatar
   
gbazin committed
209
210
211
212

    /* Allocate structure */
    p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
    if( p_vout->p_sys == NULL )
213
        return VLC_ENOMEM;
214
    memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
gbazin's avatar
   
gbazin committed
215
216
217
218
219
220

    /* Initialisations */
    p_vout->pf_init = Init;
    p_vout->pf_end = End;
    p_vout->pf_manage = Manage;
    p_vout->pf_render = NULL;
221
    p_vout->pf_display = FirstDisplay;
gbazin's avatar
   
gbazin committed
222
223
224
225
226

    p_vout->p_sys->p_ddobject = NULL;
    p_vout->p_sys->p_display = NULL;
    p_vout->p_sys->p_current_surface = NULL;
    p_vout->p_sys->p_clipper = NULL;
227
    p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
228
    p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
gbazin's avatar
   
gbazin committed
229
    p_vout->p_sys->i_changes = 0;
230
    p_vout->p_sys->b_wallpaper = 0;
231
    vlc_mutex_init( &p_vout->p_sys->lock );
gbazin's avatar
gbazin committed
232
233
    SetRectEmpty( &p_vout->p_sys->rect_display );
    SetRectEmpty( &p_vout->p_sys->rect_parent );
234
235
236
237
238
239

    /* Multimonitor stuff */
    p_vout->p_sys->hmonitor = NULL;
    p_vout->p_sys->p_display_driver = NULL;
    p_vout->p_sys->MonitorFromWindow = NULL;
    p_vout->p_sys->GetMonitorInfo = NULL;
240
    if( (huser32 = GetModuleHandle( _T("USER32") ) ) )
241
    {
242
        p_vout->p_sys->MonitorFromWindow = (HMONITOR (WINAPI *)( HWND, DWORD ))
243
            GetProcAddress( huser32, _T("MonitorFromWindow") );
244
        p_vout->p_sys->GetMonitorInfo =
245
#ifndef UNICODE
246
            GetProcAddress( huser32, "GetMonitorInfoA" );
247
248
249
#else
            GetProcAddress( huser32, _T("GetMonitorInfoW") );
#endif
250
251
252
253
254
255
    }

    var_Create( p_vout, "overlay", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_vout, "directx-use-sysmem", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
    var_Create( p_vout, "directx-hw-yuv", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_vout, "directx-3buffering", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
gbazin's avatar
   
gbazin committed
256
    var_Create( p_vout, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
257
    var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
258
    var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
gbazin's avatar
   
gbazin committed
259
260
261

    p_vout->p_sys->b_cursor_hidden = 0;
    p_vout->p_sys->i_lastmoved = mdate();
262
263
    p_vout->p_sys->i_mouse_hide_timeout =
        var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
gbazin's avatar
   
gbazin committed
264
265
266
267
268

    /* Set main window's size */
    p_vout->p_sys->i_window_width = p_vout->i_window_width;
    p_vout->p_sys->i_window_height = p_vout->i_window_height;

269
    /* Create the Vout EventThread, this thread is created by us to isolate
gbazin's avatar
   
gbazin committed
270
271
272
273
274
275
276
277
278
279
     * the Win32 PeekMessage function calls. We want to do this because
     * Windows can stay blocked inside this call for a long time, and when
     * this happens it thus blocks vlc's video_output thread.
     * DirectXEventThread will take care of the creation of the video
     * window (because PeekMessage has to be called from the same thread which
     * created the window). */
    msg_Dbg( p_vout, "creating DirectXEventThread" );
    p_vout->p_sys->p_event =
        vlc_object_create( p_vout, sizeof(event_thread_t) );
    p_vout->p_sys->p_event->p_vout = p_vout;
280
    if( vlc_thread_create( p_vout->p_sys->p_event, "Vout Events Thread",
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
281
                           EventThread, 0, 1 ) )
gbazin's avatar
   
gbazin committed
282
    {
283
        msg_Err( p_vout, "cannot create Vout EventThread" );
284
        vlc_object_release( p_vout->p_sys->p_event );
gbazin's avatar
   
gbazin committed
285
286
287
288
289
290
        p_vout->p_sys->p_event = NULL;
        goto error;
    }

    if( p_vout->p_sys->p_event->b_error )
    {
291
        msg_Err( p_vout, "Vout EventThread failed" );
gbazin's avatar
   
gbazin committed
292
293
294
295
296
        goto error;
    }

    vlc_object_attach( p_vout->p_sys->p_event, p_vout );

297
    msg_Dbg( p_vout, "Vout EventThread running" );
gbazin's avatar
   
gbazin committed
298
299
300
301

    /* Initialise DirectDraw */
    if( DirectXInitDDraw( p_vout ) )
    {
302
        msg_Err( p_vout, "cannot initialize DirectX DirectDraw" );
gbazin's avatar
   
gbazin committed
303
304
305
306
307
308
        goto error;
    }

    /* Create the directx display */
    if( DirectXCreateDisplay( p_vout ) )
    {
309
        msg_Err( p_vout, "cannot initialize DirectX DirectDraw" );
gbazin's avatar
   
gbazin committed
310
311
312
        goto error;
    }

313
314
    /* Variable to indicate if the window should be on top of others */
    /* Trigger a callback right now */
gbazin's avatar
   
gbazin committed
315
    var_Get( p_vout, "video-on-top", &val );
316
    var_Set( p_vout, "video-on-top", val );
317

318
319
320
321
322
323
324
325
326
    /* Variable to indicate if the window should be on top of others */
    /* Trigger a callback right now */
    var_Create( p_vout, "directx-wallpaper", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
    val.psz_string = _("Wallpaper");
    var_Change( p_vout, "directx-wallpaper", VLC_VAR_SETTEXT, &val, NULL );
    var_AddCallback( p_vout, "directx-wallpaper", WallpaperCallback, NULL );
    var_Get( p_vout, "directx-wallpaper", &val );
    var_Set( p_vout, "directx-wallpaper", val );

327
328
329
330
331
332
    /* disable screensaver by temporarily changing system settings */
    p_vout->p_sys->i_spi_lowpowertimeout = 0;
    p_vout->p_sys->i_spi_powerofftimeout = 0;
    p_vout->p_sys->i_spi_screensavetimeout = 0;
    var_Get( p_vout, "disable-screensaver", &val);
    if( val.b_bool ) {
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
        msg_Dbg(p_vout, "disabling screen saver");
        SystemParametersInfo(SPI_GETLOWPOWERTIMEOUT,
            0, &(p_vout->p_sys->i_spi_lowpowertimeout), 0);
        if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
            SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT, 0, NULL, 0);
        }
        SystemParametersInfo(SPI_GETPOWEROFFTIMEOUT, 0,
            &(p_vout->p_sys->i_spi_powerofftimeout), 0);
        if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
            SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT, 0, NULL, 0);
        }
        SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,
            &(p_vout->p_sys->i_spi_screensavetimeout), 0);
        if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
            SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, 0, NULL, 0);
        }
349
350
    }

351
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
352
353
354

 error:
    CloseVideo( VLC_OBJECT(p_vout) );
355
    return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
356
357
358
359
360
361
362
363
364
365
366
}

/*****************************************************************************
 * Init: initialize DirectX video thread output method
 *****************************************************************************
 * This function create the directx surfaces needed by the output thread.
 * It is called at the beginning of the thread.
 *****************************************************************************/
static int Init( vout_thread_t *p_vout )
{
    int i_chroma_backup;
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
    vlc_value_t val;

    /* Get a few default parameters */
    var_Get( p_vout, "overlay", &val );
    p_vout->p_sys->b_using_overlay = val.b_bool;
    var_Get( p_vout, "directx-use-sysmem", &val );
    p_vout->p_sys->b_use_sysmem = val.b_bool;
    var_Get( p_vout, "directx-hw-yuv", &val );
    p_vout->p_sys->b_hw_yuv = val.b_bool;
    var_Get( p_vout, "directx-3buffering", &val );
    p_vout->p_sys->b_3buf_overlay = val.b_bool;

    /* Initialise DirectDraw if not already done.
     * We do this here because on multi-monitor systems we may have to
     * re-create the directdraw surfaces. */
    if( !p_vout->p_sys->p_ddobject &&
        DirectXInitDDraw( p_vout ) != VLC_SUCCESS )
    {
        msg_Err( p_vout, "cannot initialize DirectDraw" );
        return VLC_EGENERIC;
    }

    /* Create the directx display */
    if( !p_vout->p_sys->p_display &&
        DirectXCreateDisplay( p_vout ) != VLC_SUCCESS )
    {
        msg_Err( p_vout, "cannot initialize DirectDraw" );
        return VLC_EGENERIC;
    }
gbazin's avatar
   
gbazin committed
396
397
398
399
400
401
402

    /* Initialize the output structure.
     * Since DirectDraw can do rescaling for us, stick to the default
     * coordinates and aspect. */
    p_vout->output.i_width  = p_vout->render.i_width;
    p_vout->output.i_height = p_vout->render.i_height;
    p_vout->output.i_aspect = p_vout->render.i_aspect;
403
    p_vout->fmt_out = p_vout->fmt_in;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
404
    UpdateRects( p_vout, true );
gbazin's avatar
   
gbazin committed
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437

#define MAX_DIRECTBUFFERS 1
    /* Right now we use only 1 directbuffer because we don't want the
     * video decoder to decode directly into direct buffers as they are
     * created into video memory and video memory is _really_ slow */

    /* Choose the chroma we will try first. */
    switch( p_vout->render.i_chroma )
    {
        case VLC_FOURCC('Y','U','Y','2'):
        case VLC_FOURCC('Y','U','N','V'):
            p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
            break;
        case VLC_FOURCC('U','Y','V','Y'):
        case VLC_FOURCC('U','Y','N','V'):
        case VLC_FOURCC('Y','4','2','2'):
            p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y');
            break;
        case VLC_FOURCC('Y','V','Y','U'):
            p_vout->output.i_chroma = VLC_FOURCC('Y','V','Y','U');
            break;
        default:
            p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
            break;
    }

    NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );

    i_chroma_backup = p_vout->output.i_chroma;

    if( !I_OUTPUTPICTURES )
    {
        /* hmmm, it didn't work! Let's try commonly supported chromas */
438
        if( p_vout->output.i_chroma != VLC_FOURCC('I','4','2','0') )
gbazin's avatar
   
gbazin committed
439
440
441
442
        {
            p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
            NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
        }
gbazin's avatar
   
gbazin committed
443
444
        if( !I_OUTPUTPICTURES )
        {
gbazin's avatar
   
gbazin committed
445
            /* hmmm, it still didn't work! Let's try another one */
gbazin's avatar
   
gbazin committed
446
447
448
449
450
451
452
453
454
455
456
457
458
459
            p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
            NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
        }
    }

    if( !I_OUTPUTPICTURES )
    {
        /* If it still didn't work then don't try to use an overlay */
        p_vout->output.i_chroma = i_chroma_backup;
        p_vout->p_sys->b_using_overlay = 0;
        NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
    }

    /* Change the window title bar text */
gbazin's avatar
gbazin committed
460
    PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
gbazin's avatar
   
gbazin committed
461

462
    p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
463
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
464
465
466
467
468
469
470
471
472
473
474
}

/*****************************************************************************
 * End: terminate Sys video thread output method
 *****************************************************************************
 * Terminate an output method created by Create.
 * It is called at the end of the thread.
 *****************************************************************************/
static void End( vout_thread_t *p_vout )
{
    FreePictureVec( p_vout, p_vout->p_picture, I_OUTPUTPICTURES );
475
476
477
478

    DirectXCloseDisplay( p_vout );
    DirectXCloseDDraw( p_vout );

gbazin's avatar
   
gbazin committed
479
480
481
482
483
484
485
486
487
    return;
}

/*****************************************************************************
 * CloseVideo: destroy Sys video thread output method
 *****************************************************************************
 * Terminate an output method created by Create
 *****************************************************************************/
static void CloseVideo( vlc_object_t *p_this )
488
{
gbazin's avatar
   
gbazin committed
489
    vout_thread_t * p_vout = (vout_thread_t *)p_this;
490

gbazin's avatar
   
gbazin committed
491
492
493
494
495
496
    msg_Dbg( p_vout, "CloseVideo" );

    if( p_vout->p_sys->p_event )
    {
        vlc_object_detach( p_vout->p_sys->p_event );

497
        /* Kill Vout EventThread */
498
        vlc_object_kill( p_vout->p_sys->p_event );
gbazin's avatar
   
gbazin committed
499

500
        /* we need to be sure Vout EventThread won't stay stuck in
gbazin's avatar
   
gbazin committed
501
502
         * GetMessage, so we send a fake message */
        if( p_vout->p_sys->hwnd )
503
        {
gbazin's avatar
   
gbazin committed
504
            PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
505
        }
gbazin's avatar
   
gbazin committed
506
507

        vlc_thread_join( p_vout->p_sys->p_event );
508
        vlc_object_release( p_vout->p_sys->p_event );
gbazin's avatar
   
gbazin committed
509
510
    }

gbazin's avatar
gbazin committed
511
512
    vlc_mutex_destroy( &p_vout->p_sys->lock );

513
    /* Make sure the wallpaper is restored */
514
    SwitchWallpaperMode( p_vout, false );
515

516
517
    /* restore screensaver system settings */
    if( 0 != p_vout->p_sys->i_spi_lowpowertimeout ) {
518
519
        SystemParametersInfo(SPI_SETLOWPOWERTIMEOUT,
            p_vout->p_sys->i_spi_lowpowertimeout, NULL, 0);
520
521
    }
    if( 0 != p_vout->p_sys->i_spi_powerofftimeout ) {
522
523
        SystemParametersInfo(SPI_SETPOWEROFFTIMEOUT,
            p_vout->p_sys->i_spi_powerofftimeout, NULL, 0);
524
525
    }
    if( 0 != p_vout->p_sys->i_spi_screensavetimeout ) {
526
527
        SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,
            p_vout->p_sys->i_spi_screensavetimeout, NULL, 0);
528
529
    }

ivoire's avatar
ivoire committed
530
531
    free( p_vout->p_sys );
    p_vout->p_sys = NULL;
gbazin's avatar
   
gbazin committed
532
533
534
535
536
537
}

/*****************************************************************************
 * Manage: handle Sys events
 *****************************************************************************
 * This function should be called regularly by the video output thread.
Sam Hocevar's avatar
Sam Hocevar committed
538
 * It returns a non null value if an error occurred.
gbazin's avatar
   
gbazin committed
539
540
541
 *****************************************************************************/
static int Manage( vout_thread_t *p_vout )
{
542
543
    /* If we do not control our window, we check for geometry changes
     * ourselves because the parent might not send us its events. */
gbazin's avatar
gbazin committed
544
    vlc_mutex_lock( &p_vout->p_sys->lock );
545
    if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
546
    {
gbazin's avatar
gbazin committed
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
        RECT rect_parent;
        POINT point;

        vlc_mutex_unlock( &p_vout->p_sys->lock );

        GetClientRect( p_vout->p_sys->hparent, &rect_parent );
        point.x = point.y = 0;
        ClientToScreen( p_vout->p_sys->hparent, &point );
        OffsetRect( &rect_parent, point.x, point.y );

        if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
        {
            p_vout->p_sys->rect_parent = rect_parent;

            /* This one is to force the update even if only
562
             * the position has changed */
gbazin's avatar
gbazin committed
563
564
565
566
567
568
569
570
571
572
573
574
            SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
                          rect_parent.right - rect_parent.left,
                          rect_parent.bottom - rect_parent.top, 0 );

            SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
                          rect_parent.right - rect_parent.left,
                          rect_parent.bottom - rect_parent.top, 0 );
        }
    }
    else
    {
        vlc_mutex_unlock( &p_vout->p_sys->lock );
575
576
    }

gbazin's avatar
   
gbazin committed
577
    /*
578
     * Position Change
gbazin's avatar
   
gbazin committed
579
     */
580
    if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
gbazin's avatar
   
gbazin committed
581
    {
582
583
        p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;

584
585
586
587
588
589
590
591
592
        /* Check if we are still on the same monitor */
        if( p_vout->p_sys->MonitorFromWindow &&
            p_vout->p_sys->hmonitor !=
                p_vout->p_sys->MonitorFromWindow( p_vout->p_sys->hwnd,
                                                  MONITOR_DEFAULTTONEAREST ) )
        {
            /* This will force the vout core to recreate the picture buffers */
            p_vout->i_changes |= VOUT_PICTURE_BUFFERS_CHANGE;
        }
gbazin's avatar
   
gbazin committed
593
594
    }

595
596
597
    /* Check for cropping / aspect changes */
    if( p_vout->i_changes & VOUT_CROP_CHANGE ||
        p_vout->i_changes & VOUT_ASPECT_CHANGE )
598
    {
599
600
601
        p_vout->i_changes &= ~VOUT_CROP_CHANGE;
        p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;

602
603
604
605
        p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
        p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
        p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
        p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
606
607
608
609
        p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
        p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
        p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
        p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
610
        UpdateRects( p_vout, true );
611
612
    }

613
614
615
616
617
    /* We used to call the Win32 PeekMessage function here to read the window
     * messages. But since window can stay blocked into this function for a
     * long time (for example when you move your window on the screen), I
     * decided to isolate PeekMessage in another thread. */

618
619
620
621
    if( p_vout->p_sys->i_changes & DX_WALLPAPER_CHANGE )
    {
        SwitchWallpaperMode( p_vout, !p_vout->p_sys->b_wallpaper );
        p_vout->p_sys->i_changes &= ~DX_WALLPAPER_CHANGE;
622
        DirectDrawUpdateOverlay( p_vout );
623
624
    }

gbazin's avatar
   
gbazin committed
625
626
627
628
629
630
    /*
     * Fullscreen change
     */
    if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
        || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
    {
631
        Win32ToggleFullscreen( p_vout );
gbazin's avatar
   
gbazin committed
632

gbazin's avatar
   
gbazin committed
633
634
635
636
637
638
639
        p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
        p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
    }

    /*
     * Pointer change
     */
640
    if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
641
642
        (mdate() - p_vout->p_sys->i_lastmoved) >
            p_vout->p_sys->i_mouse_hide_timeout )
gbazin's avatar
   
gbazin committed
643
    {
gbazin's avatar
gbazin committed
644
        POINT point;
645
        HWND hwnd;
gbazin's avatar
gbazin committed
646
647
648

        /* Hide the cursor only if it is inside our window */
        GetCursorPos( &point );
649
650
        hwnd = WindowFromPoint(point);
        if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
651
652
653
        {
            PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
        }
gbazin's avatar
gbazin committed
654
655
656
657
        else
        {
            p_vout->p_sys->i_lastmoved = mdate();
        }
gbazin's avatar
   
gbazin committed
658
659
    }

660
661
662
    /*
     * "Always on top" status change
     */
gbazin's avatar
   
gbazin committed
663
    if( p_vout->p_sys->b_on_top_change )
664
    {
gbazin's avatar
   
gbazin committed
665
666
667
        vlc_value_t val;
        HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );

gbazin's avatar
   
gbazin committed
668
        var_Get( p_vout, "video-on-top", &val );
zorglub's avatar
zorglub committed
669

670
        /* Set the window on top if necessary */
gbazin's avatar
   
gbazin committed
671
672
        if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
                           & WS_EX_TOPMOST ) )
673
674
675
        {
            CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
                           MF_BYCOMMAND | MFS_CHECKED );
gbazin's avatar
   
gbazin committed
676
677
            SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
                          SWP_NOSIZE | SWP_NOMOVE );
678
        }
gbazin's avatar
   
gbazin committed
679
        else
680
        /* The window shouldn't be on top */
gbazin's avatar
   
gbazin committed
681
682
        if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
                           & WS_EX_TOPMOST ) )
683
684
685
        {
            CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
                           MF_BYCOMMAND | MFS_UNCHECKED );
gbazin's avatar
   
gbazin committed
686
            SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
687
688
                          SWP_NOSIZE | SWP_NOMOVE );
        }
gbazin's avatar
   
gbazin committed
689

690
        p_vout->p_sys->b_on_top_change = false;
691
692
    }

gbazin's avatar
   
gbazin committed
693
694
    /* Check if the event thread is still running */
    if( p_vout->p_sys->p_event->b_die )
695
696
697
    {
        return VLC_EGENERIC; /* exit */
    }
gbazin's avatar
   
gbazin committed
698

699
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
700
701
702
703
704
705
706
707
708
709
710
711
712
713
}

/*****************************************************************************
 * Display: displays previously rendered output
 *****************************************************************************
 * This function sends the currently rendered image to the display, wait until
 * it is displayed and switch the two rendering buffers, preparing next frame.
 *****************************************************************************/
static void Display( vout_thread_t *p_vout, picture_t *p_pic )
{
    HRESULT dxresult;

    if( (p_vout->p_sys->p_display == NULL) )
    {
zorglub's avatar
zorglub committed
714
        msg_Warn( p_vout, "no display!" );
gbazin's avatar
   
gbazin committed
715
716
717
        return;
    }

gbazin's avatar
   
gbazin committed
718
719
720
721
722
723
724
    /* Our surface can be lost so be sure to check this
     * and restore it if need be */
    if( IDirectDrawSurface2_IsLost( p_vout->p_sys->p_display )
        == DDERR_SURFACELOST )
    {
        if( IDirectDrawSurface2_Restore( p_vout->p_sys->p_display ) == DD_OK &&
            p_vout->p_sys->b_using_overlay )
725
            DirectDrawUpdateOverlay( p_vout );
gbazin's avatar
   
gbazin committed
726
727
    }

gbazin's avatar
   
gbazin committed
728
729
730
731
732
733
734
735
736
737
    if( !p_vout->p_sys->b_using_overlay )
    {
        DDBLTFX  ddbltfx;

        /* We ask for the "NOTEARING" option */
        memset( &ddbltfx, 0, sizeof(DDBLTFX) );
        ddbltfx.dwSize = sizeof(DDBLTFX);
        ddbltfx.dwDDFX = DDBLTFX_NOTEARING;

        /* Blit video surface to display */
738
739
740
741
742
        dxresult = IDirectDrawSurface2_Blt( p_vout->p_sys->p_display,
                                            &p_vout->p_sys->rect_dest_clipped,
                                            p_pic->p_sys->p_surface,
                                            &p_vout->p_sys->rect_src_clipped,
                                            DDBLT_ASYNC, &ddbltfx );
gbazin's avatar
   
gbazin committed
743
744
        if( dxresult != DD_OK )
        {
gbazin's avatar
   
gbazin committed
745
            msg_Warn( p_vout, "could not blit surface (error %li)", dxresult );
gbazin's avatar
   
gbazin committed
746
747
748
749
750
751
752
            return;
        }
    }
    else /* using overlay */
    {
        /* Flip the overlay buffers if we are using back buffers */
        if( p_pic->p_sys->p_front_surface == p_pic->p_sys->p_surface )
753
        {
gbazin's avatar
   
gbazin committed
754
            return;
755
        }
gbazin's avatar
   
gbazin committed
756
757
758
759

        dxresult = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface,
                                             NULL, DDFLIP_WAIT );
        if( dxresult != DD_OK )
760
        {
gbazin's avatar
   
gbazin committed
761
            msg_Warn( p_vout, "could not flip overlay (error %li)", dxresult );
762
        }
gbazin's avatar
   
gbazin committed
763

gbazin's avatar
   
gbazin committed
764
765
        /* set currently displayed pic */
        p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
gbazin's avatar
   
gbazin committed
766

gbazin's avatar
   
gbazin committed
767
768
        /* Lock surface to get all the required info */
        if( DirectXLockSurface( p_vout, p_pic ) )
gbazin's avatar
   
gbazin committed
769
770
        {
            /* AAARRGG */
gbazin's avatar
   
gbazin committed
771
            msg_Warn( p_vout, "cannot lock surface" );
gbazin's avatar
   
gbazin committed
772
773
            return;
        }
gbazin's avatar
   
gbazin committed
774
        DirectXUnlockSurface( p_vout, p_pic );
gbazin's avatar
   
gbazin committed
775
776
777
    }
}

778
779
/*
** this function is only used once when the first picture is received
780
781
** this function will show the video window once video is ready for
** display.
782
*/
783
784

static void FirstDisplay( vout_thread_t *p_vout, picture_t *p_pic )
785
{
786
787
788
789
790
791
    /* get initial picture rendered on overlay surface */
    Display(p_vout, p_pic);

    IDirectDraw_WaitForVerticalBlank(p_vout->p_sys->p_ddobject,
            DDWAITVB_BLOCKBEGIN, NULL);

792
793
794
795
796
797
798
    if( p_vout->p_sys->b_using_overlay )
    {
        /* set the colorkey as the backgound brush for the video window */
        SetClassLong( p_vout->p_sys->hvideownd, GCL_HBRBACKGROUND,
                      (LONG)CreateSolidBrush( p_vout->p_sys->i_rgb_colorkey ) );
    }
    /*
799
    ** Video window is initially hidden, show it now since we got a
800
801
    ** picture to show.
    */
802
    SetWindowPos( p_vout->p_sys->hvideownd, NULL, 0, 0, 0, 0,
803
804
805
806
807
808
        SWP_ASYNCWINDOWPOS|
        SWP_FRAMECHANGED|
        SWP_SHOWWINDOW|
        SWP_NOMOVE|
        SWP_NOSIZE|
        SWP_NOZORDER );
809
810
811
812
813

    /* use and restores proper display function for further pictures */
    p_vout->pf_display = Display;
}

gbazin's avatar
   
gbazin committed
814
815
/* following functions are local */

816
817
818
/*****************************************************************************
 * DirectXEnumCallback: Device enumeration
 *****************************************************************************
zorglub's avatar
zorglub committed
819
 * This callback function is called by DirectDraw once for each
820
821
822
823
824
825
826
 * available DirectDraw device.
 *****************************************************************************/
BOOL WINAPI DirectXEnumCallback( GUID* p_guid, LPTSTR psz_desc,
                                 LPTSTR psz_drivername, VOID* p_context,
                                 HMONITOR hmon )
{
    vout_thread_t *p_vout = (vout_thread_t *)p_context;
gbazin's avatar
   
gbazin committed
827
828
    vlc_value_t device;

829
830
    msg_Dbg( p_vout, "DirectXEnumCallback: %s, %s", psz_desc, psz_drivername );

gbazin's avatar
   
gbazin committed
831
    if( hmon )
832
    {
833
834
835
        var_Get( p_vout, "directx-device", &device );

        if( ( !device.psz_string || !*device.psz_string ) &&
gbazin's avatar
   
gbazin committed
836
837
            hmon == p_vout->p_sys->hmonitor )
        {
ivoire's avatar
ivoire committed
838
            free( device.psz_string );
gbazin's avatar
   
gbazin committed
839
840
841
        }
        else if( strcmp( psz_drivername, device.psz_string ) == 0 )
        {
zorglub's avatar
zorglub committed
842
843
            MONITORINFO monitor_info;
            monitor_info.cbSize = sizeof( MONITORINFO );
gbazin's avatar
   
gbazin committed
844
845
846
847
848
849
850
851
852
853
854

            if( p_vout->p_sys->GetMonitorInfo( hmon, &monitor_info ) )
            {
                RECT rect;

                /* Move window to the right screen */
                GetWindowRect( p_vout->p_sys->hwnd, &rect );
                if( !IntersectRect( &rect, &rect, &monitor_info.rcWork ) )
                {
                    rect.left = monitor_info.rcWork.left;
                    rect.top = monitor_info.rcWork.top;
855
                    msg_Dbg( p_vout, "DirectXEnumCallback: setting window "
856
                             "position to %ld,%ld", rect.left, rect.top );
gbazin's avatar
   
gbazin committed
857
858
859
860
861
862
                    SetWindowPos( p_vout->p_sys->hwnd, NULL,
                                  rect.left, rect.top, 0, 0,
                                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
                }
            }

gbazin's avatar
   
gbazin committed
863
            p_vout->p_sys->hmonitor = hmon;
ivoire's avatar
ivoire committed
864
            free( device.psz_string );
865
866
867
        }
        else
        {
ivoire's avatar
ivoire committed
868
            free( device.psz_string );
869
            return TRUE; /* Keep enumerating */
gbazin's avatar
   
gbazin committed
870
871
        }

872
873
874
875
876
877
        msg_Dbg( p_vout, "selecting %s, %s", psz_desc, psz_drivername );
        p_vout->p_sys->p_display_driver = malloc( sizeof(GUID) );
        if( p_vout->p_sys->p_display_driver )
            memcpy( p_vout->p_sys->p_display_driver, p_guid, sizeof(GUID) );
    }

878
879
880
    return TRUE; /* Keep enumerating */
}

gbazin's avatar
   
gbazin committed
881
882
883
884
885
886
887
/*****************************************************************************
 * DirectXInitDDraw: Takes care of all the DirectDraw initialisations
 *****************************************************************************
 * This function initialise and allocate resources for DirectDraw.
 *****************************************************************************/
static int DirectXInitDDraw( vout_thread_t *p_vout )
{
888
889
890
891
892
    HRESULT dxresult;
    HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
    HRESULT (WINAPI *OurDirectDrawEnumerateEx)( LPDDENUMCALLBACKEXA, LPVOID,
                                                DWORD );
    LPDIRECTDRAW p_ddobject;
gbazin's avatar
   
gbazin committed
893
894
895

    msg_Dbg( p_vout, "DirectXInitDDraw" );

896
    /* Load direct draw DLL */
897
    p_vout->p_sys->hddraw_dll = LoadLibrary(_T("DDRAW.DLL"));
gbazin's avatar
   
gbazin committed
898
899
900
901
902
    if( p_vout->p_sys->hddraw_dll == NULL )
    {
        msg_Warn( p_vout, "DirectXInitDDraw failed loading ddraw.dll" );
        goto error;
    }
903
904

    OurDirectDrawCreate =
905
906
      (void *)GetProcAddress( p_vout->p_sys->hddraw_dll,
                              _T("DirectDrawCreate") );
907
    if( OurDirectDrawCreate == NULL )
gbazin's avatar
   
gbazin committed
908
909
910
911
912
    {
        msg_Err( p_vout, "DirectXInitDDraw failed GetProcAddress" );
        goto error;
    }

913
914
    OurDirectDrawEnumerateEx =
      (void *)GetProcAddress( p_vout->p_sys->hddraw_dll,
915
#ifndef UNICODE
916
                              "DirectDrawEnumerateExA" );
917
918
919
#else
                              _T("DirectDrawEnumerateExW") );
#endif
920

921
    if( OurDirectDrawEnumerateEx && p_vout->p_sys->MonitorFromWindow )
922
    {
gbazin's avatar
   
gbazin committed
923
924
925
        vlc_value_t device;

        var_Get( p_vout, "directx-device", &device );
926
927
928
929
930
        if( device.psz_string )
        {
            msg_Dbg( p_vout, "directx-device: %s", device.psz_string );
            free( device.psz_string );
        }
gbazin's avatar
   
gbazin committed
931

932
933
934
935
        p_vout->p_sys->hmonitor =
            p_vout->p_sys->MonitorFromWindow( p_vout->p_sys->hwnd,
                                              MONITOR_DEFAULTTONEAREST );

936
        /* Enumerate displays */
zorglub's avatar
zorglub committed
937
        OurDirectDrawEnumerateEx( DirectXEnumCallback, p_vout,
938
939
940
                                  DDENUM_ATTACHEDSECONDARYDEVICES );
    }

gbazin's avatar
   
gbazin committed
941
    /* Initialize DirectDraw now */
942
943
    dxresult = OurDirectDrawCreate( p_vout->p_sys->p_display_driver,
                                    &p_ddobject, NULL );
gbazin's avatar
   
gbazin committed
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
    if( dxresult != DD_OK )
    {
        msg_Err( p_vout, "DirectXInitDDraw cannot initialize DDraw" );
        goto error;
    }

    /* Get the IDirectDraw2 interface */
    dxresult = IDirectDraw_QueryInterface( p_ddobject, &IID_IDirectDraw2,
                                        (LPVOID *)&p_vout->p_sys->p_ddobject );
    /* Release the unused interface */
    IDirectDraw_Release( p_ddobject );
    if( dxresult != DD_OK )
    {
        msg_Err( p_vout, "cannot get IDirectDraw2 interface" );
        goto error;
    }

    /* Set DirectDraw Cooperative level, ie what control we want over Windows
     * display */
    dxresult = IDirectDraw2_SetCooperativeLevel( p_vout->p_sys->p_ddobject,
964
                                                 NULL, DDSCL_NORMAL );
gbazin's avatar
   
gbazin committed
965
966
967
968
969
970
    if( dxresult != DD_OK )
    {
        msg_Err( p_vout, "cannot set direct draw cooperative level" );
        goto error;
    }

971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
    /* Get the size of the current display device */
    if( p_vout->p_sys->hmonitor && p_vout->p_sys->GetMonitorInfo )
    {
        MONITORINFO monitor_info;
        monitor_info.cbSize = sizeof( MONITORINFO );
        p_vout->p_sys->GetMonitorInfo( p_vout->p_sys->hmonitor,
                                       &monitor_info );
        p_vout->p_sys->rect_display = monitor_info.rcMonitor;
    }
    else
    {
        p_vout->p_sys->rect_display.left = 0;
        p_vout->p_sys->rect_display.top = 0;
        p_vout->p_sys->rect_display.right  = GetSystemMetrics(SM_CXSCREEN);
        p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
    }

988
    msg_Dbg( p_vout, "screen dimensions (%lix%li,%lix%li)",
gbazin's avatar
   
gbazin committed
989
990
991
992
             p_vout->p_sys->rect_display.left,
             p_vout->p_sys->rect_display.top,
             p_vout->p_sys->rect_display.right,
             p_vout->p_sys->rect_display.bottom );
993

gbazin's avatar
   
gbazin committed
994
995
996
997
    /* Probe the capabilities of the hardware */
    DirectXGetDDrawCaps( p_vout );

    msg_Dbg( p_vout, "End DirectXInitDDraw" );
998
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
999
1000

 error: