[vlc-devel] [PATCH 3/3] vout: win32: add a Direct3D9 deinterlacer for opaque surfaces

Filip Roséen filip at atch.se
Tue Apr 11 17:48:01 CEST 2017


Hi Steve,

This reply got written in-between three different conversations going
besides my computer (which I took part it). I apologize if these
momentarily breaks (in terms of my brain focusing on replying) has
made the email hard to read/understand.

On 2017-04-11 16:50, Steve Lhomme wrote:

> ---
>  configure.ac                                  |   3 +
>  modules/video_output/Makefile.am              |   5 +-
>  modules/video_output/win32/d3d9_deinterlace.c | 292 ++++++++++++++++++++++++++
>  3 files changed, 299 insertions(+), 1 deletion(-)
>  create mode 100644 modules/video_output/win32/d3d9_deinterlace.c
> 
> diff --git a/configure.ac b/configure.ac
> index dfbb3f4919..6130c4a437 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -3276,6 +3276,9 @@ AS_IF([test "${enable_directx}" != "no"], [
>    dnl Direct3D9
>    AC_CHECK_HEADERS(d3d9.h, [
>      VLC_ADD_PLUGIN([direct3d9])
> +    AC_CHECK_HEADERS(dxva2api.h, [
> +      VLC_ADD_PLUGIN([direct3d9_deinterlace])
> +    ])
>    ])
>  
>  ])
> diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
> index 3b9fb053f6..d5c1137646 100644
> --- a/modules/video_output/Makefile.am
> +++ b/modules/video_output/Makefile.am
> @@ -214,9 +214,12 @@ libdirect3d9_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
>  	-DMODULE_NAME_IS_direct3d9
>  libdirect3d9_plugin_la_LIBADD = -lgdi32 $(LIBCOM) -luuid
>  libdirect3d9_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)'
> +libdirect3d9_deinterlace_plugin_la_SOURCES = video_output/win32/d3d9_deinterlace.c
> +libdirect3d9_deinterlace_plugin_la_LIBADD = $(LIBCOM)
>  if HAVE_WIN32_DESKTOP
>  vout_LTLIBRARIES += $(LTLIBdirect3d9)
> -EXTRA_LTLIBRARIES += libdirect3d9_plugin.la
> +vout_LTLIBRARIES += $(LTLIBdirect3d9_deinterlace)
> +EXTRA_LTLIBRARIES += libdirect3d9_plugin.la libdirect3d9_deinterlace_plugin.la
>  endif
>  
>  libdirect3d11_plugin_la_SOURCES = video_output/win32/direct3d11.c \
> diff --git a/modules/video_output/win32/d3d9_deinterlace.c b/modules/video_output/win32/d3d9_deinterlace.c
> new file mode 100644
> index 0000000000..88cc767ebf
> --- /dev/null
> +++ b/modules/video_output/win32/d3d9_deinterlace.c
> @@ -0,0 +1,292 @@
> +/*****************************************************************************
> + * d3d11_deinterlace.c: D3D11 deinterlacing filter
> + *****************************************************************************
> + * Copyright (C) 2017 Videolabs SAS
> + *
> + * Authors: Steve Lhomme <robux4 at gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU Lesser General Public License as published by
> + * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser 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.
> + *****************************************************************************/
> +
> +#ifdef HAVE_CONFIG_H
> +# include "config.h"
> +#endif
> +
> +#include <stdlib.h>
> +#include <assert.h>
> +
> +#include <vlc_common.h>
> +#include <vlc_plugin.h>
> +#include <vlc_filter.h>
> +#include <vlc_picture.h>
> +
> +#define COBJMACROS
> +#include <initguid.h>
> +#include <d3d9.h>
> +#include <dxva2api.h>
> +
> +struct picture_sys_t
> +{
> +    LPDIRECT3DSURFACE9 surface;
> +};
> +
> +struct filter_sys_t
> +{
> +    HINSTANCE                      hdecoder_dll;
> +    /* keep a reference in case the vout is released first */
> +    HINSTANCE                      d3d9_dll;
> +    IDirect3DDevice9               *d3ddev;
> +    IDirectXVideoProcessor         *processor;
> +    IDirect3DSurface9              *hw_surface;
> +};
> +
> +static picture_t *Deinterlace(filter_t *filter, picture_t *src)
> +{
> +    filter_sys_t *sys = filter->p_sys;
> +    HRESULT hr;
> +    DXVA2_VideoProcessBltParams params = {0};
> +    DXVA2_VideoSample sample = {0};
> +    D3DSURFACE_DESC dstDesc;
> +
> +    hr = IDirect3DSurface9_GetDesc( src->p_sys->surface, &dstDesc );
> +    if (FAILED(hr))
> +        return src; /* cannot deinterlace without copying fields */
> +
> +    picture_t *dst = filter_NewPicture(filter);
> +    if (dst == NULL)
> +        return src; /* cannot deinterlace without copying fields */
> +
> +    sample.SrcSurface = src->p_sys->surface;
> +    sample.SampleFormat.SampleFormat = src->b_top_field_first ?
> +                DXVA2_SampleFieldInterleavedEvenFirst :
> +                DXVA2_SampleFieldInterleavedOddFirst;
> +    sample.Start = 0;
> +    sample.End = sample.Start + 333666;
> +    sample.SampleData = DXVA2_SampleData_RFF_TFF_Present;
> +    if (src->b_top_field_first)
> +        sample.SampleData |= DXVA2_SampleData_TFF;
> +    sample.SrcRect.bottom = dstDesc.Height;
> +    sample.SrcRect.right  = dstDesc.Width;
> +    sample.DstRect        = sample.SrcRect;
> +    sample.PlanarAlpha    = DXVA2_Fixed32OpaqueAlpha();
> +
> +    params.TargetFrame = sample.Start;
> +    params.TargetRect  = sample.DstRect;
> +    params.DestData    = sample.SampleData;
> +    params.Alpha       = DXVA2_Fixed32OpaqueAlpha();
> +    params.DestFormat.SampleFormat = DXVA2_SampleProgressiveFrame;
> +    params.BackgroundColor.Cr    = 0x8000;
> +    params.BackgroundColor.Cb    = 0x8000;
> +    params.BackgroundColor.Y     = 0x1000;
> +    params.BackgroundColor.Alpha = 0xFFFF;
> +
> +    hr = IDirectXVideoProcessor_VideoProcessBlt( sys->processor,
> +                                                 sys->hw_surface,
> +                                                 &params,
> +                                                 &sample,
> +                                                 1, NULL );
> +    if (FAILED(hr))
> +        goto error;
> +
> +    hr = IDirect3DDevice9_StretchRect( sys->d3ddev,
> +                                       sys->hw_surface, NULL,
> +                                       dst->p_sys->surface, NULL,
> +                                       D3DTEXF_NONE);
> +    if (FAILED(hr))
> +        goto error;
> +
> +    picture_CopyProperties(dst, src);
> +    picture_Release(src);
> +    dst->b_progressive = true;
> +    dst->i_nb_fields = 1;
> +    return dst;
> +error:
> +    picture_Release(dst);
> +    return src;
> +}
> +
> +static int Open(vlc_object_t *obj)
> +{
> +    filter_t *filter = (filter_t *)obj;
> +    HINSTANCE hdecoder_dll = NULL;
> +    HINSTANCE d3d9_dll = NULL;
> +    HRESULT hr;
> +    picture_t *dst = NULL;
> +    GUID *processorGUIDs = NULL;
> +    GUID *processorGUID = NULL;
> +    IDirectXVideoProcessorService *processor = NULL;
> +
> +    if (filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE
> +     && filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE_10B)
> +        return VLC_EGENERIC;
> +    if (!video_format_IsSimilar(&filter->fmt_in.video, &filter->fmt_out.video))
> +        return VLC_EGENERIC;
> +
> +    d3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
> +    if (!d3d9_dll)
> +        return VLC_EGENERIC;
> +
> +    hdecoder_dll = LoadLibrary(TEXT("DXVA2.DLL"));
> +    if (!hdecoder_dll)
> +        return VLC_EGENERIC;

Leak of `d3d9_dll`; did you mean to use `goto error`?

> +
> +    dst = filter_NewPicture(filter);
> +    if (dst == NULL)
> +        return VLC_EGENERIC;

Leak of `d3d9_dll` and `hdecoder_dll`; did you mean to use `goto
error`?

> +
> +    filter_sys_t *sys = malloc(sizeof (*sys));
> +    if (unlikely(sys == NULL))
> +        goto error;
> +    memset(sys, 0, sizeof (*sys));

Strictly speaking, `memset` with `0` is not guaranteed to have
pointers in the destination object be equivalent to having assigned
`NULL` to them directly.

> +    filter->p_sys = sys;
> +
> +    HRESULT (WINAPI *CreateVideoService)(IDirect3DDevice9 *,
> +                                         REFIID riid,
> +                                         void **ppService);
> +    CreateVideoService =
> +      (void *)GetProcAddress(hdecoder_dll, "DXVA2CreateVideoService");

Missing error-check: If `GetProcAddress` fails you will have a
*null-pointer* dereference at the place where the *function-pointer*
is dereferenced (called).

> +
> +    hr = IDirect3DSurface9_GetDevice( dst->p_sys->surface, &sys->d3ddev );
> +    if (FAILED(hr))
> +        goto error;

See next comment.

> +
> +    D3DSURFACE_DESC dstDesc;
> +    hr = IDirect3DSurface9_GetDesc( dst->p_sys->surface, &dstDesc );
> +    if (FAILED(hr))
> +        goto error;

See next comment.

> +
> +    hr = CreateVideoService( sys->d3ddev, &IID_IDirectXVideoProcessorService,
> +                            (void**)&processor);
> +    if (FAILED(hr))
> +        goto error;

Is `DXVA2CreateVideoService` really guaranteed not to touch the
contents of `processor` in case of error? If it is not, then the
potential garbage will make the clean-up under the *error-label*
problematic.

Mostly asking out of curiosity, but in either case; if it is not
guaranteed something should be done about it.

> +
> +    DXVA2_VideoDesc dsc;
> +    ZeroMemory(&dsc, sizeof(dsc));
> +    dsc.SampleWidth     = dstDesc.Width;
> +    dsc.SampleHeight    = dstDesc.Height;
> +    dsc.Format          = dstDesc.Format;
> +    if (es_format_HasValidFrameRate( &filter->fmt_in )) {
> +        dsc.InputSampleFreq.Numerator   = filter->fmt_in.video.frame_rate.num;
> +        dsc.InputSampleFreq.Denominator = filter->fmt_in.video.frame_rate.den;
> +    } else {
> +        dsc.InputSampleFreq.Numerator   = 0;
> +        dsc.InputSampleFreq.Denominator = 0;
> +    }
> +    dsc.OutputFrameFreq = dsc.InputSampleFreq;
> +
> +    DXVA2_ExtendedFormat *pFormat = &dsc.SampleFormat;
> +    pFormat->SampleFormat = dst->b_top_field_first ?
> +                DXVA2_SampleFieldInterleavedEvenFirst :
> +                DXVA2_SampleFieldInterleavedOddFirst;
> +
> +    UINT count = 0;
> +    hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids( processor,
> +                                                                &dsc,
> +                                                                &count,
> +                                                                &processorGUIDs);
> +    if (FAILED(hr))
> +        goto error;
> +
> +    DXVA2_VideoProcessorCaps caps;
> +    for (UINT i=0; i<count && processorGUID==NULL; ++i) {
> +        hr = IDirectXVideoProcessorService_GetVideoProcessorCaps( processor,
> +                                                                  processorGUIDs+i,
> +                                                                  &dsc,
> +                                                                  dsc.Format,
> +                                                                  &caps);
> +        if ( SUCCEEDED(hr) && caps.DeinterlaceTechnology &&
> +             !caps.NumForwardRefSamples && !caps.NumBackwardRefSamples )
> +            processorGUID = processorGUIDs + i;
> +    }
> +
> +    if (processorGUID == NULL)
> +    {
> +        msg_Dbg(filter, "Could not find a filter to output the required format");
> +        goto error;
> +    }
> +
> +    hr = IDirectXVideoProcessorService_CreateVideoProcessor( processor,
> +                                                             processorGUID,
> +                                                             &dsc,
> +                                                             dsc.Format,
> +                                                             1,
> +                                                             &sys->processor );
> +    if (FAILED(hr))
> +        goto error;
> +
> +    hr = IDirectXVideoProcessorService_CreateSurface( processor,
> +                                                      dstDesc.Width,
> +                                                      dstDesc.Height,
> +                                                      0,
> +                                                      dstDesc.Format,
> +                                                      D3DPOOL_DEFAULT,
> +                                                      0,
> +                                                      DXVA2_VideoProcessorRenderTarget,
> +                                                      &sys->hw_surface,
> +                                                      NULL);
> +    if (FAILED(hr))
> +        goto error;
> +
> +    CoTaskMemFree(processorGUIDs);
> +    picture_Release(dst);
> +    IDirectXVideoProcessorService_Release(processor);
> +
> +    sys->hdecoder_dll = hdecoder_dll;
> +    sys->d3d9_dll     = d3d9_dll;
> +    filter->pf_video_filter = Deinterlace;
> +    filter->p_sys = sys;
> +
> +    return VLC_SUCCESS;
> +error:
> +    CoTaskMemFree(processorGUIDs);
> +    if (sys && sys->processor)
> +        IDirectXVideoProcessor_Release( sys->processor );
> +    if (processor)
> +        IDirectXVideoProcessorService_Release(processor);
> +    if (sys && sys->d3ddev)
> +        IDirect3DDevice9_Release( sys->d3ddev );
> +    if (hdecoder_dll)
> +        FreeLibrary(hdecoder_dll);
> +    if (d3d9_dll)
> +        FreeLibrary(d3d9_dll);

If the previous remarks regarding potentially missing `goto error` is
not correct, the above checks in terms of `hdecoder_dll` and
`d3d9_dll` are redundant since both are guaranteed to evaluate to
`true` (at the points where `goto error` is used).

> +    if (dst)
> +        picture_Release(dst);
> +    free(sys);
> +
> +    return VLC_EGENERIC;
> +}
> +
> +static void Close(vlc_object_t *obj)
> +{
> +    filter_t *filter = (filter_t *)obj;
> +    filter_sys_t *sys = filter->p_sys;
> +
> +    IDirect3DSurface9_Release( sys->hw_surface );
> +    IDirectXVideoProcessor_Release( sys->processor );
> +    IDirect3DDevice9_Release( sys->d3ddev );
> +    FreeLibrary( sys->hdecoder_dll );
> +    FreeLibrary( sys->d3d9_dll );
> +
> +    free(sys);
> +}
> +
> +vlc_module_begin()
> +    set_description(N_("Direct3D9 deinterlacing filter"))
> +    set_capability("video filter", 0)
> +    set_category(CAT_VIDEO)
> +    set_subcategory(SUBCAT_VIDEO_VFILTER)
> +    set_callbacks(Open, Close)
> +    add_shortcut ("deinterlace")
> +vlc_module_end()
> -- 

Best Regards,
Filip
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20170411/3e179c75/attachment.html>


More information about the vlc-devel mailing list