]> git.sesse.net Git - vlc/blobdiff - modules/video_output/directx/directx.c
* modules/*: sanitization of the modules description strings.
[vlc] / modules / video_output / directx / directx.c
index 89fba187b17de6caa1b9f2a150ec637b5304fd98..31f3d67bfd5429257798a6482fe65f75b49a946c 100644 (file)
@@ -2,7 +2,7 @@
  * vout.c: Windows DirectX video output display method
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: directx.c,v 1.7 2002/11/26 10:55:19 gbazin Exp $
+ * $Id: directx.c,v 1.16 2003/03/30 18:14:39 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -32,7 +32,7 @@
  * 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.
- * 
+ *
  *****************************************************************************/
 #include <errno.h>                                                 /* ENOMEM */
 #include <stdlib.h>                                                /* free() */
@@ -83,11 +83,14 @@ 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 );
-static int  DirectXGetSurfaceDesc ( vout_thread_t *p_vout, picture_t *p_pic );
+static int  DirectXLockSurface    ( vout_thread_t *p_vout, picture_t *p_pic );
+static int  DirectXUnlockSurface  ( vout_thread_t *p_vout, picture_t *p_pic );
 
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
+#define ON_TOP_TEXT N_("always on top")
+#define ON_TOP_LONGTEXT N_("place the directx window on top of other windows")
 #define HW_YUV_TEXT N_("use hardware YUV->RGB conversions")
 #define HW_YUV_LONGTEXT N_( \
     "Try to use hardware acceleration for YUV->RGB conversions. " \
@@ -98,17 +101,18 @@ static int  DirectXGetSurfaceDesc ( vout_thread_t *p_vout, picture_t *p_pic );
     "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." )
-#define WINDOW_TEXT N_("specify an existing window")
-#define WINDOW_LONGTEXT N_( \
-    "Specify a window to use instead of opening a new one. This option is " \
-    "DANGEROUS, use with care." )
+#define TRIPLEBUF_TEXT N_("use triple buffering for overlays")
+#define TRIPLEBUF_LONGTEXT N_( \
+    "Try to use triple bufferring when using YUV overlays. That results in " \
+    "much better video quality (no flickering)." )
 
 vlc_module_begin();
-    add_category_hint( N_("Video"), NULL );
-    add_bool( "directx-hw-yuv", 1, NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT );
-    add_bool( "directx-use-sysmem", 0, NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT );
-    add_integer( "directx-window", 0, NULL, WINDOW_TEXT, WINDOW_LONGTEXT );
-    set_description( _("DirectX video module") );
+    add_category_hint( N_("Video"), NULL, VLC_FALSE );
+    add_bool( "directx-on-top", 0, NULL, ON_TOP_TEXT, ON_TOP_LONGTEXT, VLC_FALSE );
+    add_bool( "directx-hw-yuv", 1, NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT, VLC_TRUE );
+    add_bool( "directx-use-sysmem", 0, NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT, VLC_TRUE );
+    add_bool( "directx-3buffering", 1, NULL, TRIPLEBUF_TEXT, TRIPLEBUF_LONGTEXT, VLC_TRUE );
+    set_description( _("DirectX video output") );
     set_capability( "video output", 100 );
     add_shortcut( "directx" );
     set_callbacks( OpenVideo, CloseVideo );
@@ -130,6 +134,7 @@ vlc_module_end();
 static int OpenVideo( vlc_object_t *p_this )
 {
     vout_thread_t * p_vout = (vout_thread_t *)p_this;
+    vlc_value_t val;
 
     /* Allocate structure */
     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
@@ -159,6 +164,7 @@ static int OpenVideo( vlc_object_t *p_this )
     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" );
 
     p_vout->p_sys->b_cursor_hidden = 0;
     p_vout->p_sys->i_lastmoved = mdate();
@@ -212,6 +218,11 @@ static int OpenVideo( vlc_object_t *p_this )
         goto error;
     }
 
+    /* Add a variable to indicate if the window should be on top of others */
+    var_Create( p_vout, "directx-on-top", VLC_VAR_BOOL );
+    val.b_bool = config_GetInt( p_vout, "directx-on-top" );
+    var_Set( p_vout, "directx-on-top", val );
+
     return VLC_SUCCESS;
 
  error:
@@ -322,11 +333,13 @@ static void End( vout_thread_t *p_vout )
  * Terminate an output method created by Create
  *****************************************************************************/
 static void CloseVideo( vlc_object_t *p_this )
-{   
+{
     vout_thread_t * p_vout = (vout_thread_t *)p_this;
-    
+
     msg_Dbg( p_vout, "CloseVideo" );
 
+    var_Destroy( p_vout, "directs-on-top" );
+
     DirectXCloseDisplay( p_vout );
     DirectXCloseDDraw( p_vout );
 
@@ -364,6 +377,9 @@ static void CloseVideo( vlc_object_t *p_this )
 static int Manage( vout_thread_t *p_vout )
 {
     WINDOWPLACEMENT window_placement;
+    HWND hwnd;
+    HMENU hMenu;
+    vlc_value_t val;
 
     /* If we do not control our window, we check for geometry changes
      * ourselves because the parent might not send us its events. */
@@ -378,7 +394,7 @@ static int Manage( vout_thread_t *p_vout )
      * decided to isolate PeekMessage in another thread. */
 
     /*
-     * Scale Change 
+     * Scale Change
      */
     if( p_vout->i_changes & VOUT_SCALE_CHANGE
          || p_vout->p_sys->i_changes & VOUT_SCALE_CHANGE )
@@ -393,7 +409,7 @@ static int Manage( vout_thread_t *p_vout )
     }
 
     /*
-     * Size Change 
+     * Size Change
      */
     if( p_vout->i_changes & VOUT_SIZE_CHANGE
         || p_vout->p_sys->i_changes & VOUT_SIZE_CHANGE )
@@ -455,6 +471,35 @@ static int Manage( vout_thread_t *p_vout )
         }
     }
 
+    /*
+     * "Always on top" status change
+     */
+    hwnd = p_vout->p_sys->hwnd;
+    hMenu = GetSystemMenu( hwnd , FALSE );
+    var_Get( p_vout, "directx-on-top", &val );
+    if( val.b_bool )
+    {
+        /* Set the window on top if necessary */
+        if( !( GetWindowLong( hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST ) )
+        {
+            CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
+                           MF_BYCOMMAND | MFS_CHECKED );
+            SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
+                           SWP_NOSIZE | SWP_NOMOVE );
+        }
+    }
+    else
+    {
+        /* The window shouldn't be on top */
+        if( GetWindowLong( hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST )
+        {
+            CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
+                           MF_BYCOMMAND | MFS_UNCHECKED );
+            SetWindowPos( hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
+                          SWP_NOSIZE | SWP_NOMOVE );
+        }
+    }
+
     /* Check if the event thread is still running */
     if( p_vout->p_sys->p_event->b_die )
     {
@@ -480,6 +525,16 @@ static void Display( vout_thread_t *p_vout, picture_t *p_pic )
         return;
     }
 
+    /* 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 )
+            DirectXUpdateOverlay( p_vout );
+    }
+
     if( !p_vout->p_sys->b_using_overlay )
     {
         DDBLTFX  ddbltfx;
@@ -495,20 +550,6 @@ static void Display( vout_thread_t *p_vout, picture_t *p_pic )
                                             p_pic->p_sys->p_surface,
                                             &p_vout->p_sys->rect_src_clipped,
                                             DDBLT_ASYNC, &ddbltfx );
-        if ( dxresult == DDERR_SURFACELOST )
-        {
-            /* Our surface can be lost so be sure
-             * to check this and restore it if needed */
-            IDirectDrawSurface2_Restore( p_vout->p_sys->p_display );
-
-            /* Now that the surface has been restored try to display again */
-            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 );
-        }
-
         if( dxresult != DD_OK )
         {
             msg_Warn( p_vout, "could not blit surface (error %i)", dxresult );
@@ -526,40 +567,22 @@ static void Display( vout_thread_t *p_vout, picture_t *p_pic )
 
         dxresult = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface,
                                              NULL, DDFLIP_WAIT );
-        if ( dxresult == DDERR_SURFACELOST )
-        {
-            /* Our surface can be lost so be sure
-             * to check this and restore it if needed */
-            IDirectDrawSurface2_Restore( p_vout->p_sys->p_display );
-            IDirectDrawSurface2_Restore( p_pic->p_sys->p_front_surface );
-
-            /* Now that the surface has been restored try to display again */
-            dxresult = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface,
-                                                 NULL, DDFLIP_WAIT );
-            DirectXUpdateOverlay( p_vout );
-        }
-
         if( dxresult != DD_OK )
         {
             msg_Warn( p_vout, "could not flip overlay (error %i)", dxresult );
         }
 
-        if( DirectXGetSurfaceDesc( p_vout, p_pic ) )
-        {
-            /* AAARRGG */
-            msg_Err( p_vout, "cannot get surface desc" );
-            return;
-        }
+        /* set currently displayed pic */
+        p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
 
-        if( UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma ) )
+        /* Lock surface to get all the required info */
+        if( DirectXLockSurface( p_vout, p_pic ) )
         {
             /* AAARRGG */
-            msg_Err( p_vout, "invalid pic chroma" );
+            msg_Warn( p_vout, "cannot lock surface" );
             return;
         }
-
-        /* set currently displayed pic */
-        p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
+        DirectXUnlockSurface( p_vout, p_pic );
     }
 }
 
@@ -586,8 +609,8 @@ static int DirectXInitDDraw( vout_thread_t *p_vout )
         msg_Warn( p_vout, "DirectXInitDDraw failed loading ddraw.dll" );
         goto error;
     }
-      
-    OurDirectDrawCreate = 
+
+    OurDirectDrawCreate =
       (void *)GetProcAddress(p_vout->p_sys->hddraw_dll, "DirectDrawCreate");
     if ( OurDirectDrawCreate == NULL )
     {
@@ -748,7 +771,7 @@ static int DirectXCreateClipper( vout_thread_t *p_vout )
         msg_Warn( p_vout, "cannot attach clipper to surface (error %i)",
                           dxresult );
         goto error;
-    }    
+    }
 
     return VLC_SUCCESS;
 
@@ -911,14 +934,12 @@ void DirectXUpdateOverlay( vout_thread_t *p_vout )
                                          &p_vout->p_sys->rect_src_clipped,
                                          p_vout->p_sys->p_display,
                                          &p_vout->p_sys->rect_dest_clipped,
-                                         dwFlags,
-                                         &ddofx );
+                                         dwFlags, &ddofx );
     if(dxresult != DD_OK)
     {
         msg_Warn( p_vout,
                   "DirectXUpdateOverlay cannot move or resize overlay" );
     }
-
 }
 
 /*****************************************************************************
@@ -1010,13 +1031,13 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
         /* Triple buffering rocks! it doesn't have any processing overhead
          * (you don't have to wait for the vsync) and provides for a very nice
          * video quality (no tearing). */
+        if( p_vout->p_sys->b_3buf_overlay )
+            i_ret = DirectXCreateSurface( p_vout, &p_surface,
+                                          p_vout->output.i_chroma,
+                                          p_vout->p_sys->b_using_overlay,
+                                          2 /* number of backbuffers */ );
 
-        i_ret = DirectXCreateSurface( p_vout, &p_surface,
-                                      p_vout->output.i_chroma,
-                                      p_vout->p_sys->b_using_overlay,
-                                      2 /* number of backbuffers */ );
-
-        if( i_ret != VLC_SUCCESS )
+        if( !p_vout->p_sys->b_3buf_overlay || i_ret != VLC_SUCCESS )
         {
             /* Try to reduce the number of backbuffers */
             i_ret = DirectXCreateSurface( p_vout, &p_surface,
@@ -1060,9 +1081,7 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
                 p_pic[0].p_sys->p_front_surface;
 
             /* Reset the front buffer memory */
-            if( !DirectXGetSurfaceDesc( p_vout, &front_pic ) &&
-                !UpdatePictureStruct( p_vout, &front_pic,
-                                      p_vout->output.i_chroma ) )
+            if( DirectXLockSurface( p_vout, &front_pic ) == VLC_SUCCESS )
             {
                 int i,j;
                 for( i = 0; i < front_pic.i_planes; i++ )
@@ -1070,6 +1089,8 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
                         memset( front_pic.p[i].p_pixels + j *
                                 front_pic.p[i].i_pitch, 127,
                                 front_pic.p[i].i_visible_pitch );
+
+                DirectXUnlockSurface( p_vout, &front_pic );
             }
 
             DirectXUpdateOverlay( p_vout );
@@ -1159,6 +1180,7 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
                 DirectXCloseSurface( p_vout, p_surface );
                 return VLC_ENOMEM;
             }
+
             p_pic[0].p_sys->p_surface = p_pic[0].p_sys->p_front_surface
                 = p_surface;
 
@@ -1176,25 +1198,19 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
     {
         p_pic[i].i_status = DESTROYED_PICTURE;
         p_pic[i].i_type   = DIRECT_PICTURE;
+        p_pic[i].pf_lock  = DirectXLockSurface;
+        p_pic[i].pf_unlock = DirectXUnlockSurface;
         PP_OUTPUTPICTURE[i] = &p_pic[i];
 
-        if( DirectXGetSurfaceDesc( p_vout, &p_pic[i] ) )
+        if( DirectXLockSurface( p_vout, &p_pic[i] ) != VLC_SUCCESS )
         {
             /* AAARRGG */
             FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
             I_OUTPUTPICTURES = 0;
+            msg_Err( p_vout, "cannot lock surface" );
             return VLC_EGENERIC;
         }
-
-        if( UpdatePictureStruct(p_vout, &p_pic[i], p_vout->output.i_chroma) )
-        {
-            /* Unknown chroma, tell the guy to get lost */
-            msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
-                     p_vout->output.i_chroma, (char*)&p_vout->output.i_chroma );
-            FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
-            I_OUTPUTPICTURES = 0;
-            return VLC_EGENERIC;
-        }
+        DirectXUnlockSurface( p_vout, &p_pic[i] );
     }
 
     msg_Dbg( p_vout, "End NewPictureVec (%s)",
@@ -1206,7 +1222,7 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
 /*****************************************************************************
  * FreePicture: destroy a picture vector allocated with NewPictureVec
  *****************************************************************************
- * 
+ *
  *****************************************************************************/
 static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
                             int i_num_pics )
@@ -1332,7 +1348,10 @@ static int UpdatePictureStruct( vout_thread_t *p_vout, picture_t *p_pic,
             break;
 
         default:
-            /* Not supported */
+            /* Unknown chroma, tell the guy to get lost */
+            msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
+                     p_vout->output.i_chroma,
+                     (char*)&p_vout->output.i_chroma );
             return VLC_EGENERIC;
     }
 
@@ -1393,12 +1412,12 @@ static void DirectXGetDDrawCaps( vout_thread_t *p_vout )
 }
 
 /*****************************************************************************
- * DirectXGetSurfaceDesc: Get some more information about the surface
+ * DirectXLockSurface: Lock surface and get picture data pointer
  *****************************************************************************
- * This function get and stores the surface descriptor which among things
- * has the pointer to the picture data.
+ * This function locks a surface and get the surface descriptor which amongst
+ * other things has the pointer to the picture data.
  *****************************************************************************/
-static int DirectXGetSurfaceDesc( vout_thread_t *p_vout, picture_t *p_pic )
+static int DirectXLockSurface( vout_thread_t *p_vout, picture_t *p_pic )
 {
     HRESULT dxresult;
 
@@ -1409,24 +1428,60 @@ static int DirectXGetSurfaceDesc( vout_thread_t *p_vout, picture_t *p_pic )
                                          NULL, &p_pic->p_sys->ddsd,
                                          DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
                                          NULL );
-    if ( dxresult == DDERR_SURFACELOST )
+    if( dxresult != DD_OK )
     {
-        /* Your surface can be lost so be sure
-         * to check this and restore it if needed */
-        dxresult = IDirectDrawSurface2_Restore( p_pic->p_sys->p_surface );
-        dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
+        if( dxresult == DDERR_INVALIDPARAMS )
+        {
+            /* DirectX 3 doesn't support the DDLOCK_NOSYSLOCK flag, resulting
+             * in an invalid params error */
+            dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
                                              &p_pic->p_sys->ddsd,
-                                             DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
-                                             NULL);
+                                             DDLOCK_WAIT, NULL);
+        }
+        if( dxresult == DDERR_SURFACELOST )
+        {
+            /* Your surface can be lost so be sure
+             * to check this and restore it if needed */
+
+            /* When using overlays with back-buffers, we need to restore
+             * the front buffer so the back-buffers get restored as well. */
+            if( p_vout->p_sys->b_using_overlay  )
+                IDirectDrawSurface2_Restore( p_pic->p_sys->p_front_surface );
+            else
+                IDirectDrawSurface2_Restore( p_pic->p_sys->p_surface );
+
+            dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
+                                                 &p_pic->p_sys->ddsd,
+                                                 DDLOCK_WAIT, NULL);
+            if( dxresult == DDERR_SURFACELOST )
+                msg_Dbg( p_vout, "DirectXLockSurface: DDERR_SURFACELOST" );
+        }
+        if( dxresult != DD_OK )
+        {
+            return VLC_EGENERIC;
+        }
     }
-    if( dxresult != DD_OK )
+
+    /* Now we have a pointer to the surface memory, we can update our picture
+     * structure. */
+    if( UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma )
+        != VLC_SUCCESS )
     {
-        msg_Err( p_vout, "DirectXGetSurfaceDesc cannot lock surface" );
+        DirectXUnlockSurface( p_vout, p_pic );
         return VLC_EGENERIC;
     }
+    else
+        return VLC_SUCCESS;      
+}
 
+/*****************************************************************************
+ * DirectXUnlockSurface: Unlock a surface locked by DirectXLockSurface().
+ *****************************************************************************/
+static int DirectXUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
+{
     /* Unlock the Surface */
-    dxresult = IDirectDrawSurface2_Unlock( p_pic->p_sys->p_surface, NULL );
-
-    return VLC_SUCCESS;
+    if( IDirectDrawSurface2_Unlock( p_pic->p_sys->p_surface, NULL ) == DD_OK )
+        return VLC_SUCCESS;
+    else
+        return VLC_EGENERIC;
 }