]> git.sesse.net Git - vlc/commitdiff
* modified the directx video plugin to try to create an YUV surface before
authorGildas Bazin <gbazin@videolan.org>
Sat, 18 May 2002 13:30:28 +0000 (13:30 +0000)
committerGildas Bazin <gbazin@videolan.org>
Sat, 18 May 2002 13:30:28 +0000 (13:30 +0000)
   falling back to an RGB surface when it's not possible to use overlays.
   Some graphic cards can do the YUV->RGB conversion in hardware during the
   blitting stage.
* in the directx video plugin, we now request that the RGB surface be created
   in video memory. The reasoning behind this is that usually surfaces in
   video memory benefit from more hardware acceleration (like for instance
   hw rescaling, hw blitting, etc...)
* added two options to the directx video plugin to disable the above features.
   (mainly because my video driver is buggy and doesn't handle them well).

* small cosmetic changes to the generation of the config file.

* fix for config_GetHomeDir() on win32. SHGetFolderPath() is located in
   shfolder.dll not shell32.dll.
* fix for the gtk preferences dialog box. To be sure that an int or float value
   is actually changed we call gtk_spin_button_update() in the
   GtkInt/FloatChanged() event handler.

plugins/directx/directx.c
plugins/directx/vout_directx.c
plugins/directx/vout_directx.h
plugins/directx/vout_events.c
plugins/gtk/gtk_preferences.c
src/misc/configuration.c

index 0e7304e72bd175e75da277683640abfe38c9cc7c..edfb61e0ed669c8adcc3e046cefca4d0f28fa501 100644 (file)
@@ -2,7 +2,7 @@
  * directx.c : Windows DirectX plugin for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: directx.c,v 1.7 2002/04/19 13:56:10 sam Exp $
+ * $Id: directx.c,v 1.8 2002/05/18 13:30:28 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *      
@@ -43,7 +43,22 @@ void _M( vout_getfunctions )( function_list_t * p_function_list );
 /*****************************************************************************
  * Building configuration tree
  *****************************************************************************/
+#define HW_YUV_TEXT N_("Disable hardware YUV->RGB conversions")
+#define HW_YUV_LONGTEXT N_( \
+    "Don't try to use hardware acceleration for YUV->RGB conversions. This " \
+    "option doesn't have any effect when using overlays." )
+#define SYSMEM_TEXT N_("Use video buffers in system memory")
+#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." )
+
 MODULE_CONFIG_START
+ADD_CATEGORY_HINT( N_("Video"), NULL )
+ADD_BOOL ( "no-directx-hw-yuv", NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT )
+ADD_BOOL ( "directx-use-sysmem", NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT )
+ADD_CATEGORY_HINT( N_("Audio"), NULL )
 MODULE_CONFIG_STOP
 
 MODULE_INIT_START
index 2d96d1555649c4c5da88a54194ee8db0cdcb07a3..7bdf56069907a2528b2ff553eed8f3e10bb90489 100644 (file)
@@ -2,7 +2,7 @@
  * vout_directx.c: Windows DirectX video output display method
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: vout_directx.c,v 1.32 2002/04/29 21:22:35 gbazin Exp $
+ * $Id: vout_directx.c,v 1.33 2002/05/18 13:30:28 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -129,6 +129,8 @@ static int vout_Create( vout_thread_t *p_vout )
     p_vout->p_sys->b_caps_overlay_clipping = 0;
     SetRectEmpty( &p_vout->p_sys->rect_display );
     p_vout->p_sys->b_using_overlay = !config_GetIntVariable( "nooverlay" );
+    p_vout->p_sys->b_use_sysmem = config_GetIntVariable( "directx-use-sysmem");
+    p_vout->p_sys->b_hw_yuv = !config_GetIntVariable( "no-directx-hw-yuv" );
 
     p_vout->p_sys->b_cursor_hidden = 0;
     p_vout->p_sys->i_lastmoved = mdate();
@@ -229,6 +231,9 @@ static int vout_Init( vout_thread_t *p_vout )
     p_vout->output.i_aspect = p_vout->render.i_aspect;
 
 #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 */
 
     NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
 
@@ -236,6 +241,9 @@ static int vout_Init( vout_thread_t *p_vout )
     if( p_vout->p_sys->b_using_overlay )
         SetWindowText( p_vout->p_sys->hwnd,
                        "VLC DirectX (using hardware overlay)" );
+    else if( p_vout->p_sys->b_hw_yuv )
+        SetWindowText( p_vout->p_sys->hwnd,
+                       "VLC DirectX (using hardware YUV->RGB conversion)" );
 
     return( 0 );
 }
@@ -409,14 +417,14 @@ static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
         /* We ask for the "NOTEARING" option */
         memset( &ddbltfx, 0, sizeof(DDBLTFX) );
         ddbltfx.dwSize = sizeof(DDBLTFX);
-        ddbltfx.dwDDFX = DDBLTFX_NOTEARING | DDBLT_ASYNC;
+        ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
 
         /* Blit video surface to display */
         dxresult = IDirectDrawSurface3_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,
-                                           0, &ddbltfx );
+                                           DDBLT_ASYNC, &ddbltfx );
         if ( dxresult == DDERR_SURFACELOST )
         {
             /* Our surface can be lost so be sure
@@ -428,7 +436,7 @@ static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
                                            &p_vout->p_sys->rect_dest_clipped,
                                            p_pic->p_sys->p_surface,
                                            &p_vout->p_sys->rect_src_clipped,
-                                           0, &ddbltfx );
+                                           DDBLT_ASYNC, &ddbltfx );
         }
 
         if( dxresult != DD_OK )
@@ -463,6 +471,7 @@ static void vout_Display( vout_thread_t *p_vout, picture_t *p_pic )
         if( dxresult != DD_OK )
             intf_WarnMsg( 8, "vout: couldn't flip overlay surface" );
 
+
         if( !DirectXGetSurfaceDesc( p_pic ) )
         {
             /* AAARRGG */
@@ -748,17 +757,32 @@ static int DirectXCreateSurface( vout_thread_t *p_vout,
 
     if( !b_overlay )
     {
-        /* Now try to create a plain RGB surface. */
+        boolean_t b_rgb_surface = ( i_chroma == FOURCC_RGB2 ) ||
+            ( i_chroma == FOURCC_RV15 ) || ( i_chroma == FOURCC_RV16 ) ||
+            ( i_chroma == FOURCC_RV24 ) || ( i_chroma == FOURCC_RV32 );
+
         memset( &ddsd, 0, sizeof( DDSURFACEDESC ) );
         ddsd.dwSize = sizeof(DDSURFACEDESC);
+        ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
         ddsd.dwFlags = DDSD_HEIGHT |
                        DDSD_WIDTH |
                        DDSD_CAPS;
-        ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN |
-                              DDSCAPS_SYSTEMMEMORY;
+        ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
         ddsd.dwHeight = p_vout->render.i_height;
         ddsd.dwWidth = p_vout->render.i_width;
 
+        if( p_vout->p_sys->b_use_sysmem )
+            ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+        else
+            ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
+
+        if( !b_rgb_surface )
+        {
+            ddsd.dwFlags |= DDSD_PIXELFORMAT;
+            ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
+            ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
+        }
+
         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
                                                &ddsd,
                                                &p_surface, NULL );
@@ -768,7 +792,7 @@ static int DirectXCreateSurface( vout_thread_t *p_vout,
             return 0;
         }
     }
-      
+
     /* Now that the surface is created, try to get a newer DirectX interface */
     dxresult = IDirectDrawSurface_QueryInterface( p_surface,
                                      &IID_IDirectDrawSurface3,
@@ -898,6 +922,7 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
                           int i_num_pics )
 {
     int i;
+    boolean_t b_result_ok;
     LPDIRECTDRAWSURFACE3 p_surface;
 
     intf_WarnMsg( 3, "vout: NewPictureVec" );
@@ -919,13 +944,8 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
         case FOURCC_YVYU:
             p_vout->output.i_chroma = FOURCC_YVYU;
             break;
-        case FOURCC_YV12:
-            p_vout->output.i_chroma = FOURCC_YV12;
-            break;
-        case FOURCC_I420:
-        case FOURCC_IYUV:
         default:
-            p_vout->output.i_chroma = FOURCC_IYUV;
+            p_vout->output.i_chroma = FOURCC_YV12;
             break;
     }
 
@@ -937,8 +957,6 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
      * memcpy() to the overlay surface. */
     if( p_vout->p_sys->b_using_overlay )
     {
-        boolean_t b_result_ok;
-
         /* 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). */
@@ -947,16 +965,6 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
                                             p_vout->output.i_chroma,
                                             p_vout->p_sys->b_using_overlay,
                                             2 /* number of backbuffers */ );
-        if( !b_result_ok )
-            /* Try another chroma */
-            if( p_vout->output.i_chroma == FOURCC_IYUV )
-            {
-                p_vout->output.i_chroma = FOURCC_YV12;
-                b_result_ok = DirectXCreateSurface( p_vout, &p_surface,
-                                                p_vout->output.i_chroma,
-                                                p_vout->p_sys->b_using_overlay,
-                                                2 /* number of backbuffers */);
-            }
 
         if( !b_result_ok )
             /* Try to reduce the number of backbuffers */
@@ -1023,67 +1031,80 @@ static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
         }
     }
 
-    /* As we can't have overlays, we'll try to create plain RBG surfaces in
-     * system memory. These surfaces will then be blitted onto the primary
-     * surface (display) so they can be displayed */
+    /* As we can't have an overlay, we'll try to create a plain offscreen
+     * surface. This surface will reside in video memory because there's a
+     * better chance then that we'll be able to use some kind of hardware
+     * acceleration like rescaling, blitting or YUV->RGB conversions.
+     * We then only need to blit this surface onto the main display when we
+     * want to display it */
     if( !p_vout->p_sys->b_using_overlay )
     {
-        DDPIXELFORMAT ddpfPixelFormat;
 
-        for( i = 0; i < i_num_pics; i++ )
+        if( p_vout->p_sys->b_hw_yuv )
+            b_result_ok = DirectXCreateSurface( p_vout, &p_surface,
+                                                p_vout->output.i_chroma,
+                                                p_vout->p_sys->b_using_overlay,
+                                                0 /* no back buffers */ );
+
+        if( !p_vout->p_sys->b_hw_yuv || !b_result_ok )
         {
-            if( DirectXCreateSurface( p_vout, &p_surface,
-                                      p_vout->output.i_chroma,
-                                      p_vout->p_sys->b_using_overlay,
-                                      0 /* no back buffers */ ) )
+            /* Our last choice is to use a plain RGB surface */
+            DDPIXELFORMAT ddpfPixelFormat;
+
+            ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
+            IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
+                                                &ddpfPixelFormat );
+
+            if( ddpfPixelFormat.dwFlags & DDPF_RGB )
             {
-                /* Allocate internal structure */
-                p_pic[i].p_sys = malloc( sizeof( picture_sys_t ) );
-                if( p_pic[i].p_sys == NULL )
+                switch( ddpfPixelFormat.dwRGBBitCount )
                 {
-                    DirectXCloseSurface( p_vout, p_surface );
-                    FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
-                    I_OUTPUTPICTURES = 0;
-                    return -1;
+                case 8: /* FIXME: set the palette */
+                    p_vout->output.i_chroma = FOURCC_RGB2; break;
+                case 15:
+                    p_vout->output.i_chroma = FOURCC_RV15; break;
+                case 16:
+                    p_vout->output.i_chroma = FOURCC_RV16; break;
+                case 24:
+                    p_vout->output.i_chroma = FOURCC_RV24; break;
+                case 32:
+                    p_vout->output.i_chroma = FOURCC_RV32; break;
+                default:
+                    intf_ErrMsg( "vout error: unknown screen depth" );
+                    return( 0 );
                 }
-                p_pic[i].p_sys->p_surface = p_surface;
-                p_pic[i].p_sys->p_front_surface = NULL;
-                I_OUTPUTPICTURES++;
-
+                p_vout->output.i_rmask = ddpfPixelFormat.dwRBitMask;
+                p_vout->output.i_gmask = ddpfPixelFormat.dwGBitMask;
+                p_vout->output.i_bmask = ddpfPixelFormat.dwBBitMask;
             }
-            else break;
+
+            p_vout->p_sys->b_hw_yuv = 0;
+
+            b_result_ok = DirectXCreateSurface( p_vout, &p_surface,
+                                                p_vout->output.i_chroma,
+                                                p_vout->p_sys->b_using_overlay,
+                                                0 /* no back buffers */ );
         }
 
-        if( I_OUTPUTPICTURES )
-            intf_WarnMsg( 3,"vout: DirectX RGB surface created successfully" );
-        else
-            intf_ErrMsg( "vout error: can't create RGB surface." );
-
-        /* We couldn't use an YUV overlay so we need to indicate to
-         * video_output which format we are falling back to */
-        ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
-        IDirectDrawSurface3_GetPixelFormat( p_vout->p_sys->p_display,
-                                            &ddpfPixelFormat );
-        switch( ddpfPixelFormat.dwRGBBitCount )
+        if( b_result_ok )
         {
-            case 8: /* FIXME: set the palette */
-                p_vout->output.i_chroma = FOURCC_RGB2; break;
-            case 15:
-                p_vout->output.i_chroma = FOURCC_RV15; break;
-            case 16:
-                p_vout->output.i_chroma = FOURCC_RV16; break;
-            case 24:
-                p_vout->output.i_chroma = FOURCC_RV24; break;
-            case 32:
-                p_vout->output.i_chroma = FOURCC_RV32; break;
-            default:
-                intf_ErrMsg( "vout error: unknown screen depth" );
-                return( 0 );
-        }
-        p_vout->output.i_rmask = ddpfPixelFormat.dwRBitMask;
-        p_vout->output.i_gmask = ddpfPixelFormat.dwGBitMask;
-        p_vout->output.i_bmask = ddpfPixelFormat.dwBBitMask;
+            /* Allocate internal structure */
+            p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) );
+            if( p_pic[0].p_sys == NULL )
+            {
+                DirectXCloseSurface( p_vout, p_surface );
+                return -1;
+            }
+            p_pic[0].p_sys->p_surface = p_pic[0].p_sys->p_front_surface
+                = p_surface;
 
+            I_OUTPUTPICTURES = 1;
+
+            intf_WarnMsg( 3, "vout: DirectX plain surface created "
+                             "successfully" );
+        }
+        else
+            intf_ErrMsg( "vout error: DirectX can't create plain surface." );
     }
 
 
@@ -1132,13 +1153,7 @@ static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
 
     for( i = 0; i < i_num_pics; i++ )
     {
-#if 0
-        if( p_pic->p_sys->p_front_surface && 
-            ( p_pic->p_sys->p_surface != p_pic->p_sys->p_front_surface ) )
-            DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface );
-#endif
-
-        DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_surface );
+        DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface );
 
         for( i = 0; i < i_num_pics; i++ )
         {
index fc58806d18b49ae86872e13f9e7bdad2dbee96b7..6d0fe2f9bca1e9004bfbc76f4753e64d5d89cbb4 100644 (file)
@@ -2,7 +2,7 @@
  * vout_directx.h: Windows DirectX video output header file
  *****************************************************************************
  * Copyright (C) 1998, 1999, 2000 VideoLAN
- * $Id: vout_directx.h,v 1.5 2002/04/23 22:07:05 gbazin Exp $
+ * $Id: vout_directx.h,v 1.6 2002/05/18 13:30:28 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -39,6 +39,8 @@ typedef struct vout_sys_s
     HWND                 hwnd;                  /* Handle of the main window */
 
     boolean_t    b_using_overlay;         /* Are we using an overlay surface */
+    boolean_t    b_use_sysmem;   /* Should we use system memory for surfaces */
+    boolean_t    b_hw_yuv;    /* Should we use hardware YUV->RGB conversions */
 
     /* size of the display */
     RECT         rect_display;
@@ -73,7 +75,7 @@ typedef struct vout_sys_s
     vlc_cond_t   event_thread_wait;
 
     volatile int i_event_thread_status;         /* DirectXEventThread status */
-    boolean_t    b_event_thread_die;        /* flag to kill the event thread */
+    volatile boolean_t b_event_thread_die;  /* flag to kill the event thread */
 
 } vout_sys_t;
 
index 6ae3b6be3fd377c27819484daff5186f8edb25f8..4ff8d8db260c37e9255a4a63d115f1179f27eddb 100644 (file)
@@ -2,7 +2,7 @@
  * vout_events.c: Windows DirectX video output events handler
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: vout_events.c,v 1.15 2002/04/24 23:49:32 gbazin Exp $
+ * $Id: vout_events.c,v 1.16 2002/05/18 13:30:28 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -142,7 +142,7 @@ void DirectXEventThread( vout_thread_t *p_vout )
             case VK_ESCAPE:
             case VK_F12:
                 /* exit application */
-                p_main->p_intf->b_die = 1;
+                p_main->p_intf->b_die = p_vout->p_sys->b_event_thread_die = 1;
                 break;
             }
             TranslateMessage(&msg);
@@ -154,7 +154,7 @@ void DirectXEventThread( vout_thread_t *p_vout )
             case 'q':
             case 'Q':
                 /* exit application */
-                p_main->p_intf->b_die = 1;
+                p_main->p_intf->b_die = p_vout->p_sys->b_event_thread_die = 1;
                 break;
 
             case 'f':                            /* switch to fullscreen */
@@ -512,7 +512,9 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
             DirectXUpdateOverlay( p_vout );
 
         /* signal the size change */
-        p_vout->p_sys->i_changes |= VOUT_SIZE_CHANGE;
+        if( !p_vout->p_sys->b_using_overlay &&
+            !p_vout->p_sys->b_event_thread_die )
+            p_vout->p_sys->i_changes |= VOUT_SIZE_CHANGE;
 
         return 0;
         }
@@ -522,7 +524,8 @@ static long FAR PASCAL DirectXEventProc( HWND hwnd, UINT message,
     case WM_CLOSE:
         intf_WarnMsg( 4, "vout: WinProc WM_CLOSE" );
         /* exit application */
-        p_main->p_intf->b_die = 1;
+        p_vout = (vout_thread_t *)GetWindowLong( hwnd, GWL_USERDATA );
+        p_main->p_intf->b_die = p_vout->p_sys->b_event_thread_die = 1;
         return 0;
         break;
 
index ce350dc57b65a4c0f06886935cebf88eae73ac53..f70f8d55a2792372e894aff0c09dd4e8ced9e38e 100644 (file)
@@ -2,7 +2,7 @@
  * gtk_preferences.c: functions to handle the preferences dialog box.
  *****************************************************************************
  * Copyright (C) 2000, 2001 VideoLAN
- * $Id: gtk_preferences.c,v 1.27 2002/05/04 16:17:08 gbazin Exp $
+ * $Id: gtk_preferences.c,v 1.28 2002/05/18 13:30:28 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *          Loïc Minier <lool@via.ecp.fr>
@@ -733,6 +733,7 @@ static void GtkIntChanged( GtkEditable *editable, gpointer user_data )
 
     p_config = malloc( sizeof(module_config_t) );
     p_config->i_type = MODULE_CONFIG_ITEM_INTEGER;
+    gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
     p_config->i_value = gtk_spin_button_get_value_as_int(
                             GTK_SPIN_BUTTON(editable) );
     p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
@@ -767,6 +768,7 @@ static void GtkFloatChanged( GtkEditable *editable, gpointer user_data )
 
     p_config = malloc( sizeof(module_config_t) );
     p_config->i_type = MODULE_CONFIG_ITEM_FLOAT;
+    gtk_spin_button_update( GTK_SPIN_BUTTON(editable) );
     p_config->f_value = gtk_spin_button_get_value_as_float(
                            GTK_SPIN_BUTTON(editable) );
     p_config->psz_name = (char *)gtk_object_get_data( GTK_OBJECT(editable),
index 67cf1d7f251162bd4bf6162d159f3a45b79235c0..f2e95248d94a3964693d067c8ea9dc2dd4615242 100644 (file)
@@ -2,7 +2,7 @@
  * configuration.c management of the modules configuration
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: configuration.c,v 1.23 2002/05/15 01:29:07 sam Exp $
+ * $Id: configuration.c,v 1.24 2002/05/18 13:30:28 gbazin Exp $
  *
  * Authors: Gildas Bazin <gbazin@netcourrier.com>
  *
@@ -411,8 +411,8 @@ int config_LoadConfigFile( const char *psz_module_name )
     file = fopen( psz_filename, "rt" );
     if( !file )
     {
-        intf_WarnMsg( 1, "config: couldn't open config file %s for reading (%s)",
-                         psz_filename, strerror(errno) );
+        intf_WarnMsg( 1, "config: config file %s doesn't already exist",
+                         psz_filename );
         free( psz_filename );
         vlc_mutex_unlock( &p_main->config_lock );
         return -1;
@@ -450,7 +450,8 @@ int config_LoadConfigFile( const char *psz_module_name )
             if( line[0] == '[' ) break; /* end of section */
 
             /* ignore comments or empty lines */
-            if( (line[0] == '#') || (line[0] == (char)0) ) continue;
+            if( (line[0] == '#') || (line[0] == '\n') || (line[0] == (char)0) )
+                continue;
 
             /* get rid of line feed */
             if( line[strlen(line)-1] == '\n' )
@@ -599,8 +600,8 @@ int config_SaveConfigFile( const char *psz_module_name )
     file = fopen( psz_filename, "rt" );
     if( !file )
     {
-        intf_WarnMsg( 1, "config: couldn't open config file %s for reading (%s)",
-                         psz_filename, strerror(errno) );
+        intf_WarnMsg( 1, "config: config file %s doesn't already exist",
+                         psz_filename );
     }
     else
     {
@@ -702,10 +703,11 @@ int config_SaveConfigFile( const char *psz_module_name )
         intf_WarnMsg( 5, "config: saving config for module <%s>",
                          p_module->psz_name );
 
-        fprintf( file, "[%s]\n", p_module->psz_name );
-
+        fprintf( file, "[%s]", p_module->psz_name );
         if( p_module->psz_longname )
-            fprintf( file, "###\n###  %s\n###\n", p_module->psz_longname );
+            fprintf( file, " # %s\n\n", p_module->psz_longname );
+        else
+            fprintf( file, "\n\n" );
 
         for( p_item = p_module->p_config;
              p_item->i_type != MODULE_CONFIG_HINT_END;
@@ -1022,13 +1024,13 @@ char *config_GetHomeDir( void )
 #   define CSIDL_APPDATA 0x1A
 #   define SHGFP_TYPE_CURRENT 0
 
-    HINSTANCE shell32_dll;
+    HINSTANCE shfolder_dll;
     SHGETFOLDERPATH SHGetFolderPath ;
 
     /* load the shell32 dll to retreive SHGetFolderPath */
-    if( ( shell32_dll = LoadLibrary("shell32.dll") ) != NULL )
+    if( ( shfolder_dll = LoadLibrary("shfolder.dll") ) != NULL )
     {
-        SHGetFolderPath = (void *)GetProcAddress( shell32_dll,
+        SHGetFolderPath = (void *)GetProcAddress( shfolder_dll,
                                                   "SHGetFolderPathA" );
         if ( SHGetFolderPath != NULL )
         {
@@ -1045,12 +1047,12 @@ char *config_GetHomeDir( void )
                                          NULL, SHGFP_TYPE_CURRENT,
                                          p_homedir ) )
             {
-                FreeLibrary( shell32_dll );
+                FreeLibrary( shfolder_dll );
                 return p_homedir;
             }
             free( p_homedir );
         }
-        FreeLibrary( shell32_dll );
+        FreeLibrary( shfolder_dll );
     }
 #endif