]> git.sesse.net Git - vlc/blobdiff - modules/video_output/msw/wingdi.c
Revert "Revert "redundant includes of vlc_playlist.h""
[vlc] / modules / video_output / msw / wingdi.c
index 5db738e522c298b05b1485aacca757e643ccde47..eeb6ca89bbdcfd002b79bed0952ea6ad4b0779d5 100644 (file)
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
+#include <assert.h>
 
 #include <vlc_common.h>
 #include <vlc_plugin.h>
-#include <vlc_interface.h>
-#include <vlc_playlist.h>
-#include <vlc_vout.h>
+#include <vlc_vout_display.h>
 
 #include <windows.h>
-#include <tchar.h>
 #include <commctrl.h>
 
-/*#ifdef MODULE_NAME_IS_wingapi
-    typedef struct GXDisplayProperties {
-        DWORD cxWidth;
-        DWORD cyHeight;
-        long cbxPitch;
-        long cbyPitch;
-        long cBPP;
-        DWORD ffFormat;
-    } GXDisplayProperties;
-
-    typedef struct GXScreenRect {
-        DWORD dwTop;
-        DWORD dwLeft;
-        DWORD dwWidth;
-        DWORD dwHeight;
-    } GXScreenRect;
-
-#   define GX_FULLSCREEN    0x01
-#   define GX_NORMALKEYS    0x02
-#   define GX_LANDSCAPEKEYS 0x03
-
-#   ifndef kfLandscape
-#       define kfLandscape      0x8
-#       define kfPalette        0x10
-#       define kfDirect         0x20
-#       define kfDirect555      0x40
-#       define kfDirect565      0x80
-#       define kfDirect888      0x100
-#       define kfDirect444      0x200
-#       define kfDirectInverted 0x400
-#   endif
-#endif */ /* MODULE_NAME_IS_wingapi */
-
-#include "vout.h"
-
-#define MAX_DIRECTBUFFERS 10
-
-#ifdef UNDER_CE
-#ifndef WS_OVERLAPPEDWINDOW
-#   define WS_OVERLAPPEDWINDOW 0xcf0000
-#endif
-#ifndef WS_EX_NOPARENTNOTIFY
-#   define WS_EX_NOPARENTNOTIFY 4
-#endif
-#ifndef WS_EX_APPWINDOW
-#define WS_EX_APPWINDOW 0x40000
-#endif
-//#define SetWindowLongPtr SetWindowLong
-//#define GetWindowLongPtr GetWindowLong
-//#define GWLP_USERDATA GWL_USERDATA
-#define AdjustWindowRect(a,b,c)
-#endif //UNDER_CE
+#include "common.h"
 
 #ifndef WS_NONAVDONEBUTTON
-#define WS_NONAVDONEBUTTON 0
-#endif
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-static int  OpenVideo  ( vlc_object_t * );
-static void CloseVideo ( vlc_object_t * );
-
-static int  Init      ( vout_thread_t * );
-static void End       ( vout_thread_t * );
-static int  Manage    ( vout_thread_t * );
-static void Render    ( vout_thread_t *, picture_t * );
-#ifdef MODULE_NAME_IS_wingapi
-static void FirstDisplayGAPI( vout_thread_t *, picture_t * );
-static void DisplayGAPI( vout_thread_t *, picture_t * );
-static int GAPILockSurface( vout_thread_t *, picture_t * );
-static int GAPIUnlockSurface( vout_thread_t *, picture_t * );
-#else
-static void FirstDisplayGDI( vout_thread_t *, picture_t * );
-static void DisplayGDI( vout_thread_t *, picture_t * );
+#   define WS_NONAVDONEBUTTON 0
 #endif
-static void SetPalette( vout_thread_t *, uint16_t *, uint16_t *, uint16_t * );
-
-static void InitBuffers        ( vout_thread_t * );
-
-
-
-#define DX_POSITION_CHANGE 0x1000
 
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
+static int  Open (vlc_object_t *);
+static void Close(vlc_object_t *);
+
 vlc_module_begin ()
-    set_category( CAT_VIDEO )
-    set_subcategory( SUBCAT_VIDEO_VOUT )
+    set_category(CAT_VIDEO)
+    set_subcategory(SUBCAT_VIDEO_VOUT)
 #ifdef MODULE_NAME_IS_wingapi
-    set_shortname( "Windows GAPI" )
-    set_description( N_("Windows GAPI video output") )
-    set_capability( "video output", 20 )
+    set_shortname("GAPI")
+    set_description(N_("Windows GAPI video output"))
+    set_capability("vout display", 20)
 #else
-    set_shortname( "Windows GDI" )
-    set_description( N_("Windows GDI video output") )
-    set_capability( "video output", 10 )
+    set_shortname("GDI")
+    set_description(N_("Windows GDI video output"))
+    set_capability("vout display", 10)
 #endif
-    set_callbacks( OpenVideo, CloseVideo )
+    set_callbacks(Open, Close)
 vlc_module_end ()
 
+
 /*****************************************************************************
- * OpenVideo: activate GDI video thread output method
+ * Local prototypes
  *****************************************************************************/
-static int OpenVideo ( vlc_object_t *p_this )
+static picture_pool_t *Pool  (vout_display_t *, unsigned);
+static void           Display(vout_display_t *, picture_t *);
+static int            Control(vout_display_t *, int, va_list);
+static void           Manage (vout_display_t *);
+
+static int            Init(vout_display_t *, video_format_t *, int, int);
+static void           Clean(vout_display_t *);
+
+/* */
+static int Open(vlc_object_t *object)
 {
-    vout_thread_t * p_vout = (vout_thread_t *)p_this;
+    vout_display_t *vd = (vout_display_t *)object;
+    vout_display_sys_t *sys;
 
-    p_vout->p_sys = (vout_sys_t *)calloc( 1, sizeof(vout_sys_t) );
-    if( !p_vout->p_sys ) return VLC_ENOMEM;
+    vd->sys = sys = calloc(1, sizeof(*sys));
+    if (!sys)
+        return VLC_ENOMEM;
 
 #ifdef MODULE_NAME_IS_wingapi
     /* Load GAPI */
-    p_vout->p_sys->gapi_dll = LoadLibrary( _T("GX.DLL") );
-    if( p_vout->p_sys->gapi_dll == NULL )
-    {
-        msg_Warn( p_vout, "failed loading gx.dll" );
-        free( p_vout->p_sys );
+    sys->gapi_dll = LoadLibrary(_T("GX.DLL"));
+    if (!sys->gapi_dll) {
+        msg_Warn(vd, "failed loading gx.dll");
+        free(sys);
         return VLC_EGENERIC;
     }
 
-    GXOpenDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
-        _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z") );
-    GXCloseDisplay = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
-        _T("?GXCloseDisplay@@YAHXZ") );
-    GXBeginDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
-        _T("?GXBeginDraw@@YAPAXXZ") );
-    GXEndDraw = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
-        _T("?GXEndDraw@@YAHXZ") );
-    GXGetDisplayProperties = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
-        _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ") );
-    GXSuspend = (void *)GetProcAddress( p_vout->p_sys->gapi_dll,
-        _T("?GXSuspend@@YAHXZ") );
-    GXResume = GetProcAddress( p_vout->p_sys->gapi_dll,
-        _T("?GXResume@@YAHXZ") );
-
-    if( !GXOpenDisplay || !GXCloseDisplay || !GXBeginDraw || !GXEndDraw ||
-        !GXGetDisplayProperties || !GXSuspend || !GXResume )
-    {
-        msg_Err( p_vout, "failed GetProcAddress on gapi.dll" );
-        free( p_vout->p_sys );
+    GXOpenDisplay = (void *)GetProcAddress(sys->gapi_dll,
+        _T("?GXOpenDisplay@@YAHPAUHWND__@@K@Z"));
+    GXCloseDisplay = (void *)GetProcAddress(sys->gapi_dll,
+        _T("?GXCloseDisplay@@YAHXZ"));
+    GXBeginDraw = (void *)GetProcAddress(sys->gapi_dll,
+        _T("?GXBeginDraw@@YAPAXXZ"));
+    GXEndDraw = (void *)GetProcAddress(sys->gapi_dll,
+        _T("?GXEndDraw@@YAHXZ"));
+    GXGetDisplayProperties = (void *)GetProcAddress(sys->gapi_dll,
+        _T("?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ"));
+    GXSuspend = (void *)GetProcAddress(sys->gapi_dll,
+        _T("?GXSuspend@@YAHXZ"));
+    GXResume = GetProcAddress(sys->gapi_dll,
+        _T("?GXResume@@YAHXZ"));
+
+    if (!GXOpenDisplay || !GXCloseDisplay ||
+        !GXBeginDraw || !GXEndDraw ||
+        !GXGetDisplayProperties || !GXSuspend || !GXResume) {
+        msg_Err(vd, "failed GetProcAddress on gapi.dll");
+        free(sys);
         return VLC_EGENERIC;
     }
 
-    msg_Dbg( p_vout, "GAPI DLL loaded" );
-
-    p_vout->p_sys->render_width = p_vout->render.i_width;
-    p_vout->p_sys->render_height = p_vout->render.i_height;
-#endif
-
-    p_vout->p_sys->p_event = (vlc_object_t *)
-        vlc_object_create( p_vout, sizeof( vlc_object_t ) );
-    if( !p_vout->p_sys->p_event )
-    {
-        free( p_vout->p_sys );
-        return VLC_ENOMEM;
-    }
-
-    p_vout->pf_init = Init;
-    p_vout->pf_end = End;
-    p_vout->pf_manage = Manage;
-    p_vout->pf_render = Render;
-#ifdef MODULE_NAME_IS_wingapi
-    p_vout->pf_display = FirstDisplayGAPI;
-
-    p_vout->p_sys->b_focus = 0;
-    p_vout->p_sys->b_parent_focus = 0;
-
-#else
-    p_vout->pf_display = FirstDisplayGDI;
+    msg_Dbg(vd, "GAPI DLL loaded");
 #endif
 
-    p_vout->p_sys->hwnd = p_vout->p_sys->hvideownd = NULL;
-    p_vout->p_sys->hparent = p_vout->p_sys->hfswnd = NULL;
-    p_vout->p_sys->i_changes = 0;
-    vlc_mutex_init( &p_vout->p_sys->lock );
-    SetRectEmpty( &p_vout->p_sys->rect_display );
-    SetRectEmpty( &p_vout->p_sys->rect_parent );
-
-    var_Create( p_vout, "video-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-    var_Create( p_vout, "disable-screensaver", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-
-    p_vout->p_sys->b_cursor_hidden = 0;
-    p_vout->p_sys->i_lastmoved = mdate();
-    p_vout->p_sys->i_mouse_hide_timeout =
-        var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
-
-    /* Set main window's size */
-    p_vout->p_sys->i_window_width = p_vout->i_window_width;
-    p_vout->p_sys->i_window_height = p_vout->i_window_height;
-
-    if ( CreateEventThread( p_vout ) )
-    {
-
-#ifndef UNDER_CE
-        /* Variable to indicate if the window should be on top of others */
-        /* Trigger a callback right now */
-        var_TriggerCallback( p_vout, "video-on-top" );
+    if (CommonInit(vd))
+        goto error;
+
+    /* */
+    video_format_t fmt = vd->fmt;
+    if (Init(vd, &fmt, fmt.i_width, fmt.i_height))
+        goto error;
+
+    vout_display_info_t info = vd->info;
+    info.is_slow              = false;
+    info.has_double_click     = true;
+    info.has_hide_mouse       = false;
+    info.has_pictures_invalid = true;
+
+    /* */
+    vd->fmt  = fmt;
+    vd->info = info;
+
+    vd->pool    = Pool;
+    vd->prepare = NULL;
+    vd->display = Display;
+    vd->manage  = Manage;
+    vd->control = Control;
+    return VLC_SUCCESS;
 
-        DisableScreensaver ( p_vout );
-#endif
-        return VLC_SUCCESS;
-    }
-    else
-    {
-        CloseVideo( VLC_OBJECT(p_vout) );
-        return VLC_EGENERIC;
-    }
+error:
+    Close(VLC_OBJECT(vd));
+    return VLC_EGENERIC;
 }
 
-/*****************************************************************************
- * CloseVideo: deactivate the GDI video output
- *****************************************************************************/
-static void CloseVideo ( vlc_object_t *p_this )
+/* */
+static void Close(vlc_object_t *object)
 {
-    vout_thread_t * p_vout = (vout_thread_t *)p_this;
+    vout_display_t *vd = (vout_display_t *)object;
 
-    StopEventThread( p_vout );
+    Clean(vd);
 
-#ifndef UNDER_CE
-    RestoreScreensaver( p_vout );
-#endif
+    CommonClean(vd);
 
 #ifdef MODULE_NAME_IS_wingapi
-    FreeLibrary( p_vout->p_sys->gapi_dll );
+    FreeLibrary(vd->sys->gapi_dll);
 #endif
 
-    free( p_vout->p_sys );
-    p_vout->p_sys = NULL;
+    free(vd->sys);
 }
 
-/*****************************************************************************
- * Init: initialize video thread output method
- *****************************************************************************/
-static int Init( vout_thread_t *p_vout )
+/* */
+static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
 {
-    picture_t *p_pic;
-
-    /* Initialize offscreen buffer */
-    InitBuffers( p_vout );
-
-    p_vout->p_sys->rect_display.left = 0;
-    p_vout->p_sys->rect_display.top = 0;
-    p_vout->p_sys->rect_display.right  = GetSystemMetrics(SM_CXSCREEN);
-    p_vout->p_sys->rect_display.bottom = GetSystemMetrics(SM_CYSCREEN);
-
-    I_OUTPUTPICTURES = 0;
-
-    /* Initialize the output structure */
-    switch( p_vout->p_sys->i_depth )
-    {
-    case 8:
-        p_vout->output.i_chroma = VLC_CODEC_RGB8;
-        p_vout->output.pf_setpalette = SetPalette;
-        break;
-    case 15:
-        p_vout->output.i_chroma = VLC_CODEC_RGB15;
-        p_vout->output.i_rmask  = 0x7c00;
-        p_vout->output.i_gmask  = 0x03e0;
-        p_vout->output.i_bmask  = 0x001f;
-        break;
-    case 16:
-        p_vout->output.i_chroma = VLC_CODEC_RGB16;
-        p_vout->output.i_rmask  = 0xf800;
-        p_vout->output.i_gmask  = 0x07e0;
-        p_vout->output.i_bmask  = 0x001f;
-        break;
-    case 24:
-        p_vout->output.i_chroma = VLC_CODEC_RGB24;
-        p_vout->output.i_rmask  = 0x00ff0000;
-        p_vout->output.i_gmask  = 0x0000ff00;
-        p_vout->output.i_bmask  = 0x000000ff;
-        break;
-    case 32:
-        p_vout->output.i_chroma = VLC_CODEC_RGB32;
-        p_vout->output.i_rmask  = 0x00ff0000;
-        p_vout->output.i_gmask  = 0x0000ff00;
-        p_vout->output.i_bmask  = 0x000000ff;
-        break;
-    default:
-        msg_Err( p_vout, "screen depth %i not supported",
-                 p_vout->p_sys->i_depth );
-        return VLC_EGENERIC;
-        break;
-    }
-
-    p_pic = &p_vout->p_picture[0];
-
-#ifdef MODULE_NAME_IS_wingapi
-    p_vout->output.i_width  = 0;
-    p_vout->output.i_height = 0;
-    p_pic->pf_lock  = GAPILockSurface;
-    p_pic->pf_unlock = GAPIUnlockSurface;
-    Manage( p_vout );
-    GAPILockSurface( p_vout, p_pic );
-    p_vout->i_changes = 0;
-    p_vout->output.i_width  = p_vout->p_sys->render_width;
-    p_vout->output.i_height = p_vout->p_sys->render_height;
-
-#else
-    p_vout->output.i_width  = p_vout->render.i_width;
-    p_vout->output.i_height = p_vout->render.i_height;
-
-    p_vout->fmt_out = p_vout->fmt_in;
-    p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
-#endif
-
-    p_vout->output.i_aspect = p_vout->render.i_aspect;
-
-    p_pic->p->p_pixels = p_vout->p_sys->p_pic_buffer;
-    p_pic->p->i_lines = p_vout->output.i_height;
-    p_pic->p->i_visible_lines = p_vout->output.i_height;
-    p_pic->p->i_pitch = p_vout->p_sys->i_pic_pitch;
-    p_pic->p->i_pixel_pitch = p_vout->p_sys->i_pic_pixel_pitch;
-    p_pic->p->i_visible_pitch = p_vout->output.i_width *
-        p_pic->p->i_pixel_pitch;
-    p_pic->i_planes = 1;
-    p_pic->i_status = DESTROYED_PICTURE;
-    p_pic->i_type   = DIRECT_PICTURE;
-
-    PP_OUTPUTPICTURE[ I_OUTPUTPICTURES++ ] = p_pic;
-
-    /* Change the window title bar text */
-    PostMessage( p_vout->p_sys->hwnd, WM_VLC_CHANGE_TEXT, 0, 0 );
-    UpdateRects( p_vout, true );
-
-    return VLC_SUCCESS;
+    VLC_UNUSED(count);
+    return vd->sys->pool;
 }
-
-/*****************************************************************************
- * End: terminate video thread output method
- *****************************************************************************/
-static void End( vout_thread_t *p_vout )
+static void Display(vout_display_t *vd, picture_t *picture)
 {
+    vout_display_sys_t *sys = vd->sys;
+
 #ifdef MODULE_NAME_IS_wingapi
-    GXCloseDisplay();
+    /* */
 #else
-    DeleteDC( p_vout->p_sys->off_dc );
-    DeleteObject( p_vout->p_sys->off_bitmap );
-#endif
-}
-
-/*****************************************************************************
- * Manage: handle events
- *****************************************************************************
- * This function should be called regularly by video output thread. It manages
- * console events. It returns a non null value on error.
- *****************************************************************************/
-static int Manage( vout_thread_t *p_vout )
-{
-    /* If we do not control our window, we check for geometry changes
-     * ourselves because the parent might not send us its events. */
-    vlc_mutex_lock( &p_vout->p_sys->lock );
-    if( p_vout->p_sys->hparent && !p_vout->b_fullscreen )
-    {
-        RECT rect_parent;
-        POINT point;
-
-        vlc_mutex_unlock( &p_vout->p_sys->lock );
-
-        GetClientRect( p_vout->p_sys->hparent, &rect_parent );
-        point.x = point.y = 0;
-        ClientToScreen( p_vout->p_sys->hparent, &point );
-        OffsetRect( &rect_parent, point.x, point.y );
-
-        if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) )
-        {
-            int i_x, i_y, i_width, i_height;
-            p_vout->p_sys->rect_parent = rect_parent;
-
-            /* This one is to force the update even if only
-             * the position has changed */
-            SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1,
-                          rect_parent.right - rect_parent.left,
-                          rect_parent.bottom - rect_parent.top, 0 );
-
-            SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0,
-                          rect_parent.right - rect_parent.left,
-                          rect_parent.bottom - rect_parent.top, 0 );
-
-            vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left,
-                               rect_parent.bottom - rect_parent.top,
-                               &i_x, &i_y, &i_width, &i_height );
-
-            SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP,
-                          i_x, i_y, i_width, i_height, 0 );
-        }
-    }
-    else
-    {
-        vlc_mutex_unlock( &p_vout->p_sys->lock );
-    }
-
-    /* autoscale toggle */
-    if( p_vout->i_changes & VOUT_SCALE_CHANGE )
-    {
-        p_vout->i_changes &= ~VOUT_SCALE_CHANGE;
-
-        p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" );
-        p_vout->i_zoom = (int) ZOOM_FP_FACTOR;
-
-        UpdateRects( p_vout, true );
-    }
-
-    /* scaling factor */
-    if( p_vout->i_changes & VOUT_ZOOM_CHANGE )
-    {
-        p_vout->i_changes &= ~VOUT_ZOOM_CHANGE;
-
-        p_vout->b_autoscale = false;
-        p_vout->i_zoom =
-            (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) );
-        UpdateRects( p_vout, true );
-    }
-
-    /* Check for cropping / aspect changes */
-    if( p_vout->i_changes & VOUT_CROP_CHANGE ||
-        p_vout->i_changes & VOUT_ASPECT_CHANGE )
-    {
-        p_vout->i_changes &= ~VOUT_CROP_CHANGE;
-        p_vout->i_changes &= ~VOUT_ASPECT_CHANGE;
-
-        p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset;
-        p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset;
-        p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width;
-        p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height;
-        p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect;
-        p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num;
-        p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den;
-        p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
-        UpdateRects( p_vout, true );
-    }
-
-    /*
-     * Position Change
-     */
-    if( p_vout->p_sys->i_changes & DX_POSITION_CHANGE )
-    {
-        p_vout->p_sys->i_changes &= ~DX_POSITION_CHANGE;
-    }
-
-    /* We used to call the Win32 PeekMessage function here to read the window
-     * messages. But since window can stay blocked into this function for a
-     * long time (for example when you move your window on the screen), I
-     * decided to isolate PeekMessage in another thread. */
-
-    /*
-     * Fullscreen change
-     */
-    if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE
-        || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE )
-    {
-        Win32ToggleFullscreen( p_vout );
-
-        p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
-        p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
-    }
-
-    /*
-     * Pointer change
-     */
-    if( p_vout->b_fullscreen && !p_vout->p_sys->b_cursor_hidden &&
-        (mdate() - p_vout->p_sys->i_lastmoved) >
-            p_vout->p_sys->i_mouse_hide_timeout )
-    {
-        POINT point;
-        HWND hwnd;
-
-        /* Hide the cursor only if it is inside our window */
-        GetCursorPos( &point );
-        hwnd = WindowFromPoint(point);
-        if( hwnd == p_vout->p_sys->hwnd || hwnd == p_vout->p_sys->hvideownd )
-        {
-            PostMessage( p_vout->p_sys->hwnd, WM_VLC_HIDE_MOUSE, 0, 0 );
-        }
-        else
-        {
-            p_vout->p_sys->i_lastmoved = mdate();
-        }
-    }
+#define rect_src vd->sys->rect_src
+#define rect_src_clipped vd->sys->rect_src_clipped
+#define rect_dest vd->sys->rect_dest
+#define rect_dest_clipped vd->sys->rect_dest_clipped
+    RECT rect_dst = rect_dest_clipped;
+    HDC hdc = GetDC(sys->hvideownd);
 
-    /*
-     * "Always on top" status change
-     */
-    if( p_vout->p_sys->b_on_top_change )
-    {
-        vlc_value_t val;
-        HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE );
-
-        var_Get( p_vout, "video-on-top", &val );
-
-        /* Set the window on top if necessary */
-        if( val.b_bool && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
-                           & WS_EX_TOPMOST ) )
-        {
-            CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
-                           MF_BYCOMMAND | MFS_CHECKED );
-            SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0,
-                          SWP_NOSIZE | SWP_NOMOVE );
-        }
-        else
-        /* The window shouldn't be on top */
-        if( !val.b_bool && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE )
-                           & WS_EX_TOPMOST ) )
-        {
-            CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP,
-                           MF_BYCOMMAND | MFS_UNCHECKED );
-            SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
-                          SWP_NOSIZE | SWP_NOMOVE );
-        }
-
-        p_vout->p_sys->b_on_top_change = false;
-    }
+    OffsetRect(&rect_dst, -rect_dest.left, -rect_dest.top);
+    SelectObject(sys->off_dc, sys->off_bitmap);
 
-    /* Check if the event thread is still running */
-    if( !vlc_object_alive (p_vout->p_sys->p_event) )
-    {
-        return VLC_EGENERIC; /* exit */
+    if (rect_dest_clipped.right - rect_dest_clipped.left !=
+        rect_src_clipped.right - rect_src_clipped.left ||
+        rect_dest_clipped.bottom - rect_dest_clipped.top !=
+        rect_src_clipped.bottom - rect_src_clipped.top) {
+        StretchBlt(hdc, rect_dst.left, rect_dst.top,
+                   rect_dst.right, rect_dst.bottom,
+                   sys->off_dc,
+                   rect_src_clipped.left,  rect_src_clipped.top,
+                   rect_src_clipped.right, rect_src_clipped.bottom,
+                   SRCCOPY);
+    } else {
+        BitBlt(hdc, rect_dst.left, rect_dst.top,
+               rect_dst.right, rect_dst.bottom,
+               sys->off_dc,
+               rect_src_clipped.left, rect_src_clipped.top,
+               SRCCOPY);
     }
 
-    return VLC_SUCCESS;
-}
+    ReleaseDC(sys->hvideownd, hdc);
+#undef rect_src
+#undef rect_src_clipped
+#undef rect_dest
+#undef rect_dest_clipped
+#endif
+    /* TODO */
+    picture_Release(picture);
 
-/*****************************************************************************
- * Render: render previously calculated output
- *****************************************************************************/
-static void Render( vout_thread_t *p_vout, picture_t *p_pic )
-{
-    /* No need to do anything, the fake direct buffers stay as they are */
-    (void)p_vout;
-    (void)p_pic;
+    CommonDisplay(vd);
 }
-
-/*****************************************************************************
- * Display: displays previously rendered output
- *****************************************************************************/
-#define rect_src p_vout->p_sys->rect_src
-#define rect_src_clipped p_vout->p_sys->rect_src_clipped
-#define rect_dest p_vout->p_sys->rect_dest
-#define rect_dest_clipped p_vout->p_sys->rect_dest_clipped
-
-#ifndef MODULE_NAME_IS_wingapi
-static void DisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
+static int Control(vout_display_t *vd, int query, va_list args)
 {
-    vout_sys_t *p_sys = p_vout->p_sys;
-    RECT rect_dst = rect_dest_clipped;
-    HDC hdc = GetDC( p_sys->hvideownd );
-
-    OffsetRect( &rect_dst, -rect_dest.left, -rect_dest.top );
-    SelectObject( p_sys->off_dc, p_sys->off_bitmap );
-
-    if( rect_dest_clipped.right - rect_dest_clipped.left !=
-        rect_src_clipped.right - rect_src_clipped.left ||
-        rect_dest_clipped.bottom - rect_dest_clipped.top !=
-        rect_src_clipped.bottom - rect_src_clipped.top )
-    {
-        StretchBlt( hdc, rect_dst.left, rect_dst.top,
-                    rect_dst.right, rect_dst.bottom,
-                    p_sys->off_dc, rect_src_clipped.left, rect_src_clipped.top,
-                    rect_src_clipped.right, rect_src_clipped.bottom, SRCCOPY );
-    }
-    else
-    {
-        BitBlt( hdc, rect_dst.left, rect_dst.top,
-                rect_dst.right, rect_dst.bottom,
-                p_sys->off_dc, rect_src_clipped.left,
-                rect_src_clipped.top, SRCCOPY );
+    switch (query) {
+    case VOUT_DISPLAY_RESET_PICTURES:
+        assert(0);
+        return VLC_EGENERIC;
+    default:
+        return CommonControl(vd, query, args);
     }
 
-    ReleaseDC( p_sys->hvideownd, hdc );
 }
-
-static void FirstDisplayGDI( vout_thread_t *p_vout, picture_t *p_pic )
+static void Manage(vout_display_t *vd)
 {
-    /*
-    ** Video window is initially hidden, show it now since we got a
-    ** picture to show.
-    */
-    SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
-        SWP_ASYNCWINDOWPOS|
-        SWP_FRAMECHANGED|
-        SWP_SHOWWINDOW|
-        SWP_NOMOVE|
-        SWP_NOSIZE|
-        SWP_NOZORDER );
-
-    /* get initial picture presented */
-    DisplayGDI(p_vout, p_pic);
-
-    /* use and restores proper display function for further pictures */
-    p_vout->pf_display = DisplayGDI;
+    CommonManage(vd);
 }
 
-#else
+#ifdef MODULE_NAME_IS_wingapi
+struct picture_sys_t {
+    vout_display_t *vd;
+};
 
-static int GAPILockSurface( vout_thread_t *p_vout, picture_t *p_pic )
+static int Lock(picture_t *picture)
 {
-    vout_sys_t *p_sys = p_vout->p_sys;
-    int i_x, i_y, i_width, i_height;
-    RECT video_rect;
-    POINT point;
-
-    GetClientRect( p_sys->hwnd, &video_rect);
-    vout_PlacePicture( p_vout, video_rect.right - video_rect.left,
-                       video_rect.bottom - video_rect.top,
-                       &i_x, &i_y, &i_width, &i_height );
-    point.x = point.y = 0;
-    ClientToScreen( p_sys->hwnd, &point );
-    i_x += point.x + video_rect.left;
-    i_y += point.y + video_rect.top;
-
-    if( i_width != p_vout->output.i_width ||
-        i_height != p_vout->output.i_height )
-    {
-        GXDisplayProperties gxdisplayprop = GXGetDisplayProperties();
-
-        p_sys->render_width = i_width;
-        p_sys->render_height = i_height;
-        p_vout->i_changes |= VOUT_SIZE_CHANGE;
-
-        msg_Dbg( p_vout, "vout size change (%ix%i -> %ix%i)",
-                 i_width, i_height, p_vout->output.i_width,
-                 p_vout->output.i_height );
-
-        p_vout->p_sys->i_pic_pixel_pitch = gxdisplayprop.cbxPitch;
-        p_vout->p_sys->i_pic_pitch = gxdisplayprop.cbyPitch;
-        return VLC_EGENERIC;
-    }
-    else
-    {
-        GXDisplayProperties gxdisplayprop;
-        RECT display_rect, dest_rect;
-        uint8_t *p_dest, *p_src = p_pic->p->p_pixels;
-
-        video_rect.left = i_x; video_rect.top = i_y;
-        video_rect.right = i_x + i_width;
-        video_rect.bottom = i_y + i_height;
-
-        gxdisplayprop = GXGetDisplayProperties();
-        display_rect.left = 0; display_rect.top = 0;
-        display_rect.right = gxdisplayprop.cxWidth;
-        display_rect.bottom = gxdisplayprop.cyHeight;
-
-        if( !IntersectRect( &dest_rect, &video_rect, &display_rect ) )
-        {
-            return VLC_EGENERIC;
-        }
-
-#if 0
-        msg_Err( p_vout, "video (%d,%d,%d,%d) display (%d,%d,%d,%d) "
-                 "dest (%d,%d,%d,%d)",
-                 video_rect.left, video_rect.right,
-                 video_rect.top, video_rect.bottom,
-                 display_rect.left, display_rect.right,
-                 display_rect.top, display_rect.bottom,
-                 dest_rect.left, dest_rect.right,
-                 dest_rect.top, dest_rect.bottom );
-#endif
-
-        if( !(p_dest = GXBeginDraw()) )
-        {
-#if 0
-            msg_Err( p_vout, "GXBeginDraw error %d ", GetLastError() );
-#endif
-            return VLC_EGENERIC;
-        }
+    vout_display_t *vd = picture->p_sys->vd;
+    vout_display_sys_t *sys = vd->sys;
 
-        p_src += (dest_rect.left - video_rect.left) * gxdisplayprop.cbxPitch +
-            (dest_rect.top - video_rect.top) * p_pic->p->i_pitch;
-        p_dest += dest_rect.left * gxdisplayprop.cbxPitch +
-            dest_rect.top * gxdisplayprop.cbyPitch;
-        i_width = dest_rect.right - dest_rect.left;
-        i_height = dest_rect.bottom - dest_rect.top;
+    /* */
+    if (sys->rect_dest_clipped.right  - sys->rect_dest_clipped.left != vd->fmt.i_width ||
+        sys->rect_dest_clipped.bottom - sys->rect_dest_clipped.top  != vd->fmt.i_height)
+        return VLC_EGENERIC;
 
-        p_pic->p->p_pixels = p_dest;
+    /* */
+    GXDisplayProperties gxdisplayprop = GXGetDisplayProperties();
+    uint8_t *p_pic_buffer = GXBeginDraw();
+    if (!p_pic_buffer) {
+        msg_Err(vd, "GXBeginDraw error %d ", GetLastError());
+        return VLC_EGENERIC;
     }
+    p_pic_buffer += sys->rect_dest.top  * gxdisplayprop.cbyPitch +
+                    sys->rect_dest.left * gxdisplayprop.cbxPitch;
 
-    return VLC_SUCCESS;
-}
+    /* */
+    picture->p[0].i_pitch  = gxdisplayprop.cbyPitch;
+    picture->p[0].p_pixels = p_pic_buffer;
 
-static int GAPIUnlockSurface( vout_thread_t *p_vout, picture_t *p_pic )
-{
-    GXEndDraw();
     return VLC_SUCCESS;
 }
-
-static void DisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
+static void Unlock(picture_t *picture)
 {
-}
+    vout_display_t *vd = picture->p_sys->vd;
 
-static void FirstDisplayGAPI( vout_thread_t *p_vout, picture_t *p_pic )
-{
-    /* get initial picture presented through D3D */
-    DisplayGAPI(p_vout, p_pic);
-
-    /*
-    ** Video window is initially hidden, show it now since we got a
-    ** picture to show.
-    */
-    SetWindowPos( p_vout->p_sys->hvideownd, 0, 0, 0, 0, 0,
-        SWP_ASYNCWINDOWPOS|
-        SWP_FRAMECHANGED|
-        SWP_SHOWWINDOW|
-        SWP_NOMOVE|
-        SWP_NOSIZE|
-        SWP_NOZORDER );
-
-    /* use and restores proper display function for further pictures */
-    p_vout->pf_display = DisplayGAPI;
+    GXEndDraw();
 }
-
 #endif
 
-#undef rect_src
-#undef rect_src_clipped
-#undef rect_dest
-#undef rect_dest_clipped
-/*****************************************************************************
- * SetPalette: sets an 8 bpp palette
- *****************************************************************************/
-static void SetPalette( vout_thread_t *p_vout,
-                        uint16_t *red, uint16_t *green, uint16_t *blue )
-{
-    msg_Err( p_vout, "FIXME: SetPalette unimplemented" );
-}
-
-/*****************************************************************************
- * InitBuffers: initialize an offscreen bitmap for direct buffer operations.
- *****************************************************************************/
-static void InitBuffers( vout_thread_t *p_vout )
+static int Init(vout_display_t *vd,
+                video_format_t *fmt, int width, int height)
 {
-    BITMAPINFOHEADER *p_header = &p_vout->p_sys->bitmapinfo.bmiHeader;
-    BITMAPINFO *p_info = &p_vout->p_sys->bitmapinfo;
-    HDC window_dc = GetDC( p_vout->p_sys->hvideownd );
+    vout_display_sys_t *sys = vd->sys;
 
-    /* Get screen properties */
+    /* */
+    RECT *display = &sys->rect_display;
+    display->left   = 0;
+    display->top    = 0;
 #ifdef MODULE_NAME_IS_wingapi
-    GXDisplayProperties gx_displayprop = GXGetDisplayProperties();
-    p_vout->p_sys->i_depth = gx_displayprop.cBPP;
+    display->right  = GXGetDisplayProperties().cxWidth;
+    display->bottom = GXGetDisplayProperties().cyHeight;
 #else
-    p_vout->p_sys->i_depth = GetDeviceCaps( window_dc, PLANES ) *
-        GetDeviceCaps( window_dc, BITSPIXEL );
+    display->right  = GetSystemMetrics(SM_CXSCREEN);;
+    display->bottom = GetSystemMetrics(SM_CYSCREEN);;
 #endif
-    msg_Dbg( p_vout, "GDI depth is %i", p_vout->p_sys->i_depth );
 
-#ifdef MODULE_NAME_IS_wingapi
-    GXOpenDisplay( p_vout->p_sys->hvideownd, GX_FULLSCREEN );
+    /* Initialize an offscreen bitmap for direct buffer operations. */
+
+    /* */
+    HDC window_dc = GetDC(sys->hvideownd);
 
+    /* */
+#ifdef MODULE_NAME_IS_wingapi
+    GXDisplayProperties gx_displayprop = GXGetDisplayProperties();
+    sys->i_depth = gx_displayprop.cBPP;
 #else
 
-    /* Initialize offscreen bitmap */
-    memset( p_info, 0, sizeof( BITMAPINFO ) + 3 * sizeof( RGBQUAD ) );
+    sys->i_depth = GetDeviceCaps(window_dc, PLANES) *
+                   GetDeviceCaps(window_dc, BITSPIXEL);
+#endif
 
-    p_header->biSize = sizeof( BITMAPINFOHEADER );
-    p_header->biSizeImage = 0;
-    p_header->biPlanes = 1;
-    switch( p_vout->p_sys->i_depth )
-    {
+    /* */
+    msg_Dbg(vd, "GDI depth is %i", sys->i_depth);
+    switch (sys->i_depth) {
     case 8:
-        p_header->biBitCount = 8;
-        p_header->biCompression = BI_RGB;
-        /* FIXME: we need a palette here */
+        fmt->i_chroma = VLC_CODEC_RGB8;
         break;
     case 15:
-        p_header->biBitCount = 15;
-        p_header->biCompression = BI_BITFIELDS;//BI_RGB;
-        ((DWORD*)p_info->bmiColors)[0] = 0x00007c00;
-        ((DWORD*)p_info->bmiColors)[1] = 0x000003e0;
-        ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
+        fmt->i_chroma = VLC_CODEC_RGB15;
+        fmt->i_rmask  = 0x7c00;
+        fmt->i_gmask  = 0x03e0;
+        fmt->i_bmask  = 0x001f;
         break;
     case 16:
-        p_header->biBitCount = 16;
-        p_header->biCompression = BI_BITFIELDS;//BI_RGB;
-        ((DWORD*)p_info->bmiColors)[0] = 0x0000f800;
-        ((DWORD*)p_info->bmiColors)[1] = 0x000007e0;
-        ((DWORD*)p_info->bmiColors)[2] = 0x0000001f;
+        fmt->i_chroma = VLC_CODEC_RGB16;
+        fmt->i_rmask  = 0xf800;
+        fmt->i_gmask  = 0x07e0;
+        fmt->i_bmask  = 0x001f;
         break;
     case 24:
-        p_header->biBitCount = 24;
-        p_header->biCompression = BI_RGB;
-        ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
-        ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
-        ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
+        fmt->i_chroma = VLC_CODEC_RGB24;
+        fmt->i_rmask  = 0x00ff0000;
+        fmt->i_gmask  = 0x0000ff00;
+        fmt->i_bmask  = 0x000000ff;
         break;
     case 32:
-        p_header->biBitCount = 32;
-        p_header->biCompression = BI_RGB;
-        ((DWORD*)p_info->bmiColors)[0] = 0x00ff0000;
-        ((DWORD*)p_info->bmiColors)[1] = 0x0000ff00;
-        ((DWORD*)p_info->bmiColors)[2] = 0x000000ff;
+        fmt->i_chroma = VLC_CODEC_RGB32;
+        fmt->i_rmask  = 0x00ff0000;
+        fmt->i_gmask  = 0x0000ff00;
+        fmt->i_bmask  = 0x000000ff;
         break;
     default:
-        msg_Err( p_vout, "screen depth %i not supported",
-                 p_vout->p_sys->i_depth );
-        return;
-        break;
+        msg_Err(vd, "screen depth %i not supported", sys->i_depth);
+        return VLC_EGENERIC;
+    }
+    fmt->i_width  = width;
+    fmt->i_height = height;
+
+    uint8_t *p_pic_buffer;
+    int     i_pic_pitch;
+#ifdef MODULE_NAME_IS_wingapi
+    GXOpenDisplay(sys->hvideownd, GX_FULLSCREEN);
+    EventThreadUpdateTitle(sys->event, VOUT_TITLE " (WinGAPI output)");
+
+    /* Filled by pool::lock() */
+    p_pic_buffer = NULL;
+    i_pic_pitch  = 0;
+#else
+    /* Initialize offscreen bitmap */
+    BITMAPINFO *bi = &sys->bitmapinfo;
+    memset(bi, 0, sizeof(BITMAPINFO) + 3 * sizeof(RGBQUAD));
+    if (sys->i_depth > 8) {
+        ((DWORD*)bi->bmiColors)[0] = fmt->i_rmask;
+        ((DWORD*)bi->bmiColors)[1] = fmt->i_gmask;
+        ((DWORD*)bi->bmiColors)[2] = fmt->i_bmask;;
+    }
+
+    BITMAPINFOHEADER *bih = &sys->bitmapinfo.bmiHeader;
+    bih->biSize = sizeof(BITMAPINFOHEADER);
+    bih->biSizeImage     = 0;
+    bih->biPlanes        = 1;
+    bih->biCompression   = (sys->i_depth == 15 ||
+                            sys->i_depth == 16) ? BI_BITFIELDS : BI_RGB;
+    bih->biBitCount      = sys->i_depth;
+    bih->biWidth         = fmt->i_width;
+    bih->biHeight        = -fmt->i_height;
+    bih->biClrImportant  = 0;
+    bih->biClrUsed       = 0;
+    bih->biXPelsPerMeter = 0;
+    bih->biYPelsPerMeter = 0;
+
+    i_pic_pitch = bih->biBitCount * bih->biWidth / 8;
+    sys->off_bitmap = CreateDIBSection(window_dc,
+                                       (BITMAPINFO *)bih,
+                                       DIB_RGB_COLORS,
+                                       &p_pic_buffer, NULL, 0);
+
+    sys->off_dc = CreateCompatibleDC(window_dc);
+
+    SelectObject(sys->off_dc, sys->off_bitmap);
+    ReleaseDC(sys->hvideownd, window_dc);
+
+    EventThreadUpdateTitle(sys->event, VOUT_TITLE " (WinGDI output)");
+#endif
+
+    /* */
+    picture_resource_t rsc;
+    memset(&rsc, 0, sizeof(rsc));
+#ifdef MODULE_NAME_IS_wingapi
+    rsc.p_sys = malloc(sizeof(*rsc.p_sys));
+    if (!rsc.p_sys)
+        return VLC_EGENERIC;
+    rsc.p_sys->vd = vd;
+#endif
+    rsc.p[0].p_pixels = p_pic_buffer;
+    rsc.p[0].i_lines  = fmt->i_height;
+    rsc.p[0].i_pitch  = i_pic_pitch;;
+
+    picture_t *picture = picture_NewFromResource(fmt, &rsc);
+    if (picture) {
+        picture_pool_configuration_t cfg;
+        memset(&cfg, 0, sizeof(cfg));
+        cfg.picture_count = 1;
+        cfg.picture = &picture;
+#ifdef MODULE_NAME_IS_wingapi
+        cfg.lock    = Lock;
+        cfg.unlock  = Unlock;
+#endif
+        sys->pool = picture_pool_NewExtended(&cfg);
+    } else {
+        free(rsc.p_sys);
+        sys->pool = NULL;
     }
-    p_header->biWidth = p_vout->render.i_width;
-    p_header->biHeight = -p_vout->render.i_height;
-    p_header->biClrImportant = 0;
-    p_header->biClrUsed = 0;
-    p_header->biXPelsPerMeter = 0;
-    p_header->biYPelsPerMeter = 0;
 
-    p_vout->p_sys->i_pic_pixel_pitch = p_header->biBitCount / 8;
-    p_vout->p_sys->i_pic_pitch = p_header->biBitCount * p_header->biWidth / 8;
+    UpdateRects(vd, NULL, NULL, true);
+
+    return VLC_SUCCESS;
+}
 
-    p_vout->p_sys->off_bitmap =
-        CreateDIBSection( window_dc, (BITMAPINFO *)p_header, DIB_RGB_COLORS,
-                          (void**)&p_vout->p_sys->p_pic_buffer, NULL, 0 );
+static void Clean(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
 
-    p_vout->p_sys->off_dc = CreateCompatibleDC( window_dc );
+    if (sys->pool)
+        picture_pool_Delete(sys->pool);
+    sys->pool = NULL;
 
-    SelectObject( p_vout->p_sys->off_dc, p_vout->p_sys->off_bitmap );
-    ReleaseDC( p_vout->p_sys->hvideownd, window_dc );
+#ifdef MODULE_NAME_IS_wingapi
+    GXCloseDisplay();
+#else
+    if (sys->off_dc)
+        DeleteDC(sys->off_dc);
+    if (sys->off_bitmap)
+        DeleteObject(sys->off_bitmap);
 #endif
 }