[vlc-devel] [PATCH] Direct2D video output module

David Kaplan 010of001 at gmail.com
Tue Apr 27 21:59:40 CEST 2010


Adds support for the D2D API on Win7/Vista SP2 with Platform Update
---
 configure.ac                        |   17 ++
 modules/video_output/msw/Modules.am |    8 +
 modules/video_output/msw/common.c   |    9 +-
 modules/video_output/msw/common.h   |    9 +
 modules/video_output/msw/direct2d.c |  385 +++++++++++++++++++++++++++++++++++
 modules/video_output/msw/events.c   |    3 +
 6 files changed, 428 insertions(+), 3 deletions(-)
 create mode 100644 modules/video_output/msw/direct2d.c

diff --git a/configure.ac b/configure.ac
index 9358079..e130a6f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3505,6 +3505,23 @@ then
 fi
 
 dnl
+dnl  Windows Direct2D plugin
+dnl
+AC_ARG_ENABLE(direct2d,
+  [  --enable-direct2d         Win32 Direct2D support (default enabled on Win32)])
+if test "${enable_direct2d}" != "no"; then
+  if test "${SYS}" = "mingw32" -o "${SYS}" = "mingwce"
+  then
+    AC_CHECK_HEADERS(d2d1.h,
+      [ 
+        VLC_ADD_PLUGIN([direct2d])
+        VLC_ADD_LIBS([direct2d],[-lgdi32 -lole32])
+      ], [AC_MSG_ERROR([Cannot find Direct2D headers!])]
+    )
+  fi
+fi
+
+dnl
 dnl  Windows DirectX module
 dnl
 
diff --git a/modules/video_output/msw/Modules.am b/modules/video_output/msw/Modules.am
index 51807c8..1b3a028 100644
--- a/modules/video_output/msw/Modules.am
+++ b/modules/video_output/msw/Modules.am
@@ -1,3 +1,11 @@
+SOURCES_direct2d = \
+	direct2d.c \
+	common.h \
+	events.h \
+	events.c \
+	common.c \
+	$(NULL)
+
 SOURCES_directx = \
 	directx.c \
 	common.h \
diff --git a/modules/video_output/msw/common.c b/modules/video_output/msw/common.c
index ebc814a..c4526db 100644
--- a/modules/video_output/msw/common.c
+++ b/modules/video_output/msw/common.c
@@ -48,6 +48,9 @@
 #ifdef MODULE_NAME_IS_glwin32
 #include "../opengl.h"
 #endif
+#ifdef MODULE_NAME_IS_direct2d
+#include <d2d1.h>       /* not yet included in w32api */
+#endif
 
 #include "common.h"
 
@@ -171,7 +174,7 @@ void CommonManage(vout_display_t *vd)
 
             /* FIXME I find such #ifdef quite weirds. Are they really needed ? */
 
-#if defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_wingdi) || defined(MODULE_NAME_IS_wingapi)
+#if defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_wingdi) || defined(MODULE_NAME_IS_wingapi) || defined(MODULE_NAME_IS_direct2d)
             SetWindowPos(sys->hwnd, 0, 0, 0,
                          rect_parent.right - rect_parent.left,
                          rect_parent.bottom - rect_parent.top,
@@ -340,7 +343,7 @@ void UpdateRects(vout_display_t *vd,
                      SWP_NOCOPYBITS|SWP_NOZORDER|SWP_ASYNCWINDOWPOS);
 
     /* Destination image position and dimensions */
-#if defined(MODULE_NAME_IS_direct3d)
+#if defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_direct2d)
     rect_dest.left   = 0;
     rect_dest.right  = place.width;
     rect_dest.top    = 0;
@@ -359,7 +362,7 @@ void UpdateRects(vout_display_t *vd,
 
 #endif
 
-#if defined(MODULE_NAME_IS_directx) || defined(MODULE_NAME_IS_direct3d)
+#if defined(MODULE_NAME_IS_directx) || defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_direct2d)
     /* UpdateOverlay directdraw function doesn't automatically clip to the
      * display size so we need to do it otherwise it will fail
      * It is also needed for d3d to avoid exceding our surface size */
diff --git a/modules/video_output/msw/common.h b/modules/video_output/msw/common.h
index 291d8e0..0f01e44 100644
--- a/modules/video_output/msw/common.h
+++ b/modules/video_output/msw/common.h
@@ -156,6 +156,15 @@ struct vout_display_sys_t
     vout_display_opengl_t vgl;
 #endif
 
+#ifdef MODULE_NAME_IS_direct2d
+    HINSTANCE              h_d2_dll;            /* handle of the opened d3d9 dll */
+    FLOAT                  f_d2_dpi_x;                                  /* DPI x */
+    FLOAT                  f_d2_dpi_y;                                  /* DPI y */
+    ID2D1Factory           *p_d2_factory;                         /* D2D factory */
+    ID2D1HwndRenderTarget  *p_d2_render_target;          /* D2D rendering target */
+    ID2D1Bitmap            *p_d2_bitmap;                            /* D2 bitmap */
+#endif
+
 #ifdef MODULE_NAME_IS_direct3d
     bool allow_hw_yuv;    /* Should we use hardware YUV->RGB conversions */
     /* show video on desktop window ? */
diff --git a/modules/video_output/msw/direct2d.c b/modules/video_output/msw/direct2d.c
new file mode 100644
index 0000000..d5bec06
--- /dev/null
+++ b/modules/video_output/msw/direct2d.c
@@ -0,0 +1,385 @@
+/*****************************************************************************
+ * direct2d.c : Direct2D video output plugin for vlc (Win7/Vista SP2 PF update)
+ *****************************************************************************
+ * Copyright (C) 2002-2010 the VideoLAN team
+ * $Id$
+ *
+ * Author: David Kaplan <010of001 at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <assert.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_playlist.h>
+#include <vlc_vout_display.h>
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <d2d1.h>
+
+#include "common.h"
+
+#ifndef WS_NONAVDONEBUTTON
+#   define WS_NONAVDONEBUTTON 0
+#endif
+
+/*****************************************************************************
+ * 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_shortname("Direct2D")
+    set_description(N_("Direct2D video output"))
+    set_capability("vout display", 10)
+    set_callbacks(Open, Close)
+vlc_module_end ()
+
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static picture_pool_t *Pool  (vout_display_t *, unsigned);
+static void           Prepare(vout_display_t *, picture_t *);
+static void           Display(vout_display_t *, picture_t *);
+static int            Control(vout_display_t *, int, va_list);
+static void           Manage (vout_display_t *);
+
+void D2D_CreateRenderTarget(vout_display_t *vd);
+void D2D_DestroyRenderTarget(vout_display_t *vd);
+
+/**
+* Initialises Direct2D vout module
+*/
+static int Open(vlc_object_t *object)
+{
+    vout_display_t *vd = (vout_display_t *)object;
+    vout_display_sys_t *sys;
+
+    vd->sys = sys = calloc(1, sizeof(*sys));
+    if( !sys )
+        return VLC_ENOMEM;
+
+    if( CommonInit(vd) )
+        goto error;
+    
+    sys->h_d2_dll = LoadLibrary(TEXT("D2D1.DLL"));
+    if( !sys->h_d2_dll )
+    {
+        msg_Err(vd, "Cannot load d3d9.dll, aborting");
+        goto error;
+    }
+
+    D2D1_FACTORY_OPTIONS fo = {
+        D2D1_DEBUG_LEVEL_NONE
+    };
+    
+    HRESULT (WINAPI *_D2D1CreateFactory)( D2D1_FACTORY_TYPE, REFIID, 
+        const D2D1_FACTORY_OPTIONS *, void ** );
+
+    _D2D1CreateFactory = (void *)GetProcAddress(sys->h_d2_dll, TEXT("D2D1CreateFactory"));
+    if( !_D2D1CreateFactory )
+    {
+        msg_Err(vd, 
+            "Cannot locate reference to a D2D1CreateFactory ABI in D2D1.DLL");
+        goto error;
+    }
+    msg_Dbg(vd, "D2D1.DLL loaded");
+
+    const_GUID IID_ID2D1Factory = { 
+        102048327, 28496, 18010, 
+        {146, 69, 17, 139, 253, 59, 96, 7}
+    };
+    
+    HRESULT hr = _D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, 
+        (REFIID)&IID_ID2D1Factory, &fo, (void **)&sys->p_d2_factory);
+    if( hr != S_OK ) {
+        msg_Err(vd, "Cannot create Direct2D factory (hr = 0x%x)!", (uint32_t)hr);
+        goto error;
+    }
+    
+    sys->p_d2_render_target = NULL;
+    D2D_CreateRenderTarget(vd);
+
+    vout_display_info_t info = vd->info;
+    info.is_slow              = false;
+    info.has_double_click     = true;
+    info.has_hide_mouse       = true;
+    info.has_pictures_invalid = true;
+    vd->info = info;
+    
+    RECT rc;
+    GetClientRect(sys->hvideownd, &rc);
+    D2D1_SIZE_U size = {
+        rc.right - rc.left,
+        rc.bottom - rc.top
+    };
+    
+    vd->fmt.i_chroma = VLC_CODEC_RGB32; /* masks change this to BGR32 for ID2D1Bitmap */
+    vd->fmt.i_rmask  = 0x000000ff;
+    vd->fmt.i_gmask  = 0x0000ff00;
+    vd->fmt.i_bmask  = 0x00000000; /* todo - fix this (should be 0x00ff0000) */
+    vd->fmt.i_width  = size.width;
+    vd->fmt.i_height = size.height;
+
+    vd->pool    = Pool;
+    vd->prepare = Prepare;
+    vd->display = Display;
+    vd->manage  = Manage;
+    vd->control = Control;
+    
+    EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct2D output)");
+
+    msg_Dbg(vd, "Ready");
+
+    return VLC_SUCCESS;
+
+error:
+    Close(VLC_OBJECT(vd));
+    return VLC_EGENERIC;
+}
+
+/**
+ * Close Direct2D vout
+ */
+static void Close(vlc_object_t *object)
+{
+    vout_display_t *vd = (vout_display_t *)object;
+
+    D2D_DestroyRenderTarget(vd);
+
+    if( vd->sys->pool )
+        picture_pool_Delete(vd->sys->pool);
+
+    CommonClean(vd);
+
+    free(vd->sys);
+}
+
+/**
+ * Handles pool allocations for bitmaps
+ */
+static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
+{
+    vout_display_sys_t *sys = vd->sys;
+    
+    if( !sys->pool )
+    {
+        sys->pool = picture_pool_NewFromFormat(&vd->fmt, count);
+        msg_Dbg(vd, "New picture pool created");
+    }
+    
+    return sys->pool;
+}
+
+/**
+ * Performs set up of ID2D1Bitmap memory ready for blitting
+ */
+static void Prepare(vout_display_t *vd, picture_t *picture)
+{
+    vout_display_sys_t *sys = vd->sys;
+    
+    if( sys->p_d2_render_target && sys->p_d2_bitmap )
+    {  
+        UINT32 pitch = vd->fmt.i_width * 4;
+        
+        HRESULT hr = ID2D1Bitmap_CopyFromMemory(sys->p_d2_bitmap, NULL, picture->p[0].p_pixels, pitch);
+        if( hr != S_OK )
+    {
+            msg_Err(vd, "Failed to copy bitmap memory (hr = 0x%x)!", (uint32_t)hr);
+        }
+
+        /* msg_Dbg(vd, "Bitmap dbg: target = 0x%x, pitch = %d, bitmap = 0x%x", 
+            sys->p_d2_render_target, pitch, sys->p_d2_bitmap); */
+    }
+}
+
+/**
+ * Blits a scaled picture_t to the render target
+ */
+static void Display(vout_display_t *vd, picture_t *picture)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    D2D1_RECT_F rc = {
+        sys->rect_dest.left,
+        sys->rect_dest.top,
+        sys->rect_dest.right,
+        sys->rect_dest.bottom
+    };
+
+    if( sys->p_d2_render_target && sys->p_d2_bitmap )
+    {
+        ID2D1HwndRenderTarget_BeginDraw(sys->p_d2_render_target);
+        ID2D1HwndRenderTarget_DrawBitmap(sys->p_d2_render_target, sys->p_d2_bitmap, &rc, 
+            1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, NULL);
+        ID2D1HwndRenderTarget_EndDraw(sys->p_d2_render_target, NULL, NULL);
+    }
+
+    picture_Release(picture);
+    
+    CommonDisplay(vd);
+}
+
+ /**
+  * Control event handler
+  */
+static int Control(vout_display_t *vd, int query, va_list args)
+{
+    /* vout_display_sys_t *sys = vd->sys; - unused*/
+
+    switch (query) {
+    case VOUT_DISPLAY_RESET_PICTURES:
+        /* handled by D2D itself - hardware accel if available, software if not
+        if(sys->pool) {
+            picture_pool_Delete(sys->pool);
+            sys->pool = NULL;
+        }
+        vd->fmt.i_chroma = VLC_CODEC_RGB32;
+        vd->fmt.i_rmask  = 0x000000ff;
+        vd->fmt.i_gmask  = 0x0000ff00;
+        vd->fmt.i_bmask  = 0x00000000;
+        vd->fmt.i_width  = sys->rect_dest.right - sys->rect_dest.left;
+        vd->fmt.i_height = sys->rect_dest.bottom - sys->rect_dest.top;
+        */
+        return VLC_SUCCESS;
+    default:
+        return CommonControl(vd, query, args);
+    }
+
+}
+
+/**
+ * Handles surface management
+ * ID2D1RenderTargets cannot be resized and must be recreated
+ */
+static void Manage(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    /* handled by D2D - vout_display_SendEventPicturesInvalid(vd); */
+
+    CommonManage(vd);
+    
+    static RECT prev_rc;
+    if( memcmp(&prev_rc, &sys->rect_dest, sizeof(prev_rc)) ) /* check if needs update */
+    {
+        D2D_CreateRenderTarget(vd);
+        prev_rc = sys->rect_dest;
+    }
+}
+
+/**
+ * Creates a ID2D1HwndRenderTarget and associated ID2D1Bitmap
+ */
+void D2D_CreateRenderTarget(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    D2D_DestroyRenderTarget(vd);    /* clean up current render target if necessary */
+    
+    D2D1_PIXEL_FORMAT pf = {
+        DXGI_FORMAT_B8G8R8A8_UNORM,
+        D2D1_ALPHA_MODE_IGNORE
+    };
+
+    D2D1_RENDER_TARGET_PROPERTIES rtp = {
+        D2D1_RENDER_TARGET_TYPE_DEFAULT,
+        pf,
+        0,
+        0,
+        D2D1_RENDER_TARGET_USAGE_NONE,
+        D2D1_FEATURE_LEVEL_DEFAULT
+    };
+
+    D2D1_SIZE_U size = {
+        sys->rect_dest.right - sys->rect_dest.left,
+        sys->rect_dest.bottom - sys->rect_dest.top
+    };
+    
+    D2D1_HWND_RENDER_TARGET_PROPERTIES hrtp = {
+        sys->hvideownd,
+        size,
+        D2D1_PRESENT_OPTIONS_IMMEDIATELY /* this might need fiddling */
+    };
+    
+    HRESULT hr  = ID2D1Factory_CreateHwndRenderTarget(sys->p_d2_factory, 
+        &rtp, &hrtp, &sys->p_d2_render_target);
+    if( hr != S_OK )
+    {
+        msg_Err(vd, "Cannot create render target (hvideownd = 0x%x, width = %d, height = %d, pf.format = %d, hr = 0x%x)!", 
+            (uint32_t)hrtp.hwnd, hrtp.pixelSize.width, hrtp.pixelSize.height, 
+            pf.format, (uint32_t)hr);
+        D2D_DestroyRenderTarget(vd);
+    }
+    
+    ID2D1Factory_GetDesktopDpi(sys->p_d2_factory, &sys->f_d2_dpi_x, &sys->f_d2_dpi_y);
+
+    msg_Dbg(vd, "dpi = %f, target = 0x%x", sys->f_d2_dpi_x, (uint32_t)sys->p_d2_render_target);
+    
+    D2D1_BITMAP_PROPERTIES bp = {
+        pf,
+        sys->f_d2_dpi_x,
+        sys->f_d2_dpi_y
+    };
+    
+    D2D1_SIZE_U bitmap_size = {
+        vd->fmt.i_width,
+        vd->fmt.i_height
+    };
+
+    hr = ID2D1HwndRenderTarget_CreateBitmap(sys->p_d2_render_target, 
+        bitmap_size, NULL, 0, &bp, &sys->p_d2_bitmap);
+    if( hr != S_OK )
+    {
+        msg_Err(vd, "Failed to create bitmap (hr = 0x%x)!", (uint32_t)hr);
+    }
+}
+
+/**
+ * Cleans up ID2D1HwndRenderTarget and ID2D1Bitmap
+ */
+void D2D_DestroyRenderTarget(vout_display_t *vd)
+{
+    vout_display_sys_t *sys = vd->sys;
+
+    if( sys->p_d2_render_target )
+    {
+        ID2D1HwndRenderTarget_Release(sys->p_d2_render_target);
+        sys->p_d2_render_target = NULL;
+    }
+
+    if( sys->p_d2_bitmap )
+    {
+        ID2D1Bitmap_Release(sys->p_d2_bitmap);
+        sys->p_d2_bitmap = NULL;
+    }
+
+    msg_Dbg(vd, "Destroyed");
+}
diff --git a/modules/video_output/msw/events.c b/modules/video_output/msw/events.c
index 1945b12..541d717 100644
--- a/modules/video_output/msw/events.c
+++ b/modules/video_output/msw/events.c
@@ -49,6 +49,9 @@
 #ifdef MODULE_NAME_IS_glwin32
 #include "../opengl.h"
 #endif
+#ifdef MODULE_NAME_IS_direct2d
+#include <d2d1.h>    /* not yet included in w32api */
+#endif
 
 #include <vlc_keys.h>
 #include "common.h"
-- 
1.7.0.4




More information about the vlc-devel mailing list