[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,
> + ¶ms,
> + &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