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

David Kaplan david at 2of1.org
Thu Jul 22 16:17:24 CEST 2010


sorry - got some artifacts in configure.ac - will resubmit

On Thu, Jul 22, 2010 at 5:16 PM, David Kaplan <david at 2of1.org> wrote:

> Adds support for the D2D API on Win7/Vista SP2 with Platform Update
> Requires d2d1 contrib headers
> ---
>  configure.ac                        |   27 ++-
>  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 |  399
> +++++++++++++++++++++++++++++++++++
>  modules/video_output/msw/events.c   |    3 +
>  6 files changed, 447 insertions(+), 8 deletions(-)
>  create mode 100644 modules/video_output/msw/direct2d.c
>
> diff --git a/configure.ac b/configure.ac
> index 8a8701e..45aaf30 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -876,7 +876,7 @@ AC_ARG_VAR(PKG_CONFIG_PATH,
>           [Paths where to find .pc not at the default location])
>  PKG_PROG_PKG_CONFIG()
>
> -dnl On some OS we need static linking
> +dnl On some OS we need static linking
>        AS_IF([test -n "${PKG_CONFIG}" ],[
>              AS_IF([test "${SYS}" = "mingw32" -o "${SYS}" = "mingwce" -o
> "${SYS}" = "darwin" ],[
>                  PKG_CONFIG="${PKG_CONFIG} --static"
> @@ -886,14 +886,14 @@ dnl On some OS we need static linking
>
>  dnl
>  dnl Check for zlib.h and -lz along with system -lminizip if available
> -dnl
> +dnl
>  AC_CHECK_HEADERS(zlib.h, [ have_zlib=yes ], [ have_zlib=no ])
>  AM_CONDITIONAL(HAVE_ZLIB, [ test "${have_zlib}" = "yes" ])
>  if test "${have_zlib}" = "yes"
>  then
>   VLC_ADD_LIBS([access_http gme mp4 skins2 sap mkv unzip zip],[-lz])
>   PKG_CHECK_MODULES([MINIZIP], [minizip] , [ have_minizip=yes ], [
> -    AC_CHECK_HEADERS([unzip.h], [
> +    AC_CHECK_HEADERS([unzip.h], [
>       have_minizip=yes
>       MINIZIP_LIBS="-lminizip -lz"
>     ], [
> @@ -1841,7 +1841,7 @@ lternatively you can use --disable-live555 to disable
> the liveMedia plugin.])
>         AC_MSG_RESULT(no)
>       if test "${enable_live555}" = "yes"; then
>         AC_MSG_ERROR([cannot find
> ${real_live555_tree}/liveMedia/libliveMedia.a, make sure you compiled
> live555 in ${with_live555_tree}])
> -      fi
> +      fi
>     fi
>   fi
>  fi
> @@ -2697,7 +2697,7 @@ AC_ARG_ENABLE(dxva2,
>  AS_IF([test "${enable_dxva2}" != "no"], [
>   if test "${SYS}" = "mingw32"; then
>   AS_IF([test "x${have_avcodec}" = "xyes"], [
> -    AC_CHECK_HEADERS(dxva2api.h,
> +    AC_CHECK_HEADERS(dxva2api.h,
>       [
>         AC_CHECK_HEADERS(libavcodec/dxva2.h, [
>            VLC_ADD_LIBS([avcodec],[-lole32 -lshlwapi -luuid])
> @@ -3458,6 +3458,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..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..db6a2d8 100644
> --- a/modules/video_output/msw/common.h
> +++ b/modules/video_output/msw/common.h
> @@ -157,6 +157,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..c04cdf6
> --- /dev/null
> +++ b/modules/video_output/msw/direct2d.c
> @@ -0,0 +1,399 @@
>
> +/*****************************************************************************
> + * 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, 102048327, 28496, 18010, 146, 69, 17, 139,
> 253, 59, 96, 7);
> +
> +#ifndef WS_NONAVDONEBUTTON
> +#   define WS_NONAVDONEBUTTON 0
> +#endif
> +
>
> +/*****************************************************************************
> + * 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", 10)
> +    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 *);
> +
> +void D2D_CreateRenderTarget(vout_display_t *vd);
> +void D2D_ResizeRenderTarget(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) {
> +        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->h_d2_dll,
> +        TEXT("D2D1CreateFactory"));
> +    if (!_D2D1CreateFactory) {
> +        if (object->b_force)
> +            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->p_d2_factory);
> +    if (hr != S_OK) {
> +        if (object->b_force)
> +            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)");
> +
> +#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->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);
> +
> +#ifndef NDEBUG
> +        /*msg_Dbg(vd, "Bitmap dbg: target = %p, pitch = %d, bitmap = %p",
> +            sys->p_d2_render_target, pitch, sys->p_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 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)
> +{
> +    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;
> +    }
> +}
> +
> +/**
> + * Resizes a ID2D1HWndRenderTarget
> + */
> +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->p_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, (uint32_t)hr);
> +
> +        D2D_DestroyRenderTarget(vd);
> +    }
> +}
> +
> +/**
> + * Creates a ID2D1HwndRenderTarget and associated ID2D1Bitmap
> + */
> +void D2D_CreateRenderTarget(vout_display_t *vd)
> +{
> +    vout_display_sys_t *sys = vd->sys;
> +
> +    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);
> +
> +    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);
> +    }
> +
> +#ifndef NDEBUG
> +    msg_Dbg(vd, "Render trgt dbg: dpi = %f, render_target = %p, bitmap =
> %p",
> +        sys->f_d2_dpi_x, sys->p_d2_render_target, sys->p_d2_bitmap);
> +#endif
> +}
> +
> +/**
> + * 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;
> +    }
> +
> +#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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20100722/c08834a5/attachment.html>


More information about the vlc-devel mailing list