vlc | branch: master | Steve Lhomme <[email protected]> | Tue Apr 11 11:21:45 2017 +0200| [95ef28c403ad659a32810ba76a39222dd0d8da55] | committer: Jean-Baptiste Kempf
vout: win32: add a Direct3D9 deinterlacer for opaque surfaces Close #12855 Signed-off-by: Jean-Baptiste Kempf <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=95ef28c403ad659a32810ba76a39222dd0d8da55 --- configure.ac | 10 +- modules/MODULES_LIST | 1 + modules/video_output/Makefile.am | 6 +- modules/video_output/win32/dxva2_deinterlace.c | 290 +++++++++++++++++++++++++ 4 files changed, 305 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 540dd0fb95..0cca076a69 100644 --- a/configure.ac +++ b/configure.ac @@ -3272,8 +3272,16 @@ AS_IF([test "${enable_directx}" != "no"], [ dnl Direct3D9 AC_CHECK_HEADERS(d3d9.h, [ VLC_ADD_PLUGIN([direct3d9]) - ]) + AC_CHECK_TYPES([IDirectXVideoDecoder], + [ + VLC_ADD_PLUGIN([dxva2_deinterlace]) + ], + [AC_MSG_WARN([Could not find required IDirectXVideoDecoder in dxva2api.h])], + [#include <d3d9.h> + #include <dxva2api.h>]) + + ]) ]) dnl diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST index 340c5491b6..3205a0850b 100644 --- a/modules/MODULES_LIST +++ b/modules/MODULES_LIST @@ -124,6 +124,7 @@ $Id$ * dvdread: input module for accessing DVDs, uses libdvdread * dxa9: Convert D3D9 GPU textures to YUV planes * dxva2: DxVA2 hardware-accelerated decoding + * dxva2_deinterlace: deinterlacer for DxVA 2.0 video decoding * dynamicoverlay: subpicture filter using shared memory that can be written to by external applications * edgedetection: edge detection video filter * edummy: dummy encoder diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am index 3b9fb053f6..dcd5307a4a 100644 --- a/modules/video_output/Makefile.am +++ b/modules/video_output/Makefile.am @@ -214,9 +214,13 @@ 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)' +libdxva2_deinterlace_plugin_la_SOURCES = video_output/win32/dxva2_deinterlace.c +libdxva2_deinterlace_plugin_la_LIBADD = $(LIBCOM) +libdxva2_deinterlace_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(voutdir)' if HAVE_WIN32_DESKTOP vout_LTLIBRARIES += $(LTLIBdirect3d9) -EXTRA_LTLIBRARIES += libdirect3d9_plugin.la +vout_LTLIBRARIES += $(LTLIBdxva2_deinterlace) +EXTRA_LTLIBRARIES += libdirect3d9_plugin.la libdxva2_deinterlace_plugin.la endif libdirect3d11_plugin_la_SOURCES = video_output/win32/direct3d11.c \ diff --git a/modules/video_output/win32/dxva2_deinterlace.c b/modules/video_output/win32/dxva2_deinterlace.c new file mode 100644 index 0000000000..dcfff72bd9 --- /dev/null +++ b/modules/video_output/win32/dxva2_deinterlace.c @@ -0,0 +1,290 @@ +/***************************************************************************** + * dxva2_deinterlace.c: DxVA2 deinterlacing filter + ***************************************************************************** + * Copyright (C) 2017 Videolabs SAS + * + * Authors: Steve Lhomme <[email protected]> + * + * 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.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; + filter_sys_t *sys = NULL; + 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) + goto error; + + hdecoder_dll = LoadLibrary(TEXT("DXVA2.DLL")); + if (!hdecoder_dll) + goto error; + + dst = filter_NewPicture(filter); + if (dst == NULL) + goto error; + + sys = calloc(1, sizeof (*sys)); + if (unlikely(sys == NULL)) + goto error; + + HRESULT (WINAPI *CreateVideoService)(IDirect3DDevice9 *, + REFIID riid, + void **ppService); + CreateVideoService = + (void *)GetProcAddress(hdecoder_dll, "DXVA2CreateVideoService"); + if (CreateVideoService == NULL) + goto error; + + hr = IDirect3DSurface9_GetDevice( dst->p_sys->surface, &sys->d3ddev ); + if (FAILED(hr)) + goto error; + + D3DSURFACE_DESC dstDesc; + hr = IDirect3DSurface9_GetDesc( dst->p_sys->surface, &dstDesc ); + if (FAILED(hr)) + goto error; + + hr = CreateVideoService( sys->d3ddev, &IID_IDirectXVideoProcessorService, + (void**)&processor); + if (FAILED(hr)) + goto error; + + DXVA2_VideoDesc dsc; + ZeroMemory(&dsc, sizeof(dsc)); + dsc.SampleWidth = dstDesc.Width; + dsc.SampleHeight = dstDesc.Height; + dsc.Format = dstDesc.Format; + if (filter->fmt_in.video.i_frame_rate && filter->fmt_in.video.i_frame_rate_base) { + dsc.InputSampleFreq.Numerator = filter->fmt_in.video.i_frame_rate; + dsc.InputSampleFreq.Denominator = filter->fmt_in.video.i_frame_rate_base; + } 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 (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_("DXVA2 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() _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
