[vlc-devel] [PATCH] Direct2D video output module
David Kaplan
david at 2of1.org
Wed Jul 28 10:17:11 CEST 2010
Adds support for the D2D API on Win7/Vista SP2 with Platform Update
Requires d2d1 contrib headers
---
configure.ac | 17 ++
modules/video_output/msw/Modules.am | 8 +
modules/video_output/msw/common.c | 9 +-
modules/video_output/msw/common.h | 7 +
modules/video_output/msw/direct2d.c | 417 +++++++++++++++++++++++++++++++++++
modules/video_output/msw/events.c | 3 +
6 files changed, 458 insertions(+), 3 deletions(-)
create mode 100644 modules/video_output/msw/direct2d.c
diff --git a/configure.ac b/configure.ac
index 8a8701e..738f631 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3490,6 +3490,23 @@ then
fi
dnl
+dnl Windows Direct2D plugin
+dnl
+AC_ARG_ENABLE(direct2d,
+ [ --enable-direct2d Win7/VistaPU Direct2D support (default auto 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_WARN([Cannot find Direct2D headers!])]
+ )
+ fi
+fi
+
+dnl
dnl win32 GDI plugin
dnl
AC_ARG_ENABLE(wingdi,
diff --git a/modules/video_output/msw/Modules.am b/modules/video_output/msw/Modules.am
index 51807c8..0613bae 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 5704d5c..fddbd3d 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>
+#endif
#include "common.h"
@@ -379,7 +382,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;
@@ -398,7 +401,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 */
@@ -457,7 +460,7 @@ void UpdateRects(vout_display_t *vd,
/* Apply overlay hardware constraints */
if (sys->use_overlay)
AlignRect(&rect_src_clipped, sys->i_align_src_boundary, sys->i_align_src_size);
-#elif defined(MODULE_NAME_IS_direct3d)
+#elif defined(MODULE_NAME_IS_direct3d) || defined(MODULE_NAME_IS_direct2d)
/* Needed at least with YUV content */
rect_src_clipped.left &= ~1;
rect_src_clipped.right &= ~1;
diff --git a/modules/video_output/msw/common.h b/modules/video_output/msw/common.h
index e023ef4..3a67c7d 100644
--- a/modules/video_output/msw/common.h
+++ b/modules/video_output/msw/common.h
@@ -157,6 +157,13 @@ struct vout_display_sys_t
vout_display_opengl_t vgl;
#endif
+#ifdef MODULE_NAME_IS_direct2d
+ HINSTANCE d2_dll; /* handle of the opened d2d1 dll */
+ ID2D1Factory *d2_factory; /* D2D factory */
+ ID2D1HwndRenderTarget *d2_render_target; /* D2D rendering target */
+ ID2D1Bitmap *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..11757bd
--- /dev/null
+++ b/modules/video_output/msw/direct2d.c
@@ -0,0 +1,417 @@
+/*****************************************************************************
+ * direct2d.c : Direct2D video output plugin for vlc (Win7/Vista SP2 PF Update)
+ *****************************************************************************
+ * Copyright (C) 2010 VideoLAN and AUTHORS
+ * $Id$
+ *
+ * Author: David Kaplan <david at 2of1.org>
+ *
+ * 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"
+
+#include <initguid.h>
+#undef GUID_EXT
+#define GUID_EXT
+DEFINE_GUID(IID_ID2D1Factory, 0x6152247, 0x6f50, 0x465a, 0x92, 0x45, 0x11, 0x8b, 0xfd, 0x3b, 0x60, 0x7);
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int Open (vlc_object_t *);
+static void Close(vlc_object_t *);
+
+#define D2D_HELP N_("Video output for Windows 7/Windows Vista with Platform update")
+
+vlc_module_begin ()
+ set_category(CAT_VIDEO)
+ set_subcategory(SUBCAT_VIDEO_VOUT)
+ set_help(D2D_HELP)
+ set_shortname("Direct2D")
+ set_description(N_("Direct2D video output"))
+ set_capability("vout display", 65)
+ add_shortcut("direct2d")
+ 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 *);
+
+static int D2D_CreateRenderTarget(vout_display_t *vd);
+static void D2D_ResizeRenderTarget(vout_display_t *vd);
+static 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;
+
+ sys->d2_render_target = NULL;
+
+ sys->d2_dll = LoadLibrary(TEXT("D2D1.DLL"));
+ if (!sys->d2_dll) {
+ if (object->b_force)
+ msg_Err(vd, "Cannot load D2D1.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->d2_dll,
+ TEXT("D2D1CreateFactory"));
+ if (!D2D1CreateFactory) {
+ msg_Err(vd,
+ "Cannot locate reference to a D2D1CreateFactory ABI in D2D1.DLL");
+ goto error;
+ }
+
+#ifndef NDEBUG
+ msg_Dbg(vd, "D2D1.DLL loaded");
+#endif
+
+ HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
+ (REFIID)&IID_ID2D1Factory,
+ &fo,
+ (void **)&sys->d2_factory);
+ if (hr != S_OK) {
+ msg_Err(vd, "Cannot create Direct2D factory (hr = 0x%x)!",
+ (unsigned)hr);
+ goto error;
+ }
+
+ if (CommonInit(vd))
+ goto error;
+
+ if (D2D_CreateRenderTarget(vd) != VLC_SUCCESS)
+ 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 = false;
+ vd->info = info;
+
+ vd->fmt.i_chroma = VLC_CODEC_RGB32; /* masks change this to BGR32 for ID2D1Bitmap */
+ vd->fmt.i_rmask = 0x0000ff00;
+ vd->fmt.i_gmask = 0x00ff0000;
+ vd->fmt.i_bmask = 0xff000000;
+
+ vd->pool = Pool;
+ vd->prepare = Prepare;
+ vd->display = Display;
+ vd->manage = Manage;
+ vd->control = Control;
+
+ EventThreadUpdateTitle(sys->event, VOUT_TITLE " (Direct2D output)");
+
+#ifndef NDEBUG
+ msg_Dbg(vd, "Ready");
+#endif
+
+ 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);
+#ifndef NDEBUG
+ msg_Dbg(vd, "New picture pool created");
+#endif
+ }
+
+ 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->d2_render_target && sys->d2_bitmap) {
+
+ HRESULT hr = ID2D1Bitmap_CopyFromMemory(sys->d2_bitmap,
+ NULL /*&r_src*/,
+ picture->p[0].p_pixels,
+ picture->p[0].i_pitch);
+ if (hr != S_OK)
+ msg_Err(vd, "Failed to copy bitmap memory (hr = 0x%x)!",
+ (unsigned)hr);
+
+#ifndef NDEBUG
+ /*msg_Dbg(vd, "Bitmap dbg: target = %p, pitch = %d, bitmap = %p",
+ sys->d2_render_target, pitch, sys->d2_bitmap);*/
+#endif
+ }
+}
+
+/**
+ * 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 r_dest = {
+ sys->rect_dest.left,
+ sys->rect_dest.top,
+ sys->rect_dest.right,
+ sys->rect_dest.bottom
+ };
+
+ if (sys->d2_render_target && sys->d2_bitmap) {
+ ID2D1HwndRenderTarget_BeginDraw(sys->d2_render_target);
+
+ ID2D1HwndRenderTarget_DrawBitmap(sys->d2_render_target,
+ sys->d2_bitmap,
+ &r_dest,
+ 1.0f,
+ D2D1_BITMAP_INTERPOLATION_MODE_LINEAR,
+ NULL);
+
+ HRESULT hr = ID2D1HwndRenderTarget_EndDraw(sys->d2_render_target,
+ NULL,
+ NULL);
+ if (hr == D2DERR_RECREATE_TARGET) {
+ D2D_DestroyRenderTarget(vd);
+ D2D_CreateRenderTarget(vd);
+ }
+ }
+
+ picture_Release(picture);
+
+ CommonDisplay(vd);
+}
+
+ /**
+ * Control event handler
+ */
+static int Control(vout_display_t *vd, int query, va_list args)
+{
+ 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;
+
+ CommonManage(vd);
+
+ if (sys->changes & DX_POSITION_CHANGE) {
+ D2D_ResizeRenderTarget(vd);
+ sys->changes &= ~DX_POSITION_CHANGE;
+ }
+}
+
+/**
+ * Creates a ID2D1HwndRenderTarget and associated ID2D1Bitmap
+ */
+static int D2D_CreateRenderTarget(vout_display_t *vd)
+{
+ vout_display_sys_t *sys = vd->sys;
+
+ sys->d2_render_target = NULL;
+
+ 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->d2_factory,
+ &rtp,
+ &hrtp,
+ &sys->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)!",
+ (unsigned)hrtp.hwnd, hrtp.pixelSize.width,
+ hrtp.pixelSize.height, pf.format, (unsigned)hr);
+
+ sys->d2_render_target = NULL;
+
+ return VLC_EGENERIC;
+ }
+
+ FLOAT dpi_x, dpi_y;
+
+ ID2D1Factory_GetDesktopDpi(sys->d2_factory,
+ &dpi_x,
+ &dpi_y);
+
+ D2D1_BITMAP_PROPERTIES bp = {
+ pf,
+ dpi_x,
+ dpi_y
+ };
+
+ D2D1_SIZE_U bitmap_size = {
+ vd->fmt.i_width,
+ vd->fmt.i_height
+ };
+
+ hr = ID2D1HwndRenderTarget_CreateBitmap(sys->d2_render_target,
+ bitmap_size,
+ NULL,
+ 0,
+ &bp,
+ &sys->d2_bitmap);
+ if (hr != S_OK) {
+ msg_Err(vd, "Failed to create bitmap (hr = 0x%x)!", (unsigned)hr);
+
+ sys->d2_bitmap = NULL;
+ D2D_DestroyRenderTarget(vd);
+
+ return VLC_EGENERIC;
+ }
+
+#ifndef NDEBUG
+ msg_Dbg(vd, "Render trgt dbg: dpi = %f, render_target = %p, bitmap = %p",
+ dpi_x, sys->d2_render_target, sys->d2_bitmap);
+#endif
+
+ return VLC_SUCCESS;
+}
+
+/**
+ * Resizes a ID2D1HWndRenderTarget
+ */
+static void D2D_ResizeRenderTarget(vout_display_t *vd)
+{
+ vout_display_sys_t *sys = vd->sys;
+
+ D2D1_SIZE_U size = {
+ sys->rect_dest.right - sys->rect_dest.left,
+ sys->rect_dest.bottom - sys->rect_dest.top
+ };
+
+ HRESULT hr = ID2D1HwndRenderTarget_Resize(sys->d2_render_target, &size);
+ if (hr != S_OK)
+ msg_Err(vd, "Cannot resize render target (width = %d, height = %d, hr = 0x%x)!",
+ size.width, size.height, (unsigned)hr);
+}
+
+/**
+ * Cleans up ID2D1HwndRenderTarget and ID2D1Bitmap
+ */
+static void D2D_DestroyRenderTarget(vout_display_t *vd)
+{
+ vout_display_sys_t *sys = vd->sys;
+
+ if (sys->d2_render_target) {
+ ID2D1HwndRenderTarget_Release(sys->d2_render_target);
+ sys->d2_render_target = NULL;
+ }
+
+ if (sys->d2_bitmap) {
+ ID2D1Bitmap_Release(sys->d2_bitmap);
+ sys->d2_bitmap = NULL;
+ }
+
+#ifndef NDEBUG
+ msg_Dbg(vd, "Destroyed");
+#endif
+}
diff --git a/modules/video_output/msw/events.c b/modules/video_output/msw/events.c
index d2d5e26..46c15c4 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>
+#endif
#include <vlc_keys.h>
#include "common.h"
--
1.7.0.4
More information about the vlc-devel
mailing list