directx.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:79k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * vout.c: Windows DirectX video output display method
  3.  *****************************************************************************
  4.  * Copyright (C) 2001-2004 VideoLAN
  5.  * $Id: directx.c 9269 2004-11-10 13:04:45Z gbazin $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@videolan.org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble:
  25.  *
  26.  * This plugin will use YUV overlay if supported, using overlay will result in
  27.  * the best video quality (hardware interpolation when rescaling the picture)
  28.  * and the fastest display as it requires less processing.
  29.  *
  30.  * If YUV overlay is not supported this plugin will use RGB offscreen video
  31.  * surfaces that will be blitted onto the primary surface (display) to
  32.  * effectively display the pictures. This fallback method also enables us to
  33.  * display video in window mode.
  34.  *
  35.  *****************************************************************************/
  36. #include <errno.h>                                                 /* ENOMEM */
  37. #include <stdlib.h>                                                /* free() */
  38. #include <string.h>                                            /* strerror() */
  39. #include <vlc/vlc.h>
  40. #include <vlc/intf.h>
  41. #include <vlc/vout.h>
  42. #include <windows.h>
  43. #include <ddraw.h>
  44. #include <commctrl.h>
  45. #include <multimon.h>
  46. #undef GetSystemMetrics
  47. #ifndef MONITOR_DEFAULTTONEAREST
  48. #   define MONITOR_DEFAULTTONEAREST 2
  49. #endif
  50. #include "vout.h"
  51. /*****************************************************************************
  52.  * DirectDraw GUIDs.
  53.  * Defining them here allows us to get rid of the dxguid library during
  54.  * the linking stage.
  55.  *****************************************************************************/
  56. #include <initguid.h>
  57. DEFINE_GUID( IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 );
  58. DEFINE_GUID( IID_IDirectDrawSurface2, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27 );
  59. /*****************************************************************************
  60.  * Local prototypes.
  61.  *****************************************************************************/
  62. static int  OpenVideo  ( vlc_object_t * );
  63. static void CloseVideo ( vlc_object_t * );
  64. static int  Init      ( vout_thread_t * );
  65. static void End       ( vout_thread_t * );
  66. static int  Manage    ( vout_thread_t * );
  67. static void Display   ( vout_thread_t *, picture_t * );
  68. static int  NewPictureVec  ( vout_thread_t *, picture_t *, int );
  69. static void FreePictureVec ( vout_thread_t *, picture_t *, int );
  70. static int  UpdatePictureStruct( vout_thread_t *, picture_t *, int );
  71. static int  DirectXInitDDraw      ( vout_thread_t *p_vout );
  72. static void DirectXCloseDDraw     ( vout_thread_t *p_vout );
  73. static int  DirectXCreateDisplay  ( vout_thread_t *p_vout );
  74. static void DirectXCloseDisplay   ( vout_thread_t *p_vout );
  75. static int  DirectXCreateSurface  ( vout_thread_t *p_vout,
  76.                                     LPDIRECTDRAWSURFACE2 *, int, int, int );
  77. static void DirectXCloseSurface   ( vout_thread_t *p_vout,
  78.                                     LPDIRECTDRAWSURFACE2 );
  79. static int  DirectXCreateClipper  ( vout_thread_t *p_vout );
  80. static void DirectXGetDDrawCaps   ( vout_thread_t *p_vout );
  81. static int  DirectXLockSurface    ( vout_thread_t *p_vout, picture_t *p_pic );
  82. static int  DirectXUnlockSurface  ( vout_thread_t *p_vout, picture_t *p_pic );
  83. static DWORD DirectXFindColorkey( vout_thread_t *p_vout, uint32_t i_color );
  84. void SwitchWallpaperMode( vout_thread_t *, vlc_bool_t );
  85. /* Object variables callbacks */
  86. static int FindDevicesCallback( vlc_object_t *, char const *,
  87.                                 vlc_value_t, vlc_value_t, void * );
  88. static int WallpaperCallback( vlc_object_t *, char const *,
  89.                               vlc_value_t, vlc_value_t, void * );
  90. /*****************************************************************************
  91.  * Module descriptor
  92.  *****************************************************************************/
  93. #define HW_YUV_TEXT N_("Use hardware YUV->RGB conversions")
  94. #define HW_YUV_LONGTEXT N_( 
  95.     "Try to use hardware acceleration for YUV->RGB conversions. " 
  96.     "This option doesn't have any effect when using overlays." )
  97. #define SYSMEM_TEXT N_("Use video buffers in system memory")
  98. #define SYSMEM_LONGTEXT N_( 
  99.     "Create video buffers in system memory instead of video memory. This " 
  100.     "isn't recommended as usually using video memory allows to benefit from " 
  101.     "more hardware acceleration (like rescaling or YUV->RGB conversions). " 
  102.     "This option doesn't have any effect when using overlays." )
  103. #define TRIPLEBUF_TEXT N_("Use triple buffering for overlays")
  104. #define TRIPLEBUF_LONGTEXT N_( 
  105.     "Try to use triple buffering when using YUV overlays. That results in " 
  106.     "much better video quality (no flickering)." )
  107. #define DEVICE_TEXT N_("Name of desired display device")
  108. #define DEVICE_LONGTEXT N_("In a multiple monitor configuration, you can " 
  109.     "specify the Windows device name of the display that you want the video " 
  110.     "window to open on. For example, "\\.\DISPLAY1" or " 
  111.     ""\\.\DISPLAY2"." )
  112. #define WALLPAPER_TEXT N_("Enable wallpaper mode ")
  113. #define WALLPAPER_LONGTEXT N_( 
  114.     "The wallpaper mode allows you to display the video as the desktop " 
  115.     "background. Note that this feature only works in overlay mode and " 
  116.     "the desktop must not already have a wallpaper." )
  117. static char *ppsz_dev[] = { "" };
  118. static char *ppsz_dev_text[] = { N_("Default") };
  119. vlc_module_begin();
  120.     add_bool( "directx-hw-yuv", 1, NULL, HW_YUV_TEXT, HW_YUV_LONGTEXT,
  121.               VLC_TRUE );
  122.     add_bool( "directx-use-sysmem", 0, NULL, SYSMEM_TEXT, SYSMEM_LONGTEXT,
  123.               VLC_TRUE );
  124.     add_bool( "directx-3buffering", 1, NULL, TRIPLEBUF_TEXT,
  125.               TRIPLEBUF_LONGTEXT, VLC_TRUE );
  126.     add_string( "directx-device", "", NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
  127.                 VLC_TRUE );
  128.         change_string_list( ppsz_dev, ppsz_dev_text, FindDevicesCallback );
  129.         change_action_add( FindDevicesCallback, N_("Refresh list") );
  130.     add_bool( "directx-wallpaper", 0, NULL, WALLPAPER_TEXT, WALLPAPER_LONGTEXT,
  131.               VLC_TRUE );
  132.     set_description( _("DirectX video output") );
  133.     set_capability( "video output", 100 );
  134.     add_shortcut( "directx" );
  135.     set_callbacks( OpenVideo, CloseVideo );
  136. vlc_module_end();
  137. #if 0 /* FIXME */
  138.     /* check if we registered a window class because we need to
  139.      * unregister it */
  140.     WNDCLASS wndclass;
  141.     if( GetClassInfo( GetModuleHandle(NULL), "VLC DirectX", &wndclass ) )
  142.         UnregisterClass( "VLC DirectX", GetModuleHandle(NULL) );
  143. #endif
  144. /*****************************************************************************
  145.  * OpenVideo: allocate DirectX video thread output method
  146.  *****************************************************************************
  147.  * This function allocates and initialize the DirectX vout method.
  148.  *****************************************************************************/
  149. static int OpenVideo( vlc_object_t *p_this )
  150. {
  151.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  152.     vlc_value_t val;
  153.     HMODULE huser32;
  154.     /* Allocate structure */
  155.     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
  156.     if( p_vout->p_sys == NULL )
  157.     {
  158.         msg_Err( p_vout, "out of memory" );
  159.         return VLC_ENOMEM;
  160.     }
  161.     memset( p_vout->p_sys, 0, sizeof( vout_sys_t ) );
  162.     /* Initialisations */
  163.     p_vout->pf_init = Init;
  164.     p_vout->pf_end = End;
  165.     p_vout->pf_manage = Manage;
  166.     p_vout->pf_render = NULL;
  167.     p_vout->pf_display = Display;
  168.     p_vout->p_sys->p_ddobject = NULL;
  169.     p_vout->p_sys->p_display = NULL;
  170.     p_vout->p_sys->p_current_surface = NULL;
  171.     p_vout->p_sys->p_clipper = NULL;
  172.     p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
  173.     p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
  174.     p_vout->p_sys->i_changes = 0;
  175.     p_vout->p_sys->b_wallpaper = 0;
  176.     vlc_mutex_init( p_vout, &p_vout->p_sys->lock );
  177.     SetRectEmpty( &p_vout->p_sys->rect_display );
  178.     SetRectEmpty( &p_vout->p_sys->rect_parent );
  179.     /* Multimonitor stuff */
  180.     p_vout->p_sys->hmonitor = NULL;
  181.     p_vout->p_sys->p_display_driver = NULL;
  182.     p_vout->p_sys->MonitorFromWindow = NULL;
  183.     p_vout->p_sys->GetMonitorInfo = NULL;
  184.     if( (huser32 = GetModuleHandle( "USER32" ) ) )
  185.     {
  186.         p_vout->p_sys->MonitorFromWindow =
  187.             GetProcAddress( huser32, "MonitorFromWindow" );
  188.         p_vout->p_sys->GetMonitorInfo =
  189.             GetProcAddress( huser32, "GetMonitorInfoA" );
  190.     }
  191.     var_Create( p_vout, "overlay", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  192.     var_Create( p_vout, "directx-use-sysmem", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
  193.     var_Create( p_vout, "directx-hw-yuv", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
  194.     var_Create( p_vout, "directx-3buffering", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
  195.     var_Create( p_vout, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  196.     var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
  197.     p_vout->p_sys->b_cursor_hidden = 0;
  198.     p_vout->p_sys->i_lastmoved = mdate();
  199.     /* Set main window's size */
  200.     p_vout->p_sys->i_window_width = p_vout->i_window_width;
  201.     p_vout->p_sys->i_window_height = p_vout->i_window_height;
  202.     /* Create the DirectXEventThread, this thread is created by us to isolate
  203.      * the Win32 PeekMessage function calls. We want to do this because
  204.      * Windows can stay blocked inside this call for a long time, and when
  205.      * this happens it thus blocks vlc's video_output thread.
  206.      * DirectXEventThread will take care of the creation of the video
  207.      * window (because PeekMessage has to be called from the same thread which
  208.      * created the window). */
  209.     msg_Dbg( p_vout, "creating DirectXEventThread" );
  210.     p_vout->p_sys->p_event =
  211.         vlc_object_create( p_vout, sizeof(event_thread_t) );
  212.     p_vout->p_sys->p_event->p_vout = p_vout;
  213.     if( vlc_thread_create( p_vout->p_sys->p_event, "DirectX Events Thread",
  214.                            DirectXEventThread, 0, 1 ) )
  215.     {
  216.         msg_Err( p_vout, "cannot create DirectXEventThread" );
  217.         vlc_object_destroy( p_vout->p_sys->p_event );
  218.         p_vout->p_sys->p_event = NULL;
  219.         goto error;
  220.     }
  221.     if( p_vout->p_sys->p_event->b_error )
  222.     {
  223.         msg_Err( p_vout, "DirectXEventThread failed" );
  224.         goto error;
  225.     }
  226.     vlc_object_attach( p_vout->p_sys->p_event, p_vout );
  227.     msg_Dbg( p_vout, "DirectXEventThread running" );
  228.     /* Initialise DirectDraw */
  229.     if( DirectXInitDDraw( p_vout ) )
  230.     {
  231.         msg_Err( p_vout, "cannot initialize DirectDraw" );
  232.         goto error;
  233.     }
  234.     /* Create the directx display */
  235.     if( DirectXCreateDisplay( p_vout ) )
  236.     {
  237.         msg_Err( p_vout, "cannot initialize DirectDraw" );
  238.         goto error;
  239.     }
  240.     /* Variable to indicate if the window should be on top of others */
  241.     /* Trigger a callback right now */
  242.     var_Get( p_vout, "video-on-top", &val );
  243.     var_Set( p_vout, "video-on-top", val );
  244.     /* Variable to indicate if the window should be on top of others */
  245.     /* Trigger a callback right now */
  246.     var_Create( p_vout, "directx-wallpaper", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
  247.     val.psz_string = _("Wallpaper");
  248.     var_Change( p_vout, "directx-wallpaper", VLC_VAR_SETTEXT, &val, NULL );
  249.     var_AddCallback( p_vout, "directx-wallpaper", WallpaperCallback, NULL );
  250.     var_Get( p_vout, "directx-wallpaper", &val );
  251.     var_Set( p_vout, "directx-wallpaper", val );
  252.     return VLC_SUCCESS;
  253.  error:
  254.     CloseVideo( VLC_OBJECT(p_vout) );
  255.     return VLC_EGENERIC;
  256. }
  257. /*****************************************************************************
  258.  * Init: initialize DirectX video thread output method
  259.  *****************************************************************************
  260.  * This function create the directx surfaces needed by the output thread.
  261.  * It is called at the beginning of the thread.
  262.  *****************************************************************************/
  263. static int Init( vout_thread_t *p_vout )
  264. {
  265.     int i_chroma_backup;
  266.     vlc_value_t val;
  267.     /* Get a few default parameters */
  268.     var_Get( p_vout, "overlay", &val );
  269.     p_vout->p_sys->b_using_overlay = val.b_bool;
  270.     var_Get( p_vout, "directx-use-sysmem", &val );
  271.     p_vout->p_sys->b_use_sysmem = val.b_bool;
  272.     var_Get( p_vout, "directx-hw-yuv", &val );
  273.     p_vout->p_sys->b_hw_yuv = val.b_bool;
  274.     var_Get( p_vout, "directx-3buffering", &val );
  275.     p_vout->p_sys->b_3buf_overlay = val.b_bool;
  276.     /* Initialise DirectDraw if not already done.
  277.      * We do this here because on multi-monitor systems we may have to
  278.      * re-create the directdraw surfaces. */
  279.     if( !p_vout->p_sys->p_ddobject &&
  280.         DirectXInitDDraw( p_vout ) != VLC_SUCCESS )
  281.     {
  282.         msg_Err( p_vout, "cannot initialize DirectDraw" );
  283.         return VLC_EGENERIC;
  284.     }
  285.     /* Create the directx display */
  286.     if( !p_vout->p_sys->p_display &&
  287.         DirectXCreateDisplay( p_vout ) != VLC_SUCCESS )
  288.     {
  289.         msg_Err( p_vout, "cannot initialize DirectDraw" );
  290.         return VLC_EGENERIC;
  291.     }
  292.     /* Initialize the output structure.
  293.      * Since DirectDraw can do rescaling for us, stick to the default
  294.      * coordinates and aspect. */
  295.     p_vout->output.i_width  = p_vout->render.i_width;
  296.     p_vout->output.i_height = p_vout->render.i_height;
  297.     p_vout->output.i_aspect = p_vout->render.i_aspect;
  298. #define MAX_DIRECTBUFFERS 1
  299.     /* Right now we use only 1 directbuffer because we don't want the
  300.      * video decoder to decode directly into direct buffers as they are
  301.      * created into video memory and video memory is _really_ slow */
  302.     /* Choose the chroma we will try first. */
  303.     switch( p_vout->render.i_chroma )
  304.     {
  305.         case VLC_FOURCC('Y','U','Y','2'):
  306.         case VLC_FOURCC('Y','U','N','V'):
  307.             p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
  308.             break;
  309.         case VLC_FOURCC('U','Y','V','Y'):
  310.         case VLC_FOURCC('U','Y','N','V'):
  311.         case VLC_FOURCC('Y','4','2','2'):
  312.             p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y');
  313.             break;
  314.         case VLC_FOURCC('Y','V','Y','U'):
  315.             p_vout->output.i_chroma = VLC_FOURCC('Y','V','Y','U');
  316.             break;
  317.         default:
  318.             p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
  319.             break;
  320.     }
  321.     NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
  322.     i_chroma_backup = p_vout->output.i_chroma;
  323.     if( !I_OUTPUTPICTURES )
  324.     {
  325.         /* hmmm, it didn't work! Let's try commonly supported chromas */
  326.         if( p_vout->output.i_chroma != VLC_FOURCC('I','4','2','0') )
  327.         {
  328.             p_vout->output.i_chroma = VLC_FOURCC('Y','V','1','2');
  329.             NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
  330.         }
  331.         if( !I_OUTPUTPICTURES )
  332.         {
  333.             /* hmmm, it still didn't work! Let's try another one */
  334.             p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
  335.             NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
  336.         }
  337.     }
  338.     if( !I_OUTPUTPICTURES )
  339.     {
  340.         /* If it still didn't work then don't try to use an overlay */
  341.         p_vout->output.i_chroma = i_chroma_backup;
  342.         p_vout->p_sys->b_using_overlay = 0;
  343.         NewPictureVec( p_vout, p_vout->p_picture, MAX_DIRECTBUFFERS );
  344.     }
  345.     /* Change the window title bar text */
  346.     PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
  347.     return VLC_SUCCESS;
  348. }
  349. /*****************************************************************************
  350.  * End: terminate Sys video thread output method
  351.  *****************************************************************************
  352.  * Terminate an output method created by Create.
  353.  * It is called at the end of the thread.
  354.  *****************************************************************************/
  355. static void End( vout_thread_t *p_vout )
  356. {
  357.     FreePictureVec( p_vout, p_vout->p_picture, I_OUTPUTPICTURES );
  358.     DirectXCloseDisplay( p_vout );
  359.     DirectXCloseDDraw( p_vout );
  360.     return;
  361. }
  362. /*****************************************************************************
  363.  * CloseVideo: destroy Sys video thread output method
  364.  *****************************************************************************
  365.  * Terminate an output method created by Create
  366.  *****************************************************************************/
  367. static void CloseVideo( vlc_object_t *p_this )
  368. {
  369.     vout_thread_t * p_vout = (vout_thread_t *)p_this;
  370.     msg_Dbg( p_vout, "CloseVideo" );
  371.     if( p_vout->p_sys->p_event )
  372.     {
  373.         vlc_object_detach( p_vout->p_sys->p_event );
  374.         /* Kill DirectXEventThread */
  375.         p_vout->p_sys->p_event->b_die = VLC_TRUE;
  376.         /* we need to be sure DirectXEventThread won't stay stuck in
  377.          * GetMessage, so we send a fake message */
  378.         if( p_vout->p_sys->hwnd )
  379.         {
  380.             PostMessage( p_vout->p_sys->hwnd, WM_NULL, 0, 0);
  381.         }
  382.         vlc_thread_join( p_vout->p_sys->p_event );
  383.         vlc_object_destroy( p_vout->p_sys->p_event );
  384.     }
  385.     vlc_mutex_destroy( &p_vout->p_sys->lock );
  386.     /* Make sure the wallpaper is restored */
  387.     SwitchWallpaperMode( p_vout, VLC_FALSE );
  388.     if( p_vout->p_sys )
  389.     {
  390.         free( p_vout->p_sys );
  391.         p_vout->p_sys = NULL;
  392.     }
  393. }
  394. /*****************************************************************************
  395.  * Manage: handle Sys events
  396.  *****************************************************************************
  397.  * This function should be called regularly by the video output thread.
  398.  * It returns a non null value if an error occurred.
  399.  *****************************************************************************/
  400. static int Manage( vout_thread_t *p_vout )
  401. {
  402.     WINDOWPLACEMENT window_placement;
  403.     /* If we do not control our window, we check for geometry changes
  404.      * ourselves because the parent might not send us its events. */
  405.     vlc_mutex_lock( &p_vout->p_sys->lock );
  406.     if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
  407.     {
  408.         RECT rect_parent;
  409.         POINT point;
  410.         vlc_mutex_unlock( &p_vout->p_sys->lock );
  411.         GetClientRect( p_vout->p_sys->hparent, &rect_parent );
  412.         point.x = point.y = 0;
  413.         ClientToScreen( p_vout->p_sys->hparent, &point );
  414.         OffsetRect( &rect_parent, point.x, point.y );
  415.         if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
  416.         {
  417.             p_vout->p_sys->rect_parent = rect_parent;
  418.             /* This one is to force the update even if only
  419.              * the position has changed */
  420.             SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
  421.                           rect_parent.right - rect_parent.left,
  422.                           rect_parent.bottom - rect_parent.top, 0 );
  423.             SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
  424.                           rect_parent.right - rect_parent.left,
  425.                           rect_parent.bottom - rect_parent.top, 0 );
  426.         }
  427.     }
  428.     else
  429.     {
  430.         vlc_mutex_unlock( &p_vout->p_sys->lock );
  431.     }
  432.     /*
  433.      * Position Change
  434.      */
  435.     if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
  436.     {
  437.         p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
  438.         /* Check if we are still on the same monitor */
  439.         if( p_vout->p_sys->MonitorFromWindow &&
  440.             p_vout->p_sys->hmonitor !=
  441.                 p_vout->p_sys->MonitorFromWindow( p_vout->p_sys->hwnd,
  442.                                                   MONITOR_DEFAULTTONEAREST ) )
  443.         {
  444.             /* This will force the vout core to recreate the picture buffers */
  445.             p_vout->i_changes |= VOUT_PICTURE_BUFFERS_CHANGE;
  446.         }
  447.     }
  448.     /* We used to call the Win32 PeekMessage function here to read the window
  449.      * messages. But since window can stay blocked into this function for a
  450.      * long time (for example when you move your window on the screen), I
  451.      * decided to isolate PeekMessage in another thread. */
  452.     if( p_vout->p_sys->i_changes & DX_WALLPAPER_CHANGE )
  453.     {
  454.         SwitchWallpaperMode( p_vout, !p_vout->p_sys->b_wallpaper );
  455.         p_vout->p_sys->i_changes &= ~DX_WALLPAPER_CHANGE;
  456.         DirectXUpdateOverlay( p_vout );
  457.     }
  458.     /*
  459.      * Fullscreen change
  460.      */
  461.     if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
  462.         || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
  463.     {
  464.         vlc_value_t val;
  465.         HWND hwnd = (p_vout->p_sys->hparent && p_vout->p_sys->hfswnd) ?
  466.             p_vout->p_sys->hfswnd : p_vout->p_sys->hwnd;
  467.         p_vout->b_fullscreen = ! p_vout->b_fullscreen;
  468.         /* We need to switch between Maximized and Normal sized window */
  469.         window_placement.length = sizeof(WINDOWPLACEMENT);
  470.         GetWindowPlacement( hwnd, &window_placement );
  471.         if( p_vout->b_fullscreen )
  472.         {
  473.             /* Change window style, no borders and no title bar */
  474.             int i_style = WS_CLIPCHILDREN | WS_VISIBLE;
  475.             SetWindowLong( hwnd, GWL_STYLE, i_style );
  476.             if( p_vout->p_sys->hparent )
  477.             {
  478.                 /* Retrieve current window position so fullscreen will happen
  479.                  * on the right screen */
  480.                 POINT point = {0,0};
  481.                 RECT rect;
  482.                 ClientToScreen( p_vout->p_sys->hwnd, &point );
  483.                 GetClientRect( p_vout->p_sys->hwnd, &rect );
  484.                 SetWindowPos( hwnd, 0, point.x, point.y,
  485.                               rect.right, rect.bottom,
  486.                               SWP_NOZORDER|SWP_FRAMECHANGED );
  487.                 GetWindowPlacement( hwnd, &window_placement );
  488.             }
  489.             /* Maximize window */
  490.             window_placement.showCmd = SW_SHOWMAXIMIZED;
  491.             SetWindowPlacement( hwnd, &window_placement );
  492.             SetWindowPos( hwnd, 0, 0, 0, 0, 0,
  493.                           SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
  494.             if( p_vout->p_sys->hparent )
  495.             {
  496.                 RECT rect;
  497.                 GetClientRect( hwnd, &rect );
  498.                 SetParent( p_vout->p_sys->hwnd, hwnd );
  499.                 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
  500.                               rect.right, rect.bottom,
  501.                               SWP_NOZORDER|SWP_FRAMECHANGED );
  502.             }
  503.             SetForegroundWindow( hwnd );
  504.         }
  505.         else
  506.         {
  507.             /* Change window style, no borders and no title bar */
  508.             int i_style = WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW |
  509.                 WS_SIZEBOX | WS_VISIBLE;
  510.             SetWindowLong( hwnd, GWL_STYLE, i_style );
  511.             /* Normal window */
  512.             window_placement.showCmd = SW_SHOWNORMAL;
  513.             SetWindowPlacement( hwnd, &window_placement );
  514.             SetWindowPos( hwnd, 0, 0, 0, 0, 0,
  515.                           SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
  516.             if( p_vout->p_sys->hparent )
  517.             {
  518.                 RECT rect;
  519.                 GetClientRect( p_vout->p_sys->hparent, &rect );
  520.                 SetParent( p_vout->p_sys->hwnd, p_vout->p_sys->hparent );
  521.                 SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
  522.                               rect.right, rect.bottom,
  523.                               SWP_NOZORDER|SWP_FRAMECHANGED );
  524.                 ShowWindow( hwnd, SW_HIDE );
  525.                 SetForegroundWindow( p_vout->p_sys->hparent );
  526.             }
  527.             /* Make sure the mouse cursor is displayed */
  528.             PostMessage( p_vout->p_sys->hwnd, WM_VLC_SHOW_MOUSE, 0, 0 );
  529.         }
  530.         /* Update the object variable and trigger callback */
  531.         val.b_bool = p_vout->b_fullscreen;
  532.         var_Set( p_vout, "fullscreen", val );
  533.         p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
  534.         p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
  535.     }
  536.     /*
  537.      * Pointer change
  538.      */
  539.     if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
  540.         (mdate() - p_vout->p_sys->i_lastmoved) > 5000000 )
  541.     {
  542.         POINT point;
  543.         HWND hwnd;
  544.         /* Hide the cursor only if it is inside our window */
  545.         GetCursorPos( &point );
  546.         hwnd = WindowFromPoint(point);
  547.         if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
  548.         {
  549.             PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
  550.         }
  551.         else
  552.         {
  553.             p_vout->p_sys->i_lastmoved = mdate();
  554.         }
  555.     }
  556.     /*
  557.      * "Always on top" status change
  558.      */
  559.     if( p_vout->p_sys->b_on_top_change )
  560.     {
  561.         vlc_value_t val;
  562.         HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
  563.         var_Get( p_vout, "video-on-top", &val );
  564.         /* Set the window on top if necessary */
  565.         if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
  566.                            & WS_EX_TOPMOST ) )
  567.         {
  568.             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
  569.                            MF_BYCOMMAND | MFS_CHECKED );
  570.             SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
  571.                           SWP_NOSIZE | SWP_NOMOVE );
  572.         }
  573.         else
  574.         /* The window shouldn't be on top */
  575.         if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
  576.                            & WS_EX_TOPMOST ) )
  577.         {
  578.             CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
  579.                            MF_BYCOMMAND | MFS_UNCHECKED );
  580.             SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
  581.                           SWP_NOSIZE | SWP_NOMOVE );
  582.         }
  583.         p_vout->p_sys->b_on_top_change = VLC_FALSE;
  584.     }
  585.     /* Check if the event thread is still running */
  586.     if( p_vout->p_sys->p_event->b_die )
  587.     {
  588.         return VLC_EGENERIC; /* exit */
  589.     }
  590.     return VLC_SUCCESS;
  591. }
  592. /*****************************************************************************
  593.  * Display: displays previously rendered output
  594.  *****************************************************************************
  595.  * This function sends the currently rendered image to the display, wait until
  596.  * it is displayed and switch the two rendering buffers, preparing next frame.
  597.  *****************************************************************************/
  598. static void Display( vout_thread_t *p_vout, picture_t *p_pic )
  599. {
  600.     HRESULT dxresult;
  601.     if( (p_vout->p_sys->p_display == NULL) )
  602.     {
  603.         msg_Warn( p_vout, "no display!" );
  604.         return;
  605.     }
  606.     /* Our surface can be lost so be sure to check this
  607.      * and restore it if need be */
  608.     if( IDirectDrawSurface2_IsLost( p_vout->p_sys->p_display )
  609.         == DDERR_SURFACELOST )
  610.     {
  611.         if( IDirectDrawSurface2_Restore( p_vout->p_sys->p_display ) == DD_OK &&
  612.             p_vout->p_sys->b_using_overlay )
  613.             DirectXUpdateOverlay( p_vout );
  614.     }
  615.     if( !p_vout->p_sys->b_using_overlay )
  616.     {
  617.         DDBLTFX  ddbltfx;
  618.         /* We ask for the "NOTEARING" option */
  619.         memset( &ddbltfx, 0, sizeof(DDBLTFX) );
  620.         ddbltfx.dwSize = sizeof(DDBLTFX);
  621.         ddbltfx.dwDDFX = DDBLTFX_NOTEARING;
  622.         /* Blit video surface to display */
  623.         dxresult = IDirectDrawSurface2_Blt( p_vout->p_sys->p_display,
  624.                                             &p_vout->p_sys->rect_dest_clipped,
  625.                                             p_pic->p_sys->p_surface,
  626.                                             &p_vout->p_sys->rect_src_clipped,
  627.                                             DDBLT_ASYNC, &ddbltfx );
  628.         if( dxresult != DD_OK )
  629.         {
  630.             msg_Warn( p_vout, "could not blit surface (error %li)", dxresult );
  631.             return;
  632.         }
  633.     }
  634.     else /* using overlay */
  635.     {
  636.         /* Flip the overlay buffers if we are using back buffers */
  637.         if( p_pic->p_sys->p_front_surface == p_pic->p_sys->p_surface )
  638.         {
  639.             return;
  640.         }
  641.         dxresult = IDirectDrawSurface2_Flip( p_pic->p_sys->p_front_surface,
  642.                                              NULL, DDFLIP_WAIT );
  643.         if( dxresult != DD_OK )
  644.         {
  645.             msg_Warn( p_vout, "could not flip overlay (error %li)", dxresult );
  646.         }
  647.         /* set currently displayed pic */
  648.         p_vout->p_sys->p_current_surface = p_pic->p_sys->p_front_surface;
  649.         /* Lock surface to get all the required info */
  650.         if( DirectXLockSurface( p_vout, p_pic ) )
  651.         {
  652.             /* AAARRGG */
  653.             msg_Warn( p_vout, "cannot lock surface" );
  654.             return;
  655.         }
  656.         DirectXUnlockSurface( p_vout, p_pic );
  657.     }
  658. }
  659. /* following functions are local */
  660. /*****************************************************************************
  661.  * DirectXEnumCallback: Device enumeration
  662.  *****************************************************************************
  663.  * This callback function is called by DirectDraw once for each
  664.  * available DirectDraw device.
  665.  *****************************************************************************/
  666. BOOL WINAPI DirectXEnumCallback( GUID* p_guid, LPTSTR psz_desc,
  667.                                  LPTSTR psz_drivername, VOID* p_context,
  668.                                  HMONITOR hmon )
  669. {
  670.     vout_thread_t *p_vout = (vout_thread_t *)p_context;
  671.     vlc_value_t device;
  672.     msg_Dbg( p_vout, "DirectXEnumCallback: %s, %s", psz_desc, psz_drivername );
  673.     if( hmon )
  674.     {
  675.         var_Get( p_vout, "directx-device", &device );
  676.         if( ( !device.psz_string || !*device.psz_string ) &&
  677.             hmon == p_vout->p_sys->hmonitor )
  678.         {
  679.             if( device.psz_string ) free( device.psz_string );
  680.         }
  681.         else if( strcmp( psz_drivername, device.psz_string ) == 0 )
  682.         {
  683.             MONITORINFO monitor_info;
  684.             monitor_info.cbSize = sizeof( MONITORINFO );
  685.             if( p_vout->p_sys->GetMonitorInfo( hmon, &monitor_info ) )
  686.             {
  687.                 RECT rect;
  688.                 /* Move window to the right screen */
  689.                 GetWindowRect( p_vout->p_sys->hwnd, &rect );
  690.                 if( !IntersectRect( &rect, &rect, &monitor_info.rcWork ) )
  691.                 {
  692.                     rect.left = monitor_info.rcWork.left;
  693.                     rect.top = monitor_info.rcWork.top;
  694.                     msg_Dbg( p_vout, "DirectXEnumCallback: Setting window "
  695.                              "position to %d,%d", rect.left, rect.top );
  696.                     SetWindowPos( p_vout->p_sys->hwnd, NULL,
  697.                                   rect.left, rect.top, 0, 0,
  698.                                   SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
  699.                 }
  700.             }
  701.             p_vout->p_sys->hmonitor = hmon;
  702.             if( device.psz_string ) free( device.psz_string );
  703.         }
  704.         else
  705.         {
  706.             if( device.psz_string ) free( device.psz_string );
  707.             return TRUE; /* Keep enumerating */
  708.         }
  709.         msg_Dbg( p_vout, "selecting %s, %s", psz_desc, psz_drivername );
  710.         p_vout->p_sys->p_display_driver = malloc( sizeof(GUID) );
  711.         if( p_vout->p_sys->p_display_driver )
  712.             memcpy( p_vout->p_sys->p_display_driver, p_guid, sizeof(GUID) );
  713.     }
  714.     return TRUE; /* Keep enumerating */
  715. }
  716. /*****************************************************************************
  717.  * DirectXInitDDraw: Takes care of all the DirectDraw initialisations
  718.  *****************************************************************************
  719.  * This function initialise and allocate resources for DirectDraw.
  720.  *****************************************************************************/
  721. static int DirectXInitDDraw( vout_thread_t *p_vout )
  722. {
  723.     HRESULT dxresult;
  724.     HRESULT (WINAPI *OurDirectDrawCreate)(GUID *,LPDIRECTDRAW *,IUnknown *);
  725.     HRESULT (WINAPI *OurDirectDrawEnumerateEx)( LPDDENUMCALLBACKEXA, LPVOID,
  726.                                                 DWORD );
  727.     LPDIRECTDRAW p_ddobject;
  728.     msg_Dbg( p_vout, "DirectXInitDDraw" );
  729.     /* Load direct draw DLL */
  730.     p_vout->p_sys->hddraw_dll = LoadLibrary("DDRAW.DLL");
  731.     if( p_vout->p_sys->hddraw_dll == NULL )
  732.     {
  733.         msg_Warn( p_vout, "DirectXInitDDraw failed loading ddraw.dll" );
  734.         goto error;
  735.     }
  736.     OurDirectDrawCreate =
  737.       (void *)GetProcAddress(p_vout->p_sys->hddraw_dll, "DirectDrawCreate");
  738.     if( OurDirectDrawCreate == NULL )
  739.     {
  740.         msg_Err( p_vout, "DirectXInitDDraw failed GetProcAddress" );
  741.         goto error;
  742.     }
  743.     OurDirectDrawEnumerateEx =
  744.       (void *)GetProcAddress( p_vout->p_sys->hddraw_dll,
  745.                               "DirectDrawEnumerateExA" );
  746.     if( OurDirectDrawEnumerateEx && p_vout->p_sys->MonitorFromWindow )
  747.     {
  748.         vlc_value_t device;
  749.         var_Get( p_vout, "directx-device", &device );
  750.         if( device.psz_string )
  751.         {
  752.             msg_Dbg( p_vout, "directx-device: %s", device.psz_string );
  753.             free( device.psz_string );
  754.         }
  755.         p_vout->p_sys->hmonitor =
  756.             p_vout->p_sys->MonitorFromWindow( p_vout->p_sys->hwnd,
  757.                                               MONITOR_DEFAULTTONEAREST );
  758.         /* Enumerate displays */
  759.         OurDirectDrawEnumerateEx( DirectXEnumCallback, p_vout,
  760.                                   DDENUM_ATTACHEDSECONDARYDEVICES );
  761.     }
  762.     /* Initialize DirectDraw now */
  763.     dxresult = OurDirectDrawCreate( p_vout->p_sys->p_display_driver,
  764.                                     &p_ddobject, NULL );
  765.     if( dxresult != DD_OK )
  766.     {
  767.         msg_Err( p_vout, "DirectXInitDDraw cannot initialize DDraw" );
  768.         goto error;
  769.     }
  770.     /* Get the IDirectDraw2 interface */
  771.     dxresult = IDirectDraw_QueryInterface( p_ddobject, &IID_IDirectDraw2,
  772.                                         (LPVOID *)&p_vout->p_sys->p_ddobject );
  773.     /* Release the unused interface */
  774.     IDirectDraw_Release( p_ddobject );
  775.     if( dxresult != DD_OK )
  776.     {
  777.         msg_Err( p_vout, "cannot get IDirectDraw2 interface" );
  778.         goto error;
  779.     }
  780.     /* Set DirectDraw Cooperative level, ie what control we want over Windows
  781.      * display */
  782.     dxresult = IDirectDraw2_SetCooperativeLevel( p_vout->p_sys->p_ddobject,
  783.                                                  NULL, DDSCL_NORMAL );
  784.     if( dxresult != DD_OK )
  785.     {
  786.         msg_Err( p_vout, "cannot set direct draw cooperative level" );
  787.         goto error;
  788.     }
  789.     /* Get the size of the current display device */
  790.     if( p_vout->p_sys->hmonitor && p_vout->p_sys->GetMonitorInfo )
  791.     {
  792.         MONITORINFO monitor_info;
  793.         monitor_info.cbSize = sizeof( MONITORINFO );
  794.         p_vout->p_sys->GetMonitorInfo( p_vout->p_sys->hmonitor,
  795.                                        &monitor_info );
  796.         p_vout->p_sys->rect_display = monitor_info.rcMonitor;
  797.     }
  798.     else
  799.     {
  800.         p_vout->p_sys->rect_display.left = 0;
  801.         p_vout->p_sys->rect_display.top = 0;
  802.         p_vout->p_sys->rect_display.right  = GetSystemMetrics(SM_CXSCREEN);
  803.         p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
  804.     }
  805.     msg_Dbg( p_vout, "screen dimensions (%ix%i,%ix%i)",
  806.              p_vout->p_sys->rect_display.left,
  807.              p_vout->p_sys->rect_display.top,
  808.              p_vout->p_sys->rect_display.right,
  809.              p_vout->p_sys->rect_display.bottom );
  810.     /* Probe the capabilities of the hardware */
  811.     DirectXGetDDrawCaps( p_vout );
  812.     msg_Dbg( p_vout, "End DirectXInitDDraw" );
  813.     return VLC_SUCCESS;
  814.  error:
  815.     if( p_vout->p_sys->p_ddobject )
  816.         IDirectDraw2_Release( p_vout->p_sys->p_ddobject );
  817.     if( p_vout->p_sys->hddraw_dll )
  818.         FreeLibrary( p_vout->p_sys->hddraw_dll );
  819.     p_vout->p_sys->hddraw_dll = NULL;
  820.     p_vout->p_sys->p_ddobject = NULL;
  821.     return VLC_EGENERIC;
  822. }
  823. /*****************************************************************************
  824.  * DirectXCreateDisplay: create the DirectDraw display.
  825.  *****************************************************************************
  826.  * Create and initialize display according to preferences specified in the vout
  827.  * thread fields.
  828.  *****************************************************************************/
  829. static int DirectXCreateDisplay( vout_thread_t *p_vout )
  830. {
  831.     HRESULT              dxresult;
  832.     DDSURFACEDESC        ddsd;
  833.     LPDIRECTDRAWSURFACE  p_display;
  834.     msg_Dbg( p_vout, "DirectXCreateDisplay" );
  835.     /* Now get the primary surface. This surface is what you actually see
  836.      * on your screen */
  837.     memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
  838.     ddsd.dwSize = sizeof(DDSURFACEDESC);
  839.     ddsd.dwFlags = DDSD_CAPS;
  840.     ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
  841.     dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
  842.                                            &ddsd, &p_display, NULL );
  843.     if( dxresult != DD_OK )
  844.     {
  845.         msg_Err( p_vout, "cannot get primary surface (error %li)", dxresult );
  846.         return VLC_EGENERIC;
  847.     }
  848.     dxresult = IDirectDrawSurface_QueryInterface( p_display,
  849.                                          &IID_IDirectDrawSurface2,
  850.                                          (LPVOID *)&p_vout->p_sys->p_display );
  851.     /* Release the old interface */
  852.     IDirectDrawSurface_Release( p_display );
  853.     if ( dxresult != DD_OK )
  854.     {
  855.         msg_Err( p_vout, "cannot query IDirectDrawSurface2 interface "
  856.                          "(error %li)", dxresult );
  857.         return VLC_EGENERIC;
  858.     }
  859.     /* The clipper will be used only in non-overlay mode */
  860.     DirectXCreateClipper( p_vout );
  861.     /* Make sure the colorkey will be painted */
  862.     p_vout->p_sys->i_colorkey = 1;
  863.     p_vout->p_sys->i_rgb_colorkey =
  864.         DirectXFindColorkey( p_vout, p_vout->p_sys->i_colorkey );
  865.     /* Create the actual brush */
  866.     SetClassLong( p_vout->p_sys->hvideownd, GCL_HBRBACKGROUND,
  867.                   (LONG)CreateSolidBrush( p_vout->p_sys->i_rgb_colorkey ) );
  868.     InvalidateRect( p_vout->p_sys->hvideownd, NULL, TRUE );
  869.     DirectXUpdateRects( p_vout, VLC_TRUE );
  870.     return VLC_SUCCESS;
  871. }
  872. /*****************************************************************************
  873.  * DirectXCreateClipper: Create a clipper that will be used when blitting the
  874.  *                       RGB surface to the main display.
  875.  *****************************************************************************
  876.  * This clipper prevents us to modify by mistake anything on the screen
  877.  * which doesn't belong to our window. For example when a part of our video
  878.  * window is hidden by another window.
  879.  *****************************************************************************/
  880. static int DirectXCreateClipper( vout_thread_t *p_vout )
  881. {
  882.     HRESULT dxresult;
  883.     msg_Dbg( p_vout, "DirectXCreateClipper" );
  884.     /* Create the clipper */
  885.     dxresult = IDirectDraw2_CreateClipper( p_vout->p_sys->p_ddobject, 0,
  886.                                            &p_vout->p_sys->p_clipper, NULL );
  887.     if( dxresult != DD_OK )
  888.     {
  889.         msg_Warn( p_vout, "cannot create clipper (error %li)", dxresult );
  890.         goto error;
  891.     }
  892.     /* Associate the clipper to the window */
  893.     dxresult = IDirectDrawClipper_SetHWnd( p_vout->p_sys->p_clipper, 0,
  894.                                            p_vout->p_sys->hvideownd );
  895.     if( dxresult != DD_OK )
  896.     {
  897.         msg_Warn( p_vout, "cannot attach clipper to window (error %li)",
  898.                           dxresult );
  899.         goto error;
  900.     }
  901.     /* associate the clipper with the surface */
  902.     dxresult = IDirectDrawSurface_SetClipper(p_vout->p_sys->p_display,
  903.                                              p_vout->p_sys->p_clipper);
  904.     if( dxresult != DD_OK )
  905.     {
  906.         msg_Warn( p_vout, "cannot attach clipper to surface (error %li)",
  907.                           dxresult );
  908.         goto error;
  909.     }
  910.     return VLC_SUCCESS;
  911.  error:
  912.     if( p_vout->p_sys->p_clipper )
  913.     {
  914.         IDirectDrawClipper_Release( p_vout->p_sys->p_clipper );
  915.     }
  916.     p_vout->p_sys->p_clipper = NULL;
  917.     return VLC_EGENERIC;
  918. }
  919. /*****************************************************************************
  920.  * DirectXCreateSurface: create an YUV overlay or RGB surface for the video.
  921.  *****************************************************************************
  922.  * The best method of display is with an YUV overlay because the YUV->RGB
  923.  * conversion is done in hardware.
  924.  * You can also create a plain RGB surface.
  925.  * ( Maybe we could also try an RGB overlay surface, which could have hardware
  926.  * scaling and which would also be faster in window mode because you don't
  927.  * need to do any blitting to the main display...)
  928.  *****************************************************************************/
  929. static int DirectXCreateSurface( vout_thread_t *p_vout,
  930.                                  LPDIRECTDRAWSURFACE2 *pp_surface_final,
  931.                                  int i_chroma, int b_overlay,
  932.                                  int i_backbuffers )
  933. {
  934.     HRESULT dxresult;
  935.     LPDIRECTDRAWSURFACE p_surface;
  936.     DDSURFACEDESC ddsd;
  937.     /* Create the video surface */
  938.     if( b_overlay )
  939.     {
  940.         /* Now try to create the YUV overlay surface.
  941.          * This overlay will be displayed on top of the primary surface.
  942.          * A color key is used to determine whether or not the overlay will be
  943.          * displayed, ie the overlay will be displayed in place of the primary
  944.          * surface wherever the primary surface will have this color.
  945.          * The video window has been created with a background of this color so
  946.          * the overlay will be only displayed on top of this window */
  947.         memset( &ddsd, 0, sizeof( DDSURFACEDESC ));
  948.         ddsd.dwSize = sizeof(DDSURFACEDESC);
  949.         ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
  950.         ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
  951.         ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
  952.         ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
  953.         ddsd.dwFlags |= (i_backbuffers ? DDSD_BACKBUFFERCOUNT : 0);
  954.         ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_VIDEOMEMORY;
  955.         ddsd.ddsCaps.dwCaps |= (i_backbuffers ? DDSCAPS_COMPLEX | DDSCAPS_FLIP
  956.                                 : 0 );
  957.         ddsd.dwHeight = p_vout->render.i_height;
  958.         ddsd.dwWidth = p_vout->render.i_width;
  959.         ddsd.dwBackBufferCount = i_backbuffers;
  960.         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
  961.                                                &ddsd, &p_surface, NULL );
  962.         if( dxresult != DD_OK )
  963.         {
  964.             *pp_surface_final = NULL;
  965.             return VLC_EGENERIC;
  966.         }
  967.     }
  968.     if( !b_overlay )
  969.     {
  970.         vlc_bool_t b_rgb_surface =
  971.             ( i_chroma == VLC_FOURCC('R','G','B','2') )
  972.           || ( i_chroma == VLC_FOURCC('R','V','1','5') )
  973.            || ( i_chroma == VLC_FOURCC('R','V','1','6') )
  974.             || ( i_chroma == VLC_FOURCC('R','V','2','4') )
  975.              || ( i_chroma == VLC_FOURCC('R','V','3','2') );
  976.         memset( &ddsd, 0, sizeof( DDSURFACEDESC ) );
  977.         ddsd.dwSize = sizeof(DDSURFACEDESC);
  978.         ddsd.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
  979.         ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS;
  980.         ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
  981.         ddsd.dwHeight = p_vout->render.i_height;
  982.         ddsd.dwWidth = p_vout->render.i_width;
  983.         if( p_vout->p_sys->b_use_sysmem )
  984.             ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
  985.         else
  986.             ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  987.         if( !b_rgb_surface )
  988.         {
  989.             ddsd.dwFlags |= DDSD_PIXELFORMAT;
  990.             ddsd.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
  991.             ddsd.ddpfPixelFormat.dwFourCC = i_chroma;
  992.         }
  993.         dxresult = IDirectDraw2_CreateSurface( p_vout->p_sys->p_ddobject,
  994.                                                &ddsd, &p_surface, NULL );
  995.         if( dxresult != DD_OK )
  996.         {
  997.             *pp_surface_final = NULL;
  998.             return VLC_EGENERIC;
  999.         }
  1000.     }
  1001.     /* Now that the surface is created, try to get a newer DirectX interface */
  1002.     dxresult = IDirectDrawSurface_QueryInterface( p_surface,
  1003.                                      &IID_IDirectDrawSurface2,
  1004.                                      (LPVOID *)pp_surface_final );
  1005.     IDirectDrawSurface_Release( p_surface );    /* Release the old interface */
  1006.     if ( dxresult != DD_OK )
  1007.     {
  1008.         msg_Err( p_vout, "cannot query IDirectDrawSurface2 interface "
  1009.                          "(error %li)", dxresult );
  1010.         *pp_surface_final = NULL;
  1011.         return VLC_EGENERIC;
  1012.     }
  1013.     if( b_overlay )
  1014.     {
  1015.         /* Check the overlay is useable as some graphics cards allow creating
  1016.          * several overlays but only one can be used at one time. */
  1017.         p_vout->p_sys->p_current_surface = *pp_surface_final;
  1018.         if( DirectXUpdateOverlay( p_vout ) != VLC_SUCCESS )
  1019.         {
  1020.             IDirectDrawSurface2_Release( *pp_surface_final );
  1021.             *pp_surface_final = NULL;
  1022.             msg_Err( p_vout, "overlay unuseable (might already be in use)" );
  1023.             return VLC_EGENERIC;
  1024.         }
  1025.     }
  1026.     return VLC_SUCCESS;
  1027. }
  1028. /*****************************************************************************
  1029.  * DirectXUpdateOverlay: Move or resize overlay surface on video display.
  1030.  *****************************************************************************
  1031.  * This function is used to move or resize an overlay surface on the screen.
  1032.  * Ususally the overlay is moved by the user and thus, by a move or resize
  1033.  * event (in Manage).
  1034.  *****************************************************************************/
  1035. int DirectXUpdateOverlay( vout_thread_t *p_vout )
  1036. {
  1037.     DDOVERLAYFX     ddofx;
  1038.     DWORD           dwFlags;
  1039.     HRESULT         dxresult;
  1040.     RECT            rect_src = p_vout->p_sys->rect_src_clipped;
  1041.     RECT            rect_dest = p_vout->p_sys->rect_dest_clipped;
  1042.     if( !p_vout->p_sys->b_using_overlay ) return VLC_EGENERIC;
  1043.     if( p_vout->p_sys->b_wallpaper )
  1044.     {
  1045.         int i_x, i_y, i_width, i_height;
  1046.         rect_src.left = rect_src.top = 0;
  1047.         rect_src.right = p_vout->render.i_width;
  1048.         rect_src.bottom = p_vout->render.i_height;
  1049.         rect_dest = p_vout->p_sys->rect_display;
  1050.         vout_PlacePicture( p_vout, rect_dest.right, rect_dest.bottom,
  1051.                            &i_x, &i_y, &i_width, &i_height );
  1052.         rect_dest.left += i_x;
  1053.         rect_dest.right = rect_dest.left + i_width;
  1054.         rect_dest.top += i_y;
  1055.         rect_dest.bottom = rect_dest.top + i_height;
  1056.     }
  1057.     vlc_mutex_lock( &p_vout->p_sys->lock );
  1058.     if( p_vout->p_sys->p_current_surface == NULL )
  1059.     {
  1060.         vlc_mutex_unlock( &p_vout->p_sys->lock );
  1061.         return VLC_EGENERIC;
  1062.     }
  1063.     /* The new window dimensions should already have been computed by the
  1064.      * caller of this function */
  1065.     /* Position and show the overlay */
  1066.     memset(&ddofx, 0, sizeof(DDOVERLAYFX));
  1067.     ddofx.dwSize = sizeof(DDOVERLAYFX);
  1068.     ddofx.dckDestColorkey.dwColorSpaceLowValue = p_vout->p_sys->i_colorkey;
  1069.     ddofx.dckDestColorkey.dwColorSpaceHighValue = p_vout->p_sys->i_colorkey;
  1070.     dwFlags = DDOVER_SHOW | DDOVER_KEYDESTOVERRIDE;
  1071.     dxresult = IDirectDrawSurface2_UpdateOverlay(
  1072.                    p_vout->p_sys->p_current_surface,
  1073.                    &rect_src, p_vout->p_sys->p_display, &rect_dest,
  1074.                    dwFlags, &ddofx );
  1075.     vlc_mutex_unlock( &p_vout->p_sys->lock );
  1076.     if(dxresult != DD_OK)
  1077.     {
  1078.         msg_Warn( p_vout, "DirectXUpdateOverlay cannot move/resize overlay" );
  1079.         return VLC_EGENERIC;
  1080.     }
  1081.     return VLC_SUCCESS;
  1082. }
  1083. /*****************************************************************************
  1084.  * DirectXCloseDDraw: Release the DDraw object allocated by DirectXInitDDraw
  1085.  *****************************************************************************
  1086.  * This function returns all resources allocated by DirectXInitDDraw.
  1087.  *****************************************************************************/
  1088. static void DirectXCloseDDraw( vout_thread_t *p_vout )
  1089. {
  1090.     msg_Dbg( p_vout, "DirectXCloseDDraw" );
  1091.     if( p_vout->p_sys->p_ddobject != NULL )
  1092.     {
  1093.         IDirectDraw2_Release(p_vout->p_sys->p_ddobject);
  1094.         p_vout->p_sys->p_ddobject = NULL;
  1095.     }
  1096.     if( p_vout->p_sys->hddraw_dll != NULL )
  1097.     {
  1098.         FreeLibrary( p_vout->p_sys->hddraw_dll );
  1099.         p_vout->p_sys->hddraw_dll = NULL;
  1100.     }
  1101.     if( p_vout->p_sys->p_display_driver != NULL )
  1102.     {
  1103.         free( p_vout->p_sys->p_display_driver );
  1104.         p_vout->p_sys->p_display_driver = NULL;
  1105.     }
  1106.     p_vout->p_sys->hmonitor = NULL;
  1107. }
  1108. /*****************************************************************************
  1109.  * DirectXCloseDisplay: close and reset the DirectX display device
  1110.  *****************************************************************************
  1111.  * This function returns all resources allocated by DirectXCreateDisplay.
  1112.  *****************************************************************************/
  1113. static void DirectXCloseDisplay( vout_thread_t *p_vout )
  1114. {
  1115.     msg_Dbg( p_vout, "DirectXCloseDisplay" );
  1116.     if( p_vout->p_sys->p_clipper != NULL )
  1117.     {
  1118.         msg_Dbg( p_vout, "DirectXCloseDisplay clipper" );
  1119.         IDirectDrawClipper_Release( p_vout->p_sys->p_clipper );
  1120.         p_vout->p_sys->p_clipper = NULL;
  1121.     }
  1122.     if( p_vout->p_sys->p_display != NULL )
  1123.     {
  1124.         msg_Dbg( p_vout, "DirectXCloseDisplay display" );
  1125.         IDirectDrawSurface2_Release( p_vout->p_sys->p_display );
  1126.         p_vout->p_sys->p_display = NULL;
  1127.     }
  1128. }
  1129. /*****************************************************************************
  1130.  * DirectXCloseSurface: close the YUV overlay or RGB surface.
  1131.  *****************************************************************************
  1132.  * This function returns all resources allocated for the surface.
  1133.  *****************************************************************************/
  1134. static void DirectXCloseSurface( vout_thread_t *p_vout,
  1135.                                  LPDIRECTDRAWSURFACE2 p_surface )
  1136. {
  1137.     msg_Dbg( p_vout, "DirectXCloseSurface" );
  1138.     if( p_surface != NULL )
  1139.     {
  1140.         IDirectDrawSurface2_Release( p_surface );
  1141.     }
  1142. }
  1143. /*****************************************************************************
  1144.  * NewPictureVec: allocate a vector of identical pictures
  1145.  *****************************************************************************
  1146.  * Returns 0 on success, -1 otherwise
  1147.  *****************************************************************************/
  1148. static int NewPictureVec( vout_thread_t *p_vout, picture_t *p_pic,
  1149.                           int i_num_pics )
  1150. {
  1151.     int i;
  1152.     int i_ret = VLC_SUCCESS;
  1153.     LPDIRECTDRAWSURFACE2 p_surface;
  1154.     msg_Dbg( p_vout, "NewPictureVec overlay:%s chroma:%.4s",
  1155.              p_vout->p_sys->b_using_overlay ? "yes" : "no",
  1156.              (char *)&p_vout->output.i_chroma );
  1157.     I_OUTPUTPICTURES = 0;
  1158.     /* First we try to use an YUV overlay surface.
  1159.      * The overlay surface that we create won't be used to decode directly
  1160.      * into it because accessing video memory directly is way to slow (remember
  1161.      * that pictures are decoded macroblock per macroblock). Instead the video
  1162.      * will be decoded in picture buffers in system memory which will then be
  1163.      * memcpy() to the overlay surface. */
  1164.     if( p_vout->p_sys->b_using_overlay )
  1165.     {
  1166.         /* Triple buffering rocks! it doesn't have any processing overhead
  1167.          * (you don't have to wait for the vsync) and provides for a very nice
  1168.          * video quality (no tearing). */
  1169.         if( p_vout->p_sys->b_3buf_overlay )
  1170.             i_ret = DirectXCreateSurface( p_vout, &p_surface,
  1171.                                           p_vout->output.i_chroma,
  1172.                                           p_vout->p_sys->b_using_overlay,
  1173.                                           2 /* number of backbuffers */ );
  1174.         if( !p_vout->p_sys->b_3buf_overlay || i_ret != VLC_SUCCESS )
  1175.         {
  1176.             /* Try to reduce the number of backbuffers */
  1177.             i_ret = DirectXCreateSurface( p_vout, &p_surface,
  1178.                                           p_vout->output.i_chroma,
  1179.                                           p_vout->p_sys->b_using_overlay,
  1180.                                           0 /* number of backbuffers */ );
  1181.         }
  1182.         if( i_ret == VLC_SUCCESS )
  1183.         {
  1184.             DDSCAPS dds_caps;
  1185.             picture_t front_pic;
  1186.             picture_sys_t front_pic_sys;
  1187.             front_pic.p_sys = &front_pic_sys;
  1188.             /* Allocate internal structure */
  1189.             p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) );
  1190.             if( p_pic[0].p_sys == NULL )
  1191.             {
  1192.                 DirectXCloseSurface( p_vout, p_surface );
  1193.                 return VLC_ENOMEM;
  1194.             }
  1195.             /* set front buffer */
  1196.             p_pic[0].p_sys->p_front_surface = p_surface;
  1197.             /* Get the back buffer */
  1198.             memset( &dds_caps, 0, sizeof( DDSCAPS ) );
  1199.             dds_caps.dwCaps = DDSCAPS_BACKBUFFER;
  1200.             if( DD_OK != IDirectDrawSurface2_GetAttachedSurface(
  1201.                                                 p_surface, &dds_caps,
  1202.                                                 &p_pic[0].p_sys->p_surface ) )
  1203.             {
  1204.                 msg_Warn( p_vout, "NewPictureVec could not get back buffer" );
  1205.                 /* front buffer is the same as back buffer */
  1206.                 p_pic[0].p_sys->p_surface = p_surface;
  1207.             }
  1208.             p_vout->p_sys->p_current_surface = front_pic.p_sys->p_surface =
  1209.                 p_pic[0].p_sys->p_front_surface;
  1210.             /* Reset the front buffer memory */
  1211.             if( DirectXLockSurface( p_vout, &front_pic ) == VLC_SUCCESS )
  1212.             {
  1213.                 int i,j;
  1214.                 for( i = 0; i < front_pic.i_planes; i++ )
  1215.                     for( j = 0; j < front_pic.p[i].i_visible_lines; j++)
  1216.                         memset( front_pic.p[i].p_pixels + j *
  1217.                                 front_pic.p[i].i_pitch, 127,
  1218.                                 front_pic.p[i].i_visible_pitch );
  1219.                 DirectXUnlockSurface( p_vout, &front_pic );
  1220.             }
  1221.             DirectXUpdateOverlay( p_vout );
  1222.             I_OUTPUTPICTURES = 1;
  1223.             msg_Dbg( p_vout, "YUV overlay created successfully" );
  1224.         }
  1225.     }
  1226.     /* As we can't have an overlay, we'll try to create a plain offscreen
  1227.      * surface. This surface will reside in video memory because there's a
  1228.      * better chance then that we'll be able to use some kind of hardware
  1229.      * acceleration like rescaling, blitting or YUV->RGB conversions.
  1230.      * We then only need to blit this surface onto the main display when we
  1231.      * want to display it */
  1232.     if( !p_vout->p_sys->b_using_overlay )
  1233.     {
  1234.         if( p_vout->p_sys->b_hw_yuv )
  1235.         {
  1236.             DWORD i_codes;
  1237.             DWORD *pi_codes;
  1238.             vlc_bool_t b_result = VLC_FALSE;
  1239.             /* Check if the chroma is supported first. This is required
  1240.              * because a few buggy drivers don't mind creating the surface
  1241.              * even if they don't know about the chroma. */
  1242.             if( IDirectDraw2_GetFourCCCodes( p_vout->p_sys->p_ddobject,
  1243.                                              &i_codes, NULL ) == DD_OK )
  1244.             {
  1245.                 pi_codes = malloc( i_codes * sizeof(DWORD) );
  1246.                 if( pi_codes && IDirectDraw2_GetFourCCCodes(
  1247.                     p_vout->p_sys->p_ddobject, &i_codes, pi_codes ) == DD_OK )
  1248.                 {
  1249.                     for( i = 0; i < (int)i_codes; i++ )
  1250.                     {
  1251.                         if( p_vout->output.i_chroma == pi_codes[i] )
  1252.                         {
  1253.                             b_result = VLC_TRUE;
  1254.                             break;
  1255.                         }
  1256.                     }
  1257.                 }
  1258.             }
  1259.             if( b_result )
  1260.                 i_ret = DirectXCreateSurface( p_vout, &p_surface,
  1261.                                               p_vout->output.i_chroma,
  1262.                                               0 /* no overlay */,
  1263.                                               0 /* no back buffers */ );
  1264.             else
  1265.                 p_vout->p_sys->b_hw_yuv = VLC_FALSE;
  1266.         }
  1267.         if( i_ret || !p_vout->p_sys->b_hw_yuv )
  1268.         {
  1269.             /* Our last choice is to use a plain RGB surface */
  1270.             DDPIXELFORMAT ddpfPixelFormat;
  1271.             ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
  1272.             IDirectDrawSurface2_GetPixelFormat( p_vout->p_sys->p_display,
  1273.                                                 &ddpfPixelFormat );
  1274.             if( ddpfPixelFormat.dwFlags & DDPF_RGB )
  1275.             {
  1276.                 switch( ddpfPixelFormat.dwRGBBitCount )
  1277.                 {
  1278.                 case 8: /* FIXME: set the palette */
  1279.                     p_vout->output.i_chroma = VLC_FOURCC('R','G','B','2');
  1280.                     break;
  1281.                 case 15:
  1282.                     p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
  1283.                     break;
  1284.                 case 16:
  1285.                     p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
  1286.                     break;
  1287.                 case 24:
  1288.                     p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
  1289.                     break;
  1290.                 case 32:
  1291.                     p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
  1292.                     break;
  1293.                 default:
  1294.                     msg_Err( p_vout, "unknown screen depth" );
  1295.                     return VLC_EGENERIC;
  1296.                 }
  1297.                 p_vout->output.i_rmask = ddpfPixelFormat.dwRBitMask;
  1298.                 p_vout->output.i_gmask = ddpfPixelFormat.dwGBitMask;
  1299.                 p_vout->output.i_bmask = ddpfPixelFormat.dwBBitMask;
  1300.             }
  1301.             p_vout->p_sys->b_hw_yuv = 0;
  1302.             i_ret = DirectXCreateSurface( p_vout, &p_surface,
  1303.                                           p_vout->output.i_chroma,
  1304.                                           0 /* no overlay */,
  1305.                                           0 /* no back buffers */ );
  1306.             if( i_ret && !p_vout->p_sys->b_use_sysmem )
  1307.             {
  1308.                 /* Give it a last try with b_use_sysmem enabled */
  1309.                 p_vout->p_sys->b_use_sysmem = 1;
  1310.                 i_ret = DirectXCreateSurface( p_vout, &p_surface,
  1311.                                               p_vout->output.i_chroma,
  1312.                                               0 /* no overlay */,
  1313.                                               0 /* no back buffers */ );
  1314.             }
  1315.         }
  1316.         if( i_ret == VLC_SUCCESS )
  1317.         {
  1318.             /* Allocate internal structure */
  1319.             p_pic[0].p_sys = malloc( sizeof( picture_sys_t ) );
  1320.             if( p_pic[0].p_sys == NULL )
  1321.             {
  1322.                 DirectXCloseSurface( p_vout, p_surface );
  1323.                 return VLC_ENOMEM;
  1324.             }
  1325.             p_pic[0].p_sys->p_surface = p_pic[0].p_sys->p_front_surface
  1326.                 = p_surface;
  1327.             I_OUTPUTPICTURES = 1;
  1328.             msg_Dbg( p_vout, "created plain surface of chroma:%.4s",
  1329.                      (char *)&p_vout->output.i_chroma );
  1330.         }
  1331.     }
  1332.     /* Now that we've got all our direct-buffers, we can finish filling in the
  1333.      * picture_t structures */
  1334.     for( i = 0; i < I_OUTPUTPICTURES; i++ )
  1335.     {
  1336.         p_pic[i].i_status = DESTROYED_PICTURE;
  1337.         p_pic[i].i_type   = DIRECT_PICTURE;
  1338.         p_pic[i].b_slow   = VLC_TRUE;
  1339.         p_pic[i].pf_lock  = DirectXLockSurface;
  1340.         p_pic[i].pf_unlock = DirectXUnlockSurface;
  1341.         PP_OUTPUTPICTURE[i] = &p_pic[i];
  1342.         if( DirectXLockSurface( p_vout, &p_pic[i] ) != VLC_SUCCESS )
  1343.         {
  1344.             /* AAARRGG */
  1345.             FreePictureVec( p_vout, p_pic, I_OUTPUTPICTURES );
  1346.             I_OUTPUTPICTURES = 0;
  1347.             msg_Err( p_vout, "cannot lock surface" );
  1348.             return VLC_EGENERIC;
  1349.         }
  1350.         DirectXUnlockSurface( p_vout, &p_pic[i] );
  1351.     }
  1352.     msg_Dbg( p_vout, "End NewPictureVec (%s)",
  1353.              I_OUTPUTPICTURES ? "succeeded" : "failed" );
  1354.     return VLC_SUCCESS;
  1355. }
  1356. /*****************************************************************************
  1357.  * FreePicture: destroy a picture vector allocated with NewPictureVec
  1358.  *****************************************************************************
  1359.  *
  1360.  *****************************************************************************/
  1361. static void FreePictureVec( vout_thread_t *p_vout, picture_t *p_pic,
  1362.                             int i_num_pics )
  1363. {
  1364.     int i;
  1365.     vlc_mutex_lock( &p_vout->p_sys->lock );
  1366.     p_vout->p_sys->p_current_surface = 0;
  1367.     vlc_mutex_unlock( &p_vout->p_sys->lock );
  1368.     for( i = 0; i < i_num_pics; i++ )
  1369.     {
  1370.         DirectXCloseSurface( p_vout, p_pic[i].p_sys->p_front_surface );
  1371.         for( i = 0; i < i_num_pics; i++ )
  1372.         {
  1373.             free( p_pic[i].p_sys );
  1374.         }
  1375.     }
  1376. }
  1377. /*****************************************************************************
  1378.  * UpdatePictureStruct: updates the internal data in the picture_t structure
  1379.  *****************************************************************************
  1380.  * This will setup stuff for use by the video_output thread
  1381.  *****************************************************************************/
  1382. static int UpdatePictureStruct( vout_thread_t *p_vout, picture_t *p_pic,
  1383.                                 int i_chroma )
  1384. {
  1385.     switch( p_vout->output.i_chroma )
  1386.     {
  1387.         case VLC_FOURCC('R','G','B','2'):
  1388.         case VLC_FOURCC('R','V','1','5'):
  1389.         case VLC_FOURCC('R','V','1','6'):
  1390.         case VLC_FOURCC('R','V','2','4'):
  1391.         case VLC_FOURCC('R','V','3','2'):
  1392.             p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
  1393.             p_pic->p->i_lines = p_vout->output.i_height;
  1394.             p_pic->p->i_visible_lines = p_vout->output.i_height;
  1395.             p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
  1396.             switch( p_vout->output.i_chroma )
  1397.             {
  1398.                 case VLC_FOURCC('R','G','B','2'):
  1399.                     p_pic->p->i_pixel_pitch = 1;
  1400.                     break;
  1401.                 case VLC_FOURCC('R','V','1','5'):
  1402.                 case VLC_FOURCC('R','V','1','6'):
  1403.                     p_pic->p->i_pixel_pitch = 2;
  1404.                     break;
  1405.                 case VLC_FOURCC('R','V','2','4'):
  1406.                     p_pic->p->i_pixel_pitch = 3;
  1407.                     break;
  1408.                 case VLC_FOURCC('R','V','3','2'):
  1409.                     p_pic->p->i_pixel_pitch = 4;
  1410.                     break;
  1411.                 default:
  1412.                     return VLC_EGENERIC;
  1413.             }
  1414.             p_pic->p->i_visible_pitch = p_vout->output.i_width *
  1415.               p_pic->p->i_pixel_pitch;
  1416.             p_pic->i_planes = 1;
  1417.             break;
  1418.         case VLC_FOURCC('Y','V','1','2'):
  1419.         case VLC_FOURCC('I','4','2','0'):
  1420.             /* U and V inverted compared to I420
  1421.              * Fixme: this should be handled by the vout core */
  1422.             p_vout->output.i_chroma = VLC_FOURCC('I','4','2','0');
  1423.             p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
  1424.             p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
  1425.             p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
  1426.             p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
  1427.             p_pic->p[Y_PLANE].i_pixel_pitch = 1;
  1428.             p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width *
  1429.               p_pic->p[Y_PLANE].i_pixel_pitch;
  1430.             p_pic->V_PIXELS =  p_pic->Y_PIXELS
  1431.               + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
  1432.             p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
  1433.             p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
  1434.             p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
  1435.             p_pic->p[V_PLANE].i_pixel_pitch = 1;
  1436.             p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
  1437.               p_pic->p[V_PLANE].i_pixel_pitch;
  1438.             p_pic->U_PIXELS = p_pic->V_PIXELS
  1439.               + p_pic->p[V_PLANE].i_lines * p_pic->p[V_PLANE].i_pitch;
  1440.             p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
  1441.             p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
  1442.             p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
  1443.             p_pic->p[U_PLANE].i_pixel_pitch = 1;
  1444.             p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
  1445.               p_pic->p[U_PLANE].i_pixel_pitch;
  1446.             p_pic->i_planes = 3;
  1447.             break;
  1448.         case VLC_FOURCC('I','Y','U','V'):
  1449.             p_pic->Y_PIXELS = p_pic->p_sys->ddsd.lpSurface;
  1450.             p_pic->p[Y_PLANE].i_lines = p_vout->output.i_height;
  1451.             p_pic->p[Y_PLANE].i_visible_lines = p_vout->output.i_height;
  1452.             p_pic->p[Y_PLANE].i_pitch = p_pic->p_sys->ddsd.lPitch;
  1453.             p_pic->p[Y_PLANE].i_pixel_pitch = 1;
  1454.             p_pic->p[Y_PLANE].i_visible_pitch = p_vout->output.i_width *
  1455.               p_pic->p[Y_PLANE].i_pixel_pitch;
  1456.             p_pic->U_PIXELS = p_pic->Y_PIXELS
  1457.               + p_pic->p[Y_PLANE].i_lines * p_pic->p[Y_PLANE].i_pitch;
  1458.             p_pic->p[U_PLANE].i_lines = p_vout->output.i_height / 2;
  1459.             p_pic->p[U_PLANE].i_visible_lines = p_vout->output.i_height / 2;
  1460.             p_pic->p[U_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
  1461.             p_pic->p[U_PLANE].i_pixel_pitch = 1;
  1462.             p_pic->p[U_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
  1463.               p_pic->p[U_PLANE].i_pixel_pitch;
  1464.             p_pic->V_PIXELS =  p_pic->U_PIXELS
  1465.               + p_pic->p[U_PLANE].i_lines * p_pic->p[U_PLANE].i_pitch;
  1466.             p_pic->p[V_PLANE].i_lines = p_vout->output.i_height / 2;
  1467.             p_pic->p[V_PLANE].i_visible_lines = p_vout->output.i_height / 2;
  1468.             p_pic->p[V_PLANE].i_pitch = p_pic->p[Y_PLANE].i_pitch / 2;
  1469.             p_pic->p[V_PLANE].i_pixel_pitch = 1;
  1470.             p_pic->p[V_PLANE].i_visible_pitch = p_vout->output.i_width / 2 *
  1471.               p_pic->p[V_PLANE].i_pixel_pitch;
  1472.             p_pic->i_planes = 3;
  1473.             break;
  1474.         case VLC_FOURCC('U','Y','V','Y'):
  1475.         case VLC_FOURCC('Y','U','Y','2'):
  1476.             p_pic->p->p_pixels = p_pic->p_sys->ddsd.lpSurface;
  1477.             p_pic->p->i_lines = p_vout->output.i_height;
  1478.             p_pic->p->i_visible_lines = p_vout->output.i_height;
  1479.             p_pic->p->i_pitch = p_pic->p_sys->ddsd.lPitch;
  1480.             p_pic->p->i_pixel_pitch = 2;
  1481.             p_pic->p->i_visible_pitch = p_vout->output.i_width *
  1482.               p_pic->p->i_pixel_pitch;
  1483.             p_pic->i_planes = 1;
  1484.             break;
  1485.         default:
  1486.             /* Unknown chroma, tell the guy to get lost */
  1487.             msg_Err( p_vout, "never heard of chroma 0x%.8x (%4.4s)",
  1488.                      p_vout->output.i_chroma,
  1489.                      (char*)&p_vout->output.i_chroma );
  1490.             return VLC_EGENERIC;
  1491.     }
  1492.     return VLC_SUCCESS;
  1493. }
  1494. /*****************************************************************************
  1495.  * DirectXGetDDrawCaps: Probe the capabilities of the hardware
  1496.  *****************************************************************************
  1497.  * It is nice to know which features are supported by the hardware so we can
  1498.  * find ways to optimize our rendering.
  1499.  *****************************************************************************/
  1500. static void DirectXGetDDrawCaps( vout_thread_t *p_vout )
  1501. {
  1502.     DDCAPS ddcaps;
  1503.     HRESULT dxresult;
  1504.     /* This is just an indication of whether or not we'll support overlay,
  1505.      * but with this test we don't know if we support YUV overlay */
  1506.     memset( &ddcaps, 0, sizeof( DDCAPS ));
  1507.     ddcaps.dwSize = sizeof(DDCAPS);
  1508.     dxresult = IDirectDraw2_GetCaps( p_vout->p_sys->p_ddobject,
  1509.                                      &ddcaps, NULL );
  1510.     if(dxresult != DD_OK )
  1511.     {
  1512.         msg_Warn( p_vout, "cannot get caps" );
  1513.     }
  1514.     else
  1515.     {
  1516.         vlc_bool_t bHasOverlay, bHasOverlayFourCC, bCanDeinterlace,
  1517.              bHasColorKey, bCanStretch, bCanBltFourcc,
  1518.              bAlignBoundarySrc, bAlignBoundaryDest,
  1519.              bAlignSizeSrc, bAlignSizeDest;
  1520.         /* Determine if the hardware supports overlay surfaces */
  1521.         bHasOverlay = (ddcaps.dwCaps & DDCAPS_OVERLAY) ? 1 : 0;
  1522.         /* Determine if the hardware supports overlay surfaces */
  1523.         bHasOverlayFourCC = (ddcaps.dwCaps & DDCAPS_OVERLAYFOURCC) ? 1 : 0;
  1524.         /* Determine if the hardware supports overlay deinterlacing */
  1525.         bCanDeinterlace = (ddcaps.dwCaps & DDCAPS2_CANFLIPODDEVEN) ? 1 : 0;
  1526.         /* Determine if the hardware supports colorkeying */
  1527.         bHasColorKey = (ddcaps.dwCaps & DDCAPS_COLORKEY) ? 1 : 0;
  1528.         /* Determine if the hardware supports scaling of the overlay surface */
  1529.         bCanStretch = (ddcaps.dwCaps & DDCAPS_OVERLAYSTRETCH) ? 1 : 0;
  1530.         /* Determine if the hardware supports color conversion during a blit */
  1531.         bCanBltFourcc = (ddcaps.dwCaps & DDCAPS_BLTFOURCC) ? 1 : 0;
  1532.         /* Determine overlay source boundary alignment */
  1533.         bAlignBoundarySrc = (ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYSRC) ? 1 : 0;
  1534.         /* Determine overlay destination boundary alignment */
  1535.         bAlignBoundaryDest = (ddcaps.dwCaps & DDCAPS_ALIGNBOUNDARYDEST) ? 1:0;
  1536.         /* Determine overlay destination size alignment */
  1537.         bAlignSizeSrc = (ddcaps.dwCaps & DDCAPS_ALIGNSIZESRC) ? 1 : 0;
  1538.         /* Determine overlay destination size alignment */
  1539.         bAlignSizeDest = (ddcaps.dwCaps & DDCAPS_ALIGNSIZEDEST) ? 1 : 0;
  1540.  
  1541.         msg_Dbg( p_vout, "DirectDraw Capabilities: overlay=%i yuvoverlay=%i "
  1542.                          "can_deinterlace_overlay=%i colorkey=%i stretch=%i "
  1543.                          "bltfourcc=%i",
  1544.                          bHasOverlay, bHasOverlayFourCC, bCanDeinterlace,
  1545.                          bHasColorKey, bCanStretch, bCanBltFourcc );
  1546.         if( bAlignBoundarySrc || bAlignBoundaryDest ||
  1547.             bAlignSizeSrc || bAlignSizeDest )
  1548.         {
  1549.             if( bAlignBoundarySrc ) p_vout->p_sys->i_align_src_boundary =
  1550.                 ddcaps.dwAlignBoundarySrc;
  1551.             if( bAlignBoundaryDest ) p_vout->p_sys->i_align_dest_boundary =
  1552.                 ddcaps.dwAlignBoundaryDest;
  1553.             if( bAlignSizeDest ) p_vout->p_sys->i_align_src_size =
  1554.                 ddcaps.dwAlignSizeSrc;
  1555.             if( bAlignSizeDest ) p_vout->p_sys->i_align_dest_size =
  1556.                 ddcaps.dwAlignSizeDest;
  1557.             msg_Dbg( p_vout, "align_boundary_src=%i,%i "
  1558.                      "align_boundary_dest=%i,%i "
  1559.                      "align_size_src=%i,%i align_size_dest=%i,%i",
  1560.                      bAlignBoundarySrc, p_vout->p_sys->i_align_src_boundary,
  1561.                      bAlignBoundaryDest, p_vout->p_sys->i_align_dest_boundary,
  1562.                      bAlignSizeSrc, p_vout->p_sys->i_align_src_size,
  1563.                      bAlignSizeDest, p_vout->p_sys->i_align_dest_size );
  1564.         }
  1565.         /* Don't ask for troubles */
  1566.         if( !bCanBltFourcc ) p_vout->p_sys->b_hw_yuv = FALSE;
  1567.     }
  1568. }
  1569. /*****************************************************************************
  1570.  * DirectXLockSurface: Lock surface and get picture data pointer
  1571.  *****************************************************************************
  1572.  * This function locks a surface and get the surface descriptor which amongst
  1573.  * other things has the pointer to the picture data.
  1574.  *****************************************************************************/
  1575. static int DirectXLockSurface( vout_thread_t *p_vout, picture_t *p_pic )
  1576. {
  1577.     HRESULT dxresult;
  1578.     /* Lock the surface to get a valid pointer to the picture buffer */
  1579.     memset( &p_pic->p_sys->ddsd, 0, sizeof( DDSURFACEDESC ));
  1580.     p_pic->p_sys->ddsd.dwSize = sizeof(DDSURFACEDESC);
  1581.     dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface,
  1582.                                          NULL, &p_pic->p_sys->ddsd,
  1583.                                          DDLOCK_NOSYSLOCK | DDLOCK_WAIT,
  1584.                                          NULL );
  1585.     if( dxresult != DD_OK )
  1586.     {
  1587.         if( dxresult == DDERR_INVALIDPARAMS )
  1588.         {
  1589.             /* DirectX 3 doesn't support the DDLOCK_NOSYSLOCK flag, resulting
  1590.              * in an invalid params error */
  1591.             dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
  1592.                                              &p_pic->p_sys->ddsd,
  1593.                                              DDLOCK_WAIT, NULL);
  1594.         }
  1595.         if( dxresult == DDERR_SURFACELOST )
  1596.         {
  1597.             /* Your surface can be lost so be sure
  1598.              * to check this and restore it if needed */
  1599.             /* When using overlays with back-buffers, we need to restore
  1600.              * the front buffer so the back-buffers get restored as well. */
  1601.             if( p_vout->p_sys->b_using_overlay  )
  1602.                 IDirectDrawSurface2_Restore( p_pic->p_sys->p_front_surface );
  1603.             else
  1604.                 IDirectDrawSurface2_Restore( p_pic->p_sys->p_surface );
  1605.             dxresult = IDirectDrawSurface2_Lock( p_pic->p_sys->p_surface, NULL,
  1606.                                                  &p_pic->p_sys->ddsd,
  1607.                                                  DDLOCK_WAIT, NULL);
  1608. #if 0
  1609.             if( dxresult == DDERR_SURFACELOST )
  1610.                 msg_Dbg( p_vout, "DirectXLockSurface: DDERR_SURFACELOST" );
  1611. #endif
  1612.         }
  1613.         if( dxresult != DD_OK )
  1614.         {
  1615.             return VLC_EGENERIC;
  1616.         }
  1617.     }
  1618.     /* Now we have a pointer to the surface memory, we can update our picture
  1619.      * structure. */
  1620.     if( UpdatePictureStruct( p_vout, p_pic, p_vout->output.i_chroma )
  1621.         != VLC_SUCCESS )
  1622.     {
  1623.         DirectXUnlockSurface( p_vout, p_pic );
  1624.         return VLC_EGENERIC;
  1625.     }
  1626.     else
  1627.         return VLC_SUCCESS;
  1628. }
  1629. /*****************************************************************************
  1630.  * DirectXUnlockSurface: Unlock a surface locked by DirectXLockSurface().
  1631.  *****************************************************************************/
  1632. static int DirectXUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
  1633. {
  1634.     /* Unlock the Surface */
  1635.     if( IDirectDrawSurface2_Unlock( p_pic->p_sys->p_surface, NULL ) == DD_OK )
  1636.         return VLC_SUCCESS;
  1637.     else
  1638.         return VLC_EGENERIC;
  1639. }
  1640. /*****************************************************************************
  1641.  * DirectXFindColorkey: Finds out the 32bits RGB pixel value of the colorkey
  1642.  *****************************************************************************/
  1643. static DWORD DirectXFindColorkey( vout_thread_t *p_vout, uint32_t i_color )
  1644. {
  1645.     DDSURFACEDESC ddsd;
  1646.     HRESULT dxresult;
  1647.     COLORREF i_rgb = 0;
  1648.     uint32_t i_pixel_backup;
  1649.     HDC hdc;
  1650.     ddsd.dwSize = sizeof(ddsd);
  1651.     dxresult = IDirectDrawSurface2_Lock( p_vout->p_sys->p_display, NULL,
  1652.                                          &ddsd, DDLOCK_WAIT, NULL );
  1653.     if( dxresult != DD_OK ) return 0;
  1654.     i_pixel_backup = *(uint32_t *)ddsd.lpSurface;
  1655.     switch( ddsd.ddpfPixelFormat.dwRGBBitCount )
  1656.     {
  1657.     case 4:
  1658.         *(uint8_t *)ddsd.lpSurface = 0x11;
  1659.         break;
  1660.     case 8:
  1661.         *(uint8_t *)ddsd.lpSurface = 0x01;
  1662.         break;
  1663.     case 16:
  1664.         *(uint16_t *)ddsd.lpSurface = 0x01;
  1665.         break;
  1666.     default:
  1667.         *(uint32_t *)ddsd.lpSurface = 0x01;
  1668.         break;
  1669.     }
  1670.     IDirectDrawSurface2_Unlock( p_vout->p_sys->p_display, NULL );
  1671.     if( IDirectDrawSurface2_GetDC( p_vout->p_sys->p_display, &hdc ) == DD_OK )
  1672.     {
  1673.         i_rgb = GetPixel( hdc, 0, 0 );
  1674.         IDirectDrawSurface2_ReleaseDC( p_vout->p_sys->p_display, hdc );
  1675.     }
  1676.     ddsd.dwSize = sizeof(ddsd);
  1677.     dxresult = IDirectDrawSurface2_Lock( p_vout->p_sys->p_display, NULL,
  1678.                                          &ddsd, DDLOCK_WAIT, NULL );
  1679.     if( dxresult != DD_OK ) return i_rgb;
  1680.     *(uint32_t *)ddsd.lpSurface = i_pixel_backup;
  1681.     IDirectDrawSurface2_Unlock( p_vout->p_sys->p_display, NULL );
  1682.     return i_rgb;
  1683. }
  1684. /*****************************************************************************
  1685.  * A few toolbox functions
  1686.  *****************************************************************************/
  1687. void SwitchWallpaperMode( vout_thread_t *p_vout, vlc_bool_t b_on )
  1688. {
  1689.     HWND hwnd;
  1690.     if( p_vout->p_sys->b_wallpaper == b_on ) return; /* Nothing to do */
  1691.     hwnd = FindWindow( "Progman", NULL );
  1692.     if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, "SHELLDLL_DefView", NULL );
  1693.     if( hwnd ) hwnd = FindWindowEx( hwnd, NULL, "SysListView32", NULL );
  1694.     if( !hwnd )
  1695.     {
  1696.         msg_Warn( p_vout, "couldn't find "SysListView32" window, "
  1697.                   "wallpaper mode not supported" );
  1698.         return;
  1699.     }
  1700.     p_vout->p_sys->b_wallpaper = b_on;
  1701.     msg_Dbg( p_vout, "wallpaper mode %s", b_on ? "enabled" : "disabled" );
  1702.     if( p_vout->p_sys->b_wallpaper )
  1703.     {
  1704.         p_vout->p_sys->color_bkg = ListView_GetBkColor( hwnd );
  1705.         p_vout->p_sys->color_bkgtxt = ListView_GetTextBkColor( hwnd );
  1706.         ListView_SetBkColor( hwnd, p_vout->p_sys->i_rgb_colorkey );
  1707.         ListView_SetTextBkColor( hwnd, p_vout->p_sys->i_rgb_colorkey );
  1708.     }
  1709.     else if( hwnd )
  1710.     {
  1711.         ListView_SetBkColor( hwnd, p_vout->p_sys->color_bkg );
  1712.         ListView_SetTextBkColor( hwnd, p_vout->p_sys->color_bkgtxt );
  1713.     }
  1714.     /* Update desktop */
  1715.     InvalidateRect( hwnd, NULL, TRUE );            
  1716.     UpdateWindow( hwnd );
  1717. }
  1718. /*****************************************************************************
  1719.  * config variable callback
  1720.  *****************************************************************************/
  1721. BOOL WINAPI DirectXEnumCallback2( GUID* p_guid, LPTSTR psz_desc,
  1722.                                   LPTSTR psz_drivername, VOID* p_context,
  1723.                                   HMONITOR hmon )
  1724. {
  1725.     module_config_t *p_item = (module_config_t *)p_context;
  1726.     p_item->ppsz_list =
  1727.         (char **)realloc( p_item->ppsz_list,
  1728.                           (p_item->i_list+2) * sizeof(char *) );
  1729.     p_item->ppsz_list_text =
  1730.         (char **)realloc( p_item->ppsz_list_text,
  1731.                           (p_item->i_list+2) * sizeof(char *) );
  1732.     p_item->ppsz_list[p_item->i_list] = strdup( psz_drivername );
  1733.     p_item->ppsz_list_text[p_item->i_list] = NULL;
  1734.     p_item->i_list++;
  1735.     p_item->ppsz_list[p_item->i_list] = NULL;
  1736.     p_item->ppsz_list_text[p_item->i_list] = NULL;
  1737.     return TRUE; /* Keep enumerating */
  1738. }
  1739. static int FindDevicesCallback( vlc_object_t *p_this, char const *psz_name,
  1740.                                vlc_value_t newval, vlc_value_t oldval, void *d)
  1741. {
  1742.     HRESULT (WINAPI *OurDirectDrawEnumerateEx)( LPDDENUMCALLBACKEXA, LPVOID,
  1743.                                                 DWORD );
  1744.     HINSTANCE hddraw_dll;
  1745.     module_config_t *p_item;
  1746.     int i;
  1747.     p_item = config_FindConfig( p_this, psz_name );
  1748.     if( !p_item ) return VLC_SUCCESS;
  1749.     /* Clear-up the current list */
  1750.     if( p_item->i_list )
  1751.     {
  1752.         /* Keep the first entry */
  1753.         for( i = 1; i < p_item->i_list; i++ )
  1754.         {
  1755.             free( p_item->ppsz_list[i] );
  1756.             free( p_item->ppsz_list_text[i] );
  1757.         }
  1758.         /* TODO: Remove when no more needed */
  1759.         p_item->ppsz_list[i] = NULL;
  1760.         p_item->ppsz_list_text[i] = NULL;
  1761.     }
  1762.     p_item->i_list = 1;
  1763.     /* Load direct draw DLL */
  1764.     hddraw_dll = LoadLibrary("DDRAW.DLL");
  1765.     if( hddraw_dll == NULL ) return VLC_SUCCESS;
  1766.     OurDirectDrawEnumerateEx =
  1767.       (void *)GetProcAddress( hddraw_dll, "DirectDrawEnumerateExA" );
  1768.     if( OurDirectDrawEnumerateEx )
  1769.     {
  1770.         /* Enumerate displays */
  1771.         OurDirectDrawEnumerateEx( DirectXEnumCallback2, p_item,
  1772.                                   DDENUM_ATTACHEDSECONDARYDEVICES );
  1773.     }
  1774.     FreeLibrary( hddraw_dll );
  1775.     /* Signal change to the interface */
  1776.     p_item->b_dirty = VLC_TRUE;
  1777.     return VLC_SUCCESS;
  1778. }
  1779. static int WallpaperCallback( vlc_object_t *p_this, char const *psz_cmd,
  1780.                               vlc_value_t oldval, vlc_value_t newval,
  1781.                               void *p_data )
  1782. {
  1783.     vout_thread_t *p_vout = (vout_thread_t *)p_this;
  1784.     if( (newval.b_bool && !p_vout->p_sys->b_wallpaper) ||
  1785.         (!newval.b_bool && p_vout->p_sys->b_wallpaper) )
  1786.     {
  1787.         playlist_t *p_playlist;
  1788.         p_playlist =
  1789.             (playlist_t *)vlc_object_find( p_this, VLC_OBJECT_PLAYLIST,
  1790.                                            FIND_PARENT );
  1791.         if( p_playlist )
  1792.         {
  1793.             /* Modify playlist as well because the vout might have to be
  1794.              * restarted */
  1795.             var_Create( p_playlist, "directx-wallpaper", VLC_VAR_BOOL );
  1796.             var_Set( p_playlist, "directx-wallpaper", newval );
  1797.             vlc_object_release( p_playlist );
  1798.         }
  1799.         p_vout->p_sys->i_changes |= DX_WALLPAPER_CHANGE;
  1800.     }
  1801.     return VLC_SUCCESS;
  1802. }