]> git.sesse.net Git - vlc/commitdiff
* modules/video_output/directx/*: first try at multimonitor support (untested).
authorGildas Bazin <gbazin@videolan.org>
Thu, 11 Dec 2003 23:12:46 +0000 (23:12 +0000)
committerGildas Bazin <gbazin@videolan.org>
Thu, 11 Dec 2003 23:12:46 +0000 (23:12 +0000)
* src/video_output/video_output.c: small change to allow the directx plugin to destroy/recreate picture buffers on the fly.

include/video_output.h
modules/video_output/directx/directx.c
modules/video_output/directx/events.c
modules/video_output/directx/vout.h
src/video_output/video_output.c

index 177c1ec982f833766b9b91a0ff3f94f333c6ae0b..98ca43ac480ad422ea6008d890991645deb40120 100644 (file)
@@ -2,7 +2,7 @@
  * video_output.h : video output thread
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
- * $Id: video_output.h,v 1.106 2003/12/09 19:15:03 yoann Exp $
+ * $Id: video_output.h,v 1.107 2003/12/11 23:12:46 gbazin Exp $
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *          Samuel Hocevar <sam@via.ecp.fr>
@@ -177,6 +177,8 @@ struct vout_thread_t
 #define VOUT_DEPTH_CHANGE       0x0400
 /** change chroma tables */
 #define VOUT_CHROMA_CHANGE      0x0800
+/** change/recreate picture buffers */
+#define VOUT_PICTURE_BUFFERS_CHANGE 0x1000
 /**@}*/
 
 /* Alignment flags */
index 65cc31a4e17c337a4ebb04912cc8f8284cff8d19..c559f95723871d1a56a7b66b5f6433e0ff791894 100644 (file)
@@ -2,7 +2,7 @@
  * vout.c: Windows DirectX video output display method
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: directx.c,v 1.26 2003/12/08 19:50:22 gbazin Exp $
+ * $Id: directx.c,v 1.27 2003/12/11 23:12:46 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -45,6 +45,9 @@
 #include <windows.h>
 #include <ddraw.h>
 
+#include <multimon.h>
+#undef GetSystemMetrics
+
 #include "vout.h"
 
 /*****************************************************************************
@@ -136,6 +139,7 @@ static int OpenVideo( vlc_object_t *p_this )
 {
     vout_thread_t * p_vout = (vout_thread_t *)p_this;
     vlc_value_t val, text;
+    HMODULE huser32;
 
     /* Allocate structure */
     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
@@ -159,11 +163,24 @@ static int OpenVideo( vlc_object_t *p_this )
     p_vout->p_sys->hwnd = NULL;
     p_vout->p_sys->hparent = NULL;
     p_vout->p_sys->i_changes = 0;
-    SetRectEmpty( &p_vout->p_sys->rect_display );
-    p_vout->p_sys->b_using_overlay = config_GetInt( p_vout, "overlay" );
-    p_vout->p_sys->b_use_sysmem = config_GetInt( p_vout, "directx-use-sysmem");
-    p_vout->p_sys->b_hw_yuv = config_GetInt( p_vout, "directx-hw-yuv" );
-    p_vout->p_sys->b_3buf_overlay = config_GetInt( p_vout, "directx-3buffering" );
+
+    /* 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;
+    if( (huser32 = GetModuleHandle( "USER32" ) ) )
+    {
+        p_vout->p_sys->MonitorFromWindow =
+            GetProcAddress( huser32, "MonitorFromWindow" );
+        p_vout->p_sys->GetMonitorInfo =
+            GetProcAddress( huser32, "GetMonitorInfoA" );
+    }
+
+    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 );
 
     p_vout->p_sys->b_cursor_hidden = 0;
     p_vout->p_sys->i_lastmoved = mdate();
@@ -183,9 +200,8 @@ static int OpenVideo( vlc_object_t *p_this )
     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;
-    if( vlc_thread_create( p_vout->p_sys->p_event,
-                           "DirectX Events Thread", DirectXEventThread,
-                           0, 1 ) )
+    if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
+                           DirectXEventThread, 0, 1 ) )
     {
         msg_Err( p_vout, "cannot create DirectXEventThread" );
         vlc_object_destroy( p_vout->p_sys->p_event );
@@ -241,6 +257,35 @@ static int OpenVideo( vlc_object_t *p_this )
 static int Init( vout_thread_t *p_vout )
 {
     int i_chroma_backup;
+    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;
+    }
 
     /* Initialize the output structure.
      * Since DirectDraw can do rescaling for us, stick to the default
@@ -326,6 +371,10 @@ static int Init( vout_thread_t *p_vout )
 static void End( vout_thread_t *p_vout )
 {
     FreePictureVec( p_vout, p_vout->p_picture, I_OUTPUTPICTURES );
+
+    DirectXCloseDisplay( p_vout );
+    DirectXCloseDDraw( p_vout );
+
     return;
 }
 
@@ -360,9 +409,6 @@ static void CloseVideo( vlc_object_t *p_this )
         vlc_object_destroy( p_vout->p_sys->p_event );
     }
 
-    DirectXCloseDisplay( p_vout );
-    DirectXCloseDDraw( p_vout );
-
     if( p_vout->p_sys )
     {
         free( p_vout->p_sys );
@@ -387,37 +433,32 @@ static int Manage( vout_thread_t *p_vout )
         DirectXUpdateRects( p_vout, VLC_FALSE );
     }
 
-    /* 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. */
-
     /*
-     * Scale Change
+     * Position Change
      */
-    if( p_vout->i_changes & VOUT_SCALE_CHANGE
-         || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE )
+    if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
     {
-        msg_Dbg( p_vout, "scale change" );
         if( p_vout->p_sys->b_using_overlay )
             DirectXUpdateOverlay( p_vout );
-        p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
-        p_vout->p_sys->i_changes &= ~VOUT_SCALE_CHANGE;
-    }
 
-    /*
-     * Size Change
-     */
-    if( p_vout->i_changes & VOUT_SIZE_CHANGE
-        || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE )
-    {
-        msg_Dbg( p_vout, "size change" );
-        if( p_vout->p_sys->b_using_overlay )
-            DirectXUpdateOverlay( p_vout );
-        p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
-        p_vout->p_sys->i_changes &= ~VOUT_SIZE_CHANGE;
+        /* 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;
+        }
+
+        p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
     }
 
+    /* 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. */
+
     /*
      * Fullscreen change
      */
@@ -606,6 +647,14 @@ BOOL WINAPI DirectXEnumCallback( GUID* p_guid, LPTSTR psz_desc,
     vout_thread_t *p_vout = (vout_thread_t *)p_context;
     msg_Dbg( p_vout, "DirectXEnumCallback: %s, %s", psz_desc, psz_drivername );
 
+    if( hmon && hmon == p_vout->p_sys->hmonitor )
+    {
+        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) );
+    }
+
     return TRUE; /* Keep enumerating */
 }
 
@@ -624,7 +673,7 @@ static int DirectXInitDDraw( vout_thread_t *p_vout )
 
     msg_Dbg( p_vout, "DirectXInitDDraw" );
 
-    /* load direct draw DLL */
+    /* Load direct draw DLL */
     p_vout->p_sys->hddraw_dll = LoadLibrary("DDRAW.DLL");
     if( p_vout->p_sys->hddraw_dll == NULL )
     {
@@ -644,15 +693,20 @@ static int DirectXInitDDraw( vout_thread_t *p_vout )
       (void *)GetProcAddress( p_vout->p_sys->hddraw_dll,
                               "DirectDrawEnumerateExA" );
 
-    if( OurDirectDrawEnumerateEx )
+    if( OurDirectDrawEnumerateEx && p_vout->p_sys->MonitorFromWindow )
     {
+        p_vout->p_sys->hmonitor =
+            p_vout->p_sys->MonitorFromWindow( p_vout->p_sys->hwnd,
+                                              MONITOR_DEFAULTTONEAREST );
+
         /* Enumerate displays */
         OurDirectDrawEnumerateEx( DirectXEnumCallback, p_vout, 
                                   DDENUM_ATTACHEDSECONDARYDEVICES );
     }
 
     /* Initialize DirectDraw now */
-    dxresult = OurDirectDrawCreate( NULL, &p_ddobject, NULL );
+    dxresult = OurDirectDrawCreate( p_vout->p_sys->p_display_driver,
+                                    &p_ddobject, NULL );
     if( dxresult != DD_OK )
     {
         msg_Err( p_vout, "DirectXInitDDraw cannot initialize DDraw" );
@@ -680,6 +734,27 @@ static int DirectXInitDDraw( vout_thread_t *p_vout )
         goto error;
     }
 
+    /* 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);
+    }
+
+    msg_Dbg( p_vout, "screen dimensions %ix%i",
+                      p_vout->p_sys->rect_display.right,
+                      p_vout->p_sys->rect_display.bottom );
+
     /* Probe the capabilities of the hardware */
     DirectXGetDDrawCaps( p_vout );
 
@@ -992,6 +1067,14 @@ static void DirectXCloseDDraw( vout_thread_t *p_vout )
         FreeLibrary( p_vout->p_sys->hddraw_dll );
         p_vout->p_sys->hddraw_dll = NULL;
     }
+
+    if( p_vout->p_sys->p_display_driver != NULL )
+    {
+        free( p_vout->p_sys->p_display_driver );
+        p_vout->p_sys->p_display_driver = NULL;
+    }
+
+    p_vout->p_sys->hmonitor = NULL;
 }
 
 /*****************************************************************************
@@ -1148,11 +1231,11 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
              * because a few buggy drivers don't mind creating the surface
              * even if they don't know about the chroma. */
             if( IDirectDraw2_GetFourCCCodes( p_vout->p_sys->p_ddobject,
-                                             &i_codes, NULL ) )
+                                             &i_codes, NULL ) == DD_OK )
             {
                 pi_codes = malloc( i_codes * sizeof(DWORD) );
                 if( pi_codes && IDirectDraw2_GetFourCCCodes(
-                    p_vout->p_sys->p_ddobject, &i_codes, pi_codes ) )
+                    p_vout->p_sys->p_ddobject, &i_codes, pi_codes ) == DD_OK )
                 {
                     for( i = 0; i < (int)i_codes; i++ )
                     {
@@ -1297,6 +1380,8 @@ static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
             free( p_pic[i].p_sys );
         }
     }
+
+    p_vout->p_sys->p_current_surface = 0;
 }
 
 /*****************************************************************************
index ae1ce1f1a05eb6077252f270592896affc24bec1..bd3ef5abc0cd0ee8f3a1e0f0afd309f9a6e9b7fb 100644 (file)
@@ -2,7 +2,7 @@
  * events.c: Windows DirectX video output events handler
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: events.c,v 1.31 2003/12/08 19:50:22 gbazin Exp $
+ * $Id: events.c,v 1.32 2003/12/11 23:12:46 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -269,7 +269,6 @@ void DirectXEventThread( event_thread_t *p_event )
 static int DirectXCreateWindow( vout_thread_t *p_vout )
 {
     HINSTANCE  hInstance;
-    HDC        hdc;
     HMENU      hMenu;
     RECT       rect_window;
 
@@ -280,17 +279,6 @@ static int DirectXCreateWindow( vout_thread_t *p_vout )
     /* Get this module's instance */
     hInstance = GetModuleHandle(NULL);
 
-    /* Get the current size of the display and its colour depth */
-    hdc = GetDC( NULL );
-    p_vout->p_sys->rect_display.right = GetDeviceCaps( hdc, HORZRES );
-    p_vout->p_sys->rect_display.bottom = GetDeviceCaps( hdc, VERTRES );
-    p_vout->p_sys->i_display_depth = GetDeviceCaps( hdc, BITSPIXEL );
-    msg_Dbg( p_vout, "screen dimensions %ix%i colour depth %i",
-                      p_vout->p_sys->rect_display.right,
-                      p_vout->p_sys->rect_display.bottom,
-                      p_vout->p_sys->i_display_depth );
-    ReleaseDC( NULL, hdc );
-
     /* If an external window was specified, we'll draw in it. */
     var_Get( p_vout->p_vlc, "drawable", &val );
     p_vout->p_sys->hparent = p_vout->p_sys->hwnd =
@@ -502,13 +490,16 @@ void DirectXUpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
     rect_dest.top = point.y + i_y;
     rect_dest.bottom = rect_dest.top + i_height;
 
-
     /* UpdateOverlay directdraw function doesn't automatically clip to the
      * display size so we need to do it otherwise it will fail */
 
     /* Clip the destination window */
-    IntersectRect( &rect_dest_clipped, &rect_dest,
-                   &p_vout->p_sys->rect_display );
+    if( !IntersectRect( &rect_dest_clipped, &rect_dest,
+                        &p_vout->p_sys->rect_display ) )
+    {
+        SetRectEmpty( &rect_src_clipped );
+        return;
+    }
 
 #if 0
     msg_Dbg( p_vout, "DirectXUpdateRects image_dst_clipped coords:"
@@ -550,18 +541,8 @@ void DirectXUpdateRects( vout_thread_t *p_vout, vlc_bool_t b_force )
                      rect_src_clipped.right, rect_src_clipped.bottom );
 #endif
 
-    /* Signal the size change */
-    if( !p_vout->p_sys->p_event->b_die )
-    {
-        if( p_vout->p_sys->b_using_overlay )
-        {
-            DirectXUpdateOverlay( p_vout );
-        }
-        else
-        {
-            p_vout->p_sys->i_changes |= VOUT_SIZE_CHANGE;
-        }
-    }
+    /* Signal the change in size/position */
+    p_vout->p_sys->i_changes |= DX_POSITION_CHANGE;
 
 #undef rect_src
 #undef rect_src_clipped
index 40a1750b8bc9988c25fe1fd0d39b5b30aedacf01..4aaf434c7fc8f19a42fb034526b1971171834eb2 100644 (file)
@@ -2,7 +2,7 @@
  * vout.h: Windows DirectX video output header file
  *****************************************************************************
  * Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: vout.h,v 1.9 2003/11/20 17:48:44 gbazin Exp $
+ * $Id: vout.h,v 1.10 2003/12/11 23:12:46 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -51,6 +51,12 @@ struct vout_sys_t
     HWND                 hparent;             /* Handle of the parent window */
     WNDPROC              pf_wndproc;             /* Window handling callback */
 
+    /* Multi-monitor support */
+    HMONITOR             hmonitor;          /* handle of the current monitor */
+    GUID                 *p_display_driver;
+    HMONITOR             (WINAPI* MonitorFromWindow)( HWND, DWORD );
+    BOOL                 (WINAPI* GetMonitorInfo)( HMONITOR, LPMONITORINFO );
+
     vlc_bool_t   b_using_overlay;         /* Are we using an overlay surface */
     vlc_bool_t   b_use_sysmem;   /* Should we use system memory for surfaces */
     vlc_bool_t   b_hw_yuv;    /* Should we use hardware YUV->RGB conversions */
@@ -121,3 +127,4 @@ void DirectXUpdateRects ( vout_thread_t *p_vout, vlc_bool_t b_force );
 #define WM_VLC_CREATE_VIDEO_WIN WM_APP + 1
 #define WM_VLC_DESTROY_VIDEO_WIN WM_APP + 2
 #define IDM_TOGGLE_ON_TOP WM_USER + 1
+#define DX_POSITION_CHANGE 0x1000
index 14445b5749b67fbc288dba2ab7cb94379e20e96e..b88db34e9b2726532476e8f9d0c0f0051b548a50 100644 (file)
@@ -5,7 +5,7 @@
  * thread, and destroy a previously oppened video output thread.
  *****************************************************************************
  * Copyright (C) 2000-2001 VideoLAN
- * $Id: video_output.c,v 1.241 2003/11/26 08:18:09 gbazin Exp $
+ * $Id: video_output.c,v 1.242 2003/12/11 23:12:46 gbazin Exp $
  *
  * Authors: Vincent Seguin <seguin@via.ecp.fr>
  *
@@ -1008,6 +1008,31 @@ static void RunThread( vout_thread_t *p_vout)
                 p_vout->chroma.p_module->pf_activate( VLC_OBJECT(p_vout) );
             }
         }
+
+        if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE )
+        {
+            /* This happens when the picture buffers need to be recreated.
+             * This is useful on multimonitor displays for instance.
+             *
+             * Warning: This only works when the vout creates only 1 picture
+             * buffer!! */
+            p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE;
+
+            if( !p_vout->b_direct )
+            {
+                module_Unneed( p_vout, p_vout->chroma.p_module );
+            }
+
+            vlc_mutex_lock( &p_vout->picture_lock );
+
+            p_vout->pf_end( p_vout );
+
+            I_OUTPUTPICTURES = I_RENDERPICTURES = 0;
+
+            p_vout->b_error = InitThread( p_vout );
+
+            vlc_mutex_unlock( &p_vout->picture_lock );
+        }
     }
 
     /*